This is a standalone DTM firmware for Nordic mKit-based hardware. It uses the serial port to receive DTM commands (e.g. through nRF Go Studio). By default the ports are set to USBTX and USBRX, but can be re-configured in main.cpp.

Dependencies:   BLE_API mbed nRF51822

Files at this revision

API Documentation at this revision

Comitter:
pvaibhav
Date:
Wed Jan 14 12:36:59 2015 +0000
Commit message:
Initial commit of working DTM mode via serial port

Changed in this revision

BLE_API.lib Show annotated file Show diff for this revision Revisions of this file
ble_dtm.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
nRF51822.lib Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r a2cffc867df4 BLE_API.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_API.lib	Wed Jan 14 12:36:59 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#fb2a891a0d98
diff -r 000000000000 -r a2cffc867df4 ble_dtm.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ble_dtm.cpp	Wed Jan 14 12:36:59 2015 +0000
@@ -0,0 +1,628 @@
+
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "ble_dtm.h"
+#include <stdbool.h>
+#include <string.h>
+#include "nrf51.h"
+#include "nrf51_bitfields.h"
+
+#define DTM_HEADER_OFFSET        0                                         /**< Index where the header of the pdu is located. */
+#define DTM_HEADER_SIZE          2                                         /**< Size of PDU header. */
+#define DTM_PAYLOAD_MAX_SIZE     37                                        /**< Maximum payload size allowed during dtm execution. */
+#define DTM_LENGTH_OFFSET        (DTM_HEADER_OFFSET + 1)                   /**< Index where the length of the payload is encoded. */
+#define DTM_PDU_MAX_MEMORY_SIZE  (DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE)  /**< Maximum PDU size allowed during dtm execution. */
+
+/**@details The UART poll cycle in micro seconds. 
+ *          Baud rate of 19200 bits / second, and 8 data bits, 1 start/stop bit, no flow control, 
+ *          give the time to transmit a byte: 10 bits * 1/19200 = approx: 520 us. 
+ *
+ *          To ensure no loss of bytes, the UART should be polled every 260 us. 
+ *
+ * @note If UART bit rate is changed, this value should be recalculated as well.
+ */
+#define UART_POLL_CYCLE  260
+
+#define RX_MODE          true   /**< Constant defining RX mode for radio during dtm test. */
+#define TX_MODE          false  /**< Constant defining TX mode for radio during dtm test. */
+
+#define PHYS_CH_MAX      39     /**< Maximum number of valid channels in BLE. */
+
+// Values that for now are "constants" - they could be configured by a function setting them,
+// but most of these are set by the BLE DTM standard, so changing them is not relevant.
+#define RFPHY_TEST_0X0F_REF_PATTERN  0x0f  /**<  RF-PHY test packet patterns, for the repeated octet packets. */
+#define RFPHY_TEST_0X55_REF_PATTERN  0x55  /**<  RF-PHY test packet patterns, for the repeated octet packets. */
+
+#define PRBS9_CONTENT {0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b,  \
+                       0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23,  \
+                       0x2,  0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b,  \
+                       0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca,  \
+                       0xc,  0x18, 0x53, 0x2c, 0xfd}                         /**< The PRBS9 sequence used as packet payload. */
+
+/**@brief Structure holding the PDU used for transmitting/receiving a PDU.
+ */
+typedef struct
+{
+    uint8_t content[DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE];                 /**< PDU packet content. */
+} pdu_type_t;
+
+/**@brief States used for the DTM test implementation.
+ */
+typedef enum
+{
+    STATE_UNINITIALIZED,                                                     /**< The DTM is uninitialized. */
+    STATE_IDLE,                                                              /**< State when system has just initialized, or current test has completed. */
+    STATE_TRANSMITTER_TEST,                                                  /**< State used when a DTM Transmission test is running. */
+    STATE_CARRIER_TEST,                                                      /**< State used when a DTM Carrier test is running (Vendor specific test). */
+    STATE_RECEIVER_TEST                                                      /**< State used when a DTM Receive test is running. */
+} state_t;
+
+// Internal variables set as side effects of commands or events.
+static state_t           m_state = STATE_UNINITIALIZED;                      /**< Current machine state. */
+static uint16_t          m_rx_pkt_count;                                     /**< Number of valid packets received. */
+static pdu_type_t        m_pdu;                                              /**< PDU to be sent. */
+static uint16_t          m_event;                                            /**< current command status - initially "ok", may be set if error detected, or to packet count. */
+static bool              m_new_event;                                        /**< Command has been processed - number of not yet reported event bytes. */
+static uint8_t           m_packet_length;                                    /**< Payload length of transmitted PDU, bits 2:7 of 16-bit dtm command. */
+static dtm_pkt_type_t    m_packet_type;                                      /**< Bits 0..1 of 16-bit transmit command, or 0xFFFFFFFF. */
+static dtm_freq_t        m_phys_ch;                                          /**< 0..39 physical channel number (base 2402 MHz, Interval 2 MHz), bits 8:13 of 16-bit dtm command. */
+static uint32_t          m_current_time = 0;                                 /**< Counter for interrupts from timer to ensure that the 2 bytes forming a DTM command are received within the time window. */
+
+// Nordic specific configuration values (not defined by BLE standard).
+// Definition of initial values found in ble_dtm.h
+static int32_t           m_tx_power          = DEFAULT_TX_POWER;             /**< TX power for transmission test, default to maximum value (+4 dBm). */
+static NRF_TIMER_Type *  mp_timer            = DEFAULT_TIMER;                /**< Timer to be used. */
+static IRQn_Type         m_timer_irq         = DEFAULT_TIMER_IRQn;           /**< which interrupt line to clear on every timeout */
+
+static uint8_t const     m_prbs_content[]    = PRBS9_CONTENT;                /**< Pseudo-random bit sequence defined by the BLE standard. */
+static uint8_t           m_packetHeaderLFlen = 8;                            /**< Length of length field in packet Header (in bits). */
+static uint8_t           m_packetHeaderS0len = 1;                            /**< Length of S0 field in packet Header (in bytes). */
+static uint8_t           m_packetHeaderS1len = 0;                            /**< Length of S1 field in packet Header (in bits). */
+static uint8_t           m_crcConfSkipAddr   = 1;                            /**< Leave packet address field out of CRC calculation. */
+static uint8_t           m_static_length     = 0;                            /**< Number of bytes sent in addition to the var.length payload. */
+static uint32_t          m_balen             = 3;                            /**< Base address length in bytes. */
+static uint32_t          m_endian            = RADIO_PCNF1_ENDIAN_Little;    /**< On air endianess of packet, this applies to the S0, LENGTH, S1 and the PAYLOAD fields. */
+static uint32_t          m_whitening         = RADIO_PCNF1_WHITEEN_Disabled; /**< Whitening disabled. */
+static uint8_t           m_crcLength         = RADIO_CRCCNF_LEN_Three;       /**< CRC Length (in bytes). */
+static uint32_t          m_address           = 0x71764129;                   /**< Address. */
+static uint32_t          m_crc_poly          = 0x0000065B;                   /**< CRC polynomial. */
+static uint32_t          m_crc_init          = 0x00555555;                   /**< Initial value for CRC calculation. */
+static uint8_t           m_radio_mode        = RADIO_MODE_MODE_Ble_1Mbit;    /**< nRF51 specific radio mode vale. */
+static uint32_t          m_txIntervaluS      = 625;                          /**< Time between start of Tx packets (in uS). */
+
+
+/**@brief Function for verifying that a received PDU has the expected structure and content.
+ */
+static bool check_pdu(void)
+{
+    uint8_t        k;                // Byte pointer for running through PDU payload
+    uint8_t        pattern;          // Repeating octet value in payload
+    dtm_pkt_type_t pdu_packet_type;  // Note: PDU packet type is a 4-bit field in HCI, but 2 bits in BLE DTM
+    uint8_t        length;
+
+    pdu_packet_type = (dtm_pkt_type_t)(m_pdu.content[DTM_HEADER_OFFSET] & 0x0F);
+    length          = m_pdu.content[DTM_LENGTH_OFFSET];
+
+    if ((pdu_packet_type > (dtm_pkt_type_t)PACKET_TYPE_MAX) || (length > DTM_PAYLOAD_MAX_SIZE))
+    {
+        return false;
+    }
+
+    if (pdu_packet_type == DTM_PKT_PRBS9)
+    {
+        // Payload does not consist of one repeated octet; must compare ir with entire block into
+        return (memcmp(m_pdu.content+DTM_HEADER_SIZE, m_prbs_content, length) == 0);
+    }
+
+    if (pdu_packet_type == DTM_PKT_0X0F)
+    {
+        pattern = RFPHY_TEST_0X0F_REF_PATTERN;
+    }
+    else
+    {
+        pattern = RFPHY_TEST_0X55_REF_PATTERN;
+    }
+
+    for (k = 0; k < length; k++)
+    {
+        // Check repeated pattern filling the PDU payload 
+        if (m_pdu.content[k + 2] != pattern)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+
+/**@brief Function for turning off the radio after a test.
+ *        Also called after test done, to be ready for next test.
+ */
+static void radio_reset(void)
+{
+    NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk | PPI_CHENCLR_CH1_Msk;
+
+    NRF_RADIO->SHORTS          = 0;
+    NRF_RADIO->EVENTS_DISABLED = 0;
+    NRF_RADIO->TASKS_DISABLE   = 1;
+
+    while (NRF_RADIO->EVENTS_DISABLED == 0)
+    {
+        // Do nothing
+    }
+
+    NRF_RADIO->EVENTS_DISABLED = 0;
+    NRF_RADIO->TASKS_RXEN      = 0;
+    NRF_RADIO->TASKS_TXEN      = 0;
+
+    m_rx_pkt_count = 0;
+}
+
+
+/**@brief Function for initializing the radio for DTM.
+ */
+static uint32_t radio_init(void)
+{
+    // Handle BLE Radio tuning parameters from production for DTM if required.
+    // Only needed for DTM without SoftDevice, as the SoftDevice normally handles this.
+    // PCN-083.
+    if ( ((NRF_FICR->OVERRIDEEN) & FICR_OVERRIDEEN_BLE_1MBIT_Msk) == FICR_OVERRIDEEN_BLE_1MBIT_Override)
+    {
+        NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
+        NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
+        NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
+        NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
+        NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4]| (RADIO_OVERRIDE4_ENABLE_Pos << RADIO_OVERRIDE4_ENABLE_Enabled);
+    }
+
+    // Initializing code below is quite generic - for BLE, the values are fixed, and expressions
+    // are constant. Non-constant values are essentially set in radio_prepare().
+    if (((m_tx_power & 0x03) != 0)           ||      // tx_power should be a multiple of 4
+         ((m_tx_power & 0xffffff00) != 0)    ||      // Upper 24 bits are required to be zeroed
+         ((int8_t)m_tx_power > 4)            ||      // Max tx_power is +4 dBm
+         ((int8_t)(m_tx_power & 0xff) < -40) ||      // Min tx_power is -40 dBm
+         (m_radio_mode > RADIO_MODE_MODE_Ble_1Mbit)  // Values 0-2: Proprietary mode, 3 (last valid): BLE
+       )
+    {
+        return DTM_ERROR_ILLEGAL_CONFIGURATION;
+    }
+
+    // Turn off radio before configuring it
+    radio_reset();
+
+    NRF_RADIO->TXPOWER = m_tx_power;
+    NRF_RADIO->MODE    = m_radio_mode << RADIO_MODE_MODE_Pos;
+
+    // Set the access address, address0/prefix0 used for both Rx and Tx address
+    NRF_RADIO->PREFIX0    &= ~RADIO_PREFIX0_AP0_Msk;
+    NRF_RADIO->PREFIX0    |= (m_address >> 24) & RADIO_PREFIX0_AP0_Msk;
+    NRF_RADIO->BASE0       = m_address << 8;
+    NRF_RADIO->RXADDRESSES = RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos;
+    NRF_RADIO->TXADDRESS   = (0x00 << RADIO_TXADDRESS_TXADDRESS_Pos) & RADIO_TXADDRESS_TXADDRESS_Msk;
+
+    // Configure CRC calculation
+    NRF_RADIO->CRCCNF = (m_crcConfSkipAddr << RADIO_CRCCNF_SKIP_ADDR_Pos) |
+                        (m_crcLength << RADIO_CRCCNF_LEN_Pos);
+
+    NRF_RADIO->PCNF0 = (m_packetHeaderS1len << RADIO_PCNF0_S1LEN_Pos) |
+                       (m_packetHeaderS0len << RADIO_PCNF0_S0LEN_Pos) |
+                       (m_packetHeaderLFlen << RADIO_PCNF0_LFLEN_Pos);
+
+    NRF_RADIO->PCNF1 = (m_whitening          << RADIO_PCNF1_WHITEEN_Pos) |
+                       (m_endian             << RADIO_PCNF1_ENDIAN_Pos)  |
+                       (m_balen              << RADIO_PCNF1_BALEN_Pos)   |
+                       (m_static_length      << RADIO_PCNF1_STATLEN_Pos) |
+                       (DTM_PAYLOAD_MAX_SIZE << RADIO_PCNF1_MAXLEN_Pos);
+
+    return DTM_SUCCESS;
+}
+
+
+/**@brief Function for preparing the radio. At start of each test: Turn off RF, clear interrupt flags of RF, initialize the radio
+ *        at given RF channel.
+ *
+ *@param[in] rx     boolean indicating if radio should be prepared in rx mode (true) or tx mode.
+ */
+static void radio_prepare(bool rx)
+{
+    NRF_RADIO->TEST         = 0;
+    NRF_RADIO->CRCPOLY      = m_crc_poly;
+    NRF_RADIO->CRCINIT      = m_crc_init;
+    NRF_RADIO->FREQUENCY    = (m_phys_ch << 1) + 2;                  // Actual frequency (MHz): 2400 + register value
+    NRF_RADIO->PACKETPTR    = (uint32_t)&m_pdu;                      // Setting packet pointer will start the radio
+    NRF_RADIO->EVENTS_READY = 0;
+    NRF_RADIO->SHORTS       = (1 << RADIO_SHORTS_READY_START_Pos) |  // Shortcut between READY event and START task
+                              (1 << RADIO_SHORTS_END_DISABLE_Pos);   // Shortcut between END event and DISABLE task
+
+    if (rx)
+    {
+        NRF_RADIO->EVENTS_END = 0;
+        NRF_RADIO->TASKS_RXEN = 1;  // shorts will start radio in RX mode when it is ready
+    }
+    else // tx
+    {
+        NRF_RADIO->TXPOWER = m_tx_power;
+    }
+}
+
+
+/**@brief Function for terminating the ongoing test (if any) and closing down the radio.
+ */
+static void dtm_test_done(void)
+{
+    NRF_RADIO->TEST = 0;
+    NRF_PPI->CHENCLR = 0x01;
+    NRF_PPI->CH[0].EEP = 0;     // Break connection from timer to radio to stop transmit loop
+    NRF_PPI->CH[0].TEP = 0;
+
+    radio_reset();
+    m_state = STATE_IDLE;
+}
+
+
+/**@brief Function for configuring the timer for 625us cycle time.
+ */
+static uint32_t timer_init(void)
+{
+    // Use 16MHz from external crystal
+    // This could be customized for RC/Xtal, or even to use a 32 kHz crystal
+    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
+    NRF_CLOCK->TASKS_HFCLKSTART    = 1;
+
+    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
+    {
+        // Do nothing while waiting for the clock to start
+    }
+
+    mp_timer->TASKS_STOP        = 1;                      // Stop timer, if it was running
+    mp_timer->TASKS_CLEAR       = 1;
+    mp_timer->MODE              = TIMER_MODE_MODE_Timer;  // Timer mode (not counter)
+    mp_timer->EVENTS_COMPARE[0] = 0;                      // clean up possible old events
+    mp_timer->EVENTS_COMPARE[1] = 0;
+    mp_timer->EVENTS_COMPARE[2] = 0;
+    mp_timer->EVENTS_COMPARE[3] = 0;
+
+    // Timer is polled, but enable the compare0 interrupt in order to wakeup from CPU sleep
+    mp_timer->INTENSET    = TIMER_INTENSET_COMPARE0_Msk;
+    mp_timer->SHORTS      = 1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos;  // Clear the count every time timer reaches the CCREG0 count
+    mp_timer->PRESCALER   = 4;                                     // Input clock is 16MHz, timer clock = 2 ^ prescale -> interval 1us
+    mp_timer->CC[0]       = m_txIntervaluS;                        // 625uS with 1MHz clock to the timer
+    mp_timer->CC[1]       = UART_POLL_CYCLE;                       // 260uS with 1MHz clock to the timer
+    mp_timer->TASKS_START = 1;                                     // Start the timer - it will be running continuously
+    m_current_time        = 0;
+    return DTM_SUCCESS;
+}
+
+
+/**@brief Function for handling vendor specific commands.
+ *        Used when packet type is set to Vendor specific.
+ *        The length field is used for encoding vendor specific command.
+ *        The frequency field is used for encoding vendor specific options to the command.
+ *
+ * @param[in]   vendor_cmd      Vendor specific command to be executed.
+ * @param[in]   vendor_option   Vendor specific option to the vendor command.
+ *
+ * @return      DTM_SUCCESS or one of the DTM_ERROR_ values
+ */
+static uint32_t dtm_vendor_specific_pkt(uint32_t vendor_cmd, dtm_freq_t vendor_option)
+{
+    switch (vendor_cmd)
+    {
+        // nRFgo Studio uses CARRIER_TEST_STUDIO to indicate a continuous carrier without
+        // a modulated signal.
+        case CARRIER_TEST:
+        case CARRIER_TEST_STUDIO:
+            // Not a packet type, but used to indicate that a continuous carrier signal
+            // should be transmitted by the radio.
+            radio_prepare(TX_MODE);
+            NRF_RADIO->TEST = (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos) |
+                              (RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos);
+
+            // Shortcut between READY event and START task
+            NRF_RADIO->SHORTS = 1 << RADIO_SHORTS_READY_START_Pos;
+
+            // Shortcut will start radio in Tx mode when it is ready
+            NRF_RADIO->TASKS_TXEN = 1;
+            m_state               = STATE_CARRIER_TEST;
+            break;
+
+        case SET_TX_POWER:
+            if (!dtm_set_txpower(vendor_option))
+            {
+                return DTM_ERROR_ILLEGAL_CONFIGURATION;
+            }
+            break;
+
+        case SELECT_TIMER:
+            if (!dtm_set_timer(vendor_option))
+            {
+                return DTM_ERROR_ILLEGAL_CONFIGURATION;
+            }
+            break;
+    }
+    // Event code is unchanged, successful
+    return DTM_SUCCESS;
+}
+
+
+uint32_t dtm_init(void)
+{
+    if ((timer_init() != DTM_SUCCESS) || (radio_init() != DTM_SUCCESS))
+    {
+        return DTM_ERROR_ILLEGAL_CONFIGURATION;
+    }
+    m_new_event = false;
+    m_state     = STATE_IDLE;
+
+    // Enable wake-up on event
+    SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
+
+    return DTM_SUCCESS;
+}
+
+
+uint32_t dtm_wait(void)
+{
+    // Enable wake-up on event
+    SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
+
+    for (;;)
+    {
+        // Event may be the reception of a packet - 
+        // handle radio first, to give it highest priority:
+        if (NRF_RADIO->EVENTS_END != 0)
+        {
+            NRF_RADIO->EVENTS_END = 0;
+            NVIC_ClearPendingIRQ(RADIO_IRQn);
+
+            if (m_state == STATE_RECEIVER_TEST)
+            {
+                NRF_RADIO->TASKS_RXEN = 1;
+                if ((NRF_RADIO->CRCSTATUS == 1) && check_pdu())
+                {
+                    // Count the number of successfully received packets
+                    m_rx_pkt_count++;
+                }
+                // Note that failing packets are simply ignored (CRC or contents error).
+
+                // Zero fill all pdu fields to avoid stray data
+                memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
+            }
+            // If no RECEIVER_TEST is running, ignore incoming packets (but do clear IRQ!)
+        }
+
+        // Check for timeouts:
+        if (mp_timer->EVENTS_COMPARE[0] != 0)
+        {
+            mp_timer->EVENTS_COMPARE[0] = 0;
+        }
+        else if (mp_timer->EVENTS_COMPARE[1] != 0)
+        {
+            // Reset timeout event flag for next iteration.
+            mp_timer->EVENTS_COMPARE[1] = 0;
+            NVIC_ClearPendingIRQ(m_timer_irq);
+            return ++m_current_time;
+        }
+
+        // Other events: No processing
+    }
+}
+
+
+uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload)
+{
+    // Save specified packet in static variable for tx/rx functions to use.
+    // Note that BLE conformance testers always use full length packets.
+    m_packet_length = ((uint8_t)length & 0xFF);
+    m_packet_type   = payload;
+    m_phys_ch       = freq;
+
+    // Clean out any non-retrieved event that might linger from an earlier test
+    m_new_event     = true;
+ 
+    // Set default event; any error will set it to LE_TEST_STATUS_EVENT_ERROR
+    m_event         = LE_TEST_STATUS_EVENT_SUCCESS;
+    
+    if (m_state == STATE_UNINITIALIZED)
+    {
+        // Application has not explicitly initialized DTM, 
+        return DTM_ERROR_UNINITIALIZED;
+    }
+
+    if (cmd == LE_RESET)
+    {
+        // Note that timer will continue running after a reset
+        dtm_test_done();
+        return DTM_SUCCESS;
+    }
+
+    if (cmd == LE_TEST_END)
+    {
+        if (m_state == STATE_IDLE)
+        {
+            // Sequencing error - only rx or tx test may be ended!
+            m_event = LE_TEST_STATUS_EVENT_ERROR;
+            return DTM_ERROR_INVALID_STATE;
+        }
+        m_event = LE_PACKET_REPORTING_EVENT | m_rx_pkt_count;
+        dtm_test_done();
+        return DTM_SUCCESS;
+    }
+
+    if (m_state != STATE_IDLE)
+    {
+        // Sequencing error - only TEST_END/RESET are legal while test is running
+        // Note: State is unchanged; ongoing test not affected
+        m_event = LE_TEST_STATUS_EVENT_ERROR;               
+        return DTM_ERROR_INVALID_STATE;   
+    }
+
+    if (m_phys_ch > PHYS_CH_MAX)
+    {
+        // Parameter error
+        // Note: State is unchanged; ongoing test not affected
+        m_event = LE_TEST_STATUS_EVENT_ERROR;               
+        return DTM_ERROR_ILLEGAL_CHANNEL;
+    }
+
+    m_rx_pkt_count = 0;
+
+    if (cmd == LE_RECEIVER_TEST)
+    {
+        // Zero fill all pdu fields to avoid stray data from earlier test run
+        memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
+        radio_prepare(RX_MODE);                      // Reinitialize "everything"; RF interrupts OFF
+        m_state = STATE_RECEIVER_TEST;
+        return DTM_SUCCESS;
+    }
+
+    if (cmd == LE_TRANSMITTER_TEST)
+    {
+        if (m_packet_length > DTM_PAYLOAD_MAX_SIZE)
+        {
+            // Parameter error
+            m_event = LE_TEST_STATUS_EVENT_ERROR;
+            return DTM_ERROR_ILLEGAL_LENGTH;
+        }
+
+        // Note that PDU uses 4 bits even though BLE DTM uses only 2 (the HCI SDU uses all 4)
+        m_pdu.content[DTM_HEADER_OFFSET] = ((uint8_t)m_packet_type & 0x0F); 
+        m_pdu.content[DTM_LENGTH_OFFSET] = m_packet_length;
+        
+        switch (m_packet_type)
+        {
+            case DTM_PKT_PRBS9:
+                // Non-repeated, must copy entire pattern to PDU
+                memcpy(m_pdu.content + DTM_HEADER_SIZE, m_prbs_content, length);
+                break;
+                
+            case DTM_PKT_0X0F:
+                // Bit pattern 00001111 repeated
+                memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X0F_REF_PATTERN, length);
+                break;
+                
+            case DTM_PKT_0X55:
+                // Bit pattern 01010101 repeated
+                memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X55_REF_PATTERN, length);
+                break;
+                
+            case DTM_PKT_VENDORSPECIFIC:
+                // The length field is for indicating the vendor specific command to execute.
+                // The frequency field is used for vendor specific options to the command.
+                return dtm_vendor_specific_pkt(length, freq);
+                
+            default:
+                // Parameter error 
+                m_event = LE_TEST_STATUS_EVENT_ERROR;         
+                return DTM_ERROR_ILLEGAL_CONFIGURATION;
+        }
+
+        // Initialize CRC value, set channel:
+        radio_prepare(TX_MODE);
+        // Configure PPI so that timer will activate radio every 625 us
+        NRF_PPI->CH[0].EEP = (uint32_t)&mp_timer->EVENTS_COMPARE[0];
+        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN;
+        NRF_PPI->CHENSET   = 0x01;
+        m_state            = STATE_TRANSMITTER_TEST;
+    }
+    return DTM_SUCCESS;
+}
+
+
+bool dtm_event_get(dtm_event_t *p_dtm_event)
+{
+    bool was_new = m_new_event;
+    // mark the current event as retrieved
+    m_new_event  = false;
+    *p_dtm_event = m_event;
+    // return value indicates whether this value was already retrieved.
+    return was_new;
+}
+
+
+// =================================================================================================
+// Configuration functions (only for parameters not definitely determined by the BLE DTM standard).
+// These functions return true if successful, false if value could not be set
+
+
+/**@brief Function for configuring the output power for transmitter test.
+          This function may be called directly, or through dtm_cmd() specifying
+          DTM_PKT_VENDORSPECIFIC as payload, SET_TX_POWER as length, and the dBm value as frequency.
+ */
+bool dtm_set_txpower(uint32_t new_tx_power)
+{
+    // radio->TXPOWER register is 32 bits, low octet a signed value, upper 24 bits zeroed
+    int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);
+    
+    if (m_state > STATE_IDLE)
+    {
+        // radio must be idle to change the tx power
+        return false;
+    }
+
+    if ((new_power8 > 4) || (new_power8 < -40))
+    {
+        // Parameter outside valid range: nRF radio is restricted to the range -40 dBm to +4 dBm
+        return false;
+    }
+
+    if (new_tx_power & 0x03) 
+    {
+        // Parameter error: The nRF51 radio requires settings that are a multiple of 4.
+        return false;
+    }
+    m_tx_power = new_tx_power;
+
+    return true;
+}
+
+
+/**@brief Function for selecting a timer resource.
+ *        This function may be called directly, or through dtm_cmd() specifying
+ *        DTM_PKT_VENDORSPECIFIC as payload, SELECT_TIMER as length, and the timer as freq
+ *
+ * @param[in] new_timer     Timer id for the timer to use: 0, 1, or 2.
+ *
+ * @return true if the timer was successfully changed, false otherwise.
+ */
+bool dtm_set_timer(uint32_t new_timer)
+{
+    if (m_state > STATE_IDLE)
+    {
+        return false;
+    }
+    if (new_timer == 0)
+    {
+        mp_timer    = NRF_TIMER0;
+        m_timer_irq = TIMER0_IRQn;
+    }
+    else if (new_timer == 1)
+    {
+        mp_timer    = NRF_TIMER1;
+        m_timer_irq = TIMER1_IRQn;
+    }
+    else if (new_timer == 2)
+    {
+        mp_timer    = NRF_TIMER2;
+        m_timer_irq = TIMER2_IRQn;
+    }
+    else
+    {
+        // Parameter error: Only TIMER 0, 1, 2 provided by nRF51   
+        return false;
+    }
+    // New timer has been selected:
+    return true;
+}
+
+/// @} 
diff -r 000000000000 -r a2cffc867df4 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jan 14 12:36:59 2015 +0000
@@ -0,0 +1,167 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "mbed.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "nrf51.h"
+#include "nrf51_bitfields.h"
+#include "ble_dtm.h"
+#include "nrf_gpio.h"
+
+// Configuration parameters.
+#define BITRATE         UART_BAUDRATE_BAUDRATE_Baud19200  /**< Serial bitrate on the UART */
+#define TX_PIN_NUMBER   USBTX /**< Use proper value for your hardware */
+#define RX_PIN_NUMBER   USBRX /**< Use proper value for your hardware */
+#define MAX_ITERATIONS_NEEDED_FOR_NEXT_BYTE 21
+/**@brief Function for UART initialization.
+ */
+static void uart_init(void)
+{
+    // Configure UART0 pins.
+    nrf_gpio_cfg_output(TX_PIN_NUMBER);
+    nrf_gpio_cfg_input(RX_PIN_NUMBER, NRF_GPIO_PIN_NOPULL);
+
+    NRF_UART0->PSELTXD       = TX_PIN_NUMBER;
+    NRF_UART0->PSELRXD       = RX_PIN_NUMBER;
+    NRF_UART0->BAUDRATE      = BITRATE;
+
+    // Clean out possible events from earlier operations
+    NRF_UART0->EVENTS_RXDRDY = 0;
+    NRF_UART0->EVENTS_TXDRDY = 0;
+    NRF_UART0->EVENTS_ERROR  = 0;
+
+    // Activate UART.
+    NRF_UART0->ENABLE        = UART_ENABLE_ENABLE_Enabled;
+    NRF_UART0->INTENSET      = 0;
+    NRF_UART0->TASKS_STARTTX = 1;
+    NRF_UART0->TASKS_STARTRX = 1;
+}
+
+
+/**@brief Function for splitting UART command bit fields into separate command parameters for the DTM library.
+*
+ * @param[in]   command   The packed UART command.
+ * @return      result status from dtmlib.
+ */
+static uint32_t dtm_cmd_put(uint16_t command)
+{
+    dtm_cmd_t      command_code = (command >> 14) & 0x03;
+    dtm_freq_t     freq         = (command >> 8) & 0x3F;
+    uint32_t       length       = (command >> 2) & 0x3F;
+    dtm_pkt_type_t payload      = command & 0x03;
+
+    // Check for Vendor Specific payload.
+    if (payload == 0x03) {
+        /* Note that in a HCI adaption layer, as well as in the DTM PDU format,
+           the value 0x03 is a distinct bit pattern (PRBS15). Even though BLE does not
+           support PRBS15, this implementation re-maps 0x03 to DTM_PKT_VENDORSPECIFIC,
+           to avoid the risk of confusion, should the code be extended to greater coverage.
+        */
+        payload = DTM_PKT_VENDORSPECIFIC;
+    }
+    return dtm_cmd(command_code, freq, length, payload);
+}
+
+/**@brief Function for application main entry.
+ *
+ * @details This function serves as an adaptation layer between a 2-wire UART interface and the
+ *          dtmlib. After initialization, DTM commands submitted through the UART are forwarded to
+ *          dtmlib and events (i.e. results from the command) is reported back through the UART.
+ */
+int main(void)
+{
+    uint32_t    current_time;
+    uint32_t    dtm_error_code;
+    uint32_t    msb_time          = 0;     // Time when MSB of the DTM command was read. Used to catch stray bytes from "misbehaving" testers.
+    bool        is_msb_read       = false; // True when MSB of the DTM command has been read and the application is waiting for LSB.
+    uint16_t    dtm_cmd_from_uart = 0;     // Packed command containing command_code:freqency:length:payload in 2:6:6:2 bits.
+    uint8_t     rx_byte;                   // Last byte read from UART.
+    dtm_event_t result;                    // Result of a DTM operation.
+
+    uart_init();
+
+    // Turn default LED on to indicate power
+    nrf_gpio_cfg_output(LED1);
+    nrf_gpio_pin_set(LED1);
+
+    dtm_error_code = dtm_init();
+    if (dtm_error_code != DTM_SUCCESS) {
+        // If DTM cannot be correctly initialized, then we just return.
+        return -1;
+    }
+
+    for (;;) {
+        // Will return every timeout, 625 us.
+        current_time = dtm_wait();
+
+        if (NRF_UART0->EVENTS_RXDRDY == 0) {
+            // Nothing read from the UART.
+            continue;
+        }
+        NRF_UART0->EVENTS_RXDRDY = 0;
+        rx_byte                  = (uint8_t)NRF_UART0->RXD;
+
+        if (!is_msb_read) {
+            // This is first byte of two-byte command.
+            is_msb_read       = true;
+            dtm_cmd_from_uart = ((dtm_cmd_t)rx_byte) << 8;
+            msb_time          = current_time;
+
+            // Go back and wait for 2nd byte of command word.
+            continue;
+        }
+
+        // This is the second byte read; combine it with the first and process command
+        if (current_time > (msb_time + MAX_ITERATIONS_NEEDED_FOR_NEXT_BYTE)) {
+            // More than ~5mS after msb: Drop old byte, take the new byte as MSB.
+            // The variable is_msb_read will remains true.
+            // Go back and wait for 2nd byte of the command word.
+            dtm_cmd_from_uart = ((dtm_cmd_t)rx_byte) << 8;
+            msb_time          = current_time;
+            continue;
+        }
+
+        // 2-byte UART command received.
+        is_msb_read        = false;
+        dtm_cmd_from_uart |= (dtm_cmd_t)rx_byte;
+
+        if (dtm_cmd_put(dtm_cmd_from_uart) != DTM_SUCCESS) {
+            // Extended error handling may be put here.
+            // Default behavior is to return the event on the UART (see below);
+            // the event report will reflect any lack of success.
+        }
+
+        // Retrieve result of the operation. This implementation will busy-loop
+        // for the duration of the byte transmissions on the UART.
+        if (dtm_event_get(&result)) {
+            // Report command status on the UART.
+            // Transmit MSB of the result.
+            NRF_UART0->TXD = (result >> 8) & 0xFF;
+            // Wait until MSB is sent.
+            while (NRF_UART0->EVENTS_TXDRDY != 1) {
+                // Do nothing.
+            }
+            NRF_UART0->EVENTS_TXDRDY = 0;
+
+            // Transmit LSB of the result.
+            NRF_UART0->TXD = result & 0xFF;
+            // Wait until LSB is sent.
+            while (NRF_UART0->EVENTS_TXDRDY != 1) {
+                // Do nothing.
+            }
+            NRF_UART0->EVENTS_TXDRDY = 0;
+        }
+    }
+}
+
+/// @}
diff -r 000000000000 -r a2cffc867df4 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jan 14 12:36:59 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5
\ No newline at end of file
diff -r 000000000000 -r a2cffc867df4 nRF51822.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF51822.lib	Wed Jan 14 12:36:59 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#17fe69405098