![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
MPU6050
Dependencies: BLE_API MPU6050 mbed nRF51822
Fork of NordicDTMviaUART by
ble_dtm.cpp@1:91caa6c7f077, 2015-09-22 (annotated)
- Committer:
- DarkerL
- Date:
- Tue Sep 22 04:49:00 2015 +0000
- Revision:
- 1:91caa6c7f077
- Parent:
- 0:a2cffc867df4
BLE_MPU6050
Who changed what in which revision?
User | Revision | Line number | New 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 | /// @} |