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

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?

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