Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed nRF51822
Diff: ble_dtm.cpp
- Revision:
- 0:a2cffc867df4
--- /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;
+}
+
+/// @}