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
main.cpp@0:a2cffc867df4, 2015-01-14 (annotated)
- Committer:
- pvaibhav
- Date:
- Wed Jan 14 12:36:59 2015 +0000
- Revision:
- 0:a2cffc867df4
Initial commit of working DTM mode via serial port
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pvaibhav | 0:a2cffc867df4 | 1 | /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. |
pvaibhav | 0:a2cffc867df4 | 2 | * |
pvaibhav | 0:a2cffc867df4 | 3 | * The information contained herein is property of Nordic Semiconductor ASA. |
pvaibhav | 0:a2cffc867df4 | 4 | * Terms and conditions of usage are described in detail in NORDIC |
pvaibhav | 0:a2cffc867df4 | 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. |
pvaibhav | 0:a2cffc867df4 | 6 | * |
pvaibhav | 0:a2cffc867df4 | 7 | * Licensees are granted free, non-transferable use of the information. NO |
pvaibhav | 0:a2cffc867df4 | 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from |
pvaibhav | 0:a2cffc867df4 | 9 | * the file. |
pvaibhav | 0:a2cffc867df4 | 10 | * |
pvaibhav | 0:a2cffc867df4 | 11 | */ |
pvaibhav | 0:a2cffc867df4 | 12 | |
pvaibhav | 0:a2cffc867df4 | 13 | #include "mbed.h" |
pvaibhav | 0:a2cffc867df4 | 14 | #include <stdint.h> |
pvaibhav | 0:a2cffc867df4 | 15 | #include <stdbool.h> |
pvaibhav | 0:a2cffc867df4 | 16 | #include "nrf51.h" |
pvaibhav | 0:a2cffc867df4 | 17 | #include "nrf51_bitfields.h" |
pvaibhav | 0:a2cffc867df4 | 18 | #include "ble_dtm.h" |
pvaibhav | 0:a2cffc867df4 | 19 | #include "nrf_gpio.h" |
pvaibhav | 0:a2cffc867df4 | 20 | |
pvaibhav | 0:a2cffc867df4 | 21 | // Configuration parameters. |
pvaibhav | 0:a2cffc867df4 | 22 | #define BITRATE UART_BAUDRATE_BAUDRATE_Baud19200 /**< Serial bitrate on the UART */ |
pvaibhav | 0:a2cffc867df4 | 23 | #define TX_PIN_NUMBER USBTX /**< Use proper value for your hardware */ |
pvaibhav | 0:a2cffc867df4 | 24 | #define RX_PIN_NUMBER USBRX /**< Use proper value for your hardware */ |
pvaibhav | 0:a2cffc867df4 | 25 | #define MAX_ITERATIONS_NEEDED_FOR_NEXT_BYTE 21 |
pvaibhav | 0:a2cffc867df4 | 26 | /**@brief Function for UART initialization. |
pvaibhav | 0:a2cffc867df4 | 27 | */ |
pvaibhav | 0:a2cffc867df4 | 28 | static void uart_init(void) |
pvaibhav | 0:a2cffc867df4 | 29 | { |
pvaibhav | 0:a2cffc867df4 | 30 | // Configure UART0 pins. |
pvaibhav | 0:a2cffc867df4 | 31 | nrf_gpio_cfg_output(TX_PIN_NUMBER); |
pvaibhav | 0:a2cffc867df4 | 32 | nrf_gpio_cfg_input(RX_PIN_NUMBER, NRF_GPIO_PIN_NOPULL); |
pvaibhav | 0:a2cffc867df4 | 33 | |
pvaibhav | 0:a2cffc867df4 | 34 | NRF_UART0->PSELTXD = TX_PIN_NUMBER; |
pvaibhav | 0:a2cffc867df4 | 35 | NRF_UART0->PSELRXD = RX_PIN_NUMBER; |
pvaibhav | 0:a2cffc867df4 | 36 | NRF_UART0->BAUDRATE = BITRATE; |
pvaibhav | 0:a2cffc867df4 | 37 | |
pvaibhav | 0:a2cffc867df4 | 38 | // Clean out possible events from earlier operations |
pvaibhav | 0:a2cffc867df4 | 39 | NRF_UART0->EVENTS_RXDRDY = 0; |
pvaibhav | 0:a2cffc867df4 | 40 | NRF_UART0->EVENTS_TXDRDY = 0; |
pvaibhav | 0:a2cffc867df4 | 41 | NRF_UART0->EVENTS_ERROR = 0; |
pvaibhav | 0:a2cffc867df4 | 42 | |
pvaibhav | 0:a2cffc867df4 | 43 | // Activate UART. |
pvaibhav | 0:a2cffc867df4 | 44 | NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; |
pvaibhav | 0:a2cffc867df4 | 45 | NRF_UART0->INTENSET = 0; |
pvaibhav | 0:a2cffc867df4 | 46 | NRF_UART0->TASKS_STARTTX = 1; |
pvaibhav | 0:a2cffc867df4 | 47 | NRF_UART0->TASKS_STARTRX = 1; |
pvaibhav | 0:a2cffc867df4 | 48 | } |
pvaibhav | 0:a2cffc867df4 | 49 | |
pvaibhav | 0:a2cffc867df4 | 50 | |
pvaibhav | 0:a2cffc867df4 | 51 | /**@brief Function for splitting UART command bit fields into separate command parameters for the DTM library. |
pvaibhav | 0:a2cffc867df4 | 52 | * |
pvaibhav | 0:a2cffc867df4 | 53 | * @param[in] command The packed UART command. |
pvaibhav | 0:a2cffc867df4 | 54 | * @return result status from dtmlib. |
pvaibhav | 0:a2cffc867df4 | 55 | */ |
pvaibhav | 0:a2cffc867df4 | 56 | static uint32_t dtm_cmd_put(uint16_t command) |
pvaibhav | 0:a2cffc867df4 | 57 | { |
pvaibhav | 0:a2cffc867df4 | 58 | dtm_cmd_t command_code = (command >> 14) & 0x03; |
pvaibhav | 0:a2cffc867df4 | 59 | dtm_freq_t freq = (command >> 8) & 0x3F; |
pvaibhav | 0:a2cffc867df4 | 60 | uint32_t length = (command >> 2) & 0x3F; |
pvaibhav | 0:a2cffc867df4 | 61 | dtm_pkt_type_t payload = command & 0x03; |
pvaibhav | 0:a2cffc867df4 | 62 | |
pvaibhav | 0:a2cffc867df4 | 63 | // Check for Vendor Specific payload. |
pvaibhav | 0:a2cffc867df4 | 64 | if (payload == 0x03) { |
pvaibhav | 0:a2cffc867df4 | 65 | /* Note that in a HCI adaption layer, as well as in the DTM PDU format, |
pvaibhav | 0:a2cffc867df4 | 66 | the value 0x03 is a distinct bit pattern (PRBS15). Even though BLE does not |
pvaibhav | 0:a2cffc867df4 | 67 | support PRBS15, this implementation re-maps 0x03 to DTM_PKT_VENDORSPECIFIC, |
pvaibhav | 0:a2cffc867df4 | 68 | to avoid the risk of confusion, should the code be extended to greater coverage. |
pvaibhav | 0:a2cffc867df4 | 69 | */ |
pvaibhav | 0:a2cffc867df4 | 70 | payload = DTM_PKT_VENDORSPECIFIC; |
pvaibhav | 0:a2cffc867df4 | 71 | } |
pvaibhav | 0:a2cffc867df4 | 72 | return dtm_cmd(command_code, freq, length, payload); |
pvaibhav | 0:a2cffc867df4 | 73 | } |
pvaibhav | 0:a2cffc867df4 | 74 | |
pvaibhav | 0:a2cffc867df4 | 75 | /**@brief Function for application main entry. |
pvaibhav | 0:a2cffc867df4 | 76 | * |
pvaibhav | 0:a2cffc867df4 | 77 | * @details This function serves as an adaptation layer between a 2-wire UART interface and the |
pvaibhav | 0:a2cffc867df4 | 78 | * dtmlib. After initialization, DTM commands submitted through the UART are forwarded to |
pvaibhav | 0:a2cffc867df4 | 79 | * dtmlib and events (i.e. results from the command) is reported back through the UART. |
pvaibhav | 0:a2cffc867df4 | 80 | */ |
pvaibhav | 0:a2cffc867df4 | 81 | int main(void) |
pvaibhav | 0:a2cffc867df4 | 82 | { |
pvaibhav | 0:a2cffc867df4 | 83 | uint32_t current_time; |
pvaibhav | 0:a2cffc867df4 | 84 | uint32_t dtm_error_code; |
pvaibhav | 0:a2cffc867df4 | 85 | uint32_t msb_time = 0; // Time when MSB of the DTM command was read. Used to catch stray bytes from "misbehaving" testers. |
pvaibhav | 0:a2cffc867df4 | 86 | bool is_msb_read = false; // True when MSB of the DTM command has been read and the application is waiting for LSB. |
pvaibhav | 0:a2cffc867df4 | 87 | uint16_t dtm_cmd_from_uart = 0; // Packed command containing command_code:freqency:length:payload in 2:6:6:2 bits. |
pvaibhav | 0:a2cffc867df4 | 88 | uint8_t rx_byte; // Last byte read from UART. |
pvaibhav | 0:a2cffc867df4 | 89 | dtm_event_t result; // Result of a DTM operation. |
pvaibhav | 0:a2cffc867df4 | 90 | |
pvaibhav | 0:a2cffc867df4 | 91 | uart_init(); |
pvaibhav | 0:a2cffc867df4 | 92 | |
pvaibhav | 0:a2cffc867df4 | 93 | // Turn default LED on to indicate power |
pvaibhav | 0:a2cffc867df4 | 94 | nrf_gpio_cfg_output(LED1); |
pvaibhav | 0:a2cffc867df4 | 95 | nrf_gpio_pin_set(LED1); |
pvaibhav | 0:a2cffc867df4 | 96 | |
pvaibhav | 0:a2cffc867df4 | 97 | dtm_error_code = dtm_init(); |
pvaibhav | 0:a2cffc867df4 | 98 | if (dtm_error_code != DTM_SUCCESS) { |
pvaibhav | 0:a2cffc867df4 | 99 | // If DTM cannot be correctly initialized, then we just return. |
pvaibhav | 0:a2cffc867df4 | 100 | return -1; |
pvaibhav | 0:a2cffc867df4 | 101 | } |
pvaibhav | 0:a2cffc867df4 | 102 | |
pvaibhav | 0:a2cffc867df4 | 103 | for (;;) { |
pvaibhav | 0:a2cffc867df4 | 104 | // Will return every timeout, 625 us. |
pvaibhav | 0:a2cffc867df4 | 105 | current_time = dtm_wait(); |
pvaibhav | 0:a2cffc867df4 | 106 | |
pvaibhav | 0:a2cffc867df4 | 107 | if (NRF_UART0->EVENTS_RXDRDY == 0) { |
pvaibhav | 0:a2cffc867df4 | 108 | // Nothing read from the UART. |
pvaibhav | 0:a2cffc867df4 | 109 | continue; |
pvaibhav | 0:a2cffc867df4 | 110 | } |
pvaibhav | 0:a2cffc867df4 | 111 | NRF_UART0->EVENTS_RXDRDY = 0; |
pvaibhav | 0:a2cffc867df4 | 112 | rx_byte = (uint8_t)NRF_UART0->RXD; |
pvaibhav | 0:a2cffc867df4 | 113 | |
pvaibhav | 0:a2cffc867df4 | 114 | if (!is_msb_read) { |
pvaibhav | 0:a2cffc867df4 | 115 | // This is first byte of two-byte command. |
pvaibhav | 0:a2cffc867df4 | 116 | is_msb_read = true; |
pvaibhav | 0:a2cffc867df4 | 117 | dtm_cmd_from_uart = ((dtm_cmd_t)rx_byte) << 8; |
pvaibhav | 0:a2cffc867df4 | 118 | msb_time = current_time; |
pvaibhav | 0:a2cffc867df4 | 119 | |
pvaibhav | 0:a2cffc867df4 | 120 | // Go back and wait for 2nd byte of command word. |
pvaibhav | 0:a2cffc867df4 | 121 | continue; |
pvaibhav | 0:a2cffc867df4 | 122 | } |
pvaibhav | 0:a2cffc867df4 | 123 | |
pvaibhav | 0:a2cffc867df4 | 124 | // This is the second byte read; combine it with the first and process command |
pvaibhav | 0:a2cffc867df4 | 125 | if (current_time > (msb_time + MAX_ITERATIONS_NEEDED_FOR_NEXT_BYTE)) { |
pvaibhav | 0:a2cffc867df4 | 126 | // More than ~5mS after msb: Drop old byte, take the new byte as MSB. |
pvaibhav | 0:a2cffc867df4 | 127 | // The variable is_msb_read will remains true. |
pvaibhav | 0:a2cffc867df4 | 128 | // Go back and wait for 2nd byte of the command word. |
pvaibhav | 0:a2cffc867df4 | 129 | dtm_cmd_from_uart = ((dtm_cmd_t)rx_byte) << 8; |
pvaibhav | 0:a2cffc867df4 | 130 | msb_time = current_time; |
pvaibhav | 0:a2cffc867df4 | 131 | continue; |
pvaibhav | 0:a2cffc867df4 | 132 | } |
pvaibhav | 0:a2cffc867df4 | 133 | |
pvaibhav | 0:a2cffc867df4 | 134 | // 2-byte UART command received. |
pvaibhav | 0:a2cffc867df4 | 135 | is_msb_read = false; |
pvaibhav | 0:a2cffc867df4 | 136 | dtm_cmd_from_uart |= (dtm_cmd_t)rx_byte; |
pvaibhav | 0:a2cffc867df4 | 137 | |
pvaibhav | 0:a2cffc867df4 | 138 | if (dtm_cmd_put(dtm_cmd_from_uart) != DTM_SUCCESS) { |
pvaibhav | 0:a2cffc867df4 | 139 | // Extended error handling may be put here. |
pvaibhav | 0:a2cffc867df4 | 140 | // Default behavior is to return the event on the UART (see below); |
pvaibhav | 0:a2cffc867df4 | 141 | // the event report will reflect any lack of success. |
pvaibhav | 0:a2cffc867df4 | 142 | } |
pvaibhav | 0:a2cffc867df4 | 143 | |
pvaibhav | 0:a2cffc867df4 | 144 | // Retrieve result of the operation. This implementation will busy-loop |
pvaibhav | 0:a2cffc867df4 | 145 | // for the duration of the byte transmissions on the UART. |
pvaibhav | 0:a2cffc867df4 | 146 | if (dtm_event_get(&result)) { |
pvaibhav | 0:a2cffc867df4 | 147 | // Report command status on the UART. |
pvaibhav | 0:a2cffc867df4 | 148 | // Transmit MSB of the result. |
pvaibhav | 0:a2cffc867df4 | 149 | NRF_UART0->TXD = (result >> 8) & 0xFF; |
pvaibhav | 0:a2cffc867df4 | 150 | // Wait until MSB is sent. |
pvaibhav | 0:a2cffc867df4 | 151 | while (NRF_UART0->EVENTS_TXDRDY != 1) { |
pvaibhav | 0:a2cffc867df4 | 152 | // Do nothing. |
pvaibhav | 0:a2cffc867df4 | 153 | } |
pvaibhav | 0:a2cffc867df4 | 154 | NRF_UART0->EVENTS_TXDRDY = 0; |
pvaibhav | 0:a2cffc867df4 | 155 | |
pvaibhav | 0:a2cffc867df4 | 156 | // Transmit LSB of the result. |
pvaibhav | 0:a2cffc867df4 | 157 | NRF_UART0->TXD = result & 0xFF; |
pvaibhav | 0:a2cffc867df4 | 158 | // Wait until LSB is sent. |
pvaibhav | 0:a2cffc867df4 | 159 | while (NRF_UART0->EVENTS_TXDRDY != 1) { |
pvaibhav | 0:a2cffc867df4 | 160 | // Do nothing. |
pvaibhav | 0:a2cffc867df4 | 161 | } |
pvaibhav | 0:a2cffc867df4 | 162 | NRF_UART0->EVENTS_TXDRDY = 0; |
pvaibhav | 0:a2cffc867df4 | 163 | } |
pvaibhav | 0:a2cffc867df4 | 164 | } |
pvaibhav | 0:a2cffc867df4 | 165 | } |
pvaibhav | 0:a2cffc867df4 | 166 | |
pvaibhav | 0:a2cffc867df4 | 167 | /// @} |