dtm_uart.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /**
  2. * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. /**
  41. @defgroup dtm_standalone main.c
  42. @{
  43. @ingroup ble_sdk_app_dtm_serial
  44. @brief Stand-alone DTM application for UART interface.
  45. */
  46. #include <stdint.h>
  47. #include <stdbool.h>
  48. #include "nrf.h"
  49. #include "ble_dtm.h"
  50. #include "nrf_gpio.h"
  51. #include "dtm_uart.h"
  52. #include "nrf_error.h"
  53. #include "app_util.h"
  54. #include "nrf_drv_uart.h"
  55. #include "nrf_peripherals.h"
  56. #include "app_util_platform.h"
  57. //Configuration parameters.
  58. #define BITRATE UART_BAUDRATE_BAUDRATE_Baud57600 /**< Serial bitrate on the UART */
  59. //@note: The BLE DTM 2-wire UART standard specifies 8 data bits, 1 stop bit, no flow control.
  60. //These parameters are not configurable in the BLE standard.
  61. /**@details Maximum iterations needed in the main loop between stop bit 1st byte and start bit 2nd
  62. * byte. DTM standard allows 5000us delay between stop bit 1st byte and start bit 2nd byte.
  63. * As the time is only known when a byte is received, then the time between between stop bit 1st
  64. * byte and stop bit 2nd byte becomes:
  65. * 5000us + transmission time of 2nd byte.
  66. *
  67. * Byte transmission time is (Baud rate of 19200):
  68. * 10bits * 1/19200 = approx. 520 us/byte (8 data bits + start & stop bit).
  69. *
  70. * Loop time on polling UART register for received byte is defined in ble_dtm.c as:
  71. * UART_POLL_CYCLE = 260 us
  72. *
  73. * The max time between two bytes thus becomes (loop time: 260us / iteration):
  74. * (5000us + 520us) / 260us / iteration = 21.2 iterations.
  75. *
  76. * This is rounded down to 21.
  77. *
  78. * @note If UART bit rate is changed, this value should be recalculated as well.
  79. */
  80. static uint32_t m_baud_rates[] = {[UART_BAUD_RATE_1200] = NRF_UART_BAUDRATE_1200,
  81. [UART_BAUD_RATE_2400] = NRF_UART_BAUDRATE_2400,
  82. [UART_BAUD_RATE_4800] = NRF_UART_BAUDRATE_4800,
  83. [UART_BAUD_RATE_9600] = NRF_UART_BAUDRATE_9600,
  84. [UART_BAUD_RATE_14400] = NRF_UART_BAUDRATE_14400,
  85. [UART_BAUD_RATE_19200] = NRF_UART_BAUDRATE_19200,
  86. [UART_BAUD_RATE_28800] = NRF_UART_BAUDRATE_28800,
  87. [UART_BAUD_RATE_38400] = NRF_UART_BAUDRATE_38400,
  88. [UART_BAUD_RATE_57600] = NRF_UART_BAUDRATE_57600,
  89. [UART_BAUD_RATE_76800] = NRF_UART_BAUDRATE_76800,
  90. [UART_BAUD_RATE_115200] = NRF_UART_BAUDRATE_115200 };
  91. static uint32_t m_iteration[] = {[UART_BAUD_RATE_1200] = 51,
  92. [UART_BAUD_RATE_2400] = 35,
  93. [UART_BAUD_RATE_4800] = 27,
  94. [UART_BAUD_RATE_9600] = 23,
  95. [UART_BAUD_RATE_14400] = 21,
  96. [UART_BAUD_RATE_19200] = 21,
  97. [UART_BAUD_RATE_28800] = 20,
  98. [UART_BAUD_RATE_38400] = 20,
  99. [UART_BAUD_RATE_57600] = 19,
  100. [UART_BAUD_RATE_76800] = 19,
  101. [UART_BAUD_RATE_115200] = 19, };
  102. static uint32_t m_iterations_next_byte_max = 51;
  103. static nrf_drv_uart_t m_dtm_uart_driver = NRF_DRV_UART_INSTANCE(0);
  104. /**@brief Function for UART initialization.
  105. */
  106. static uint32_t uart_init(app_uart_stream_comm_params_t * p_comm_params)
  107. {
  108. if (p_comm_params->baud_rate > UART_BAUD_RATE_115200)
  109. {
  110. return NRF_ERROR_INVALID_PARAM;
  111. }
  112. nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
  113. config.pselrxd = p_comm_params->rx_pin_no;
  114. config.pseltxd = p_comm_params->tx_pin_no;
  115. config.baudrate = (nrf_uart_baudrate_t) m_baud_rates[p_comm_params->baud_rate];
  116. config.hwfc = NRF_UART_HWFC_DISABLED;
  117. config.parity = NRF_UART_PARITY_EXCLUDED;
  118. #ifdef UART_PRESENT
  119. //Current implementation of DTM requires legacy UART features and
  120. // it will not work on nrf52810.
  121. config.use_easy_dma = false;
  122. #endif
  123. nrf_drv_uart_uninit(&m_dtm_uart_driver);
  124. uint32_t err_code = nrf_drv_uart_init(&m_dtm_uart_driver, &config, NULL);
  125. if (err_code != NRF_SUCCESS)
  126. {
  127. return err_code;
  128. }
  129. nrf_drv_uart_rx_enable(&m_dtm_uart_driver);
  130. m_iterations_next_byte_max = m_iteration[p_comm_params->baud_rate];
  131. return NRF_SUCCESS;
  132. }
  133. /**@brief Function for splitting UART command bit fields into separate command parameters for the DTM library.
  134. *
  135. * @param[in] command The packed UART command.
  136. * @return result status from dtmlib.
  137. */
  138. static uint32_t dtm_cmd_put(uint16_t command)
  139. {
  140. dtm_cmd_t command_code = (command >> 14) & 0x03;
  141. dtm_freq_t freq = (command >> 8) & 0x3F;
  142. uint32_t length = (command >> 2) & 0x3F;
  143. dtm_pkt_type_t payload = command & 0x03;
  144. //Check for Vendor Specific payload.
  145. if (payload == 0x03)
  146. {
  147. /* Note that in a HCI adaption layer, as well as in the DTM PDU format,
  148. the value 0x03 is a distinct bit pattern (PRBS15). Even though BLE does not
  149. support PRBS15, this implementation re-maps 0x03 to DTM_PKT_VENDORSPECIFIC,
  150. to avoid the risk of confusion, should the code be extended to greater coverage.
  151. */
  152. payload = DTM_PKT_VENDORSPECIFIC;
  153. }
  154. return dtm_cmd(command_code, freq, length, payload);
  155. }
  156. /**@brief Function for application main entry.
  157. *
  158. * @details This function serves as an adaptation layer between a 2-wire UART interface and the
  159. * dtmlib. After initialization, DTM commands submitted through the UART are forwarded to
  160. * dtmlib and events (i.e. results from the command) is reported back through the UART.
  161. */
  162. uint32_t dtm_start(app_uart_stream_comm_params_t uart_comm_params)
  163. {
  164. uint32_t current_time;
  165. uint32_t dtm_error_code;
  166. uint32_t msb_time = 0; //Time when MSB of the DTM command was read. Used to catch stray bytes from "misbehaving" testers.
  167. bool is_msb_read = false; //True when MSB of the DTM command has been read and the application is waiting for LSB.
  168. uint16_t dtm_cmd_from_uart = 0; //Packed command containing command_code:freqency:length:payload in 2:6:6:2 bits.
  169. uint8_t rx_byte; //Last byte read from UART.
  170. dtm_event_t result; //Result of a DTM operation.
  171. uint32_t err_code;
  172. err_code = uart_init(&uart_comm_params);
  173. if (err_code != NRF_SUCCESS)
  174. {
  175. return err_code;
  176. }
  177. dtm_error_code = dtm_init();
  178. if (dtm_error_code != DTM_SUCCESS)
  179. {
  180. //If DTM cannot be correctly initialized, then we just return.
  181. return NRF_ERROR_INTERNAL;
  182. }
  183. for (;; )
  184. {
  185. //Will return every timeout, 625 us.
  186. current_time = dtm_wait();
  187. if (NRF_SUCCESS != nrf_drv_uart_rx(&m_dtm_uart_driver, &rx_byte,1))
  188. {
  189. return NRF_ERROR_INTERNAL;
  190. }
  191. if (!is_msb_read)
  192. {
  193. //This is first byte of two-byte command.
  194. is_msb_read = true;
  195. dtm_cmd_from_uart = ((dtm_cmd_t)rx_byte) << 8;
  196. msb_time = current_time;
  197. //Go back and wait for 2nd byte of command word.
  198. continue;
  199. }
  200. //This is the second byte read; combine it with the first and process command
  201. if (current_time > (msb_time + m_iterations_next_byte_max))
  202. {
  203. //More than ~5mS after msb: Drop old byte, take the new byte as MSB.
  204. //The variable is_msb_read will remains true.
  205. //Go back and wait for 2nd byte of the command word.
  206. dtm_cmd_from_uart = ((dtm_cmd_t)rx_byte) << 8;
  207. msb_time = current_time;
  208. continue;
  209. }
  210. //2-byte UART command received.
  211. is_msb_read = false;
  212. dtm_cmd_from_uart |= (dtm_cmd_t)rx_byte;
  213. if (dtm_cmd_put(dtm_cmd_from_uart) != DTM_SUCCESS)
  214. {
  215. //Extended error handling may be put here.
  216. //Default behavior is to return the event on the UART (see below);
  217. //the event report will reflect any lack of success.
  218. }
  219. //Retrieve result of the operation. This implementation will busy-loop
  220. //for the duration of the byte transmissions on the UART.
  221. if (dtm_event_get(&result))
  222. {
  223. //Report command status on the UART.
  224. uint8_t tx_byte = (result >> 8) & 0xFF;
  225. //Transmit MSB of the result.
  226. (void)nrf_drv_uart_tx(&m_dtm_uart_driver, &tx_byte, 1);
  227. //Transmit LSB of the result.
  228. tx_byte = result & 0xFF;
  229. (void)nrf_drv_uart_tx(&m_dtm_uart_driver, &tx_byte, 1);
  230. }
  231. }
  232. }
  233. /// @}