ble_dtm.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. #include "ble_dtm.h"
  13. #include <stdbool.h>
  14. #include <string.h>
  15. #include "nrf.h"
  16. #define DTM_HEADER_OFFSET 0 /**< Index where the header of the pdu is located. */
  17. #define DTM_HEADER_SIZE 2 /**< Size of PDU header. */
  18. #define DTM_PAYLOAD_MAX_SIZE 37 /**< Maximum payload size allowed during dtm execution. */
  19. #define DTM_LENGTH_OFFSET (DTM_HEADER_OFFSET + 1) /**< Index where the length of the payload is encoded. */
  20. #define DTM_PDU_MAX_MEMORY_SIZE (DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE) /**< Maximum PDU size allowed during dtm execution. */
  21. /**@details The UART poll cycle in micro seconds.
  22. * Baud rate of 19200 bits / second, and 8 data bits, 1 start/stop bit, no flow control,
  23. * give the time to transmit a byte: 10 bits * 1/19200 = approx: 520 us.
  24. *
  25. * To ensure no loss of bytes, the UART should be polled every 260 us.
  26. *
  27. * @note If UART bit rate is changed, this value should be recalculated as well.
  28. */
  29. #define UART_POLL_CYCLE 260
  30. #define RX_MODE true /**< Constant defining RX mode for radio during dtm test. */
  31. #define TX_MODE false /**< Constant defining TX mode for radio during dtm test. */
  32. #define PHYS_CH_MAX 39 /**< Maximum number of valid channels in BLE. */
  33. // Values that for now are "constants" - they could be configured by a function setting them,
  34. // but most of these are set by the BLE DTM standard, so changing them is not relevant.
  35. #define RFPHY_TEST_0X0F_REF_PATTERN 0x0f /**< RF-PHY test packet patterns, for the repeated octet packets. */
  36. #define RFPHY_TEST_0X55_REF_PATTERN 0x55 /**< RF-PHY test packet patterns, for the repeated octet packets. */
  37. #define PRBS9_CONTENT {0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b, \
  38. 0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23, \
  39. 0x2, 0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b, \
  40. 0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca, \
  41. 0xc, 0x18, 0x53, 0x2c, 0xfd} /**< The PRBS9 sequence used as packet payload. */
  42. /**@brief Structure holding the PDU used for transmitting/receiving a PDU.
  43. */
  44. typedef struct
  45. {
  46. uint8_t content[DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE]; /**< PDU packet content. */
  47. } pdu_type_t;
  48. /**@brief States used for the DTM test implementation.
  49. */
  50. typedef enum
  51. {
  52. STATE_UNINITIALIZED, /**< The DTM is uninitialized. */
  53. STATE_IDLE, /**< State when system has just initialized, or current test has completed. */
  54. STATE_TRANSMITTER_TEST, /**< State used when a DTM Transmission test is running. */
  55. STATE_CARRIER_TEST, /**< State used when a DTM Carrier test is running (Vendor specific test). */
  56. STATE_RECEIVER_TEST /**< State used when a DTM Receive test is running. */
  57. } state_t;
  58. // Internal variables set as side effects of commands or events.
  59. static state_t m_state = STATE_UNINITIALIZED; /**< Current machine state. */
  60. static uint16_t m_rx_pkt_count; /**< Number of valid packets received. */
  61. static pdu_type_t m_pdu; /**< PDU to be sent. */
  62. static uint16_t m_event; /**< current command status - initially "ok", may be set if error detected, or to packet count. */
  63. static bool m_new_event; /**< Command has been processed - number of not yet reported event bytes. */
  64. static uint8_t m_packet_length; /**< Payload length of transmitted PDU, bits 2:7 of 16-bit dtm command. */
  65. static dtm_pkt_type_t m_packet_type; /**< Bits 0..1 of 16-bit transmit command, or 0xFFFFFFFF. */
  66. 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. */
  67. 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. */
  68. // Nordic specific configuration values (not defined by BLE standard).
  69. // Definition of initial values found in ble_dtm.h
  70. static int32_t m_tx_power = DEFAULT_TX_POWER; /**< TX power for transmission test, default to maximum value (+4 dBm). */
  71. static NRF_TIMER_Type * mp_timer = DEFAULT_TIMER; /**< Timer to be used. */
  72. static IRQn_Type m_timer_irq = DEFAULT_TIMER_IRQn; /**< which interrupt line to clear on every timeout */
  73. static uint8_t const m_prbs_content[] = PRBS9_CONTENT; /**< Pseudo-random bit sequence defined by the BLE standard. */
  74. static uint8_t m_packetHeaderLFlen = 8; /**< Length of length field in packet Header (in bits). */
  75. static uint8_t m_packetHeaderS0len = 1; /**< Length of S0 field in packet Header (in bytes). */
  76. static uint8_t m_packetHeaderS1len = 0; /**< Length of S1 field in packet Header (in bits). */
  77. static uint8_t m_crcConfSkipAddr = 1; /**< Leave packet address field out of CRC calculation. */
  78. static uint8_t m_static_length = 0; /**< Number of bytes sent in addition to the var.length payload. */
  79. static uint32_t m_balen = 3; /**< Base address length in bytes. */
  80. 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. */
  81. static uint32_t m_whitening = RADIO_PCNF1_WHITEEN_Disabled; /**< Whitening disabled. */
  82. static uint8_t m_crcLength = RADIO_CRCCNF_LEN_Three; /**< CRC Length (in bytes). */
  83. static uint32_t m_address = 0x71764129; /**< Address. */
  84. static uint32_t m_crc_poly = 0x0000065B; /**< CRC polynomial. */
  85. static uint32_t m_crc_init = 0x00555555; /**< Initial value for CRC calculation. */
  86. static uint8_t m_radio_mode = RADIO_MODE_MODE_Ble_1Mbit; /**< nRF51 specific radio mode vale. */
  87. static uint32_t m_txIntervaluS = 625; /**< Time between start of Tx packets (in uS). */
  88. /**@brief Function for verifying that a received PDU has the expected structure and content.
  89. */
  90. static bool check_pdu(void)
  91. {
  92. uint8_t k; // Byte pointer for running through PDU payload
  93. uint8_t pattern; // Repeating octet value in payload
  94. dtm_pkt_type_t pdu_packet_type; // Note: PDU packet type is a 4-bit field in HCI, but 2 bits in BLE DTM
  95. uint8_t length;
  96. pdu_packet_type = (dtm_pkt_type_t)(m_pdu.content[DTM_HEADER_OFFSET] & 0x0F);
  97. length = m_pdu.content[DTM_LENGTH_OFFSET];
  98. if ((pdu_packet_type > (dtm_pkt_type_t)PACKET_TYPE_MAX) || (length > DTM_PAYLOAD_MAX_SIZE))
  99. {
  100. return false;
  101. }
  102. if (pdu_packet_type == DTM_PKT_PRBS9)
  103. {
  104. // Payload does not consist of one repeated octet; must compare ir with entire block into
  105. return (memcmp(m_pdu.content+DTM_HEADER_SIZE, m_prbs_content, length) == 0);
  106. }
  107. if (pdu_packet_type == DTM_PKT_0X0F)
  108. {
  109. pattern = RFPHY_TEST_0X0F_REF_PATTERN;
  110. }
  111. else
  112. {
  113. pattern = RFPHY_TEST_0X55_REF_PATTERN;
  114. }
  115. for (k = 0; k < length; k++)
  116. {
  117. // Check repeated pattern filling the PDU payload
  118. if (m_pdu.content[k + 2] != pattern)
  119. {
  120. return false;
  121. }
  122. }
  123. return true;
  124. }
  125. /**@brief Function for turning off the radio after a test.
  126. * Also called after test done, to be ready for next test.
  127. */
  128. static void radio_reset(void)
  129. {
  130. NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk | PPI_CHENCLR_CH1_Msk;
  131. NRF_RADIO->SHORTS = 0;
  132. NRF_RADIO->EVENTS_DISABLED = 0;
  133. NRF_RADIO->TASKS_DISABLE = 1;
  134. while (NRF_RADIO->EVENTS_DISABLED == 0)
  135. {
  136. // Do nothing
  137. }
  138. NRF_RADIO->EVENTS_DISABLED = 0;
  139. NRF_RADIO->TASKS_RXEN = 0;
  140. NRF_RADIO->TASKS_TXEN = 0;
  141. m_rx_pkt_count = 0;
  142. }
  143. /**@brief Function for initializing the radio for DTM.
  144. */
  145. static uint32_t radio_init(void)
  146. {
  147. #ifdef NRF51
  148. // Handle BLE Radio tuning parameters from production for DTM if required.
  149. // Only needed for DTM without SoftDevice, as the SoftDevice normally handles this.
  150. // PCN-083.
  151. if ( ((NRF_FICR->OVERRIDEEN) & FICR_OVERRIDEEN_BLE_1MBIT_Msk) == FICR_OVERRIDEEN_BLE_1MBIT_Override)
  152. {
  153. NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
  154. NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
  155. NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
  156. NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
  157. NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4];
  158. }
  159. #endif // NRF51
  160. // Initializing code below is quite generic - for BLE, the values are fixed, and expressions
  161. // are constant. Non-constant values are essentially set in radio_prepare().
  162. if (((m_tx_power & 0x03) != 0) || // tx_power should be a multiple of 4
  163. ((m_tx_power & 0xffffff00) != 0) || // Upper 24 bits are required to be zeroed
  164. ((int8_t)m_tx_power > 4) || // Max tx_power is +4 dBm
  165. ((int8_t)(m_tx_power & 0xff) < -40) || // Min tx_power is -40 dBm
  166. (m_radio_mode > RADIO_MODE_MODE_Ble_1Mbit) // Values 0-2: Proprietary mode, 3 (last valid): BLE
  167. )
  168. {
  169. return DTM_ERROR_ILLEGAL_CONFIGURATION;
  170. }
  171. // Turn off radio before configuring it
  172. radio_reset();
  173. NRF_RADIO->TXPOWER = m_tx_power;
  174. NRF_RADIO->MODE = m_radio_mode << RADIO_MODE_MODE_Pos;
  175. // Set the access address, address0/prefix0 used for both Rx and Tx address
  176. NRF_RADIO->PREFIX0 &= ~RADIO_PREFIX0_AP0_Msk;
  177. NRF_RADIO->PREFIX0 |= (m_address >> 24) & RADIO_PREFIX0_AP0_Msk;
  178. NRF_RADIO->BASE0 = m_address << 8;
  179. NRF_RADIO->RXADDRESSES = RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos;
  180. NRF_RADIO->TXADDRESS = (0x00 << RADIO_TXADDRESS_TXADDRESS_Pos) & RADIO_TXADDRESS_TXADDRESS_Msk;
  181. // Configure CRC calculation
  182. NRF_RADIO->CRCCNF = (m_crcConfSkipAddr << RADIO_CRCCNF_SKIP_ADDR_Pos) |
  183. (m_crcLength << RADIO_CRCCNF_LEN_Pos);
  184. NRF_RADIO->PCNF0 = (m_packetHeaderS1len << RADIO_PCNF0_S1LEN_Pos) |
  185. (m_packetHeaderS0len << RADIO_PCNF0_S0LEN_Pos) |
  186. (m_packetHeaderLFlen << RADIO_PCNF0_LFLEN_Pos);
  187. NRF_RADIO->PCNF1 = (m_whitening << RADIO_PCNF1_WHITEEN_Pos) |
  188. (m_endian << RADIO_PCNF1_ENDIAN_Pos) |
  189. (m_balen << RADIO_PCNF1_BALEN_Pos) |
  190. (m_static_length << RADIO_PCNF1_STATLEN_Pos) |
  191. (DTM_PAYLOAD_MAX_SIZE << RADIO_PCNF1_MAXLEN_Pos);
  192. return DTM_SUCCESS;
  193. }
  194. /**@brief Function for preparing the radio. At start of each test: Turn off RF, clear interrupt flags of RF, initialize the radio
  195. * at given RF channel.
  196. *
  197. *@param[in] rx boolean indicating if radio should be prepared in rx mode (true) or tx mode.
  198. */
  199. static void radio_prepare(bool rx)
  200. {
  201. #ifdef NRF51
  202. NRF_RADIO->TEST = 0;
  203. #elif defined(NRF52)
  204. NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
  205. (RADIO_MODECNF0_DTX_B1 << RADIO_MODECNF0_DTX_Pos);
  206. #endif // NRF51 / NRF52
  207. NRF_RADIO->CRCPOLY = m_crc_poly;
  208. NRF_RADIO->CRCINIT = m_crc_init;
  209. NRF_RADIO->FREQUENCY = (m_phys_ch << 1) + 2; // Actual frequency (MHz): 2400 + register value
  210. NRF_RADIO->PACKETPTR = (uint32_t)&m_pdu; // Setting packet pointer will start the radio
  211. NRF_RADIO->EVENTS_READY = 0;
  212. NRF_RADIO->SHORTS = (1 << RADIO_SHORTS_READY_START_Pos) | // Shortcut between READY event and START task
  213. (1 << RADIO_SHORTS_END_DISABLE_Pos); // Shortcut between END event and DISABLE task
  214. if (rx)
  215. {
  216. NRF_RADIO->EVENTS_END = 0;
  217. NRF_RADIO->TASKS_RXEN = 1; // shorts will start radio in RX mode when it is ready
  218. }
  219. else // tx
  220. {
  221. NRF_RADIO->TXPOWER = m_tx_power;
  222. }
  223. }
  224. /**@brief Function for terminating the ongoing test (if any) and closing down the radio.
  225. */
  226. static void dtm_test_done(void)
  227. {
  228. #ifdef NRF51
  229. NRF_RADIO->TEST = 0;
  230. #elif defined(NRF52)
  231. NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
  232. (RADIO_MODECNF0_DTX_B1 << RADIO_MODECNF0_DTX_Pos);
  233. #endif // NRF51 / NRF52
  234. NRF_PPI->CHENCLR = 0x01;
  235. NRF_PPI->CH[0].EEP = 0; // Break connection from timer to radio to stop transmit loop
  236. NRF_PPI->CH[0].TEP = 0;
  237. radio_reset();
  238. m_state = STATE_IDLE;
  239. }
  240. /**@brief Function for configuring the timer for 625us cycle time.
  241. */
  242. static uint32_t timer_init(void)
  243. {
  244. // Use 16MHz from external crystal
  245. // This could be customized for RC/Xtal, or even to use a 32 kHz crystal
  246. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
  247. NRF_CLOCK->TASKS_HFCLKSTART = 1;
  248. while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
  249. {
  250. // Do nothing while waiting for the clock to start
  251. }
  252. mp_timer->TASKS_STOP = 1; // Stop timer, if it was running
  253. mp_timer->TASKS_CLEAR = 1;
  254. mp_timer->MODE = TIMER_MODE_MODE_Timer; // Timer mode (not counter)
  255. mp_timer->EVENTS_COMPARE[0] = 0; // clean up possible old events
  256. mp_timer->EVENTS_COMPARE[1] = 0;
  257. mp_timer->EVENTS_COMPARE[2] = 0;
  258. mp_timer->EVENTS_COMPARE[3] = 0;
  259. // Timer is polled, but enable the compare0 interrupt in order to wakeup from CPU sleep
  260. mp_timer->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
  261. mp_timer->SHORTS = 1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos; // Clear the count every time timer reaches the CCREG0 count
  262. mp_timer->PRESCALER = 4; // Input clock is 16MHz, timer clock = 2 ^ prescale -> interval 1us
  263. mp_timer->CC[0] = m_txIntervaluS; // 625uS with 1MHz clock to the timer
  264. mp_timer->CC[1] = UART_POLL_CYCLE; // 260uS with 1MHz clock to the timer
  265. mp_timer->TASKS_START = 1; // Start the timer - it will be running continuously
  266. m_current_time = 0;
  267. return DTM_SUCCESS;
  268. }
  269. /**@brief Function for handling vendor specific commands.
  270. * Used when packet type is set to Vendor specific.
  271. * The length field is used for encoding vendor specific command.
  272. * The frequency field is used for encoding vendor specific options to the command.
  273. *
  274. * @param[in] vendor_cmd Vendor specific command to be executed.
  275. * @param[in] vendor_option Vendor specific option to the vendor command.
  276. *
  277. * @return DTM_SUCCESS or one of the DTM_ERROR_ values
  278. */
  279. static uint32_t dtm_vendor_specific_pkt(uint32_t vendor_cmd, dtm_freq_t vendor_option)
  280. {
  281. switch (vendor_cmd)
  282. {
  283. // nRFgo Studio uses CARRIER_TEST_STUDIO to indicate a continuous carrier without
  284. // a modulated signal.
  285. case CARRIER_TEST:
  286. case CARRIER_TEST_STUDIO:
  287. // Not a packet type, but used to indicate that a continuous carrier signal
  288. // should be transmitted by the radio.
  289. radio_prepare(TX_MODE);
  290. #ifdef NRF51
  291. NRF_RADIO->TEST = (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos) |
  292. (RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos);
  293. #elif defined(NRF52)
  294. NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
  295. (RADIO_MODECNF0_DTX_B1 << RADIO_MODECNF0_DTX_Pos);
  296. #endif // NRF51 / NRF52
  297. // Shortcut between READY event and START task
  298. NRF_RADIO->SHORTS = 1 << RADIO_SHORTS_READY_START_Pos;
  299. // Shortcut will start radio in Tx mode when it is ready
  300. NRF_RADIO->TASKS_TXEN = 1;
  301. m_state = STATE_CARRIER_TEST;
  302. break;
  303. case SET_TX_POWER:
  304. if (!dtm_set_txpower(vendor_option))
  305. {
  306. return DTM_ERROR_ILLEGAL_CONFIGURATION;
  307. }
  308. break;
  309. case SELECT_TIMER:
  310. if (!dtm_set_timer(vendor_option))
  311. {
  312. return DTM_ERROR_ILLEGAL_CONFIGURATION;
  313. }
  314. break;
  315. }
  316. // Event code is unchanged, successful
  317. return DTM_SUCCESS;
  318. }
  319. uint32_t dtm_init(void)
  320. {
  321. if ((timer_init() != DTM_SUCCESS) || (radio_init() != DTM_SUCCESS))
  322. {
  323. return DTM_ERROR_ILLEGAL_CONFIGURATION;
  324. }
  325. m_new_event = false;
  326. m_state = STATE_IDLE;
  327. // Enable wake-up on event
  328. SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
  329. return DTM_SUCCESS;
  330. }
  331. uint32_t dtm_wait(void)
  332. {
  333. // Enable wake-up on event
  334. SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
  335. for (;;)
  336. {
  337. // Event may be the reception of a packet -
  338. // handle radio first, to give it highest priority:
  339. if (NRF_RADIO->EVENTS_END != 0)
  340. {
  341. NRF_RADIO->EVENTS_END = 0;
  342. NVIC_ClearPendingIRQ(RADIO_IRQn);
  343. if (m_state == STATE_RECEIVER_TEST)
  344. {
  345. NRF_RADIO->TASKS_RXEN = 1;
  346. if ((NRF_RADIO->CRCSTATUS == 1) && check_pdu())
  347. {
  348. // Count the number of successfully received packets
  349. m_rx_pkt_count++;
  350. }
  351. // Note that failing packets are simply ignored (CRC or contents error).
  352. // Zero fill all pdu fields to avoid stray data
  353. memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
  354. }
  355. // If no RECEIVER_TEST is running, ignore incoming packets (but do clear IRQ!)
  356. }
  357. // Check for timeouts:
  358. if (mp_timer->EVENTS_COMPARE[0] != 0)
  359. {
  360. mp_timer->EVENTS_COMPARE[0] = 0;
  361. }
  362. else if (mp_timer->EVENTS_COMPARE[1] != 0)
  363. {
  364. // Reset timeout event flag for next iteration.
  365. mp_timer->EVENTS_COMPARE[1] = 0;
  366. NVIC_ClearPendingIRQ(m_timer_irq);
  367. return ++m_current_time;
  368. }
  369. // Other events: No processing
  370. }
  371. }
  372. uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload)
  373. {
  374. // Save specified packet in static variable for tx/rx functions to use.
  375. // Note that BLE conformance testers always use full length packets.
  376. m_packet_length = ((uint8_t)length & 0xFF);
  377. m_packet_type = payload;
  378. m_phys_ch = freq;
  379. // Clean out any non-retrieved event that might linger from an earlier test
  380. m_new_event = true;
  381. // Set default event; any error will set it to LE_TEST_STATUS_EVENT_ERROR
  382. m_event = LE_TEST_STATUS_EVENT_SUCCESS;
  383. if (m_state == STATE_UNINITIALIZED)
  384. {
  385. // Application has not explicitly initialized DTM,
  386. return DTM_ERROR_UNINITIALIZED;
  387. }
  388. if (cmd == LE_RESET)
  389. {
  390. // Note that timer will continue running after a reset
  391. dtm_test_done();
  392. return DTM_SUCCESS;
  393. }
  394. if (cmd == LE_TEST_END)
  395. {
  396. if (m_state == STATE_IDLE)
  397. {
  398. // Sequencing error - only rx or tx test may be ended!
  399. m_event = LE_TEST_STATUS_EVENT_ERROR;
  400. return DTM_ERROR_INVALID_STATE;
  401. }
  402. m_event = LE_PACKET_REPORTING_EVENT | m_rx_pkt_count;
  403. dtm_test_done();
  404. return DTM_SUCCESS;
  405. }
  406. if (m_state != STATE_IDLE)
  407. {
  408. // Sequencing error - only TEST_END/RESET are legal while test is running
  409. // Note: State is unchanged; ongoing test not affected
  410. m_event = LE_TEST_STATUS_EVENT_ERROR;
  411. return DTM_ERROR_INVALID_STATE;
  412. }
  413. if (m_phys_ch > PHYS_CH_MAX)
  414. {
  415. // Parameter error
  416. // Note: State is unchanged; ongoing test not affected
  417. m_event = LE_TEST_STATUS_EVENT_ERROR;
  418. return DTM_ERROR_ILLEGAL_CHANNEL;
  419. }
  420. m_rx_pkt_count = 0;
  421. if (cmd == LE_RECEIVER_TEST)
  422. {
  423. // Zero fill all pdu fields to avoid stray data from earlier test run
  424. memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
  425. radio_prepare(RX_MODE); // Reinitialize "everything"; RF interrupts OFF
  426. m_state = STATE_RECEIVER_TEST;
  427. return DTM_SUCCESS;
  428. }
  429. if (cmd == LE_TRANSMITTER_TEST)
  430. {
  431. if (m_packet_length > DTM_PAYLOAD_MAX_SIZE)
  432. {
  433. // Parameter error
  434. m_event = LE_TEST_STATUS_EVENT_ERROR;
  435. return DTM_ERROR_ILLEGAL_LENGTH;
  436. }
  437. // Note that PDU uses 4 bits even though BLE DTM uses only 2 (the HCI SDU uses all 4)
  438. m_pdu.content[DTM_HEADER_OFFSET] = ((uint8_t)m_packet_type & 0x0F);
  439. m_pdu.content[DTM_LENGTH_OFFSET] = m_packet_length;
  440. switch (m_packet_type)
  441. {
  442. case DTM_PKT_PRBS9:
  443. // Non-repeated, must copy entire pattern to PDU
  444. memcpy(m_pdu.content + DTM_HEADER_SIZE, m_prbs_content, length);
  445. break;
  446. case DTM_PKT_0X0F:
  447. // Bit pattern 00001111 repeated
  448. memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X0F_REF_PATTERN, length);
  449. break;
  450. case DTM_PKT_0X55:
  451. // Bit pattern 01010101 repeated
  452. memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X55_REF_PATTERN, length);
  453. break;
  454. case DTM_PKT_VENDORSPECIFIC:
  455. // The length field is for indicating the vendor specific command to execute.
  456. // The frequency field is used for vendor specific options to the command.
  457. return dtm_vendor_specific_pkt(length, freq);
  458. default:
  459. // Parameter error
  460. m_event = LE_TEST_STATUS_EVENT_ERROR;
  461. return DTM_ERROR_ILLEGAL_CONFIGURATION;
  462. }
  463. // Initialize CRC value, set channel:
  464. radio_prepare(TX_MODE);
  465. // Configure PPI so that timer will activate radio every 625 us
  466. NRF_PPI->CH[0].EEP = (uint32_t)&mp_timer->EVENTS_COMPARE[0];
  467. NRF_PPI->CH[0].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN;
  468. NRF_PPI->CHENSET = 0x01;
  469. m_state = STATE_TRANSMITTER_TEST;
  470. }
  471. return DTM_SUCCESS;
  472. }
  473. bool dtm_event_get(dtm_event_t *p_dtm_event)
  474. {
  475. bool was_new = m_new_event;
  476. // mark the current event as retrieved
  477. m_new_event = false;
  478. *p_dtm_event = m_event;
  479. // return value indicates whether this value was already retrieved.
  480. return was_new;
  481. }
  482. // =================================================================================================
  483. // Configuration functions (only for parameters not definitely determined by the BLE DTM standard).
  484. // These functions return true if successful, false if value could not be set
  485. /**@brief Function for configuring the output power for transmitter test.
  486. This function may be called directly, or through dtm_cmd() specifying
  487. DTM_PKT_VENDORSPECIFIC as payload, SET_TX_POWER as length, and the dBm value as frequency.
  488. */
  489. bool dtm_set_txpower(uint32_t new_tx_power)
  490. {
  491. // radio->TXPOWER register is 32 bits, low octet a signed value, upper 24 bits zeroed
  492. int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);
  493. if (m_state > STATE_IDLE)
  494. {
  495. // radio must be idle to change the tx power
  496. return false;
  497. }
  498. if ((new_power8 > 4) || (new_power8 < -40))
  499. {
  500. // Parameter outside valid range: nRF radio is restricted to the range -40 dBm to +4 dBm
  501. return false;
  502. }
  503. if (new_tx_power & 0x03)
  504. {
  505. // Parameter error: The nRF51 radio requires settings that are a multiple of 4.
  506. return false;
  507. }
  508. m_tx_power = new_tx_power;
  509. return true;
  510. }
  511. /**@brief Function for selecting a timer resource.
  512. * This function may be called directly, or through dtm_cmd() specifying
  513. * DTM_PKT_VENDORSPECIFIC as payload, SELECT_TIMER as length, and the timer as freq
  514. *
  515. * @param[in] new_timer Timer id for the timer to use: 0, 1, or 2.
  516. *
  517. * @return true if the timer was successfully changed, false otherwise.
  518. */
  519. bool dtm_set_timer(uint32_t new_timer)
  520. {
  521. if (m_state > STATE_IDLE)
  522. {
  523. return false;
  524. }
  525. if (new_timer == 0)
  526. {
  527. mp_timer = NRF_TIMER0;
  528. m_timer_irq = TIMER0_IRQn;
  529. }
  530. else if (new_timer == 1)
  531. {
  532. mp_timer = NRF_TIMER1;
  533. m_timer_irq = TIMER1_IRQn;
  534. }
  535. else if (new_timer == 2)
  536. {
  537. mp_timer = NRF_TIMER2;
  538. m_timer_irq = TIMER2_IRQn;
  539. }
  540. else
  541. {
  542. // Parameter error: Only TIMER 0, 1, 2 provided by nRF51
  543. return false;
  544. }
  545. // New timer has been selected:
  546. return true;
  547. }
  548. /// @}