diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:08:59 +0200 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2018-08-23 17:12:21 +0200 |
commit | 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a (patch) | |
tree | ab49cc16ed0b853452c5c2ed2d3042416d628986 /thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf | |
download | iot-sensors-master.tar.gz iot-sensors-master.tar.bz2 iot-sensors-master.tar.xz iot-sensors-master.zip |
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf')
35 files changed, 6951 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb.c new file mode 100644 index 0000000..5624d19 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb.c @@ -0,0 +1,1603 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nrf_error.h" +#include "nrf_esb.h" +#include "nrf_esb_error_codes.h" +#include "nrf_gpio.h" +#include <string.h> +#include <stddef.h> +#include "sdk_common.h" +#include "sdk_macros.h" +#include "app_util.h" +#include "nrf_log.h" +#include "nrf_delay.h" + +#define BIT_MASK_UINT_8(x) (0xFF >> (8 - (x))) +#define NRF_ESB_PIPE_COUNT 8 + +// Constant parameters +#define RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS (48) /**< 2 Mb RX wait for acknowledgment time-out value. Smallest reliable value - 43. */ +#define RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS (64) /**< 1 Mb RX wait for acknowledgment time-out value. Smallest reliable value - 59. */ +#define RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS (250) /**< 250 Kb RX wait for acknowledgment time-out value. */ +#define RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS_BLE (73) /**< 1 Mb RX wait for acknowledgment time-out (combined with BLE). Smallest reliable value - 68.*/ + +// Interrupt flags +#define NRF_ESB_INT_TX_SUCCESS_MSK 0x01 /**< Interrupt mask value for TX success. */ +#define NRF_ESB_INT_TX_FAILED_MSK 0x02 /**< Interrupt mask value for TX failure. */ +#define NRF_ESB_INT_RX_DATA_RECEIVED_MSK 0x04 /**< Interrupt mask value for RX_DR. */ + +#define NRF_ESB_PID_RESET_VALUE 0xFF /**< Invalid PID value which is guaranteed to not collide with any valid PID value. */ +#define NRF_ESB_PID_MAX 3 /**< Maximum value for PID. */ +#define NRF_ESB_CRC_RESET_VALUE 0xFFFF /**< CRC reset value. */ + +// Internal Enhanced ShockBurst module state. +typedef enum { + NRF_ESB_STATE_IDLE, /**< Module idle. */ + NRF_ESB_STATE_PTX_TX, /**< Module transmitting without acknowledgment. */ + NRF_ESB_STATE_PTX_TX_ACK, /**< Module transmitting with acknowledgment. */ + NRF_ESB_STATE_PTX_RX_ACK, /**< Module transmitting with acknowledgment and reception of payload with the acknowledgment response. */ + NRF_ESB_STATE_PRX, /**< Module receiving packets without acknowledgment. */ + NRF_ESB_STATE_PRX_SEND_ACK, /**< Module transmitting acknowledgment in RX mode. */ +} nrf_esb_mainstate_t; + + +#define DISABLE_RF_IRQ() NVIC_DisableIRQ(RADIO_IRQn) +#define ENABLE_RF_IRQ() NVIC_EnableIRQ(RADIO_IRQn) + +#define _RADIO_SHORTS_COMMON ( RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \ + RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk ) + +#define VERIFY_PAYLOAD_LENGTH(p) \ +do \ +{ \ + if (p->length == 0 || \ + p->length > NRF_ESB_MAX_PAYLOAD_LENGTH || \ + (m_config_local.protocol == NRF_ESB_PROTOCOL_ESB && \ + p->length > m_config_local.payload_length)) \ + { \ + return NRF_ERROR_INVALID_LENGTH; \ + } \ +}while (0) + + +/* @brief Structure holding pipe info PID and CRC and acknowledgment payload. */ +typedef struct +{ + uint16_t crc; /**< CRC value of the last received packet (Used to detect retransmits). */ + uint8_t pid; /**< Packet ID of the last received packet (Used to detect retransmits). */ + bool ack_payload; /**< Flag indicating the state of the transmission of acknowledgment payloads. */ +} pipe_info_t; + + +/* @brief First-in, first-out queue of payloads to be transmitted. */ +typedef struct +{ + nrf_esb_payload_t * p_payload[NRF_ESB_TX_FIFO_SIZE]; /**< Pointer to the actual queue. */ + uint32_t entry_point; /**< Current start of queue. */ + uint32_t exit_point; /**< Current end of queue. */ + uint32_t count; /**< Current number of elements in the queue. */ +} nrf_esb_payload_tx_fifo_t; + + +/* @brief First-in, first-out queue of received payloads. */ +typedef struct +{ + nrf_esb_payload_t * p_payload[NRF_ESB_RX_FIFO_SIZE]; /**< Pointer to the actual queue. */ + uint32_t entry_point; /**< Current start of queue. */ + uint32_t exit_point; /**< Current end of queue. */ + uint32_t count; /**< Current number of elements in the queue. */ +} nrf_esb_payload_rx_fifo_t; + + +/**@brief Enhanced ShockBurst address. + * + * Enhanced ShockBurst addresses consist of a base address and a prefix + * that is unique for each pipe. See @ref esb_addressing in the ESB user + * guide for more information. +*/ +typedef struct +{ + uint8_t base_addr_p0[4]; /**< Base address for pipe 0 encoded in big endian. */ + uint8_t base_addr_p1[4]; /**< Base address for pipe 1-7 encoded in big endian. */ + uint8_t pipe_prefixes[8]; /**< Address prefix for pipe 0 to 7. */ + uint8_t num_pipes; /**< Number of pipes available. */ + uint8_t addr_length; /**< Length of the address including the prefix. */ + uint8_t rx_pipes_enabled; /**< Bitfield for enabled pipes. */ + uint8_t rf_channel; /**< Channel to use (must be between 0 and 100). */ +} nrf_esb_address_t; + + +// Module state +static bool m_esb_initialized = false; +static nrf_esb_mainstate_t m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; +static nrf_esb_payload_t * mp_current_payload; + +static nrf_esb_event_handler_t m_event_handler; + +// Address parameters +__ALIGN(4) static nrf_esb_address_t m_esb_addr = NRF_ESB_ADDR_DEFAULT; + +// RF parameters +static nrf_esb_config_t m_config_local; + +// TX FIFO +static nrf_esb_payload_t m_tx_fifo_payload[NRF_ESB_TX_FIFO_SIZE]; +static nrf_esb_payload_tx_fifo_t m_tx_fifo; + +// RX FIFO +static nrf_esb_payload_t m_rx_fifo_payload[NRF_ESB_RX_FIFO_SIZE]; +static nrf_esb_payload_rx_fifo_t m_rx_fifo; + +// Payload buffers +static uint8_t m_tx_payload_buffer[NRF_ESB_MAX_PAYLOAD_LENGTH + 2]; +static uint8_t m_rx_payload_buffer[NRF_ESB_MAX_PAYLOAD_LENGTH + 2]; + +// Run time variables +static volatile uint32_t m_interrupt_flags = 0; +static uint8_t m_pids[NRF_ESB_PIPE_COUNT]; +static pipe_info_t m_rx_pipe_info[NRF_ESB_PIPE_COUNT]; +static volatile uint32_t m_retransmits_remaining; +static volatile uint32_t m_last_tx_attempts; +static volatile uint32_t m_wait_for_ack_timeout_us; + +// nRF52 address workaround enable +#ifdef NRF52 +static bool m_address_hang_fix_enable = true; +#endif +static uint32_t m_radio_shorts_common = _RADIO_SHORTS_COMMON; + +// These function pointers are changed dynamically, depending on protocol configuration and state. +static void (*on_radio_disabled)(void) = 0; +static void (*on_radio_end)(void) = 0; +static void (*update_rf_payload_format)(uint32_t payload_length) = 0; + + +// The following functions are assigned to the function pointers above. +static void on_radio_disabled_tx_noack(void); +static void on_radio_disabled_tx(void); +static void on_radio_disabled_tx_wait_for_ack(void); +static void on_radio_disabled_rx(void); +static void on_radio_disabled_rx_ack(void); + + +#define NRF_ESB_ADDR_UPDATE_MASK_BASE0 (1 << 0) /*< Mask value to signal updating BASE0 radio address. */ +#define NRF_ESB_ADDR_UPDATE_MASK_BASE1 (1 << 1) /*< Mask value to signal updating BASE1 radio address. */ +#define NRF_ESB_ADDR_UPDATE_MASK_PREFIX (1 << 2) /*< Mask value to signal updating radio prefixes. */ + + +// Function to do bytewise bit-swap on an unsigned 32-bit value +static uint32_t bytewise_bit_swap(uint8_t const * p_inp) +{ + uint32_t inp = (*(uint32_t*)p_inp); +#if __CORTEX_M == (0x04U) + return __REV((uint32_t)__RBIT(inp)); //lint -esym(628, __rev) -esym(526, __rev) -esym(628, __rbit) -esym(526, __rbit) */ +#else + inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4; + inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2; + inp = (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1; + return inp; +#endif +} + + +// Internal function to convert base addresses from nRF24L type addressing to nRF51 type addressing +static uint32_t addr_conv(uint8_t const* p_addr) +{ + return __REV(bytewise_bit_swap(p_addr)); //lint -esym(628, __rev) -esym(526, __rev) */ +} + + +static ret_code_t apply_address_workarounds() +{ +#ifdef NRF52 + // Set up radio parameters. + NRF_RADIO->MODECNF0 = (NRF_RADIO->MODECNF0 & ~RADIO_MODECNF0_RU_Msk) | RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos; + + // Workaround for nRF52832 Rev 1 Errata 102 and nRF52832 Rev 1 Errata 106. This will reduce sensitivity by 3dB. + *((volatile uint32_t *)0x40001774) = (*((volatile uint32_t *)0x40001774) & 0xFFFFFFFE) | 0x01000000; +#endif + return NRF_SUCCESS; +} + + +static void update_rf_payload_format_esb_dpl(uint32_t payload_length) +{ +#if (NRF_ESB_MAX_PAYLOAD_LENGTH <= 32) + // Using 6 bits for length + NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | + (6 << RADIO_PCNF0_LFLEN_Pos) | + (3 << RADIO_PCNF0_S1LEN_Pos) ; +#else + // Using 8 bits for length + NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | + (8 << RADIO_PCNF0_LFLEN_Pos) | + (3 << RADIO_PCNF0_S1LEN_Pos) ; +#endif + NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | + (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | + ((m_esb_addr.addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | + (0 << RADIO_PCNF1_STATLEN_Pos) | + (NRF_ESB_MAX_PAYLOAD_LENGTH << RADIO_PCNF1_MAXLEN_Pos); +} + + +static void update_rf_payload_format_esb(uint32_t payload_length) +{ + NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) | + (0 << RADIO_PCNF0_LFLEN_Pos) | + (1 << RADIO_PCNF0_S1LEN_Pos); + + NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | + (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | + ((m_esb_addr.addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | + (payload_length << RADIO_PCNF1_STATLEN_Pos) | + (payload_length << RADIO_PCNF1_MAXLEN_Pos); +} + + +static void update_radio_addresses(uint8_t update_mask) +{ + if ((update_mask & NRF_ESB_ADDR_UPDATE_MASK_BASE0) != 0) + { + NRF_RADIO->BASE0 = addr_conv(m_esb_addr.base_addr_p0); + } + + if ((update_mask & NRF_ESB_ADDR_UPDATE_MASK_BASE1) != 0) + { + NRF_RADIO->BASE1 = addr_conv(m_esb_addr.base_addr_p1); + } + + if ((update_mask & NRF_ESB_ADDR_UPDATE_MASK_PREFIX) != 0) + { + NRF_RADIO->PREFIX0 = bytewise_bit_swap(&m_esb_addr.pipe_prefixes[0]); + NRF_RADIO->PREFIX1 = bytewise_bit_swap(&m_esb_addr.pipe_prefixes[4]); + } +} + + +static void update_radio_tx_power() +{ + NRF_RADIO->TXPOWER = m_config_local.tx_output_power << RADIO_TXPOWER_TXPOWER_Pos; +} + + +static bool update_radio_bitrate() +{ + NRF_RADIO->MODE = m_config_local.bitrate << RADIO_MODE_MODE_Pos; + + switch (m_config_local.bitrate) + { + case NRF_ESB_BITRATE_2MBPS: +#ifdef NRF52 + case NRF_ESB_BITRATE_2MBPS_BLE: +#endif + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS; + break; + + case NRF_ESB_BITRATE_1MBPS: + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS; + break; + +#ifdef NRF51 + case NRF_ESB_BITRATE_250KBPS: + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS; + break; +#endif + + case NRF_ESB_BITRATE_1MBPS_BLE: + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS_BLE; + break; + + default: + // Should not be reached + return false; + } + return true; +} + + +static bool update_radio_protocol() +{ + switch (m_config_local.protocol) + { + case NRF_ESB_PROTOCOL_ESB_DPL: + update_rf_payload_format = update_rf_payload_format_esb_dpl; + break; + + case NRF_ESB_PROTOCOL_ESB: + update_rf_payload_format = update_rf_payload_format_esb; + break; + + default: + // Should not be reached + return false; + } + return true; +} + + +static bool update_radio_crc() +{ + switch(m_config_local.crc) + { + case NRF_ESB_CRC_16BIT: + NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value + NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1 + break; + + case NRF_ESB_CRC_8BIT: + NRF_RADIO->CRCINIT = 0xFFUL; // Initial value + NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8+x^2^x^1+1 + break; + + case NRF_ESB_CRC_OFF: + break; + + default: + return false; + } + NRF_RADIO->CRCCNF = m_config_local.crc << RADIO_CRCCNF_LEN_Pos; + return true; +} + + +static bool update_radio_parameters() +{ + bool params_valid = true; + update_radio_tx_power(); + params_valid &= update_radio_bitrate(); + params_valid &= update_radio_protocol(); + params_valid &= update_radio_crc(); + update_rf_payload_format(m_config_local.payload_length); + params_valid &= (m_config_local.retransmit_delay >= NRF_ESB_RETRANSMIT_DELAY_MIN); + return params_valid; +} + + +static void reset_fifos() +{ + m_tx_fifo.entry_point = 0; + m_tx_fifo.exit_point = 0; + m_tx_fifo.count = 0; + + m_rx_fifo.entry_point = 0; + m_rx_fifo.exit_point = 0; + m_rx_fifo.count = 0; +} + + +static void initialize_fifos() +{ + reset_fifos(); + + for (int i = 0; i < NRF_ESB_TX_FIFO_SIZE; i++) + { + m_tx_fifo.p_payload[i] = &m_tx_fifo_payload[i]; + } + + for (int i = 0; i < NRF_ESB_RX_FIFO_SIZE; i++) + { + m_rx_fifo.p_payload[i] = &m_rx_fifo_payload[i]; + } +} + + +static void tx_fifo_remove_last() +{ + if (m_tx_fifo.count > 0) + { + DISABLE_RF_IRQ(); + + m_tx_fifo.count--; + if (++m_tx_fifo.exit_point >= NRF_ESB_TX_FIFO_SIZE) + { + m_tx_fifo.exit_point = 0; + } + + ENABLE_RF_IRQ(); + } +} + +/** @brief Function to push the content of the rx_buffer to the RX FIFO. + * + * The module will point the register NRF_RADIO->PACKETPTR to a buffer for receiving packets. + * After receiving a packet the module will call this function to copy the received data to + * the RX FIFO. + * + * @param pipe Pipe number to set for the packet. + * @param pid Packet ID. + * + * @retval true Operation successful. + * @retval false Operation failed. + */ +static bool rx_fifo_push_rfbuf(uint8_t pipe, uint8_t pid) +{ + if (m_rx_fifo.count < NRF_ESB_RX_FIFO_SIZE) + { + if (m_config_local.protocol == NRF_ESB_PROTOCOL_ESB_DPL) + { + if (m_rx_payload_buffer[0] > NRF_ESB_MAX_PAYLOAD_LENGTH) + { + return false; + } + + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->length = m_rx_payload_buffer[0]; + } + else if (m_config_local.mode == NRF_ESB_MODE_PTX) + { + // Received packet is an acknowledgment + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->length = 0; + } + else + { + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->length = m_config_local.payload_length; + } + + memcpy(m_rx_fifo.p_payload[m_rx_fifo.entry_point]->data, &m_rx_payload_buffer[2], + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->length); + + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->pipe = pipe; + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->rssi = NRF_RADIO->RSSISAMPLE; + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->pid = pid; + m_rx_fifo.p_payload[m_rx_fifo.entry_point]->noack = !(m_rx_payload_buffer[1] & 0x01); + if (++m_rx_fifo.entry_point >= NRF_ESB_RX_FIFO_SIZE) + { + m_rx_fifo.entry_point = 0; + } + m_rx_fifo.count++; + + return true; + } + + return false; +} + + +static void sys_timer_init() +{ + // Configure the system timer with a 1 MHz base frequency + NRF_ESB_SYS_TIMER->PRESCALER = 4; + NRF_ESB_SYS_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit; + NRF_ESB_SYS_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk; +} + + +static void ppi_init() +{ + NRF_PPI->CH[NRF_ESB_PPI_TIMER_START].EEP = (uint32_t)&NRF_RADIO->EVENTS_READY; + NRF_PPI->CH[NRF_ESB_PPI_TIMER_START].TEP = (uint32_t)&NRF_ESB_SYS_TIMER->TASKS_START; + + NRF_PPI->CH[NRF_ESB_PPI_TIMER_STOP].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS; + NRF_PPI->CH[NRF_ESB_PPI_TIMER_STOP].TEP = (uint32_t)&NRF_ESB_SYS_TIMER->TASKS_STOP; + + NRF_PPI->CH[NRF_ESB_PPI_RX_TIMEOUT].EEP = (uint32_t)&NRF_ESB_SYS_TIMER->EVENTS_COMPARE[0]; + NRF_PPI->CH[NRF_ESB_PPI_RX_TIMEOUT].TEP = (uint32_t)&NRF_RADIO->TASKS_DISABLE; + + NRF_PPI->CH[NRF_ESB_PPI_TX_START].EEP = (uint32_t)&NRF_ESB_SYS_TIMER->EVENTS_COMPARE[1]; + NRF_PPI->CH[NRF_ESB_PPI_TX_START].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN; +} + + +static void start_tx_transaction() +{ + bool ack; + + m_last_tx_attempts = 1; + // Prepare the payload + mp_current_payload = m_tx_fifo.p_payload[m_tx_fifo.exit_point]; + + + switch (m_config_local.protocol) + { + case NRF_ESB_PROTOCOL_ESB: + update_rf_payload_format(mp_current_payload->length); + m_tx_payload_buffer[0] = mp_current_payload->pid; + m_tx_payload_buffer[1] = 0; + memcpy(&m_tx_payload_buffer[2], mp_current_payload->data, mp_current_payload->length); + + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; + + // Configure the retransmit counter + m_retransmits_remaining = m_config_local.retransmit_count; + on_radio_disabled = on_radio_disabled_tx; + m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK; + break; + + case NRF_ESB_PROTOCOL_ESB_DPL: + ack = !mp_current_payload->noack || !m_config_local.selective_auto_ack; + m_tx_payload_buffer[0] = mp_current_payload->length; + m_tx_payload_buffer[1] = mp_current_payload->pid << 1; + m_tx_payload_buffer[1] |= mp_current_payload->noack ? 0x00 : 0x01; + memcpy(&m_tx_payload_buffer[2], mp_current_payload->data, mp_current_payload->length); + + // Handling ack if noack is set to false or if selective auto ack is turned off + if (ack) + { + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; + + // Configure the retransmit counter + m_retransmits_remaining = m_config_local.retransmit_count; + on_radio_disabled = on_radio_disabled_tx; + m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK; + } + else + { + NRF_RADIO->SHORTS = m_radio_shorts_common; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + on_radio_disabled = on_radio_disabled_tx_noack; + m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX; + } + break; + + default: + // Should not be reached + break; + } + + NRF_RADIO->TXADDRESS = mp_current_payload->pipe; + NRF_RADIO->RXADDRESSES = 1 << mp_current_payload->pipe; + + NRF_RADIO->FREQUENCY = m_esb_addr.rf_channel; + NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; + + NVIC_ClearPendingIRQ(RADIO_IRQn); + NVIC_EnableIRQ(RADIO_IRQn); + + NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->EVENTS_PAYLOAD = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + + DEBUG_PIN_SET(DEBUGPIN4); + NRF_RADIO->TASKS_TXEN = 1; +} + + +static void on_radio_disabled_tx_noack() +{ + m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK; + tx_fifo_remove_last(); + + if (m_tx_fifo.count == 0) + { + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + NVIC_SetPendingIRQ(ESB_EVT_IRQ); + } + else + { + NVIC_SetPendingIRQ(ESB_EVT_IRQ); + start_tx_transaction(); + } +} + + +static void on_radio_disabled_tx() +{ + // Remove the DISABLED -> RXEN shortcut, to make sure the radio stays + // disabled after the RX window + NRF_RADIO->SHORTS = m_radio_shorts_common; + + // Make sure the timer is started the next time the radio is ready, + // and that it will disable the radio automatically if no packet is + // received by the time defined in m_wait_for_ack_timeout_us + NRF_ESB_SYS_TIMER->CC[0] = m_wait_for_ack_timeout_us; + NRF_ESB_SYS_TIMER->CC[1] = m_config_local.retransmit_delay - 130; + NRF_ESB_SYS_TIMER->TASKS_CLEAR = 1; + NRF_ESB_SYS_TIMER->EVENTS_COMPARE[0] = 0; + NRF_ESB_SYS_TIMER->EVENTS_COMPARE[1] = 0; + + NRF_PPI->CHENSET = (1 << NRF_ESB_PPI_TIMER_START) | + (1 << NRF_ESB_PPI_RX_TIMEOUT) | + (1 << NRF_ESB_PPI_TIMER_STOP); + NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TX_START); + NRF_RADIO->EVENTS_END = 0; + + if (m_config_local.protocol == NRF_ESB_PROTOCOL_ESB) + { + update_rf_payload_format(0); + } + + NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; + on_radio_disabled = on_radio_disabled_tx_wait_for_ack; + m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_RX_ACK; +} + + +static void on_radio_disabled_tx_wait_for_ack() +{ + // This marks the completion of a TX_RX sequence (TX with ACK) + + // Make sure the timer will not deactivate the radio if a packet is received + NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TIMER_START) | + (1 << NRF_ESB_PPI_RX_TIMEOUT) | + (1 << NRF_ESB_PPI_TIMER_STOP); + + // If the radio has received a packet and the CRC status is OK + if (NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) + { + NRF_ESB_SYS_TIMER->TASKS_STOP = 1; + NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TX_START); + m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK; + m_last_tx_attempts = m_config_local.retransmit_count - m_retransmits_remaining + 1; + + tx_fifo_remove_last(); + + if (m_config_local.protocol != NRF_ESB_PROTOCOL_ESB && m_rx_payload_buffer[0] > 0) + { + if (rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS, m_rx_payload_buffer[1] >> 1)) + { + m_interrupt_flags |= NRF_ESB_INT_RX_DATA_RECEIVED_MSK; + } + } + + if ((m_tx_fifo.count == 0) || (m_config_local.tx_mode == NRF_ESB_TXMODE_MANUAL)) + { + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + NVIC_SetPendingIRQ(ESB_EVT_IRQ); + } + else + { + NVIC_SetPendingIRQ(ESB_EVT_IRQ); + start_tx_transaction(); + } + } + else + { + if (m_retransmits_remaining-- == 0) + { + NRF_ESB_SYS_TIMER->TASKS_STOP = 1; + NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TX_START); + // All retransmits are expended, and the TX operation is suspended + m_last_tx_attempts = m_config_local.retransmit_count + 1; + m_interrupt_flags |= NRF_ESB_INT_TX_FAILED_MSK; + + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + NVIC_SetPendingIRQ(ESB_EVT_IRQ); + } + else + { + // There are still more retransmits left, TX mode should be + // entered again as soon as the system timer reaches CC[1]. + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk; + update_rf_payload_format(mp_current_payload->length); + NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; + on_radio_disabled = on_radio_disabled_tx; + m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK; + NRF_ESB_SYS_TIMER->TASKS_START = 1; + NRF_PPI->CHENSET = (1 << NRF_ESB_PPI_TX_START); + if (NRF_ESB_SYS_TIMER->EVENTS_COMPARE[1]) + { + NRF_RADIO->TASKS_TXEN = 1; + } + } + } +} + +static void clear_events_restart_rx(void) +{ + NRF_RADIO->SHORTS = m_radio_shorts_common; + update_rf_payload_format(m_config_local.payload_length); + NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; + NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->TASKS_DISABLE = 1; + + while (NRF_RADIO->EVENTS_DISABLED == 0); + + NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_TXEN_Msk; + + NRF_RADIO->TASKS_RXEN = 1; +} + +static void on_radio_disabled_rx(void) +{ + bool ack = false; + bool retransmit_payload = false; + bool send_rx_event = true; + pipe_info_t * p_pipe_info; + + if (NRF_RADIO->CRCSTATUS == 0) + { + clear_events_restart_rx(); + return; + } + + if (m_rx_fifo.count >= NRF_ESB_RX_FIFO_SIZE) + { + clear_events_restart_rx(); + return; + } + + p_pipe_info = &m_rx_pipe_info[NRF_RADIO->RXMATCH]; + if (NRF_RADIO->RXCRC == p_pipe_info->crc && + (m_rx_payload_buffer[1] >> 1) == p_pipe_info->pid + ) + { + retransmit_payload = true; + send_rx_event = false; + } + + p_pipe_info->pid = m_rx_payload_buffer[1] >> 1; + p_pipe_info->crc = NRF_RADIO->RXCRC; + + if ((m_config_local.selective_auto_ack == false) || ((m_rx_payload_buffer[1] & 0x01) == 1)) + { + ack = true; + } + + if (ack) + { + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk; + + switch (m_config_local.protocol) + { + case NRF_ESB_PROTOCOL_ESB_DPL: + { + if (m_tx_fifo.count > 0 && + (m_tx_fifo.p_payload[m_tx_fifo.exit_point]->pipe == NRF_RADIO->RXMATCH) + ) + { + // Pipe stays in ACK with payload until TX FIFO is empty + // Do not report TX success on first ack payload or retransmit + if (p_pipe_info->ack_payload == true && !retransmit_payload) + { + if (++m_tx_fifo.exit_point >= NRF_ESB_TX_FIFO_SIZE) + { + m_tx_fifo.exit_point = 0; + } + + m_tx_fifo.count--; + + // ACK payloads also require TX_DS + // (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf'). + m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK; + } + + p_pipe_info->ack_payload = true; + + mp_current_payload = m_tx_fifo.p_payload[m_tx_fifo.exit_point]; + + update_rf_payload_format(mp_current_payload->length); + m_tx_payload_buffer[0] = mp_current_payload->length; + memcpy(&m_tx_payload_buffer[2], + mp_current_payload->data, + mp_current_payload->length); + } + else + { + p_pipe_info->ack_payload = false; + update_rf_payload_format(0); + m_tx_payload_buffer[0] = 0; + } + + m_tx_payload_buffer[1] = m_rx_payload_buffer[1]; + } + break; + + case NRF_ESB_PROTOCOL_ESB: + { + update_rf_payload_format(0); + m_tx_payload_buffer[0] = m_rx_payload_buffer[0]; + m_tx_payload_buffer[1] = 0; + } + break; + } + + m_nrf_esb_mainstate = NRF_ESB_STATE_PRX_SEND_ACK; + NRF_RADIO->TXADDRESS = NRF_RADIO->RXMATCH; + NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; + on_radio_disabled = on_radio_disabled_rx_ack; + } + else + { + clear_events_restart_rx(); + } + + if (send_rx_event) + { + // Push the new packet to the RX buffer and trigger a received event if the operation was + // successful. + if (rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH, p_pipe_info->pid)) + { + m_interrupt_flags |= NRF_ESB_INT_RX_DATA_RECEIVED_MSK; + NVIC_SetPendingIRQ(ESB_EVT_IRQ); + } + } +} + + +static void on_radio_disabled_rx_ack(void) +{ + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_TXEN_Msk; + update_rf_payload_format(m_config_local.payload_length); + + NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; + on_radio_disabled = on_radio_disabled_rx; + + m_nrf_esb_mainstate = NRF_ESB_STATE_PRX; +} + + +/**@brief Function for clearing pending interrupts. + * + * @param[in,out] p_interrupts Pointer to the value that holds the current interrupts. + * + * @retval NRF_SUCCESS If the interrupts were cleared successfully. + * @retval NRF_ERROR_NULL If the required parameter was NULL. + * @retval NRF_INVALID_STATE If the module is not initialized. + */ +static uint32_t nrf_esb_get_clear_interrupts(uint32_t * p_interrupts) +{ + VERIFY_TRUE(m_esb_initialized, NRF_ERROR_INVALID_STATE); + VERIFY_PARAM_NOT_NULL(p_interrupts); + + DISABLE_RF_IRQ(); + + *p_interrupts = m_interrupt_flags; + m_interrupt_flags = 0; + + ENABLE_RF_IRQ(); + + return NRF_SUCCESS; +} + + +void RADIO_IRQHandler() +{ + if (NRF_RADIO->EVENTS_READY && (NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk)) + { + NRF_RADIO->EVENTS_READY = 0; + DEBUG_PIN_SET(DEBUGPIN1); + } + + if (NRF_RADIO->EVENTS_END && (NRF_RADIO->INTENSET & RADIO_INTENSET_END_Msk)) + { + NRF_RADIO->EVENTS_END = 0; + DEBUG_PIN_SET(DEBUGPIN2); + + // Call the correct on_radio_end function, depending on the current protocol state + if (on_radio_end) + { + on_radio_end(); + } + } + + if (NRF_RADIO->EVENTS_DISABLED && (NRF_RADIO->INTENSET & RADIO_INTENSET_DISABLED_Msk)) + { + NRF_RADIO->EVENTS_DISABLED = 0; + DEBUG_PIN_SET(DEBUGPIN3); + + // Call the correct on_radio_disable function, depending on the current protocol state + if (on_radio_disabled) + { + on_radio_disabled(); + } + } + + DEBUG_PIN_CLR(DEBUGPIN1); + DEBUG_PIN_CLR(DEBUGPIN2); + DEBUG_PIN_CLR(DEBUGPIN3); + DEBUG_PIN_CLR(DEBUGPIN4); +} + + +uint32_t nrf_esb_init(nrf_esb_config_t const * p_config) +{ + uint32_t err_code; + + VERIFY_PARAM_NOT_NULL(p_config); + + if (m_esb_initialized) + { + err_code = nrf_esb_disable(); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + + m_event_handler = p_config->event_handler; + + memcpy(&m_config_local, p_config, sizeof(nrf_esb_config_t)); + + m_interrupt_flags = 0; + + memset(m_rx_pipe_info, 0, sizeof(m_rx_pipe_info)); + memset(m_pids, 0, sizeof(m_pids)); + + VERIFY_TRUE(update_radio_parameters(), NRF_ERROR_INVALID_PARAM); + + // Configure radio address registers according to ESB default values + NRF_RADIO->BASE0 = 0xE7E7E7E7; + NRF_RADIO->BASE1 = 0x43434343; + NRF_RADIO->PREFIX0 = 0x23C343E7; + NRF_RADIO->PREFIX1 = 0x13E363A3; + + initialize_fifos(); + + sys_timer_init(); + + ppi_init(); + + NVIC_SetPriority(RADIO_IRQn, m_config_local.radio_irq_priority & ESB_IRQ_PRIORITY_MSK); + NVIC_SetPriority(ESB_EVT_IRQ, m_config_local.event_irq_priority & ESB_IRQ_PRIORITY_MSK); + NVIC_EnableIRQ(ESB_EVT_IRQ); + +#ifdef NRF52 + if(m_address_hang_fix_enable) + { + // Setup a timeout timer to start on an ADDRESS match, and stop on a BCMATCH event. + // If the BCMATCH event never occurs the CC[0] event will fire, and the timer interrupt will disable the radio to recover. + m_radio_shorts_common |= RADIO_SHORTS_ADDRESS_BCSTART_Msk; + NRF_RADIO->BCC = 2; + NRF_ESB_BUGFIX_TIMER->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos; + NRF_ESB_BUGFIX_TIMER->PRESCALER = 4; + NRF_ESB_BUGFIX_TIMER->CC[0] = 5; + NRF_ESB_BUGFIX_TIMER->SHORTS = TIMER_SHORTS_COMPARE0_STOP_Msk | TIMER_SHORTS_COMPARE0_CLEAR_Msk; + NRF_ESB_BUGFIX_TIMER->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos; + NRF_ESB_BUGFIX_TIMER->INTENSET = TIMER_INTENSET_COMPARE0_Msk; + NRF_ESB_BUGFIX_TIMER->TASKS_CLEAR = 1; + NVIC_SetPriority(NRF_ESB_BUGFIX_TIMER_IRQn, 5); + NVIC_EnableIRQ(NRF_ESB_BUGFIX_TIMER_IRQn); + + NRF_PPI->CH[NRF_ESB_PPI_BUGFIX1].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS; + NRF_PPI->CH[NRF_ESB_PPI_BUGFIX1].TEP = (uint32_t)&NRF_ESB_BUGFIX_TIMER->TASKS_START; + + NRF_PPI->CH[NRF_ESB_PPI_BUGFIX2].EEP = (uint32_t)&NRF_RADIO->EVENTS_BCMATCH; + NRF_PPI->CH[NRF_ESB_PPI_BUGFIX2].TEP = (uint32_t)&NRF_ESB_BUGFIX_TIMER->TASKS_STOP; + + NRF_PPI->CH[NRF_ESB_PPI_BUGFIX3].EEP = (uint32_t)&NRF_RADIO->EVENTS_BCMATCH; + NRF_PPI->CH[NRF_ESB_PPI_BUGFIX3].TEP = (uint32_t)&NRF_ESB_BUGFIX_TIMER->TASKS_CLEAR; + + NRF_PPI->CHENSET = (1 << NRF_ESB_PPI_BUGFIX1) | (1 << NRF_ESB_PPI_BUGFIX2) | (1 << NRF_ESB_PPI_BUGFIX3); + } +#endif + + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + m_esb_initialized = true; + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_suspend(void) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + // Clear PPI + NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TIMER_START) | + (1 << NRF_ESB_PPI_TIMER_STOP) | + (1 << NRF_ESB_PPI_RX_TIMEOUT) | + (1 << NRF_ESB_PPI_TX_START); + + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_disable(void) +{ + // Clear PPI + NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TIMER_START) | + (1 << NRF_ESB_PPI_TIMER_STOP) | + (1 << NRF_ESB_PPI_RX_TIMEOUT) | + (1 << NRF_ESB_PPI_TX_START); + + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + + reset_fifos(); + + memset(m_rx_pipe_info, 0, sizeof(m_rx_pipe_info)); + memset(m_pids, 0, sizeof(m_pids)); + + // Disable the radio + NVIC_DisableIRQ(ESB_EVT_IRQ); + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos | + RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos; + + return NRF_SUCCESS; +} + + +bool nrf_esb_is_idle(void) +{ + return m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE; +} + + +void ESB_EVT_IRQHandler(void) +{ + ret_code_t err_code; + uint32_t interrupts; + nrf_esb_evt_t event; + + event.tx_attempts = m_last_tx_attempts; + + err_code = nrf_esb_get_clear_interrupts(&interrupts); + if (err_code == NRF_SUCCESS && m_event_handler != 0) + { + if (interrupts & NRF_ESB_INT_TX_SUCCESS_MSK) + { + event.evt_id = NRF_ESB_EVENT_TX_SUCCESS; + m_event_handler(&event); + } + if (interrupts & NRF_ESB_INT_TX_FAILED_MSK) + { + event.evt_id = NRF_ESB_EVENT_TX_FAILED; + m_event_handler(&event); + } + if (interrupts & NRF_ESB_INT_RX_DATA_RECEIVED_MSK) + { + event.evt_id = NRF_ESB_EVENT_RX_RECEIVED; + m_event_handler(&event); + } + } +} + +uint32_t nrf_esb_write_payload(nrf_esb_payload_t const * p_payload) +{ + VERIFY_TRUE(m_esb_initialized, NRF_ERROR_INVALID_STATE); + VERIFY_PARAM_NOT_NULL(p_payload); + VERIFY_PAYLOAD_LENGTH(p_payload); + VERIFY_FALSE(m_tx_fifo.count >= NRF_ESB_TX_FIFO_SIZE, NRF_ERROR_NO_MEM); + VERIFY_TRUE(p_payload->pipe < NRF_ESB_PIPE_COUNT, NRF_ERROR_INVALID_PARAM); + + DISABLE_RF_IRQ(); + + memcpy(m_tx_fifo.p_payload[m_tx_fifo.entry_point], p_payload, sizeof(nrf_esb_payload_t)); + + m_pids[p_payload->pipe] = (m_pids[p_payload->pipe] + 1) % (NRF_ESB_PID_MAX + 1); + m_tx_fifo.p_payload[m_tx_fifo.entry_point]->pid = m_pids[p_payload->pipe]; + + if (++m_tx_fifo.entry_point >= NRF_ESB_TX_FIFO_SIZE) + { + m_tx_fifo.entry_point = 0; + } + + m_tx_fifo.count++; + + ENABLE_RF_IRQ(); + + + if (m_config_local.mode == NRF_ESB_MODE_PTX && + m_config_local.tx_mode == NRF_ESB_TXMODE_AUTO && + m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE) + { + start_tx_transaction(); + } + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_read_rx_payload(nrf_esb_payload_t * p_payload) +{ + VERIFY_TRUE(m_esb_initialized, NRF_ERROR_INVALID_STATE); + VERIFY_PARAM_NOT_NULL(p_payload); + + if (m_rx_fifo.count == 0) + { + return NRF_ERROR_NOT_FOUND; + } + + DISABLE_RF_IRQ(); + + p_payload->length = m_rx_fifo.p_payload[m_rx_fifo.exit_point]->length; + p_payload->pipe = m_rx_fifo.p_payload[m_rx_fifo.exit_point]->pipe; + p_payload->rssi = m_rx_fifo.p_payload[m_rx_fifo.exit_point]->rssi; + p_payload->pid = m_rx_fifo.p_payload[m_rx_fifo.exit_point]->pid; + p_payload->noack = m_rx_fifo.p_payload[m_rx_fifo.exit_point]->noack; + memcpy(p_payload->data, m_rx_fifo.p_payload[m_rx_fifo.exit_point]->data, p_payload->length); + + if (++m_rx_fifo.exit_point >= NRF_ESB_RX_FIFO_SIZE) + { + m_rx_fifo.exit_point = 0; + } + + m_rx_fifo.count--; + + ENABLE_RF_IRQ(); + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_start_tx(void) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + if (m_tx_fifo.count == 0) + { + return NRF_ERROR_BUFFER_EMPTY; + } + + start_tx_transaction(); + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_start_rx(void) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + NRF_RADIO->INTENCLR = 0xFFFFFFFF; + NRF_RADIO->EVENTS_DISABLED = 0; + on_radio_disabled = on_radio_disabled_rx; + + NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_TXEN_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + m_nrf_esb_mainstate = NRF_ESB_STATE_PRX; + + NRF_RADIO->RXADDRESSES = m_esb_addr.rx_pipes_enabled; + NRF_RADIO->FREQUENCY = m_esb_addr.rf_channel; + NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; + + NVIC_ClearPendingIRQ(RADIO_IRQn); + NVIC_EnableIRQ(RADIO_IRQn); + + NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->EVENTS_PAYLOAD = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + + NRF_RADIO->TASKS_RXEN = 1; + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_stop_rx(void) +{ + if (m_nrf_esb_mainstate == NRF_ESB_STATE_PRX) + { + NRF_RADIO->SHORTS = 0; + NRF_RADIO->INTENCLR = 0xFFFFFFFF; + on_radio_disabled = NULL; + NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->TASKS_DISABLE = 1; + while (NRF_RADIO->EVENTS_DISABLED == 0); + m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE; + + return NRF_SUCCESS; + } + + return NRF_ESB_ERROR_NOT_IN_RX_MODE; +} + + +uint32_t nrf_esb_flush_tx(void) +{ + VERIFY_TRUE(m_esb_initialized, NRF_ERROR_INVALID_STATE); + + DISABLE_RF_IRQ(); + + m_tx_fifo.count = 0; + m_tx_fifo.entry_point = 0; + m_tx_fifo.exit_point = 0; + + ENABLE_RF_IRQ(); + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_pop_tx(void) +{ + VERIFY_TRUE(m_esb_initialized, NRF_ERROR_INVALID_STATE); + VERIFY_TRUE(m_tx_fifo.count > 0, NRF_ERROR_BUFFER_EMPTY); + + DISABLE_RF_IRQ(); + + if (++m_tx_fifo.entry_point >= NRF_ESB_TX_FIFO_SIZE) + { + m_tx_fifo.entry_point = 0; + } + m_tx_fifo.count--; + + ENABLE_RF_IRQ(); + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_flush_rx(void) +{ + VERIFY_TRUE(m_esb_initialized, NRF_ERROR_INVALID_STATE); + + DISABLE_RF_IRQ(); + + m_rx_fifo.count = 0; + m_rx_fifo.entry_point = 0; + m_rx_fifo.exit_point = 0; + + memset(m_rx_pipe_info, 0, sizeof(m_rx_pipe_info)); + + ENABLE_RF_IRQ(); + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_set_address_length(uint8_t length) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_TRUE(length > 2 && length < 6, NRF_ERROR_INVALID_PARAM); + + /* + Workaround for nRF52832 Rev 1 Errata 107 + Check if pipe 0 or pipe 1-7 has a 'zero address'. + Avoid using access addresses in the following pattern (where X is don't care): + ADDRLEN=5 + BASE0 = 0x0000XXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0x00XXXXXX + + ADDRLEN=4 + BASE0 = 0x00XXXXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0x00XXXXXX + */ + uint32_t base_address_mask = length == 5 ? 0xFFFF0000 : 0xFF000000; + if((NRF_RADIO->BASE0 & base_address_mask) == 0 && (NRF_RADIO->PREFIX0 & 0x000000FF) == 0) + { + return NRF_ERROR_INVALID_PARAM; + } + if((NRF_RADIO->BASE1 & base_address_mask) == 0 && ((NRF_RADIO->PREFIX0 & 0x0000FF00) == 0 ||(NRF_RADIO->PREFIX0 & 0x00FF0000) == 0 || (NRF_RADIO->PREFIX0 & 0xFF000000) == 0 || + (NRF_RADIO->PREFIX1 & 0xFF000000) == 0 || (NRF_RADIO->PREFIX1 & 0x00FF0000) == 0 ||(NRF_RADIO->PREFIX1 & 0x0000FF00) == 0 || (NRF_RADIO->PREFIX1 & 0x000000FF) == 0)) + { + return NRF_ERROR_INVALID_PARAM; + } + + m_esb_addr.addr_length = length; + + update_rf_payload_format(m_config_local.payload_length); + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_set_base_address_0(uint8_t const * p_addr) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_PARAM_NOT_NULL(p_addr); + + /* + Workaround for nRF52832 Rev 1 Errata 107 + Check if pipe 0 or pipe 1-7 has a 'zero address'. + Avoid using access addresses in the following pattern (where X is don't care): + ADDRLEN=5 + BASE0 = 0x0000XXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0x00XXXXXX + + ADDRLEN=4 + BASE0 = 0x00XXXXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0x00XXXXXX + */ + uint32_t base_address_mask = m_esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000; + if((addr_conv(p_addr) & base_address_mask) == 0 && (NRF_RADIO->PREFIX0 & 0x000000FF) == 0) + { + return NRF_ERROR_INVALID_PARAM; + } + + memcpy(m_esb_addr.base_addr_p0, p_addr, 4); + + update_radio_addresses(NRF_ESB_ADDR_UPDATE_MASK_BASE0); + + return apply_address_workarounds(); +} + + +uint32_t nrf_esb_set_base_address_1(uint8_t const * p_addr) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_PARAM_NOT_NULL(p_addr); + + /* + Workaround for nRF52832 Rev 1 Errata 107 + Check if pipe 0 or pipe 1-7 has a 'zero address'. + Avoid using access addresses in the following pattern (where X is don't care): + ADDRLEN=5 + BASE0 = 0x0000XXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0x00XXXXXX + + ADDRLEN=4 + BASE0 = 0x00XXXXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0x00XXXXXX + */ + uint32_t base_address_mask = m_esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000; + if((addr_conv(p_addr) & base_address_mask) == 0 && ((NRF_RADIO->PREFIX0 & 0x0000FF00) == 0 ||(NRF_RADIO->PREFIX0 & 0x00FF0000) == 0 || (NRF_RADIO->PREFIX0 & 0xFF000000) == 0 || + (NRF_RADIO->PREFIX1 & 0xFF000000) == 0 || (NRF_RADIO->PREFIX1 & 0x00FF0000) == 0 ||(NRF_RADIO->PREFIX1 & 0x0000FF00) == 0 || (NRF_RADIO->PREFIX1 & 0x000000FF) == 0)) + { + return NRF_ERROR_INVALID_PARAM; + } + + memcpy(m_esb_addr.base_addr_p1, p_addr, 4); + + update_radio_addresses(NRF_ESB_ADDR_UPDATE_MASK_BASE1); + + return apply_address_workarounds(); +} + + +uint32_t nrf_esb_set_prefixes(uint8_t const * p_prefixes, uint8_t num_pipes) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_PARAM_NOT_NULL(p_prefixes); + VERIFY_TRUE(num_pipes < 9, NRF_ERROR_INVALID_PARAM); + + /* + Workaround for nRF52832 Rev 1 Errata 107 + Check if pipe 0 or pipe 1-7 has a 'zero address'. + Avoid using access addresses in the following pattern (where X is don't care): + ADDRLEN=5 + BASE0 = 0x0000XXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0x00XXXXXX + + ADDRLEN=4 + BASE0 = 0x00XXXXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0x00XXXXXX + */ + uint32_t base_address_mask = m_esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000; + if(num_pipes >= 1 && (NRF_RADIO->BASE0 & base_address_mask) == 0 && p_prefixes[0] == 0) + { + return NRF_ERROR_INVALID_PARAM; + } + + if((NRF_RADIO->BASE1 & base_address_mask) == 0) + { + for (uint8_t i = 1; i < num_pipes; i++) + { + if (p_prefixes[i] == 0) + { + return NRF_ERROR_INVALID_PARAM; + } + } + } + + memcpy(m_esb_addr.pipe_prefixes, p_prefixes, num_pipes); + m_esb_addr.num_pipes = num_pipes; + m_esb_addr.rx_pipes_enabled = BIT_MASK_UINT_8(num_pipes); + + update_radio_addresses(NRF_ESB_ADDR_UPDATE_MASK_PREFIX); + + return apply_address_workarounds(); +} + + +uint32_t nrf_esb_update_prefix(uint8_t pipe, uint8_t prefix) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_TRUE(pipe < 8, NRF_ERROR_INVALID_PARAM); + + /* + Workaround for nRF52832 Rev 1 Errata 107 + Check if pipe 0 or pipe 1-7 has a 'zero address'. + Avoid using access addresses in the following pattern (where X is don't care): + ADDRLEN=5 + BASE0 = 0x0000XXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x0000XXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x0000XXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x0000XXXX, PREFIX1 = 0x00XXXXXX + + ADDRLEN=4 + BASE0 = 0x00XXXXXX, PREFIX0 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX0 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX0 = 0x00XXXXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXXXX00 + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXXXX00XX + BASE1 = 0x00XXXXXX, PREFIX1 = 0xXX00XXXX + BASE1 = 0x00XXXXXX, PREFIX1 = 0x00XXXXXX + */ + uint32_t base_address_mask = m_esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000; + if (pipe == 0) + { + if((NRF_RADIO->BASE0 & base_address_mask) == 0 && prefix == 0) + { + return NRF_ERROR_INVALID_PARAM; + } + } + else{ + if((NRF_RADIO->BASE1 & base_address_mask) == 0 && prefix == 0) + { + return NRF_ERROR_INVALID_PARAM; + } + } + + m_esb_addr.pipe_prefixes[pipe] = prefix; + + update_radio_addresses(NRF_ESB_ADDR_UPDATE_MASK_PREFIX); + + return apply_address_workarounds(); +} + + +uint32_t nrf_esb_enable_pipes(uint8_t enable_mask) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + m_esb_addr.rx_pipes_enabled = enable_mask; + + return apply_address_workarounds(); +} + + +uint32_t nrf_esb_set_rf_channel(uint32_t channel) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_TRUE(channel <= 100, NRF_ERROR_INVALID_PARAM); + + m_esb_addr.rf_channel = channel; + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_get_rf_channel(uint32_t * p_channel) +{ + VERIFY_PARAM_NOT_NULL(p_channel); + + *p_channel = m_esb_addr.rf_channel; + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_set_tx_power(nrf_esb_tx_power_t tx_output_power) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + if ( m_config_local.tx_output_power != tx_output_power ) + { + m_config_local.tx_output_power = tx_output_power; + update_radio_tx_power(); + } + + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_set_retransmit_delay(uint16_t delay) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_TRUE(delay >= NRF_ESB_RETRANSMIT_DELAY_MIN, NRF_ERROR_INVALID_PARAM); + + m_config_local.retransmit_delay = delay; + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_set_retransmit_count(uint16_t count) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + m_config_local.retransmit_count = count; + return NRF_SUCCESS; +} + + +uint32_t nrf_esb_set_bitrate(nrf_esb_bitrate_t bitrate) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + + m_config_local.bitrate = bitrate; + return update_radio_bitrate() ? NRF_SUCCESS : NRF_ERROR_INVALID_PARAM; +} + + +uint32_t nrf_esb_reuse_pid(uint8_t pipe) +{ + VERIFY_TRUE(m_nrf_esb_mainstate == NRF_ESB_STATE_IDLE, NRF_ERROR_BUSY); + VERIFY_TRUE(pipe < 8, NRF_ERROR_INVALID_PARAM); + + m_pids[pipe] = (m_pids[pipe] + NRF_ESB_PID_MAX) % (NRF_ESB_PID_MAX + 1); + return NRF_SUCCESS; +} + + +// Handler for +#ifdef NRF52 +void NRF_ESB_BUGFIX_TIMER_IRQHandler(void) +{ + if(NRF_ESB_BUGFIX_TIMER->EVENTS_COMPARE[0]) + { + NRF_ESB_BUGFIX_TIMER->EVENTS_COMPARE[0] = 0; + + // If the timeout timer fires and we are in the PTX receive ACK state, disable the radio + if(m_nrf_esb_mainstate == NRF_ESB_STATE_PTX_RX_ACK) + { + NRF_RADIO->TASKS_DISABLE = 1; + } + } +} +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb.h new file mode 100644 index 0000000..0c80efb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb.h @@ -0,0 +1,609 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __NRF_ESB_H +#define __NRF_ESB_H + +#include <stdbool.h> +#include <stdint.h> +#include "nrf.h" +#include "app_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup nrf_esb Enhanced ShockBurst + * @{ + * @ingroup proprietary_api + * + * @brief Enhanced ShockBurst (ESB) is a basic protocol that supports two-way data + * packet communication including packet buffering, packet acknowledgment, + * and automatic retransmission of lost packets. + */ + +/** @name Debug pins + * @{ + * @brief If NRF_ESB_DEBUG is defined, these GPIO pins can be used for debug timing. + */ + +#define DEBUGPIN1 12 //!< If NRF_ESB_DEBUG is defined, this GPIO pin is set with every radio interrupt. +#define DEBUGPIN2 13 //!< If NRF_ESB_DEBUG is defined, this GPIO pin is set with every NRF_RADIO->EVENTS_END. +#define DEBUGPIN3 14 //!< If NRF_ESB_DEBUG is defined, this GPIO pin is set with every NRF_RADIO->EVENTS_DISABLED. +#define DEBUGPIN4 15 //!< If NRF_ESB_DEBUG is defined, this GPIO pin is set when the radio is set to start transmission. + + +#ifdef NRF_ESB_DEBUG +#define DEBUG_PIN_SET(a) (NRF_GPIO->OUTSET = (1 << (a))) //!< Used internally to set debug pins. +#define DEBUG_PIN_CLR(a) (NRF_GPIO->OUTCLR = (1 << (a))) //!< Used internally to clear debug pins. +#else +#define DEBUG_PIN_SET(a) //!< Used internally to set debug pins. +#define DEBUG_PIN_CLR(a) //!< Used internally to clear debug pins. +#endif + + /** @} */ + +#define NRF_ESB_RETRANSMIT_DELAY_MIN 135 + +// Hardcoded parameters - change if necessary +#ifndef NRF_ESB_MAX_PAYLOAD_LENGTH +#define NRF_ESB_MAX_PAYLOAD_LENGTH 32 //!< The maximum size of the payload. Valid values are 1 to 252. +#endif + +#define NRF_ESB_TX_FIFO_SIZE 8 //!< The size of the transmission first-in, first-out buffer. +#define NRF_ESB_RX_FIFO_SIZE 8 //!< The size of the reception first-in, first-out buffer. + +// 252 is the largest possible payload size according to the nRF5 architecture. +STATIC_ASSERT(NRF_ESB_MAX_PAYLOAD_LENGTH <= 252); + +#define NRF_ESB_SYS_TIMER NRF_TIMER2 //!< The timer that is used by the module. +#define NRF_ESB_SYS_TIMER_IRQ_Handler TIMER2_IRQHandler //!< The handler that is used by @ref NRF_ESB_SYS_TIMER. + +#define NRF_ESB_PPI_TIMER_START 10 //!< The PPI channel used for starting the timer. +#define NRF_ESB_PPI_TIMER_STOP 11 //!< The PPI channel used for stopping the timer. +#define NRF_ESB_PPI_RX_TIMEOUT 12 //!< The PPI channel used for RX time-out. +#define NRF_ESB_PPI_TX_START 13 //!< The PPI channel used for starting TX. + +/**@cond NO_DOXYGEN */ + +// nRF52 address fix timer and PPI defines +#ifdef NRF52 +#define NRF_ESB_PPI_BUGFIX1 9 +#define NRF_ESB_PPI_BUGFIX2 8 +#define NRF_ESB_PPI_BUGFIX3 7 + +#define NRF_ESB_BUGFIX_TIMER NRF_TIMER3 +#define NRF_ESB_BUGFIX_TIMER_IRQn TIMER3_IRQn +#define NRF_ESB_BUGFIX_TIMER_IRQHandler TIMER3_IRQHandler +#endif + +/** @endcond */ + +// Interrupt flags +#define NRF_ESB_INT_TX_SUCCESS_MSK 0x01 //!< The flag used to indicate a success since the last event. +#define NRF_ESB_INT_TX_FAILED_MSK 0x02 //!< The flag used to indicate a failure since the last event. +#define NRF_ESB_INT_RX_DR_MSK 0x04 //!< The flag used to indicate that a packet was received since the last event. + +#define NRF_ESB_PID_RESET_VALUE 0xFF //!< Invalid PID value that is guaranteed to not collide with any valid PID value. +#define NRF_ESB_PID_MAX 3 //!< The maximum value for PID. +#define NRF_ESB_CRC_RESET_VALUE 0xFFFF //!< The CRC reset value. + +#define ESB_EVT_IRQ SWI0_IRQn //!< The ESB event IRQ number when running on an nRF5 device. +#define ESB_EVT_IRQHandler SWI0_IRQHandler //!< The handler for @ref ESB_EVT_IRQ when running on an nRF5 device. + +#if defined(NRF52) +#define ESB_IRQ_PRIORITY_MSK 0x07 //!< The mask used to enforce a valid IRQ priority. +#else +#define ESB_IRQ_PRIORITY_MSK 0x03 //!< The mask used to enforce a valid IRQ priority. +#endif + +/** @brief Default address configuration for ESB. + * @details Roughly equal to the nRF24Lxx default (except for the number of pipes, because more pipes are supported). */ +#define NRF_ESB_ADDR_DEFAULT \ +{ \ + .base_addr_p0 = { 0xE7, 0xE7, 0xE7, 0xE7 }, \ + .base_addr_p1 = { 0xC2, 0xC2, 0xC2, 0xC2 }, \ + .pipe_prefixes = { 0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 }, \ + .addr_length = 5, \ + .num_pipes = 8, \ + .rf_channel = 2, \ + .rx_pipes_enabled = 0xFF \ +} + + +/** @brief Default radio parameters. + * @details Roughly equal to the nRF24Lxx default parameters (except for CRC, which is set to 16 bit, and protocol, which is set to DPL). */ +#define NRF_ESB_DEFAULT_CONFIG {.protocol = NRF_ESB_PROTOCOL_ESB_DPL, \ + .mode = NRF_ESB_MODE_PTX, \ + .event_handler = 0, \ + .bitrate = NRF_ESB_BITRATE_2MBPS, \ + .crc = NRF_ESB_CRC_16BIT, \ + .tx_output_power = NRF_ESB_TX_POWER_0DBM, \ + .retransmit_delay = 250, \ + .retransmit_count = 3, \ + .tx_mode = NRF_ESB_TXMODE_AUTO, \ + .radio_irq_priority = 1, \ + .event_irq_priority = 2, \ + .payload_length = 32, \ + .selective_auto_ack = false \ +} + + +/** @brief Default legacy radio parameters. Identical to the nRF24Lxx defaults. */ +#define NRF_ESB_LEGACY_CONFIG {.protocol = NRF_ESB_PROTOCOL_ESB, \ + .mode = NRF_ESB_MODE_PTX, \ + .event_handler = 0, \ + .bitrate = NRF_ESB_BITRATE_2MBPS, \ + .crc = NRF_ESB_CRC_8BIT, \ + .tx_output_power = NRF_ESB_TX_POWER_0DBM, \ + .retransmit_delay = 600, \ + .retransmit_count = 3, \ + .tx_mode = NRF_ESB_TXMODE_AUTO, \ + .radio_irq_priority = 1, \ + .event_irq_priority = 2, \ + .payload_length = 32, \ + .selective_auto_ack = false \ +} + + +/** @brief Macro to create an initializer for a TX data packet. + * + * @details This macro generates an initializer. Using the initializer is more efficient + * than setting the individual parameters dynamically. + * + * @param[in] _pipe The pipe to use for the data packet. + * @param[in] ... Comma separated list of character data to put in the TX buffer. + * Supported values consist of 1 to 63 characters. + * + * @return Initializer that sets up the pipe, length, and byte array for content of the TX data. + */ +#define NRF_ESB_CREATE_PAYLOAD(_pipe, ...) \ + {.pipe = _pipe, .length = NUM_VA_ARGS(__VA_ARGS__), .data = {__VA_ARGS__}}; \ + STATIC_ASSERT(NUM_VA_ARGS(__VA_ARGS__) > 0 && NUM_VA_ARGS(__VA_ARGS__) <= 63) + + +/**@brief Enhanced ShockBurst protocols. */ +typedef enum { + NRF_ESB_PROTOCOL_ESB, /**< Enhanced ShockBurst with fixed payload length. */ + NRF_ESB_PROTOCOL_ESB_DPL /**< Enhanced ShockBurst with dynamic payload length. */ +} nrf_esb_protocol_t; + + +/**@brief Enhanced ShockBurst modes. */ +typedef enum { + NRF_ESB_MODE_PTX, /**< Primary transmitter mode. */ + NRF_ESB_MODE_PRX /**< Primary receiver mode. */ +} nrf_esb_mode_t; + + +/**@brief Enhanced ShockBurst bitrate modes. */ +typedef enum { + NRF_ESB_BITRATE_2MBPS = RADIO_MODE_MODE_Nrf_2Mbit, /**< 2 Mb radio mode. */ + NRF_ESB_BITRATE_1MBPS = RADIO_MODE_MODE_Nrf_1Mbit, /**< 1 Mb radio mode. */ + NRF_ESB_BITRATE_250KBPS = RADIO_MODE_MODE_Nrf_250Kbit, /**< 250 Kb radio mode. */ + NRF_ESB_BITRATE_1MBPS_BLE = RADIO_MODE_MODE_Ble_1Mbit, /**< 1 Mb radio mode using @e Bluetooth low energy radio parameters. */ +#if defined(NRF52) + NRF_ESB_BITRATE_2MBPS_BLE = 4 /**< 2 Mb radio mode using @e Bluetooth low energy radio parameters. */ +#endif +} nrf_esb_bitrate_t; + + +/**@brief Enhanced ShockBurst CRC modes. */ +typedef enum { + NRF_ESB_CRC_16BIT = RADIO_CRCCNF_LEN_Two, /**< Use two-byte CRC. */ + NRF_ESB_CRC_8BIT = RADIO_CRCCNF_LEN_One, /**< Use one-byte CRC. */ + NRF_ESB_CRC_OFF = RADIO_CRCCNF_LEN_Disabled /**< Disable CRC. */ +} nrf_esb_crc_t; + + +/**@brief Enhanced ShockBurst radio transmission power modes. */ +typedef enum { + NRF_ESB_TX_POWER_4DBM = RADIO_TXPOWER_TXPOWER_Pos4dBm, /**< 4 dBm radio transmit power. */ +#if defined(NRF52) + NRF_ESB_TX_POWER_3DBM = RADIO_TXPOWER_TXPOWER_Pos3dBm, /**< 3 dBm radio transmit power. */ +#endif + NRF_ESB_TX_POWER_0DBM = RADIO_TXPOWER_TXPOWER_0dBm, /**< 0 dBm radio transmit power. */ + NRF_ESB_TX_POWER_NEG4DBM = RADIO_TXPOWER_TXPOWER_Neg4dBm, /**< -4 dBm radio transmit power. */ + NRF_ESB_TX_POWER_NEG8DBM = RADIO_TXPOWER_TXPOWER_Neg8dBm, /**< -8 dBm radio transmit power. */ + NRF_ESB_TX_POWER_NEG12DBM = RADIO_TXPOWER_TXPOWER_Neg12dBm, /**< -12 dBm radio transmit power. */ + NRF_ESB_TX_POWER_NEG16DBM = RADIO_TXPOWER_TXPOWER_Neg16dBm, /**< -16 dBm radio transmit power. */ + NRF_ESB_TX_POWER_NEG20DBM = RADIO_TXPOWER_TXPOWER_Neg20dBm, /**< -20 dBm radio transmit power. */ + NRF_ESB_TX_POWER_NEG30DBM = RADIO_TXPOWER_TXPOWER_Neg30dBm /**< -30 dBm radio transmit power. */ +} nrf_esb_tx_power_t; + + +/**@brief Enhanced ShockBurst transmission modes. */ +typedef enum { + NRF_ESB_TXMODE_AUTO, /**< Automatic TX mode: When the TX FIFO contains packets and the radio is idle, packets are sent automatically. */ + NRF_ESB_TXMODE_MANUAL, /**< Manual TX mode: Packets are not sent until @ref nrf_esb_start_tx is called. This mode can be used to ensure consistent packet timing. */ + NRF_ESB_TXMODE_MANUAL_START /**< Manual start TX mode: Packets are not sent until @ref nrf_esb_start_tx is called. Then, transmission continues automatically until the TX FIFO is empty. */ +} nrf_esb_tx_mode_t; + + +/**@brief Enhanced ShockBurst event IDs used to indicate the type of the event. */ +typedef enum +{ + NRF_ESB_EVENT_TX_SUCCESS, /**< Event triggered on TX success. */ + NRF_ESB_EVENT_TX_FAILED, /**< Event triggered on TX failure. */ + NRF_ESB_EVENT_RX_RECEIVED /**< Event triggered on RX received. */ +} nrf_esb_evt_id_t; + + +/**@brief Enhanced ShockBurst payload. + * + * @details The payload is used both for transmissions and for acknowledging a + * received packet with a payload. +*/ +typedef struct +{ + uint8_t length; //!< Length of the packet (maximum value is @ref NRF_ESB_MAX_PAYLOAD_LENGTH). + uint8_t pipe; //!< Pipe used for this payload. + int8_t rssi; //!< RSSI for the received packet. + uint8_t noack; //!< Flag indicating that this packet will not be acknowledgement. + uint8_t pid; //!< PID assigned during communication. + uint8_t data[NRF_ESB_MAX_PAYLOAD_LENGTH]; //!< The payload data. +} nrf_esb_payload_t; + + +/**@brief Enhanced ShockBurst event. */ +typedef struct +{ + nrf_esb_evt_id_t evt_id; //!< Enhanced ShockBurst event ID. + uint32_t tx_attempts; //!< Number of TX retransmission attempts. +} nrf_esb_evt_t; + + +/**@brief Definition of the event handler for the module. */ +typedef void (* nrf_esb_event_handler_t)(nrf_esb_evt_t const * p_event); + + +/**@brief Main configuration structure for the module. */ +typedef struct +{ + nrf_esb_protocol_t protocol; //!< Enhanced ShockBurst protocol. + nrf_esb_mode_t mode; //!< Enhanced ShockBurst mode. + nrf_esb_event_handler_t event_handler; //!< Enhanced ShockBurst event handler. + + // General RF parameters + nrf_esb_bitrate_t bitrate; //!< Enhanced ShockBurst bitrate mode. + nrf_esb_crc_t crc; //!< Enhanced ShockBurst CRC mode. + + nrf_esb_tx_power_t tx_output_power; //!< Enhanced ShockBurst radio transmission power mode. + + uint16_t retransmit_delay; //!< The delay between each retransmission of unacknowledged packets. + uint16_t retransmit_count; //!< The number of retransmission attempts before transmission fail. + + // Control settings + nrf_esb_tx_mode_t tx_mode; //!< Enhanced ShockBurst transmission mode. + + uint8_t radio_irq_priority; //!< nRF radio interrupt priority. + uint8_t event_irq_priority; //!< ESB event interrupt priority. + uint8_t payload_length; //!< Length of the payload (maximum length depends on the platforms that are used on each side). + + bool selective_auto_ack; //!< Enable or disable selective auto acknowledgement. +} nrf_esb_config_t; + + +/**@brief Function for initializing the Enhanced ShockBurst module. + * + * @param p_config Parameters for initializing the module. + * + * @retval NRF_SUCCESS If initialization was successful. + * @retval NRF_ERROR_NULL If the @p p_config argument was NULL. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_init(nrf_esb_config_t const * p_config); + + +/**@brief Function for suspending the Enhanced ShockBurst module. + * + * Calling this function stops ongoing communications without changing the queues. + * + * @retval NRF_SUCCESS If Enhanced ShockBurst was suspended. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_suspend(void); + + +/**@brief Function for disabling the Enhanced ShockBurst module. + * + * Calling this function disables the Enhanced ShockBurst module immediately. + * Doing so might stop ongoing communications. + * + * @note All queues are flushed by this function. + * + * @retval NRF_SUCCESS If Enhanced ShockBurst was disabled. + */ +uint32_t nrf_esb_disable(void); + + +/**@brief Function for checking if the Enhanced ShockBurst module is idle. + * + * @retval true If the module is idle. + * @retval false If the module is busy. + */ +bool nrf_esb_is_idle(void); + + +/**@brief Function for writing a payload for transmission or acknowledgement. + * + * This function writes a payload that is added to the queue. When the module is in PTX mode, the + * payload is queued for a regular transmission. When the module is in PRX mode, the payload + * is queued for when a packet is received that requires an acknowledgement with payload. + * + * @param[in] p_payload Pointer to the structure that contains information and state of the payload. + * + * @retval NRF_SUCCESS If the payload was successfully queued for writing. + * @retval NRF_ERROR_NULL If the required parameter was NULL. + * @retval NRF_INVALID_STATE If the module is not initialized. + * @retval NRF_ERROR_NOT_SUPPORTED If @p p_payload->noack was false, but selective acknowledgement is not enabled. + * @retval NRF_ERROR_NO_MEM If the TX FIFO is full. + * @retval NRF_ERROR_INVALID_LENGTH If the payload length was invalid (zero or larger than the allowed maximum). + */ +uint32_t nrf_esb_write_payload(nrf_esb_payload_t const * p_payload); + + +/**@brief Function for reading an RX payload. + * + * @param[in,out] p_payload Pointer to the structure that contains information and state of the payload. + * + * @retval NRF_SUCCESS If the data was read successfully. + * @retval NRF_ERROR_NULL If the required parameter was NULL. + * @retval NRF_INVALID_STATE If the module is not initialized. + */ +uint32_t nrf_esb_read_rx_payload(nrf_esb_payload_t * p_payload); + + +/**@brief Function for starting transmission. + * + * @retval NRF_SUCCESS If the TX started successfully. + * @retval NRF_ERROR_BUFFER_EMPTY If the TX did not start because the FIFO buffer is empty. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_start_tx(void); + + +/**@brief Function for starting to transmit data from the FIFO buffer. + * + * @retval NRF_SUCCESS If the transmission was started successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_start_rx(void); + + +/** @brief Function for stopping data reception. + * + * @retval NRF_SUCCESS If data reception was stopped successfully. + * @retval NRF_ESB_ERROR_NOT_IN_RX_MODE If the function failed because the module is not in RX mode. + */ +uint32_t nrf_esb_stop_rx(void); + + +/**@brief Function for removing remaining items from the TX buffer. + * + * This function clears the TX FIFO buffer. + * + * @retval NRF_SUCCESS If pending items in the TX buffer were successfully cleared. + * @retval NRF_INVALID_STATE If the module is not initialized. + */ +uint32_t nrf_esb_flush_tx(void); + + +/**@brief Function for removing the first item from the TX buffer. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_INVALID_STATE If the module is not initialized. + * @retval NRF_ERROR_BUFFER_EMPTY If there are no items in the queue to remove. + */ +uint32_t nrf_esb_pop_tx(void); + + +/**@brief Function for removing remaining items from the RX buffer. + * + * @retval NRF_SUCCESS If the pending items in the RX buffer were successfully cleared. + * @retval NRF_INVALID_STATE If the module is not initialized. + */ +uint32_t nrf_esb_flush_rx(void); + + +/**@brief Function for setting the length of the address. + * + * @param[in] length Length of the ESB address (in bytes). + * + * @retval NRF_SUCCESS If the address length was set successfully. + * @retval NRF_ERROR_INVALID_PARAM If the address length was invalid. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_set_address_length(uint8_t length); + + +/**@brief Function for setting the base address for pipe 0. + * + * @param[in] p_addr Pointer to the address data. + * + * @retval NRF_SUCCESS If the base address was set successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + * @retval NRF_ERROR_INVALID_PARAM If the function failed because the address given was too close to a zero address. + * @retval NRF_ERROR_NULL If the required parameter was NULL. + */ +uint32_t nrf_esb_set_base_address_0(uint8_t const * p_addr); + + +/**@brief Function for setting the base address for pipe 1 to pipe 7. + * + * @param[in] p_addr Pointer to the address data. + * + * @retval NRF_SUCCESS If the base address was set successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + * @retval NRF_ERROR_INVALID_PARAM If the function failed because the address given was too close to a zero address. + * @retval NRF_ERROR_NULL If the required parameter was NULL. + */ +uint32_t nrf_esb_set_base_address_1(uint8_t const * p_addr); + + +/**@brief Function for setting the number of pipes and the pipe prefix addresses. + * + * This function configures the number of available pipes, enables the pipes, + * and sets their prefix addresses. + * + * @param[in] p_prefixes Pointer to a char array that contains the prefix for each pipe. + * @param[in] num_pipes Number of pipes. + * + * @retval NRF_SUCCESS If the prefix addresses were set successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + * @retval NRF_ERROR_NULL If a required parameter was NULL. + * @retval NRF_ERROR_INVALID_PARAM If an invalid number of pipes was given or if the address given was too close to a zero address. + */ +uint32_t nrf_esb_set_prefixes(uint8_t const * p_prefixes, uint8_t num_pipes); + + +/**@brief Function for enabling pipes. + * + * The @p enable_mask parameter must contain the same number of pipes as has been configured + * with @ref nrf_esb_set_prefixes. + * + * @param enable_mask Bitfield mask to enable or disable pipes. Setting a bit to + * 0 disables the pipe. Setting a bit to 1 enables the pipe. + * + * @retval NRF_SUCCESS If the pipes were enabled and disabled successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + * @retval NRF_ERROR_INVALID_PARAM If the function failed because the address given was too close to a zero address. + */ +uint32_t nrf_esb_enable_pipes(uint8_t enable_mask); + + +/**@brief Function for updating the prefix for a pipe. + * + * @param pipe Pipe for which to set the prefix. + * @param prefix Prefix to set for the pipe. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + * @retval NRF_ERROR_INVALID_PARAM If the given pipe number was invalid or if the address given was too close to a zero address. + */ +uint32_t nrf_esb_update_prefix(uint8_t pipe, uint8_t prefix); + + +/** @brief Function for setting the channel to use for the radio. + * + * The module must be in an idle state to call this function. As a PTX, the + * application must wait for an idle state and as a PRX, the application must stop RX + * before changing the channel. After changing the channel, operation can be resumed. + * + * @param[in] channel Channel to use for radio. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_INVALID_STATE If the module is not initialized. + * @retval NRF_ERROR_BUSY If the module was not in idle state. + * @retval NRF_ERROR_INVALID_PARAM If the channel is invalid (larger than 100). + */ +uint32_t nrf_esb_set_rf_channel(uint32_t channel); + + +/**@brief Function for getting the current radio channel. + * + * @param[in, out] p_channel Pointer to the channel data. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_NULL If the required parameter was NULL. + */ +uint32_t nrf_esb_get_rf_channel(uint32_t * p_channel); + + +/**@brief Function for setting the radio output power. + * + * @param[in] tx_output_power Output power. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_set_tx_power(nrf_esb_tx_power_t tx_output_power); + + +/**@brief Function for setting the packet retransmit delay. + * + * @param[in] delay Delay between retransmissions. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_set_retransmit_delay(uint16_t delay); + + +/**@brief Function for setting the number of retransmission attempts. + * + * @param[in] count Number of retransmissions. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_set_retransmit_count(uint16_t count); + + +/**@brief Function for setting the radio bitrate. + * + * @param[in] bitrate Radio bitrate. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_set_bitrate(nrf_esb_bitrate_t bitrate); + + +/**@brief Function for reusing a packet ID for a specific pipe. + * + * The ESB protocol uses a 2-bit sequence number (packet ID) to identify + * retransmitted packets. By default, the packet ID is incremented for every + * uploaded packet. Use this function to prevent this and send two different + * packets with the same packet ID. + * + * @param[in] pipe Pipe. + * + * @retval NRF_SUCCESS If the operation completed successfully. + * @retval NRF_ERROR_BUSY If the function failed because the radio is busy. + */ +uint32_t nrf_esb_reuse_pid(uint8_t pipe); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // NRF_ESB diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb_error_codes.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb_error_codes.h new file mode 100644 index 0000000..88b24ff --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb_error_codes.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __NRF_ESB_ERROR_CODES_H__ +#define __NRF_ESB_ERROR_CODES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NRF_ERROR_BUFFER_EMPTY (0x0100) + +#define NRF_ESB_ERROR_NOT_IN_RX_MODE (0x0101) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb_resources.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb_resources.h new file mode 100644 index 0000000..3e1af51 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/esb/nrf_esb_resources.h @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_ESB_RESOURCES_H__ +#define NRF_ESB_RESOURCES_H__ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrf_esb_resources ESB resources + * @{ + * @ingroup nrf_esb + */ + +#ifndef ESB_ALTERNATIVE_RESOURCES + #define ESB_PPI_CHANNELS_USED 0x00000007uL /**< PPI channels used by ESB (not available to the application). */ + #define ESB_TIMERS_USED 0x00000004uL /**< Timers used by ESB. */ + #define ESB_SWI_USED 0x00000001uL /**< Software interrupts used by ESB. */ +#else + #define ESB_PPI_CHANNELS_USED 0x00000700uL /**< PPI channels used by ESB (not available to the application). */ + #define ESB_TIMERS_USED 0x00000001uL /**< Timers used by ESB. */ + #define ESB_SWI_USED 0x00000002uL /**< Software interrupts used by ESB. */ +#endif + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif /* NRF_ESB_RESOURCES_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf51_arm.lib b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf51_arm.lib Binary files differnew file mode 100644 index 0000000..e0e9915 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf51_arm.lib diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf51_sd_resources_arm.lib b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf51_sd_resources_arm.lib Binary files differnew file mode 100644 index 0000000..aedb24e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf51_sd_resources_arm.lib diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52840_arm.lib b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52840_arm.lib Binary files differnew file mode 100644 index 0000000..63503ab --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52840_arm.lib diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52840_sd_resources_arm.lib b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52840_sd_resources_arm.lib Binary files differnew file mode 100644 index 0000000..25cb7d3 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52840_sd_resources_arm.lib diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52_arm.lib b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52_arm.lib Binary files differnew file mode 100644 index 0000000..afd9a9b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52_arm.lib diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52_sd_resources_arm.lib b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52_sd_resources_arm.lib Binary files differnew file mode 100644 index 0000000..12596fc --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/gzll_nrf52_sd_resources_arm.lib diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/license.txt b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/license.txt new file mode 100644 index 0000000..957d928 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/arm/license.txt @@ -0,0 +1,37 @@ +Copyright (c) 2010 - 2018, Nordic Semiconductor ASA + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form, except as embedded into a Nordic + Semiconductor ASA integrated circuit in a product or a software update for + such product, must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. Neither the name of Nordic Semiconductor ASA nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +4. This software, with or without modification, must only be used with a + Nordic Semiconductor ASA integrated circuit. + +5. Any software provided in binary form under this license must not be reverse + engineered, decompiled, modified and/or disassembled. + +THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/config/nrf_gzp_config.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/config/nrf_gzp_config.h new file mode 100644 index 0000000..801cc3f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/config/nrf_gzp_config.h @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2008 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __GZP_CONFIG_H +#define __GZP_CONFIG_H + +#include "nrf.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Definition of "secret key" used during "Host ID exchange". + */ + +#define GZP_SECRET_KEY {1, 23, 45, 57, 26, 68, 12, 64, 13, 73, 13, 62, 26, 45, 12, 77} + +//----------------------------------------------------------------------------- + +/** + Definition of the first static selected pairing channel. Should be located in + the lower Nth of the channel range, where N is the size if the channel subset + selected by the application. +*/ +#define GZP_CHANNEL_LOW 2 + +/** + Definition of the second static selected pairing channel. Should be located in + the upper Nth of the channel range, where N is the size if the channel subset + selected by the application. +*/ +#define GZP_CHANNEL_HIGH 79 + +/** + Definition of the static "global" pairing address. +*/ +#define GZP_ADDRESS 4, 6, 8, 10 + +/** + Reduced TX power for use during close proximity pairing. + */ +#define GZP_POWER NRF_GZLL_TX_POWER_N16_DBM + +/** + Definition of pairing request timeout. +*/ +#define GZP_REQ_TX_TIMEOUT 200 + +/** + Definition of the maximimum number of "backoff" packets (step 0) to be transmitted. +*/ +#define GZP_MAX_BACKOFF_PACKETS 100 + +/** + Definition of the period a device shall wait before attempting to send the packet for + fetching the pairing response (step 1). +*/ +#define GZP_TX_ACK_WAIT_TIMEOUT (GZP_CLOSE_PROXIMITY_BACKOFF_RX_TIMEOUT + 50) + +/** + Definition of the period a device in close proximity shall back off on the pairing + address after a backoff packet has been received. +*/ +#define GZP_CLOSE_PROXIMITY_BACKOFF_RX_TIMEOUT ((GZP_REQ_TX_TIMEOUT / 2) + 50) + +/** + Definition of the period a device NOT in close proximity shall back off on the pairing + address after a backoff packet has been received. +*/ +#define GZP_NOT_PROXIMITY_BACKOFF_RX_TIMEOUT (GZP_CLOSE_PROXIMITY_BACKOFF_RX_TIMEOUT + GZP_STEP1_RX_TIMEOUT) + +/** + Definition of the time the host waits for a device to complete + transmission of the pairing request step 1 packet. +*/ +#define GZP_STEP1_RX_TIMEOUT (((GZP_REQ_TX_TIMEOUT / 2) + GZP_TX_ACK_WAIT_TIMEOUT) + 50) + +/** + Definition of the lowest boundary for the channel range to be used. +*/ +#define GZP_CHANNEL_MIN 2 + +/** + Definition of the upper boundary for the channel range to be used. +*/ +#define GZP_CHANNEL_MAX 80 + +/** + Definition of the minimum channel spacing for the channel subset generated + during pairing. +*/ +#define GZP_CHANNEL_SPACING_MIN 5 + +/** + Non volatile memory (Flash or OTP) storage address. A device will + require GZP_DEVICE_PARAMS_STORAGE_SIZE bytes of memory, and + Host 11 bytes. When using flash memory, storage address should + be a multiple of chip page size. +*/ +#define GZP_PARAMS_STORAGE_ADR 0x00001000 + +/** + Number of bytes available for parameter storage in Device. + It is equal to flash page size on nRF5x chips. +*/ +#if defined (NRF51) + #define GZP_DEVICE_PARAMS_STORAGE_SIZE 1024 +#elif defined (NRF52_SERIES) + #define GZP_DEVICE_PARAMS_STORAGE_SIZE 4096 +#else + #error Chip type is undefined! +#endif + +/** + Maximum Device TX payload length [bytes]. + */ +#define GZP_MAX_FW_PAYLOAD_LENGTH 17 + +/** + Maximum Host ACK payload length [bytes]. + */ +#define GZP_MAX_ACK_PAYLOAD_LENGTH 10 + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf51_gcc.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf51_gcc.a Binary files differnew file mode 100644 index 0000000..8c9fe0a --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf51_gcc.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf51_sd_resources_gcc.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf51_sd_resources_gcc.a Binary files differnew file mode 100644 index 0000000..4896b0c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf51_sd_resources_gcc.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52840_gcc.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52840_gcc.a Binary files differnew file mode 100644 index 0000000..911ae7d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52840_gcc.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52840_sd_resources_gcc.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52840_sd_resources_gcc.a Binary files differnew file mode 100644 index 0000000..46284ef --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52840_sd_resources_gcc.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52_gcc.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52_gcc.a Binary files differnew file mode 100644 index 0000000..d463ca4 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52_gcc.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52_sd_resources_gcc.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52_sd_resources_gcc.a Binary files differnew file mode 100644 index 0000000..052634c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/gzll_nrf52_sd_resources_gcc.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/license.txt b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/license.txt new file mode 100644 index 0000000..957d928 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/gcc/license.txt @@ -0,0 +1,37 @@ +Copyright (c) 2010 - 2018, Nordic Semiconductor ASA + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form, except as embedded into a Nordic + Semiconductor ASA integrated circuit in a product or a software update for + such product, must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. Neither the name of Nordic Semiconductor ASA nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +4. This software, with or without modification, must only be used with a + Nordic Semiconductor ASA integrated circuit. + +5. Any software provided in binary form under this license must not be reverse + engineered, decompiled, modified and/or disassembled. + +THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf51_iar.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf51_iar.a Binary files differnew file mode 100644 index 0000000..bf4ad39 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf51_iar.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf51_sd_resources_iar.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf51_sd_resources_iar.a Binary files differnew file mode 100644 index 0000000..23fcdd1 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf51_sd_resources_iar.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52840_iar.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52840_iar.a Binary files differnew file mode 100644 index 0000000..755dbfd --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52840_iar.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52840_sd_resources_iar.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52840_sd_resources_iar.a Binary files differnew file mode 100644 index 0000000..b7971e6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52840_sd_resources_iar.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52_iar.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52_iar.a Binary files differnew file mode 100644 index 0000000..36e7653 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52_iar.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52_sd_resources_iar.a b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52_sd_resources_iar.a Binary files differnew file mode 100644 index 0000000..d09ca0f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/gzll_nrf52_sd_resources_iar.a diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/license.txt b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/license.txt new file mode 100644 index 0000000..957d928 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/iar/license.txt @@ -0,0 +1,37 @@ +Copyright (c) 2010 - 2018, Nordic Semiconductor ASA + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form, except as embedded into a Nordic + Semiconductor ASA integrated circuit in a product or a software update for + such product, must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. Neither the name of Nordic Semiconductor ASA nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +4. This software, with or without modification, must only be used with a + Nordic Semiconductor ASA integrated circuit. + +5. Any software provided in binary form under this license must not be reverse + engineered, decompiled, modified and/or disassembled. + +THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll.h new file mode 100644 index 0000000..79a9ee8 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll.h @@ -0,0 +1,937 @@ +/** + * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Gazell Link Layer API. + */ + +#ifndef NRF_GZLL_H__ +#define NRF_GZLL_H__ + +#include <stdbool.h> +#include "nrf.h" +#include "nrf_gzll_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** +* @defgroup gzll_02_api Gazell Link Layer +* @{ +* @ingroup modules_01_gzll +* @brief Gazell Link Layer Application Programming Interface (API). +*/ + +/** + * @enum nrf_gzll_mode_t + * @brief Enumerator used for selecting Gazell mode. + */ +typedef enum +{ + NRF_GZLL_MODE_DEVICE, ///< Device mode + NRF_GZLL_MODE_HOST, ///< Host mode + NRF_GZLL_MODE_SUSPEND, ///< Suspend mode ("disabled with timer running") +} nrf_gzll_mode_t; + +/** + * @enum nrf_gzll_device_channel_selection_policy_t + * @brief Enumerator used for selecting Gazell Device channel + * selection policy. + */ +typedef enum +{ + NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_SUCCESSFUL, ///< Start on previous successful channel + NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_CURRENT, ///< Start on channel currently monitored by Host +} nrf_gzll_device_channel_selection_policy_t; + +/** + * @enum nrf_gzll_tx_power_t + * @brief Enumerator used for selecting the transmit (TX) power. + */ +typedef enum +{ + NRF_GZLL_TX_POWER_4_DBM, ///< 4 dBm transmit power. + NRF_GZLL_TX_POWER_0_DBM, ///< 0 dBm transmit power. + NRF_GZLL_TX_POWER_N4_DBM, ///< -4 dBm transmit power. + NRF_GZLL_TX_POWER_N8_DBM, ///< -8 dBm transmit power. + NRF_GZLL_TX_POWER_N12_DBM, ///< -12 dBm transmit power. + NRF_GZLL_TX_POWER_N16_DBM, ///< -16 dBm transmit power. + NRF_GZLL_TX_POWER_N20_DBM ///< -20 dBm transmit power. +} nrf_gzll_tx_power_t; + +/** + * @enum nrf_gzll_datarate_t + * @brief Enumerator used for selecting the radio datarate. + */ +typedef enum +{ +#ifdef NRF51 + NRF_GZLL_DATARATE_250KBIT = 0, ///< 250 Kbps datarate, available only for the nRF51. +#endif + NRF_GZLL_DATARATE_1MBIT = 1, ///< 1 Mbps datarate. + NRF_GZLL_DATARATE_2MBIT = 2 ///< 2 Mbps datarate. +} nrf_gzll_datarate_t; + +/** + * @enum nrf_gzll_xosc_ctl_t + * @brief Enumerator used for specifying whether switching the + * external 16 MHz oscillator on/off shall be handled automatically + * inside Gazell or manually by the application. + */ +typedef enum +{ + NRF_GZLL_XOSC_CTL_AUTO, ///< Switch XOSC on/off automatically + NRF_GZLL_XOSC_CTL_MANUAL ///< Switch XOSC on/off manually +} nrf_gzll_xosc_ctl_t; + +/** + * @enum nrf_gzll_error_code_t + * @brief Enumerator used for error codes for Gazell API functions + */ +typedef enum +{ + NRF_GZLL_ERROR_CODE_NO_ERROR = 0, ///< No error has been detected. + NRF_GZLL_ERROR_CODE_FAILED_TO_INITIALIZE = 1, ///< The function NRF_GZLL_init failed. + NRF_GZLL_ERROR_CODE_ATTEMPTED_TO_CONFIGURE_WHEN_ENABLED = 2, ///< A call to a configuration 'set' function was made while Gazell was enabled. + NRF_GZLL_ERROR_CODE_POINTER_IS_NULL = 3, ///< A null pointer was given as an input to a function. + NRF_GZLL_ERROR_CODE_INVALID_PIPE = 4, ///< An invalid pipe number was given as an input to a function. + NRF_GZLL_ERROR_CODE_INVALID_MODE = 5, ///< An invalid value for the nrf_gzll_mode_t enumerator was given as input to a function. + NRF_GZLL_ERROR_CODE_INVALID_PAYLOAD_LENGTH = 6, ///< An invalid payload length was given as an input to a function. + NRF_GZLL_ERROR_CODE_INVALID_CHANNEL_TABLE_SIZE = 7, ///< An invalid channel table size was given as an input to a function. + NRF_GZLL_ERROR_CODE_INSUFFICIENT_PACKETS_AVAILABLE = 8, ///< There are insufficient packets in the Gazell memory pool to successfully execute the operation. + NRF_GZLL_ERROR_CODE_ATTEMPTED_TO_ADD_TO_FULL_FIFO = 9, ///< There is insufficient space in the TX FIFO for the data packet. + NRF_GZLL_ERROR_CODE_NO_SPACE_IN_RX_FIFO_FOR_ACK = 10, ///< There is insufficient space in the RX FIFO for the ACK. + NRF_GZLL_ERROR_CODE_ATTEMPTED_TO_FETCH_FROM_EMPTY_FIFO = 11, ///< Attempted to fetch a packet from an empty FIFO. Use the functions nrf_gzll_get_tx_fifo_packet_count() or nrf_gzll_get_rx_fifo_packet_count() + NRF_GZLL_ERROR_CODE_ATTEMPTED_TO_FLUSH_WHEN_ENABLED = 12, ///< Attempted to fetch a packet from an empty FIFO. Use the functions nrf_gzll_get_tx_fifo_packet_count() or nrf_gzll_get_rx_fifo_packet_count() + NRF_GZLL_ERROR_CODE_INVALID_PARAMETER = 14, ///< Attempted to set a variable which was not valid. + NRF_GZLL_ERROR_CODE_INTERNAL_ASSERT_OCCURRED = 15, ///< An internal assert occurred. + NRF_GZLL_ERROR_CODE_CALLBACK_NOT_IMPLEMENTED = 16, ///< A callback was called but not implemented by the application. + NRF_GZLL_ERROR_CODE_INVALID_ADDRESS = 17, ///< Invalid pipe 0 address detected, see Anomaly 107 at nRF52832 errata document. + NRF_GZLL_ERROR_CODE_NUMBER_OF_ERROR_CODES = 18, ///< Number of possible error codes. +} nrf_gzll_error_code_t; + +/** + * @struct nrf_gzll_device_tx_info_t; + * @brief Data structure containing information about the last packet + * transmission. + */ +typedef struct +{ + bool payload_received_in_ack; ///< A payload was received in the ACK. + uint16_t num_tx_attempts; ///< Number of attempts used on previous Device packet transmission. + uint16_t num_channel_switches; ///< Number of channel switches needed during previous packet transmission. + int8_t rssi; ///< Received signal strength indicator in dBm. @sa nrf_gzll_enable_rssi(). + uint8_t rf_channel; ///< Channel on which packet has been transmitted. +} nrf_gzll_device_tx_info_t; + + +/** + * @struct nrf_gzll_host_rx_info_t; + * @brief Data structure containing information about the last packet + * received. + */ +typedef struct +{ + bool packet_removed_from_tx_fifo; ///< A payload was received in the ACK. + int8_t rssi; ///< Received signal strength indicator in dBm. @sa nrf_gzll_enable_rssi(). + uint8_t rf_channel; ///< Channel on which packet has been received. +} nrf_gzll_host_rx_info_t; + + +typedef struct +{ + uint32_t packets_num; ///< Number of succesfully transmitted packets + uint32_t timeouts_num; ///< Total timeouts number + uint32_t channel_timeouts[NRF_GZLL_CONST_MAX_CHANNEL_TABLE_SIZE]; ///< Transmission timeouts per channel + uint32_t channel_packets[NRF_GZLL_CONST_MAX_CHANNEL_TABLE_SIZE]; ///< Succesfully transmitted packets per channel +} nrf_gzll_tx_statistics_t; + + +/**< Transmission timeout callback function definition */ +typedef void (*nrf_gzll_tx_timeout_callback)(uint32_t pipe, uint8_t rf_channel); + + +/**< Transmission CRC failure callback function definition */ +typedef void (*nrf_gzll_crc_failure_callback)(uint32_t pipe, uint8_t rf_channel); + + +#if defined(NRF52_SERIES) || defined(__SDK_DOXYGEN__) +/** + * @brief Data structure holding external front + * end control configuration. + */ +typedef struct +{ + bool pa_enabled; ///< Flag indicating if PA control is enabled. + bool pa_active_high; ///< Flag indicating if PA is active in high input state. + uint8_t pa_gpio_pin; ///< Number of output pin used for PA control. + uint8_t pa_gpiote_channel; ///< Number of GPIOTE channel used for PA control. + bool lna_enabled; ///< Flag indicating if LNA control is enabled. + bool lna_active_high; ///< Flag indicating if LNA is active in high input state. + uint8_t lna_gpio_pin; ///< Number of output pin used for LNA control. + uint8_t lna_gpiote_channel; ///< Number of GPIOTE channel used for LNA control. + NRF_TIMER_Type * timer; ///< Pointer to the TIMER instance. + uint8_t ppi_channels[NRF_GZLL_PA_LNA_PPI_CHANNELS_NUM]; ///< PPI channels used to control front end. + uint8_t ramp_up_time; ///< Determines how early should the PA/LNA be turned one before RADIO activity. Should be less than @ref NRF_GZLL_PA_LNA_MAX_RAMP_UP_TIME. +} nrf_gzll_pa_lna_cfg_t; +#endif + +/******************************************************************************/ +/** @name General API functions + * @{ */ +/******************************************************************************/ + +/** + * @brief Initialize Gazell. + * + * @param mode The mode to initialize Gazell in. + * + * @retval true if Gazell initialized. + * @retval false if Gazell failed to initialize. + */ +bool nrf_gzll_init(nrf_gzll_mode_t mode); + +/** + * @brief Enable Gazell. + * + * When enabled the behaviour described for the current Gazell Link Layer mode + * will apply. + * + * @retval false if nrf_gzll_init has not previously been called or invalid address + * has been set - see Anomaly 107 at nRF52832 errata document. + */ +bool nrf_gzll_enable(void); + +/** + * @brief Disable Gazell. + * + * When calling this function the Gazell Link Layer will begin disabling, + * and will be fully disabled when Gazell calls nrf_gzll_disabled(). + * If there are any pending notifications, or if any new notifications are + * being added to the internal notification queue while Gazell is disabling, + * these will be sent to the application before Gazell is fully disabled. + * + * After Gazell has been fully disabled, no more notifications will be sent to + * the application. + */ +void nrf_gzll_disable(void); + +/** Check whether Gazell is enabled or disabled. + * + * @retval true If Gazell is enabled. + * @retval false If Gazell is disabled. + */ +bool nrf_gzll_is_enabled(void); + +/** @} */ + +/******************************************************************************/ +/** @name Device mode callback functions + * @{ */ +/******************************************************************************/ + +/** + * @brief ACK received callback (Device mode only). + * + * This callback is made when the Device receives an ACK (acknowledgement) + * packet. + * @sa nrf_gzll_ack_payload_received. + * + * @param pipe is the pipe on which an ACK packet was received. + * @param tx_info struct used to indicate whether a payload was received in the + * ack, as well as the number of TX attempts and channel switches required. + */ +void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info); + +/** + * @brief Transmission failed callback (Device mode only). + * + * This callback is made when a packet does not receive an ACK after + * nrf_gzll_max_retries is reached. The packet is deleted by Gazell. + * + * @param pipe is the pipe on which the transmission failed. + * @param tx_info struct used to indicate whether a payload was received + * in the ack, as well as RSSI and the number of TX attempts and + * channel switches required. + */ +void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info); + +/** @} */ + +/******************************************************************************/ +/** @name Host mode callback functions + * @{ */ +/******************************************************************************/ + +/** + * @brief Data packet received callback (Host mode only). + * + * This callback is made when a Host receives a data packet from a Device. + * + * @param pipe is the pipe on which the data packet was received. + * @param rx_info struct used to indicate whether a payload was removed from the + * pipe's TX FIFO, as well as RSSI. + */ +void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info); + +/** @} */ + +/******************************************************************************/ +/** @name Callback functions for both Device and Host mode + * @{ */ +/******************************************************************************/ + +/** + * @brief Disabled callback. + * + * This is called after Gazell enters the disabled state. + * There is no further CPU use by Gazell, the radio is disabled and the timer is + * powered down. + */ +void nrf_gzll_disabled(void); + +/** + * @brief Mode changed callbackl. + * + * This function is called after the Gazell mode has been changed. + * This function can only be called when Gazell is enabled. + */ +void nrf_gzll_mode_changed(void); + +/** @} */ + +/******************************************************************************/ +/** @name Packet transmission and receiving functions + * @{ */ +/******************************************************************************/ + +/** + * @brief Add a packet to the tail of the TX FIFO. + * + * In Device mode, the packet will be added. + * In Host mode, the payload will be piggybacked onto an ACK. + * + * @param pipe Pipe to which to add the payload. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @param p_payload Pointer to the payload. + * @param length Number of bytes of the payload to transmit + * (0 to NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH). + * + * @retval true if the packet was successfully added to the TX FIFO. + * @retval false if unsuccessful, check nrf_gzll_error_code_t for more information. + */ +bool nrf_gzll_add_packet_to_tx_fifo(uint32_t pipe, uint8_t * p_payload, uint32_t length); + +/** + * @brief Fetch a packet from the head of the RX FIFO. + * + * @param pipe Pipe from which to fetch the payload. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @param p_payload Pointer to copy the payload to. + * @param p_length Length must be at least as large as the the number of bytes + * in the received payload length. + * + * @retval true If the fetch was successful. + * @retval false If unsuccessful, check nrf_gzll_error_code_t for more information. + */ +bool nrf_gzll_fetch_packet_from_rx_fifo(uint32_t pipe, uint8_t * p_payload, uint32_t * p_length); + +/** + * @brief Get the number of packets in the TX FIFO on a specific pipe. + * + * @param pipe The pipe for which to check. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * + * @retval >=0 The number of packets in the TX FIFO for the pipe. + * @retval -1 If the pipe number is invalid. + */ +int32_t nrf_gzll_get_tx_fifo_packet_count(uint32_t pipe); + +/** + * @brief Get the number of packets in the RX FIFO on a specific pipe. + * + * @param pipe The pipe for which to check. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @retval >=0 The number of packets in the RX FIFO for the pipe. + * @retval -1 If the pipe number is invalid. + */ +int32_t nrf_gzll_get_rx_fifo_packet_count(uint32_t pipe); + +/** + * @brief Get the total number of packets residing in all TX and RX FIFOs. + * + * Can be used to check against NRF_GZLL_CONST_MAX_TOTAL_PACKETS to + * determine if there is free space in the memory pool for more packets. + * + * @return The number of packets residing in all TX and RX FIFOs. + */ +uint32_t nrf_gzll_get_total_allocated_packet_count(void); + +/** + * @brief Check if adding a packet to a pipe's TX FIFO should be successful. + * + * Checks if there is another space in the pipe's TX and RX FIFOs + * as well as enough overall space in the packet pool. + * + * @param pipe The pip for which to check. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * + * @retval true If there is another space. + * @retval false If there is not enough space, or the pipe is invalid. + */ +bool nrf_gzll_ok_to_add_packet_to_tx_fifo(uint32_t pipe); + +/** + * @brief Flush the RX FIFO for a specific pipe. + * + * Delete all the packets and free the memory of the TX FIFO for a + * specific pipe. + * + * Note that it is not allowed to flush a TX FIFO when + * Gazell is enabled. + * + * @param pipe is the pipe for which to flush. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @retval true if the pipe was flushed. + * @retval false if the pipe was not flushed. + */ +bool nrf_gzll_flush_tx_fifo(uint32_t pipe); + +/** + * @brief Flush the RX FIFO for a specific pipe. + * + * Delete all the packets and free the memory of the RX FIFO for a + * specific pipe. + * + * @param pipe is the pipe for which to flush. This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @retval true if the pipe was flushed. + * @retval false if the pipe was not flushed. + */ +bool nrf_gzll_flush_rx_fifo(uint32_t pipe); + +/** + * @brief Function for enabling transmission statistics. + * + * @param p_statistics Pointer to the statistics structure. + * + * @return True if channel statistics has been enabled, false otherwise. + */ +bool nrf_gzll_tx_statistics_enable(nrf_gzll_tx_statistics_t * p_statistics); + +/** + * @brief Function for disabling transmission statistics. + */ +void nrf_gzll_tx_statistics_disable(void); + +/** + * @brief Function for obtaining number of transmission timeouts for specific channel. + * + * @param[in] channel_index Channel index in channel table. + * @param[out] p_timeouts Pointer for the result. + * + * @return True in case of success, false otherwise. + */ +bool nrf_gzll_get_channel_timeouts(uint8_t channel_index, uint32_t *p_timeouts); + +/** + * @brief Function for clearing transmission statistic structure. + */ +void nrf_gzll_reset_tx_statistics(void); + +/** @} */ + +/******************************************************************************/ +/** @name Configuration functions + * + * Configuration 'set' functions may only be called while Gazell is disabled. The + * new parameter comes into effect when Gazell is enabled again. + * + * Configuration 'get' functions may be called at any time. + * + * @{ */ +/******************************************************************************/ + +/** + * @brief Function for registering callback to be called on the transmission timeout. + */ +void nrf_gzll_tx_timeout_callback_register(nrf_gzll_tx_timeout_callback callback); + + +/** + * @brief Function for registering callback to be called on the packet CRC failure. + */ +void nrf_gzll_crc_failure_callback_register(nrf_gzll_crc_failure_callback callback); + + +/** + * @brief Set the mode. + * + * @param mode The mode to be used. + * See nrf_gzll_mode_t for a list of valid modes. + * + * It is allowed to change mode when Gazell is enabled. If the mode is + * being changed while Gazell is enabled, the mode will not change right away. + * In this case the callback function nrf_gzll_mode_changed() will be called + * after the mdoe has changed. + * + * @retval true If the parameter was set. + */ +bool nrf_gzll_set_mode(nrf_gzll_mode_t mode); + +/** + * @brief Get function counterpart to nrf_gzll_set_mode(). + * + * @return The current mode. + */ +nrf_gzll_mode_t nrf_gzll_get_mode(void); + +/** + * @brief Set the base address for pipe 0. + * + * The full on-air address for each pipe is composed of a multi-byte base address + * prepended to a prefix byte. + * + * For packets to be received correctly, the most significant byte of + * the base address should not be an alternating sequence of 0s and 1s i.e. + * it should not be 0x55 or 0xAA. + * + * @param base_address The 4 byte base address. All bytes are used. + * + * @note Due to the nRF52 Anomaly 107, pipe 0 address should not have + * both prefix and two LSB of base address set to 0. + * + * @retval true If the parameter was set. + * @return false If Gazell was enabled. + */ +bool nrf_gzll_set_base_address_0(uint32_t base_address); + +/** + * @brief Get function counterpart to nrf_gzll_set_base_address_0(). + * + * @return Base address 0. + */ +uint32_t nrf_gzll_get_base_address_0(void); + +/** + * @brief Set the base address for pipes 1-7. + * + * Pipes 1 through 7 share base_address_1. @sa nrf_gzll_set_base_address_0. + * + * @param base_address The 4 byte base address. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled. + */ +bool nrf_gzll_set_base_address_1(uint32_t base_address); + +/** + * @brief Get function counterpart to nrf_gzll_set_base_address_1(). + * + * @return Base address 1. + */ +uint32_t nrf_gzll_get_base_address_1(void); + +/** + * @brief Set the address prefix byte for a specific pipe. + * + * Each pipe should have its own unique prefix byte. + * + * @param pipe The pipe that the address should apply to. + * This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @param address_prefix_byte The address prefix byte. + * + * @note Due to the Anomaly 107, pipe 0 address should not have + * both prefix and two LSB of base address set to 0. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled, or if the pipe was invalid. + */ +bool nrf_gzll_set_address_prefix_byte(uint32_t pipe, uint8_t address_prefix_byte); + +/** + * @brief Get function counterpart to nrf_gzll_set_address_prefix_byte(). + * + * @param pipe The pipe for which to get the address. + * This value must be < NRF_GZLL_CONST_PIPE_COUNT. + * @param p_out_address_prefix_byte The pointer in which to return the + * address prefix byte. + * + * @retval true If the parameter was returned. + * @retval false If Gazell was enabled, the pipe was invalid or + * out_address was a NULL pointer. + */ +bool nrf_gzll_get_address_prefix_byte(uint32_t pipe, uint8_t * p_out_address_prefix_byte); + +/** + * @brief Set which pipes shall listen for packets in Host mode. + * + * This value is a bitmap, and each bit corresponds to a given pipe number. + * Bit 0 set to "1" enables pipes 0, bit 1 set to "1" enables pipe 1 + * and so forth. + * The maximum number of pipes is defined by NRF_GZLL_CONST_PIPE_COUNT. + * + * @param pipes A bitmap specifying which pipes to monitor. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled. + */ +bool nrf_gzll_set_rx_pipes_enabled(uint32_t pipes); + +/** + * @brief Get function counterpart to nrf_gzll_set_rx_pipes_enabled(). + * + * @return Bitmap holding the current enabled pipes. + */ +uint32_t nrf_gzll_get_rx_pipes_enabled(void); + +/** + * @brief Set the timeslot period. + * + * The length in microseconds of a Gazell link layer timeslot. + * + * The minimum value of the timeslot period is dependent of the + * radio data rate (@sa nrf_gzll_set_datarate()). + * + * - For NRF_GZLL_DATARATE_2MBIT the timeslot period must be >= 600 us. + * - For NRF_GZLL_DATARATE_1MBIT the timeslot period must be >= 900 us. + * - For NRF_GZLL_DATARATE_250KBIT the timeslot period must be >= 2700 us. + * + * @param period_us The timeslot period in microseconds. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled. + */ +bool nrf_gzll_set_timeslot_period(uint32_t period_us); + +/** + * @brief Get function counterpart to nrf_gzll_get_timeslot_period(). + * + * @return The current timeslot period. + */ +uint32_t nrf_gzll_get_timeslot_period(void); + +/** + * @brief Set the Device channel selection policy + * + * The policy determines the initial channel when starting a new packet. + * transmission. + * + * @param policy The channel selection policy. + * + * @arg NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_SUCCESSFUL specifies + * that a new packet transmission always shall use the previous + * successful channel from the channel table. If Gazell is "in sync", Gazell + * will wait until this channel is being monitored by the Host before starting + * the transmission. + * + * @arg NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_CURRENT specifies that + * Gazell shall transmit on the channel that is currently being monitored by the + * Host. This parameter is only used when Gazell is "in sync". When "out of" sync, + * Gazell will always start using the "previous successful" channel. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled or the policy was invalid. + */ +bool nrf_gzll_set_device_channel_selection_policy(nrf_gzll_device_channel_selection_policy_t policy); + +/** + * @brief Get function counterpart to nrf_gzll_set_device_channel_selection_policy(). + * + * @return the Device channel selection policy. + */ +nrf_gzll_device_channel_selection_policy_t nrf_gzll_get_device_channel_selection_policy(void); + +/** + * @brief Set the number of timeslots that Gazell shall + * reside on a single channel before switching to another channel. + * + * This parameter applies in Host mode and for a Device that is + * in the "in sync" state. + * + * Since the Device and Host can not be in perfect synchronization, a + * transmission should overlap to adjacent timeslots on the Host. + * Therefore this value should be at least 2. + * + * @sa nrf_gzll_set_timeslots_per_channel_when_device_out_of_sync + * + * @param timeslots The number of timeslots to reside on + * each channel before channel switch. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled. + */ +bool nrf_gzll_set_timeslots_per_channel(uint32_t timeslots); + +/** + * @brief Get function counterpart to nrf_gzll_set_timeslots_per_channel(). + * + * @return The current number of timeslots. + */ +uint32_t nrf_gzll_get_timeslots_per_channel(void); + +/** + * @brief Set the number of timeslots that a Gazell shall + * reside on a single channel before switching to another channel when + * in the "out of sync" state. + * + * This value should be set so that the Device transmits on one channel + * while the Host goes through a full channel rotation, i.e., + * channel_table_size*timeslots_per_channel. + * This ensures that the channels on the Device and Host will coincide + * at some point. + * Further increasing the value has been observed to provide better performance + * in the presence of interferers. + * + * @param timeslots The number of timeslots to reside on + * each channel before channel switch. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled. + */ +bool nrf_gzll_set_timeslots_per_channel_when_device_out_of_sync(uint32_t timeslots); + +/** + * @brief Get function counterpart to + * nrf_gzll_set_timeslots_per_channel_when_device_out_of_sync(). + * + * @return The current number of timeslots. + */ +uint32_t nrf_gzll_get_timeslots_per_channel_when_device_out_of_sync(void); + +/** + * @brief Set the number of timeslots after a successful + * reception of a Device or Host packet that the Gazell Link Layer shall assume + * that the link is synchronized. A value of 0 implies that the + * link is always out of sync. + * + * @param lifetime The sync lifetime in number of timeslots. + * + * @retval true If the sync lifetime was set. + * @retval false If Gazell was enabled. + */ +bool nrf_gzll_set_sync_lifetime(uint32_t lifetime); + +/** + * @brief Get function counterpart to nrf_gzll_set_sync_lifetime(). + * + * @return The sync lifetime measured in number of timeslots. + */ +uint32_t nrf_gzll_get_sync_lifetime(void); + +/** + * @brief Set the maximum number of TX attempts + * that can be used for a single packet. + * + * After the maximum number of attempts have been spent without + * receiving any ACK from the Host, the transmission will be terminated + * and the nrf_gzll_device_tx_failed() callback will be called. A zero + * value of the function parameter implies the infinite number of TX attempts. + * + * @param max_tx_attempts The maximum number of TX attempts. + */ +void nrf_gzll_set_max_tx_attempts(uint16_t max_tx_attempts); + +/** + * @brief Get function counterpart to nrf_gzll_set_max_tx_attempts(). + * + * @return The current max Device TX attempts. + */ +uint16_t nrf_gzll_get_max_tx_attempts(void); + +/** + * @brief Set the table of Radio Frequency (RF) channels. + * + * The valid channels are in the range 0 <= channel <= 125, where the + * actual centre frequency is (2400 + channel) MHz. + * The maximum channel table size is defined by + * NRF_GZLL_CONST_MAX_CHANNEL_TABLE_SIZE. + * + * @param p_channel_table Pointer to the channel table. + * @param size The size of the channel table. + * + * @retval true If the channel table was set. + * @retval false If Gazell was enabled, or the channel_table pointer was NULL, + * or the size was invalid. + */ +bool nrf_gzll_set_channel_table(uint8_t * p_channel_table, uint32_t size); + +/** + * @brief Get the table of Radio Frequency (RF) channels. + * + * @param p_channel_table Pointer to copy the channel table to. + * @param p_size Pointer to copy the size of the channel table to. + * The value already at size must be at least the size + * of the channel table. + * + * @retval true If the channel table was copied to channel_table. + * @retval false If the channel_table pointer was NULL, + * or the size was not large enough. + */ +bool nrf_gzll_get_channel_table(uint8_t * p_channel_table, uint32_t * p_size); + +/** + * @brief Get the current channel table size. + * + * @return The current channel table size. + */ +uint32_t nrf_gzll_get_channel_table_size(void); + +/** + * @brief Set the radio TX power. + * + * @param tx_power TX power. + * + * @retval true If the parameter was set. + * @retval false If the TX power was invalid. +*/ +bool nrf_gzll_set_tx_power(nrf_gzll_tx_power_t tx_power); + +/** + * @brief Get function counterpart to nrf_gzll_set_tx_power(). + * + * @return The current TX power. + */ +nrf_gzll_tx_power_t nrf_gzll_get_tx_power(void); + +/** + * @brief Set the radio datarate. + * + * @param data_rate Datarate. + * + * @retval true If the parameter was set. + * @retval false If Gazell was enabled or the datarate was invalid. + */ +bool nrf_gzll_set_datarate(nrf_gzll_datarate_t data_rate); + +/** + * @brief Get function counterpart to nrf_gzll_set_datarate(). + * + * @return The current datarate. + */ +nrf_gzll_datarate_t nrf_gzll_get_datarate(void); + +/** + * @brief Set whether start/stop of external oscillator (XOSC) shall be handled + * automatically inside Gazell or manually by the application. + * + * When controlling the XOSC manually from the application it is + * required that the XOSC is started before Gazell is enabled. + * + * When start/stop of the XOSC is handled automatically by Gazell, + * the XOSC will only be running when needed, that is when the radio + * is being used or when Gazell needs to maintain synchronization. + * + * It is required that the XOSC is started in order for the radio to be + * able to send or receive any packets. + * + * @param xosc_ctl setting for XOSC control. + * + * @retval true if the parameter was set. + * @retval false if Gazell was enabled or the xosc_ctl value was invalid. + */ +bool nrf_gzll_set_xosc_ctl(nrf_gzll_xosc_ctl_t xosc_ctl); + +/** + * Get function counterpart for nrf_gzll_set_xosc_ctl(); + * + * @return The XOSC control setting. + */ +nrf_gzll_xosc_ctl_t nrf_gzll_get_xosc_ctl(void); + +/** + * @brief Set Gazell to disable automatically after a certain number of timeslot ticks. + * + * @param num_ticks Number of timeslot ticks. + * + */ +void nrf_gzll_set_auto_disable(uint32_t num_ticks); + +#if defined(NRF52_SERIES) || defined(__SDK_DOXYGEN__) +/** + * @brief Set up external front end control. + * + * @param p_pa_lna_cfg Pointer to the configuration struct. + */ +bool nrf_gzll_set_pa_lna_cfg(nrf_gzll_pa_lna_cfg_t const * p_pa_lna_cfg); +#endif + +/** + * @brief Get the number of timeslot ticks that have occurred since + * nrf_gzll_init() was called. + * + * @return Number of timeslot ticks. + * + */ +uint32_t nrf_gzll_get_tick_count(void); + +/** + * @brief Clear the internal timeslot tick count variable that is read + * by nrf_gzll_get_tick_count(). + * + */ +void nrf_gzll_clear_tick_count(void); + +/** @} */ + +/******************************************************************************/ +/** @name Error handling functions + * @{ */ +/******************************************************************************/ + +/** + * @brief Gets the Gazell error code. + * + * @return The current error code. + */ +nrf_gzll_error_code_t nrf_gzll_get_error_code(void); + + +/** + * @brief Reset the Gazell error code. + * + * The error code is reset to NRF_GZLL_ERROR_CODE_NO_ERRROR. + */ +void nrf_gzll_reset_error_code(void); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_constants.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_constants.h new file mode 100644 index 0000000..80df7c1 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_constants.h @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2011 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Gazell Link Layer constants and default values. + * + * NOTE! Changing values here has no effect. They are only provided as a reference. + */ + +#ifndef NRF_GZLL_CONSTANTS_H__ +#define NRF_GZLL_CONSTANTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup gzll_02_api + * @{ + */ + + +/*****************************************************************************/ +/** @name Hardware resources used by Gazell */ +/*****************************************************************************/ +#define NRF_GZLL_HIGH_IRQ_PRIORITY 0 ///< Interrupt priority the Gazell timer and the radio +#define NRF_GZLL_LOW_IRQ_PRIORITY 1 ///< Interrupt priority for Gazell callback functions. + +#ifndef USE_SD_HW_RESOURCES + +#define NRF_GZLL_SWI_IRQn SWI0_IRQn ///< Software interrupt # used for callback functions. +#define NRF_GZLL_SWI_IRQ_HANDLER SWI0_IRQHandler ///< Software interrupt handler used for callback functions. +#define NRF_GZLL_TIMER NRF_TIMER2 ///< Timer to be used as flywheel timer. +#define NRF_GZLL_TIMER_IRQn TIMER2_IRQn ///< Interrupt # for the timer. +#define NRF_GZLL_TIMER_IRQ_HANDLER TIMER2_IRQHandler ///< Interrupt handler for the timer. + +// In addition, Gazell uses the radio peripheral and radio interrupts. + +/* + * PPI configuration + */ +#define NRF_GZLL_PPI_EEP0 (NRF_PPI->CH0_EEP) ///< Gazell PPI event endpoint 0 +#define NRF_GZLL_PPI_TEP0 (NRF_PPI->CH0_TEP) ///< Gazell PPI task endpoint 0 +#define NRF_GZLL_PPI_EEP1 (NRF_PPI->CH1_EEP) ///< Gazell PPI event endpoint 1 +#define NRF_GZLL_PPI_TEP1 (NRF_PPI->CH1_TEP) ///< Gazell PPI task endpoint 1 +#define NRF_GZLL_PPI_EEP2 (NRF_PPI->CH2_EEP) ///< Gazell PPI event endpoint 2 +#define NRF_GZLL_PPI_TEP2 (NRF_PPI->CH2_TEP) ///< Gazell PPI task endpoint 2 + +#define NRF_GZLL_PPI_CHEN_MSK_0_AND_1 (0x03) ///< Channel enable/disable mask for PPI endpoint 0 and 1. +#define NRF_GZLL_PPI_CHEN_MSK_2 (0x04) ///< Channel enable/disable mask for PPI endpoint 2. + +#else + +#define NRF_GZLL_SWI_IRQn SWI1_IRQn ///< Software interrupt # used for callback functions. +#define NRF_GZLL_SWI_IRQ_HANDLER SWI1_IRQHandler ///< Software interrupt handler used for callback functions. +#define NRF_GZLL_TIMER NRF_TIMER0 ///< Timer to be used as flywheel timer. +#define NRF_GZLL_TIMER_PERPOWER_Msk POWER_PERPOWER_TIMER0_Msk ///< PERPOWER mask for the timer. +#define NRF_GZLL_TIMER_IRQn TIMER0_IRQn ///< Interrupt # for the timer. +#define NRF_GZLL_TIMER_IRQ_HANDLER TIMER0_IRQHandler ///< Interrupt handler for the timer. + +// In addition, Gazell uses the radio peripheral and radio interrupts. + +/* + * PPI configuration + */ +#define NRF_GZLL_PPI_EEP0 (NRF_PPI->CH8_EEP) ///< Gazell PPI event endpoint 0 +#define NRF_GZLL_PPI_TEP0 (NRF_PPI->CH8_TEP) ///< Gazell PPI task endpoint 0 +#define NRF_GZLL_PPI_EEP1 (NRF_PPI->CH9_EEP) ///< Gazell PPI event endpoint 1 +#define NRF_GZLL_PPI_TEP1 (NRF_PPI->CH9_TEP) ///< Gazell PPI task endpoint 1 +#define NRF_GZLL_PPI_EEP2 (NRF_PPI->CH10_EEP) ///< Gazell PPI event endpoint 2 +#define NRF_GZLL_PPI_TEP2 (NRF_PPI->CH10_TEP) ///< Gazell PPI task endpoint 2 + +#define NRF_GZLL_PPI_CHEN_MSK_0_AND_1 (0x300) ///< Channel enable/disable mask for PPI endpoint 0 and 1. +#define NRF_GZLL_PPI_CHEN_MSK_2 (0x400) ///< Channel enable/disable mask for PPI endpoint 2. + +#endif +/** @} */ + +/*****************************************************************************/ +/** @name Constant pipe and FIFO configuration */ +/*****************************************************************************/ +#define NRF_GZLL_CONST_PIPE_COUNT 8 ///< Number of TX pipes (at least one for each Device-Host pairs). +#define NRF_GZLL_CONST_FIFO_LENGTH 3 ///< Maximum number of packets allowed in a TX or RX FIFO. +#define NRF_GZLL_CONST_MAX_TOTAL_PACKETS 6 ///< Maximum number of packets available for reservation at any one time. +#define NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH 32 ///< Maximum allowed payload length in bytes. +#define NRF_GZLL_CONST_CALLBACK_QUEUE_LENGTH 10 ///< Maximum number of notifications allowed in the callback queue. +/** @} */ + +/*****************************************************************************/ +/** @name Default radio configuration */ +/*****************************************************************************/ +#define NRF_GZLL_DEFAULT_TX_POWER NRF_GZLL_TX_POWER_0_DBM ///< Default TX power. +#define NRF_GZLL_DEFAULT_DATARATE NRF_GZLL_DATARATE_2MBIT ///< Default data rate. + +#define NRF_GZLL_DEFAULT_CHANNEL_TABLE {4, 25, 42, 63, 77} ///< Default channel table. +#define NRF_GZLL_DEFAULT_CHANNEL_TABLE_SIZE 5 ///< Default channel table size. +#define NRF_GZLL_CONST_MAX_CHANNEL_TABLE_SIZE 16 ///< Maximum channel table size allowed by Gazell. +/** @} */ + +/*****************************************************************************/ +/** @name Default Address configuration */ +/*****************************************************************************/ + +/* +Corresponds to Legacy nRFgo SDK Gazell config: +#define GZLL_DEFAULT_ADDRESS_PIPE0 {0x01, 0x04, 0x07, 0x0A, 0x0D} +#define GZLL_DEFAULT_ADDRESS_PIPE1 {0x02, 0x05, 0x08, 0x0B, 0x0E} +#define GZLL_DEFAULT_ADDRESS_PIPE2 3 +#define GZLL_DEFAULT_ADDRESS_PIPE3 4 +#define GZLL_DEFAULT_ADDRESS_PIPE4 5 +#define GZLL_DEFAULT_ADDRESS_PIPE5 6 +*/ + +#define NRF_GZLL_DEFAULT_FULL_ADDRESS_PIPE0 {0x01, 0x04, 0x07, 0x0A, 0x0D} ///< Corresponding legacy Gazell pipe 0 address. +#define NRF_GZLL_DEFAULT_BASE_ADDRESS_0 0x0D0A0704 ///< Default base address 0. +#define NRF_GZLL_DEFAULT_BASE_ADDRESS_1 0x0E0B0805 ///< Default base address 1. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_0 1 ///< Default prefix address pipe 0. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_1 2 ///< Default prefix address pipe 1. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_2 3 ///< Default prefix address pipe 2. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_3 4 ///< Default prefix address pipe 3. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_4 5 ///< Default prefix address pipe 4. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_5 6 ///< Default prefix address pipe 5. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_6 7 ///< Default prefix address pipe 6. +#define NRF_GZLL_DEFAULT_PREFIX_BYTE_7 8 ///< Default prefix address pipe 7. +#define NRF_GZLL_DEFAULT_BASE_ADDRESS_LENGTH NRF_GZLL_BASE_ADDRESS_LENGTH_4B ///< Default on-air base address length. +#define NRF_GZLL_DEFAULT_RX_PIPES_ENABLED 0x000000FF ///< Enabled Rx pipes. See nrf_gzll_set_rx_pipes_enabled(). +/** @} */ + +/*****************************************************************************/ +/** @name Default timeslot and synchronization configuration */ +/*****************************************************************************/ +#define NRF_GZLL_DEFAULT_TIMESLOT_PERIOD 600 ///< Default timeslot period. +#define NRF_GZLL_DEFAULT_TIMESLOTS_PER_CHANNEL 2 ///< Timeslots use by the Host and by the Device when communication is in sync. +#define NRF_GZLL_DEFAULT_DEVICE_CHANNEL_SELECTION_POLICY NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_SUCCESSFUL ///< Default channel Gazell Device channel selection policy +#define NRF_GZLL_DEFAULT_MAX_TX_ATTEMPTS 0 ///< Default maximum TX attempts for each packet. A value of zero implies the infinite number of TX attempts. +#define NRF_GZLL_DEFAULT_XOSC_CTL NRF_GZLL_XOSC_CTL_AUTO ///< Deafult setting for controlling the XOSC +#define NRF_GZLL_DEFAULT_TIMESLOTS_PER_CHANNEL_WHEN_DEVICE_OUT_OF_SYNC 15 ///< Timeslots use by the Device before communication is in sync. +#define NRF_GZLL_DEFAULT_SYNC_LIFETIME (3 * NRF_GZLL_DEFAULT_CHANNEL_TABLE_SIZE * NRF_GZLL_DEFAULT_TIMESLOTS_PER_CHANNEL) ///< Number of timeslots to keep the timer running so that communication remains synchronized. +/** @} */ + +#define NRF_GZLL_PA_LNA_MAX_RAMP_UP_TIME 129 ///< Max external front end ramp up time [us]. +#define NRF_GZLL_PA_LNA_PPI_CHANNELS_NUM 4 ///< Number of PPI channels used for front end control. + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_error.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_error.h new file mode 100644 index 0000000..6806a1b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_error.h @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Gazell error API. + */ + +#ifndef NRF_GZLL_ERROR_H__ +#define NRF_GZLL_ERROR_H__ + +#include "sdk_errors.h" +#include "nrf_gzll.h" +#include "app_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GAZELLE_ERROR_CODE_CHECK(GZLL_RESULT) \ + do \ + { \ + if ((GZLL_RESULT) == false) \ + { \ + nrf_gzll_error_code_t gzll_error_code = nrf_gzll_get_error_code(); \ + ret_code_t error_code = gzll_error_code + NRF_ERROR_GAZELLE_ERR_BASE; \ + APP_ERROR_HANDLER(error_code); \ + } \ + } while (0) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_resources.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_resources.h new file mode 100644 index 0000000..f419b6a --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzll_resources.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_GZLL_RESOURCES_H__ +#define NRF_GZLL_RESOURCES_H__ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GAZELL_ALTERNATIVE_RESOURCES + #define GZLL_PPI_CHANNELS_USED 0x00000007uL /**< PPI channels utilized by Gazell (not available to th spplication). */ + #define GZLL_TIMERS_USED 0x00000004uL /**< Timers used by Gazell. */ + #define GZLL_SWI_USED 0x00000001uL /**< Software interrupts used by Gazell */ +#else + #define GZLL_PPI_CHANNELS_USED 0x00000700uL /**< PPI channels utilized by Gazell (not available to th spplication). */ + #define GZLL_TIMERS_USED 0x00000001uL /**< Timers used by Gazell. */ + #define GZLL_SWI_USED 0x00000002uL /**< Software interrupts used by Gazell */ +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* NRF_GZLL_RESOURCES_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp.c new file mode 100644 index 0000000..07e0488 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp.c @@ -0,0 +1,363 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Implementation of Gazell Pairing Library (gzp), Common functions. + * @defgroup gzp_source_common Gazell Pairing common functions implementation + * @{ + * @ingroup gzp_04_source + */ + + +#include "nrf_gzp.h" +#include "nrf_gzll.h" +#include "nrf_ecb.h" +#include <string.h> + + +#define SOURCE_FILE NRF_SOURCE_FILE_GZP ///< File identifer for asserts. + + +/******************************************************************************/ +/** @name Global variables + * @{ */ +/******************************************************************************/ + +/** + * Constant holding base address part of the pairing address. + */ +static const uint8_t pairing_base_address[4] = { GZP_ADDRESS }; + +/** + * Constant holding prefix byte of the pairing address. + */ +static const uint8_t pairing_address_prefix_byte = 0; + +/** + * Constant holding pre-defined "validation ID". + */ +static const uint8_t gzp_validation_id[GZP_VALIDATION_ID_LENGTH] = GZP_VALIDATION_ID; + +/** + * Constant holding pre-defined "secret key". + */ +static const uint8_t gzp_secret_key[16] = GZP_SECRET_KEY; + +/** + * Variable used for AES key selection + */ +static gzp_key_select_t gzp_key_select; + + +/** @} */ + + +/******************************************************************************/ +/** @name Misc. external variables. + * @{ */ +/******************************************************************************/ +static uint8_t gzp_session_token[GZP_SESSION_TOKEN_LENGTH]; +static uint8_t gzp_dyn_key[GZP_DYN_KEY_LENGTH]; + +/** @} */ + +/******************************************************************************/ +/** @name Implementation common internal GZP functions + * @{ */ +/******************************************************************************/ +bool gzp_update_radio_params(const uint8_t* system_address) +{ + uint8_t i; + uint8_t channels[NRF_GZLL_CONST_MAX_CHANNEL_TABLE_SIZE]; + uint32_t channel_table_size; + uint32_t pairing_base_address_32, system_address_32; + bool update_ok = true; + bool gzll_enabled_state; + + gzll_enabled_state = nrf_gzll_is_enabled(); + + // Configure "global" pairing address + pairing_base_address_32 = (pairing_base_address[0]) + + ((uint32_t)pairing_base_address[1] << 8) + + ((uint32_t)pairing_base_address[2] << 16) + + ((uint32_t)pairing_base_address[3] << 24) ; + if (system_address != NULL) + { + system_address_32 = (system_address[0]) + + ((uint32_t)system_address[1] << 8) + + ((uint32_t)system_address[2] << 16) + + ((uint32_t)system_address[3] << 24) ; + } + else + { + return false; + } + + nrf_gzp_disable_gzll(); + update_ok = update_ok && nrf_gzll_set_base_address_0(pairing_base_address_32); + update_ok = update_ok && nrf_gzll_set_address_prefix_byte(GZP_PAIRING_PIPE, pairing_address_prefix_byte); + update_ok = update_ok && nrf_gzll_set_base_address_1(system_address_32); + + // Configure address for pipe 1 - 5. Address byte set to equal pipe number. + for (i = 1; i < NRF_GZLL_CONST_PIPE_COUNT; i++) + { + update_ok = update_ok && nrf_gzll_set_address_prefix_byte(i,i); + } + + channel_table_size = nrf_gzll_get_channel_table_size(); + gzp_generate_channels(&channels[0], system_address, channel_table_size); + + // Write generated channel subset to Gazell Link Layer + update_ok = update_ok && nrf_gzll_set_channel_table(&channels[0], channel_table_size); + if (gzll_enabled_state) + { + update_ok = update_ok && nrf_gzll_enable(); + } + return update_ok; +} + +void gzp_generate_channels(uint8_t* ch_dst, const uint8_t* system_address, uint8_t channel_tab_size) +{ + uint8_t binsize, spacing, i; + + binsize = (GZP_CHANNEL_MAX - GZP_CHANNEL_MIN) / channel_tab_size; + + ch_dst[0] = GZP_CHANNEL_LOW; + ch_dst[channel_tab_size - 1] = GZP_CHANNEL_HIGH; + + if (system_address != NULL) + { + for (i = 1; i < (channel_tab_size - 1); i++) + { + ch_dst[i] = (binsize * i) + (system_address[i % 4] % binsize); + } + } + + // If channels are too close, shift them to better positions + for (i = 1; i < channel_tab_size; i++) + { + spacing = (ch_dst[i] - ch_dst[i - 1]); + if (spacing < GZP_CHANNEL_SPACING_MIN) + { + ch_dst[i] += (GZP_CHANNEL_SPACING_MIN - spacing); + } + } +} + +__INLINE void nrf_gzp_disable_gzll(void) +{ + if (nrf_gzll_is_enabled()) + { + nrf_gzll_disable(); + __WFI(); + while (nrf_gzll_is_enabled()) + { + } + } +} + +#ifndef GZP_CRYPT_DISABLE + +void gzp_xor_cipher(uint8_t* dst, const uint8_t* src, const uint8_t* pad, uint8_t length) +{ + uint8_t i; + + for (i = 0; i < length; i++) + { + *dst = *src ^ *pad; + dst++; + src++; + pad++; + } +} + +bool gzp_validate_id(const uint8_t* id) +{ + return (memcmp(id, (void*)gzp_validation_id, GZP_VALIDATION_ID_LENGTH) == 0); +} + +void gzp_add_validation_id(uint8_t* dst) +{ + memcpy(dst, (void const*)gzp_validation_id, GZP_VALIDATION_ID_LENGTH); +} + +void gzp_crypt_set_session_token(const uint8_t * token) +{ + memcpy(gzp_session_token, (void const*)token, GZP_SESSION_TOKEN_LENGTH); +} + +void gzp_crypt_set_dyn_key(const uint8_t* key) +{ + memcpy(gzp_dyn_key, (void const*)key, GZP_DYN_KEY_LENGTH); +} + +void gzp_crypt_get_session_token(uint8_t * dst_token) +{ + memcpy(dst_token, (void const*)gzp_session_token, GZP_SESSION_TOKEN_LENGTH); +} + +void gzp_crypt_get_dyn_key(uint8_t* dst_key) +{ + memcpy(dst_key, (void const*)gzp_dyn_key, GZP_DYN_KEY_LENGTH); +} + +void gzp_crypt_select_key(gzp_key_select_t key_select) +{ + gzp_key_select = key_select; +} + +void gzp_crypt(uint8_t* dst, const uint8_t* src, uint8_t length) +{ + uint8_t i; + uint8_t key[16]; + uint8_t iv[16]; + + // Build AES key based on "gzp_key_select" + + switch (gzp_key_select) + { + case GZP_ID_EXCHANGE: + memcpy(key, (void const*)gzp_secret_key, 16); + break; + case GZP_KEY_EXCHANGE: + memcpy(key, (void const*)gzp_secret_key, 16); + gzp_get_host_id(key); + break; + case GZP_DATA_EXCHANGE: + memcpy(key, (void const*)gzp_secret_key, 16); + memcpy(key, (void const*)gzp_dyn_key, GZP_DYN_KEY_LENGTH); + break; + default: + return; + } + + // Build init vector from "gzp_session_token" + for (i = 0; i < 16; i++) + { + if (i < GZP_SESSION_TOKEN_LENGTH) + { + iv[i] = gzp_session_token[i]; + } + else + { + iv[i] = 0; + } + } + + // Set up hal_aes using new key and init vector + (void)nrf_ecb_init(); + nrf_ecb_set_key(key); + //hal_aes_setup(false, ECB, key, NULL); // Note, here we skip the IV as we use ECB mode + + // Encrypt IV using ECB mode + (void)nrf_ecb_crypt(iv, iv); + + // Encrypt data by XOR'ing with AES output + gzp_xor_cipher(dst, src, iv, length); + +} + +void gzp_random_numbers_generate(uint8_t * dst, uint8_t n) +{ + uint8_t i; + + NRF_RNG->EVENTS_VALRDY=0; + NRF_RNG->TASKS_START = 1; + for (i = 0; i < n; i++) + { + while (NRF_RNG->EVENTS_VALRDY==0) + {} + dst[i] = (uint8_t)NRF_RNG->VALUE; + NRF_RNG->EVENTS_VALRDY=0; + } + NRF_RNG->TASKS_STOP = 1; +} + + +/******************************************************************************/ +/** @name Implementation of nRF51 specific GZP functions + * @{ */ +/******************************************************************************/ + +/** +* @brief Function for setting the Primask variable. Only necessary if ARMCC +* compiler skips __set_PRIMASK at high optimization levels. +* +* @param primask The primask value. 1 to disable interrupts, 0 otherwise. +*/ +static void nrf_gzp_set_primask(uint32_t primask) +{ + #if defined(__CC_ARM) + //lint -save -e10 -e618 -e438 -e550 -e526 -e628 -e526 + volatile register uint32_t __regPriMask __ASM("primask"); + __regPriMask = (primask); + #else + __set_PRIMASK(primask); + #endif + //lint -restore +} + +void nrf_gzp_flush_rx_fifo(uint32_t pipe) +{ + static uint8_t dummy_packet[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; + uint32_t length; + + nrf_gzp_set_primask(1); + while (nrf_gzll_get_rx_fifo_packet_count(pipe) >0) + { + length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; + (void)nrf_gzll_fetch_packet_from_rx_fifo(pipe,dummy_packet,&length); + } + nrf_gzp_set_primask(0); +} +/** @} */ + + + +/******************************************************************************/ +/** @name Implementation of debug functions + * @{ */ +/******************************************************************************/ + + +/** @} */ + +/** @} */ +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp.h new file mode 100644 index 0000000..336151f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp.h @@ -0,0 +1,665 @@ +/** + * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Gazell Pairing API + */ + +#ifndef __GZP_H +#define __GZP_H + +#include "nrf.h" +#include "nrf_gzp_config.h" +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/** +* @defgroup gzp_02_api Gazell Pairing +* @{ +* @ingroup modules_02_gzp +* @brief Gazell Pairing Application Programming Interface (API). +*/ + + +/******************************************************************************/ +/** @name Pairing configuration defines + * @{ */ +/******************************************************************************/ + + +#define GZP_PAIRING_PIPE 0 ///< Pipe reserved for initial pairing communication. +#define GZP_DATA_PIPE 1 ///< Pipe reserved for GZP encrypted data communication (one pipe only). +#define GZP_TX_RX_TRANS_DELAY 10 ///< Time to wait between request and fetch packets in RX_PERIODS (2 timeslot periods) +#define GZP_SYSTEM_ADDRESS_WIDTH 4 ///< Must equal Gazell base address length. + + +#define GZP_VALIDATION_ID {0x32, 0x53, 0x66} ///< Validation ID. Required to be shared by Host and Device. Not a secret. +#define GZP_VALIDATION_ID_LENGTH 3 ///< Validation ID length in bytes. +#define GZP_HOST_ID_LENGTH 5 ///< Host ID length in bytes. +#define GZP_SESSION_TOKEN_LENGTH GZP_HOST_ID_LENGTH ///< Session token length in bytes. +#define GZP_DYN_KEY_LENGTH (16 - GZP_VALIDATION_ID_LENGTH) ///< Dynamic key length in bytes. + +#define GZP_HOST_RX_POWER_THRESHOLD -64 ///< RSSI threshold for when signal strength in RX packet power is high enough. + +/** @} */ + + +/******************************************************************************/ +/** @name Device -> Host packet definitions + * @{ */ +/******************************************************************************/ + +#define GZP_CMD_HOST_ADDRESS_REQ_PAYLOAD_LENGTH 1 ///< "Host address request" packet, payload length + +#define GZP_CMD_HOST_ADDRESS_FETCH_PAYLOAD_LENGTH 1 ///< "Host address fetch" packet, payload length + +#define GZP_CMD_HOST_ID_REQ_SESSION_TOKEN 1 ///< "Host ID request" packet, session token position +#define GZP_CMD_HOST_ID_REQ_PAYLOAD_LENGTH (GZP_CMD_HOST_ID_REQ_SESSION_TOKEN + GZP_SESSION_TOKEN_LENGTH) ///< "Host ID request" payload length + +#if (GZP_CMD_HOST_ID_REQ_PAYLOAD_LENGTH > 17) +#error GZP_SESSION_TOKEN_LENGTH too long. +#endif + + +#define GZP_CMD_HOST_ID_FETCH_VALIDATION_ID 1 ///< "Host ID fetch" packet +#define GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH (GZP_CMD_HOST_ID_FETCH_VALIDATION_ID + GZP_VALIDATION_ID_LENGTH) ///< "Host ID fetch" payload length + +#if (GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH > 17) +#error GZP_VALIDATION_ID_LENGTH set too long. +#endif + +#define GZP_CMD_KEY_UPDATE_PREPARE_PAYLOAD_LENGTH 1 ///< "Key update prepare" payload length + +#define GZP_CMD_KEY_UPDATE_VALIDATION_ID 1 ///< "Key update" packet, validation ID position +#define GZP_CMD_KEY_UPDATE_NEW_KEY (GZP_CMD_KEY_UPDATE_VALIDATION_ID + GZP_VALIDATION_ID_LENGTH) ///< "Key update" packet, new key position +#define GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH (GZP_CMD_KEY_UPDATE_NEW_KEY + GZP_DYN_KEY_LENGTH) ///< "Key update" packet, payload length + +#if (GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH > 17) +#error Sum (GZP_VALIDATION_ID_LENGTH + GZP_DYN_KEY_LENGTH) too high. +#endif + + +#define GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID 1 ///< "Encrypted user data" packet, validation ID position +#define GZP_CMD_ENCRYPTED_USER_DATA_PAYLOAD ((GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID + GZP_VALIDATION_ID_LENGTH)) ///< "Encrypted user data" packet, user data position +#define GZP_ENCRYPTED_USER_DATA_PACKET_OVERHEAD ( GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID + GZP_VALIDATION_ID_LENGTH) ///< "Encrypted user data" packet, packet overhead length +#define GZP_ENCRYPTED_USER_DATA_MAX_LENGTH (17 - GZP_ENCRYPTED_USER_DATA_PACKET_OVERHEAD) ///< "Encrypted user data" packet, max payload length + +#if (GZP_MAX_FW_PAYLOAD_LENGTH < 17) + #error GZP_MAX_FW_PAYLOAD_LENGTH must be greater or equal to 17. +#endif + +#define GZP_CMD_FETCH_RESP_PAYLOAD_LENGTH 1 ///< General "fetch response" packet, payload_length + +/** @} */ + + +/******************************************************************************/ +/** @name Host -> Device packet definitions + * @{ */ +/******************************************************************************/ + + +#define GZP_CMD_HOST_ADDRESS_RESP_ADDRESS 1 ///< "Host address fetch" response packet, address position +#define GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH (GZP_CMD_HOST_ADDRESS_RESP_ADDRESS + GZP_SYSTEM_ADDRESS_WIDTH) ///< ///< "Host address fetch" response packet, payload length + +#if (GZP_MAX_ACK_PAYLOAD_LENGTH < GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH) + #error GZP_MAX_ACK_PAYLOAD_LENGTH must be greater or equal to GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH. +#endif + + +#define GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID 1 ///< "Host ID fetch" response packet, validation ID position +#define GZP_CMD_HOST_ID_FETCH_RESP_STATUS (GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID + GZP_VALIDATION_ID_LENGTH) ///< "Host ID fetch" response packet, status position +#define GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID (GZP_CMD_HOST_ID_FETCH_RESP_STATUS + 1) ///< "Host ID fetch" response packet, Host ID position +#define GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH (GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID + GZP_HOST_ID_LENGTH) ///< "Host ID fetch" response packet, payload length + +#if (GZP_MAX_ACK_PAYLOAD_LENGTH < GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH) + #error GZP_MAX_ACK_PAYLOAD_LENGTH must be greater or equal to GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH. +#endif + + +#define GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN 1 ///< "Key update prepare" response packet, session token position +#define GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH (GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN + GZP_SESSION_TOKEN_LENGTH) ///< "Key update prepare" response packet, payload length position + +#if (GZP_MAX_ACK_PAYLOAD_LENGTH < GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH) + #error GZP_MAX_ACK_PAYLOAD_LENGTH must be greater or equal to GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH. +#endif + + +#define GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN 1 ///< "Encrypted user data" response packet, session token position +#define GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID (GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN + GZP_SESSION_TOKEN_LENGTH) ///< "Encrypted user data" response packet, validation ID position +#define GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH (GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID + GZP_VALIDATION_ID_LENGTH) ///< "Encrypted user data" response packet, payload length position + +#if (GZP_MAX_ACK_PAYLOAD_LENGTH < GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH) + #error GZP_MAX_ACK_PAYLOAD_LENGTH must be greater or equal to GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH. +#endif + +#if (GZP_VALIDATION_ID_LENGTH > GZP_HOST_ID_LENGTH) + #error GZP_HOST_ID_LENGTH should be greater or equal to GZP_VALIDATION_ID_LENGTH. +#endif + +#if (GZP_SESSION_TOKEN_LENGTH != GZP_HOST_ID_LENGTH) + #error GZP_SESSION_TOKEN_LENGTH must equal GZP_HOST_ID_LENGTH. +#endif + +#ifdef GZLL_CRYPT_ENABLE + #error Gazell encryption can not be enabled when using the Gazell pairing library. \ + GZLL_CRYPT_ENABLE must be undefined. +#endif + +/** @} */ + + +/******************************************************************************/ +/** @name Typedefs + * @{ */ +/******************************************************************************/ + + +/** + * @enum gzp_key_select_t + * @brief Enumerator used for selecting the key to be used for encryption. + */ +typedef enum +{ + GZP_ID_EXCHANGE, ///< "Secret key" only + GZP_KEY_EXCHANGE, ///< "Secret key" and "Host ID" + GZP_DATA_EXCHANGE ///< "Dynamic key" and "Host ID" +} gzp_key_select_t; + + +/** + * @enum gzp_cmd_t + * @brief Enumerator used in the first payload byte of each packet to + * indicate the packet type. + */ +typedef enum +{ + GZP_CMD_HOST_ADDRESS_REQ = 0, ///< Host address request + GZP_CMD_HOST_ADDRESS_FETCH, ///< Host address fetch + GZP_CMD_HOST_ID_REQ, ///< Host ID request + GZP_CMD_HOST_ID_FETCH, ///< Host ID fetch request + GZP_CMD_KEY_UPDATE_PREPARE, ///< Key update prepare + GZP_CMD_KEY_UPDATE, ///< Key update + GZP_CMD_ENCRYPTED_USER_DATA, ///< Encrypted user data + GZP_CMD_FETCH_RESP, ///< Fetch response + GZP_CMD_HOST_ADDRESS_RESP, ///< Host address response + GZP_CMD_HOST_ID_FETCH_RESP, ///< Host ID fetch response + GZP_CMD_KEY_UPDATE_PREPARE_RESP, ///< Key update prepare + GZP_CMD_ENCRYPTED_USER_DATA_RESP, ///< Encrypted user data response +} gzp_cmd_t; + + +/** + * @enum gzp_id_req_res_t + * @brief Enumerator used to identify the state of the current + * Host ID request. + */ +typedef enum +{ + GZP_ID_RESP_PENDING, ///< ID response pending + GZP_ID_RESP_GRANTED, ///< ID response granted + GZP_ID_RESP_REJECTED, ///< ID response rejected + GZP_ID_RESP_FAILED, ///< ID response failed + GZP_ID_RESP_NO_REQUEST ///< Default value. No ID request has yet been received. +} gzp_id_req_res_t; + + +/** @} */ + + +/******************************************************************************/ +/** @name Misc. function prototypes + * @{ */ +/******************************************************************************/ + +/** + * Set the session token. + * + * @param token Pointer to the session token to set. + */ +void gzp_crypt_set_session_token(const uint8_t *token); + + +/** + * Get the session token. + * + * @param dst_token Pointer to write the session token. + */ +void gzp_crypt_get_session_token(uint8_t *dst_token); + + +/** + * Set the dynamic key. + * + * @param dyn_key Pointer to the dynamic key to set. + */ +void gzp_crypt_set_dyn_key(const uint8_t* dyn_key); + + +/** + * Get the dynamic key. + * + * @param dst_key Pointer to write the dynamic key too. + */ +void gzp_crypt_get_dyn_key(uint8_t *dst_key); + + +/** + * Set the Host ID. + * + * @param src Pointer to the Host ID to set. + */ +static void gzp_set_host_id(const uint8_t* src); + + +/** + * Get the Host ID. + * + * @param dst Pointer to write the Host ID to. + */ +void gzp_get_host_id(uint8_t *dst); + + +/** + * Selecting what key-set that should be used when encrypting data + * using gzp_crypt(). + * + * @param key_select Key-set to use. + */ +void gzp_crypt_select_key(gzp_key_select_t key_select); + + +/** + * Encypt / decrypt data. + * + * The current "session token" will be used as initialization vector (IV). + * The AES key to be used is selected by gzp_crypt_select_key(). + * AES is a symmetric encryption scheme, this function can be used + * to perform both encryption and decryption. + * + * @param dst Destination to write encrypted data to. Should be 16 bytes long. + * @param src Source data to encrypt. + * @param length Length in bytes of src. + */ +void gzp_crypt(uint8_t* dst, const uint8_t* src, uint8_t length); + + +/** + * Compare the *src_id with a pre-defined validation ID. + * + * @param src_id Pointer to the source validation ID to compare to. + * + * @retval true If *src_id equals the pre-defined ID. + * @retval false If *src_id does not equal the pre-defined ID. + */ +bool gzp_validate_id(const uint8_t *src_id); + + +/** + * Add the pre-defined validation ID to dst_id. + * GZP_VALIDATION_ID_LENGTH bytes will be added. + * + * @param dst_id Pointer to add the GZP validation ID to. + */ +void gzp_add_validation_id(uint8_t *dst_id); + + +/** + * Generate random bytes. + * + * @param dst Destination to write the random bytes to. + * @param n Number of bytes to generate. + */ +void gzp_random_numbers_generate(uint8_t *dst, uint8_t n); + + +/** + * Update the channel table and the system address. + * + * The channel table is updated to pseudo-random set generated using the + * system address. The channel table still includes GZP_CHANNEL_MAX and + * GZP_CHANNEL_MIN. + * The system address is applied to base address 1 and therefore applies + * to pipes 1-7. + * + * @param system_address Pointer to the system_address to set. + * + * @retval true If theradio parameters were updated successfully. + * @retval false If there was an error updated the radio parameters. + */ +bool gzp_update_radio_params(const uint8_t *system_address); + + +/** + * Generate a set of channels from a 4 byte address. + * + * @param ch_dst Destination to write the channel set to. The channel set + * includes GZP_CHANNEL_MAX and GZP_CHANNEL_MIN. + * @param address Four byte address to generate the channel set from. + * @param channel_set_size Size of the channel set to generate. + */ +void gzp_generate_channels(uint8_t *ch_dst, const uint8_t * address, uint8_t channel_set_size); + + +/** + * Perform an XOR on two byte strings. + * + * @param dst Destination to write the result to. Should be of size length. + * @param src + * @param pad + * @param length Number of bytes to perform the XOR operation on. + */ +void gzp_xor_cipher(uint8_t* dst, const uint8_t* src, const uint8_t* pad, uint8_t length); + + +/******************************************************************************/ +/** @name Common Device and Host functions + * @{ */ +/******************************************************************************/ + + +/** + * Initialization function. This function initializes the Gazell Pairing Library. + + * This function must be called before any of the other Gazell Pairing Library functions are + * used and must be called @b after gzll_init() is called. + * + */ +void gzp_init(void); + +/** + * Function for erasing all pairing data. + */ +void gzp_erase_pairing_data(void); + +/** + * Disable Gazell and sleep while waiting for nrf_gzll_disabled callback. + */ +void nrf_gzp_disable_gzll(void); + +/** + Function for cancelling an ongoing (pending) "Host ID request". + + After calling this function the "Host ID request" status will go to + "ID request Idle". +*/ +void gzp_id_req_cancel(void); + +/** + * Flush the GZLL RX FIFO for a specific pipe while GZLL is disabled. + * + * @param pipe Pipe. + */ +void nrf_gzp_flush_rx_fifo(uint32_t pipe); + +/** +@name Device functions +*/ + +/** + * Check whether current GZP packet transaction has completed. + * + * @retval true + * @retval false + */ +bool nrf_gzp_tx_complete(void); + +/** + * Check whether previous GZP packet transaction was successful. + * + * @retval true + * @retval false + */ +bool nrf_gzp_tx_success(void); + +/** + * Reset tx_complete status. + */ +void nrf_gzp_reset_tx_complete(void); + +/** + * Reset tx_success status. + */ +void nrf_gzp_reset_tx_success(void); + +/** +* Function to check whether a Device has existing pairing data, implying that it is +* paired to a Host. +* +* @retval -2 The pairing database is empty. +* @retval -1 The device has a system address but no Host ID. +* @retval >=0 The device has a system address and HostID at this index value in the database. +*/ +int8_t gzp_get_pairing_status(void); + +/** + Function for sending a "system address" request to a Host. + + When calling this function the Device will attempt acquiring the "system address" from + any Host within close proximity. + + If a host is located within close proximity and pairing is enabled in the Host, + a "system address" will be sent in return to the Device. + + The new "system address" will apply immediately in the Device, and the new "system address" + will be stored in non volatile (NV) memory. + + Note. Using OTP devices limits the number of times a new "system address" can + be stored in NV memory. + + @return + + @retval true if new "system address" was received from a Host. + @retval false if no "system address" was received from a Host. +*/ +bool gzp_address_req_send(void); + +/** + Function for sending a "Host ID request" to a Host. + + The "Host ID" is needed to be able to send encrypted data using + gzp_crypt_data_send(). + + The request will be sent using the "system address" previously received using + gzp_address_req_send(). + + It is not required that the Host is within close proximity in order to acquire the + "Host ID". + + The new "Host ID" will apply immediately for the Device, and the new "Host ID" + will be stored in non volatile (NV) memory. + + Note. Using OTP devices limits the number of times a new "Host ID" can + be stored in NV memory. + + @return + + @retval GZP_ID_RESP_PENDING if a "Host ID request" has been sent to the Host, but the Host application has + not yet decided whether to Grant or Reject the "ID request". + @retval GZP_ID_RESP_GRANTED if the "Host ID" has been received from the Host. The received "Host ID" will be stored + in non volatile memory. + @retval GZP_ID_RESP_REJECTED if the Host application has rejected the "Host ID request". + @retval GZP_ID_RESP_FAILED if failing to send a request or receive a response from the Host. +*/ +gzp_id_req_res_t gzp_id_req_send(void); + +/** + Function for sending encrypted user data to the Host. + + Before any data can be sent the Device must acquire both the Host's + "system address" by using gzp_address_req_send() and the "Host ID" by using + gzp_id_req_send(). + + @param *src is a pointer to the data packet to be sent. + @param length is the length of the data packet to be sent. + + + @return + @retval true if the data was successfully transmitted and decrypted by the Host. + @retval false if data transmission failed or Host failed to decryption data correctly. +*/ +bool gzp_crypt_data_send(const uint8_t *src, uint8_t length); + + +/** +@name Host functions +*/ + +/** + Function for enabling/disabling pairing in a host. When pairing is enabled the host will + be monitoring for "system address" and "Host ID" requests from Devices. + + A "system address request" received from a Device will always be granted. + When a "host ID request" has been received, the Host application have to grant, + reject or cancel this by using one of the following functions: + + - gzp_id_req_grant() + - gzp_id_req_reject() + - gzp_id_req_cancel() + + @param enable + @arg true enables pairing. + @arg false disables pairing. +*/ +void gzp_pairing_enable(bool enable); + +/** + * Execute the Gazell Pairing Library Host operation. + * + * This function must be called regularly by the Host application. + */ +void gzp_host_execute(void); + +/** + * Address exchanged check. + * + * @retval true If a "system address" was delivered to a requesting Device during the + * previous call to gzp_host_execute(); + * @retval false Otherwise. +*/ +bool gzp_address_exchanged(void); + +/** + Function for checking if a "Host ID request" has been received from a Device. + + If a request has been received, the Pairing library will enter "ID request pending" + state. + + The application is responsible for responding to this request by calling + one of the following functions: + + - gzp_id_req_grant() + - gzp_id_req_reject() + - gzp_id_req_cancel() + + @retval true if a "Host ID request" has been received (internal state is "ID request pending") + @retval false if no "Host ID request" has been received (internal state is "ID request idle") +*/ +bool gzp_id_req_received(void); + +/** + Function for rejecting the previously received "Host ID request". This function should be called + only when a "Host ID request" has been received (internal state is "ID request pending"). + + The internal state of the Pairing library will remain "ID request pending" until the a "reject" message + has been successfully transmitted to the requesting Device. After this the internal state will + change to "ID request idle". +*/ +void gzp_id_req_reject(void); + +/** + * Function for granting the previously received "Host ID request". This function should be called + only when a "Host ID request" has been received (internal state is "ID request pending"). + + The internal state of the Pairing library will remain "ID request pending" until the "Host ID" has + been successfully transmitted to the requesting Device. After this the internal state will + change to "ID request idle". +*/ +void gzp_id_req_grant(void); + + +/** + * Check if user data has been received. + * + * @retval true If encrypted user data has been received. + * @retval false Otherwise. +*/ +bool gzp_crypt_user_data_received(void); + +/** + Function for reading encrypted user data. + + Note that the read user data will be automatically decrypted. Only data + that was decrypted correctly will be presented. + + @param dst* is a pointer to where the received data will be written. + @param length* is a pointer for returning the number of bytes received. Only 1 byte will + be writtem to length*. + + @return + @retval true if data has been received and is written to dst* + @retval false if no data has been received. +*/ +bool gzp_crypt_user_data_read(uint8_t* dst, uint8_t* length); + + +/** + Function emulating behavior of gzll_rx_start() in legeacy nRF24xx Gaell + linbrary. + + This functions sets Gazell in Host mode and starts reception (enable). +*/ +void gzll_rx_start(void); + + +/** @} */ +/** @} */ +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_device.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_device.c new file mode 100644 index 0000000..7ee4037 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_device.c @@ -0,0 +1,1146 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Implementation of Gazell Pairing Library (gzp), Device functions. + * @defgroup gzp_source_device Gazell Pairing Device implementation. + * @{ + * @ingroup gzp_04_source + */ + + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include "nrf_gzll.h" +#include "nrf_gzp.h" +#include "nrf_delay.h" +#include "nrf_nvmc.h" + +#define SOURCE_FILE NRF_SOURCE_FILE_GZP_DEVICE ///< File identifer for asserts. + +/******************************************************************************/ +/** @name Misc. defines + * @{ */ +/******************************************************************************/ + +#define GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS 0 ///< System address position. +#define GZP_PARAMS_DB_ELEMENT_HOST_ID (GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS + GZP_SYSTEM_ADDRESS_WIDTH) ///< Host ID position +#define GZP_PARAMS_DB_ELEMENT_SIZE (GZP_SYSTEM_ADDRESS_WIDTH + GZP_HOST_ID_LENGTH)///< Total size +#define GZP_PARAMS_DB_MAX_ENTRIES 14 ///< Maximum allowed entries in the database. + +/** @} */ + +/******************************************************************************/ +/** @name Derived parameters + * @{ */ +/******************************************************************************/ + +//lint -esym(40, GZP_PARAMS_STORAGE_ADR) "Undeclare identifier" +#define GZP_PARAMS_DB_ADR GZP_PARAMS_STORAGE_ADR ///< +#define GZP_PARAMS_DB_SIZE (GZP_PARAMS_DB_MAX_ENTRIES * GZP_PARAMS_DB_ELEMENT_SIZE) ///< + +#define GZP_INDEX_DB_ADR (GZP_PARAMS_STORAGE_ADR + GZP_PARAMS_DB_SIZE) ///< +#define GZP_INDEX_DB_SIZE (GZP_DEVICE_PARAMS_STORAGE_SIZE - GZP_PARAMS_DB_SIZE) ///< + +#if (GZP_DEVICE_PARAMS_STORAGE_SIZE < GZP_PARAMS_DB_SIZE) + #error GZP_DEVICE_PARAMS_STORAGE_SIZE must be greater or equal to GZP_PAIRING_PARAMS_DB_SIZE +#elif (GZP_DEVICE_PARAMS_STORAGE_SIZE == GZP_PARAMS_DB_SIZE ) + #warning GZP_DEVICE_PARAMS_STORAGE_SIZE to low to be able store any pairing parameters NV memory +#endif +/** @} */ + + +/******************************************************************************/ +/** @name Typedefs + * @{ */ +/******************************************************************************/ + + +/** + * Possible return values for the function gzp_tx_rx_transaction() + */ +typedef enum +{ + GZP_TX_RX_SUCCESS, ///< ACK received. Transaction successful. + GZP_TX_RX_FAILED_TO_SEND, ///< + GZP_TX_RX_NO_RESPONSE ///< +} gzp_tx_rx_trans_result_t; +/** @} */ + + +/******************************************************************************/ +/** @name Internal variables + * @{ */ +/******************************************************************************/ + +static uint8_t gzp_system_address[GZP_SYSTEM_ADDRESS_WIDTH]; ///< +static uint8_t gzp_host_id[GZP_HOST_ID_LENGTH]; ///< +static uint8_t dyn_key[GZP_DYN_KEY_LENGTH]; +static bool gzp_id_req_pending = false; + +/** @} */ + + +/******************************************************************************/ +/** @name Internal (static) function prototypes + * @{ */ +/******************************************************************************/ + +/** + * Function for sending an encrypted packet. + * + * The function waits for the transmission to complete. + * + * @param tx_packet Pointer to the packet to be sent. + * @param length Length of the packet to be sent. + * @param pipe Pipe on which the packet should be sent. + * + * @retval true If the transmission succeeded. + * @retval false If the transmission failed (timed out). + */ +static bool gzp_tx_packet(const uint8_t* tx_packet, uint8_t length, uint8_t pipe); + +/** + * Function sending the packet *tx_packet and a subsequent packet fetching the response + * to *tx_packet. + * + * @param tx_packet is a pointer to the packet to be sent. + * @param tx_length is the length of the packet to be sent. + * @param rx_dst is a pointer to where the received response packet should be stored. + * @param rx_length is a pointer to where the length of the received packet should be stored. + * @param pipe is the pipe on which the packet should be sent. + * + * @return result of the transaction. + */ + static gzp_tx_rx_trans_result_t gzp_tx_rx_transaction(const uint8_t *tx_packet, uint8_t tx_length, uint8_t *rx_dst, uint32_t *rx_length, uint8_t pipe); + +/** + * Function for sending an encrypted packet. The function detects whether the correct + * key was used, and attempts to send a "key update" to the host if the wrong key was being + * used. + + * @param tx_packet is a pointer to the packet to be sent. + * @param length is the length of the packet to be sent. + + * @retval true if transmission succeeded and packet was decrypted correctly by host. + * @retval false if transmission failed or packet was not decrypted correctly by host. + */ +static bool gzp_crypt_tx_transaction(const uint8_t *tx_packet, uint8_t length); + +/** + * Function updateing the "dynamic key" and sending a "key update" to the host. + * + * @retval true if key update succeeded. + * @retval false if if key update failed. + */ +static bool gzp_key_update(void); + +/** + * Function for adding an element to "parameters data base" in non volatile (NV) memory. An element is + * GZP_PARAMS_ELEMENT_SYSTEM_ADDRESS bytes long, holding the "system address" and "host ID". + * + * The "parameters data base" can store up to GZP_DEVICE_PAIRING_PARAMS_DB_MAX_ENTRIES + * elements. + * + * @param src_element is a pointer to the element. + * @param index is a number between 0 and (GZP_PARAMS_DB_MAX_ENTRIES - 1) + * selecting the location in which the element will be stored. + */ +static void gzp_params_db_add(const uint8_t *src_element, uint8_t index); + +/** + * Function for reading an element from "parameters data base" in non volatile (NV) memory. An element is + * GZP_PARAMS_ELEMENT_SYSTEM_ADDRESS bytes long, holding the "system address" and "host ID". + * + * @param dst_element is a pointer where the read element should be stored. + * @param index is a number between 0 and (GZP_PARAMS_DB_MAX_ENTRIES - 1). + * selecting the location that should be read. + */ +static void gzp_params_db_read(uint8_t* dst_element, uint8_t index); + +/** + * Function for writing an index to the "index data base" in non volatile (NV) memory. + * + * @param index is the index to be written to the data base. + */ +static void gzp_index_db_add(uint8_t index); + +/** + * Function for reading the index previously written to the "index data base" in NV memory. + * + * @return + */ +static uint8_t gzp_index_db_read(void); + +/** + * Check "index data base" is full. + * + * @retval true + * @retval false + */ +static bool gzp_index_db_full(void); + +/** + * Function returning @b true if the "index data base" is empty. + * + * @retval true + * @retval false + */ +static bool gzp_index_db_empty(void); + +/** + * Function returning @b true if array contains only 1s (0xff). + * + * @param *src is a pointer to the array to be evaluated. + * @param length is the length of the array to be evaluated. + * + * @retval true + * @retval false + */ +static bool gzp_array_is_set(const uint8_t* src, uint8_t length); + +/** + * Function for storing the current "system address" and "host ID" in NV memory. + * + * @param store_all selects whether only "system address" or both "system address" and + * "host ID" should be stored. + * @arg true selects that both should be stored. + * @arg false selects that only "system address" should be stored. + * + * @retval true + * @retval false + */ +static bool gzp_params_store(bool store_all); + +/** + * Restore the "system address" and "host ID" from NV memory. + * @retval true + * @retval false + */ +static bool gzp_params_restore(void); + +/** + * Delay function. Will add a delay equal to GZLL_RX_PERIOD * rx_periods [us]. + * + * @param rx_periods + */ +void gzp_delay_rx_periods(uint32_t rx_periods); + +/** + * Delay function. Will add a delay equal to GZLL_RX_PERIOD * rx_periods [us] using the + * gazell timer and not a delay loop. + * + * @param rx_periods + */ +void gzp_tick_sleep_rx_periods(uint32_t rx_periods); + +/* + * Print debug string. By default does nothing. + * + * If GZP_DEBUG is defined then the print string function is required to + * be implemented. + */ +void print_string(char* p_expr); + +/** @} */ + +/******************************************************************************/ +/** @name Internal (static) variables + * @{ */ +/******************************************************************************/ + +static nrf_gzll_device_tx_info_t latest_tx_info; ///< Information about the last TX attempt, e.g. RSSI of ACK. + +static volatile bool tx_complete; ///< Flag to indicate whether a GZLL TX attempt has completed. +static bool tx_success; ///< Flag to indicate whether a GZLL TX attempt was successful. + +// Define Macro to make array initialization nicer +#define REP4(X) X X X X + +#if defined(__ICCARM__) + #if GZP_PARAMS_DB_ADR == 0x1000 + static const uint32_t database[GZP_DEVICE_PARAMS_STORAGE_SIZE/4] @ "gzp_dev_data" + #elif GZP_PARAMS_DB_ADR == 0x15000 + static const uint32_t database[GZP_DEVICE_PARAMS_STORAGE_SIZE/4] @ "gzp_dev_data_sd" + #else + #error + #endif +#else +static const uint32_t database[GZP_DEVICE_PARAMS_STORAGE_SIZE / 4] __attribute__((at(GZP_PARAMS_DB_ADR))) +#endif += { + #define STATIC_INIT_VALUE 0xFFFFFFFF + #define STATIC_INIT_COUNT (GZP_DEVICE_PARAMS_STORAGE_SIZE / 4) + #define INIT_1 STATIC_INIT_VALUE, + #define INIT_4 REP4(INIT_1) + #define INIT_16 REP4(INIT_4) + #define INIT_64 REP4(INIT_16) + #define INIT_256 REP4(INIT_64) + #define INIT_1024 REP4(INIT_256) + + #if (STATIC_INIT_COUNT == 256) + INIT_256 + #elif (STATIC_INIT_COUNT == 1024) + INIT_1024 + #else + #error Gazell Pairing Library database not initialized properly! + #endif +}; ///< Database for storing keys. + + +/** @} */ + + +/******************************************************************************/ +// Implementation: Device-specific API functions +/******************************************************************************/ + + +void gzp_init() +{ + gzp_id_req_pending = false; + +#ifndef GZP_NV_STORAGE_DISABLE + (void)gzp_params_restore(); +#endif + + // Update radio parameters from gzp_system_address + (void)gzp_update_radio_params(gzp_system_address); +} + + +void gzp_erase_pairing_data(void) +{ + // Erase database flash page so that it can be later written to. + nrf_nvmc_page_erase((uint32_t)database); +} + +bool gzp_address_req_send() +{ + //lint -save -e514 Unusual use of a Boolean expression (gzll_update_ok &= ...) + uint8_t i; + bool retval = false; + bool success; + uint8_t address_req[GZP_CMD_HOST_ADDRESS_REQ_PAYLOAD_LENGTH]; + uint8_t rx_payload[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; + uint32_t rx_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; + nrf_gzll_tx_power_t temp_power; + uint32_t temp_max_tx_attempts; + bool gzll_update_ok = true; + + + // Store parameters that are temporarily changed + temp_max_tx_attempts = nrf_gzll_get_max_tx_attempts(); + temp_power = nrf_gzll_get_tx_power(); + + // Modify parameters + nrf_gzp_disable_gzll(); + nrf_gzll_set_max_tx_attempts(GZP_REQ_TX_TIMEOUT); + gzll_update_ok &= nrf_gzll_set_tx_power(GZP_POWER); + + // Flush RX FIFO + gzll_update_ok &= nrf_gzll_flush_rx_fifo(GZP_PAIRING_PIPE); + gzll_update_ok &= nrf_gzll_enable(); + // Build "request" packet + address_req[0] = (uint8_t)GZP_CMD_HOST_ADDRESS_REQ; + + // Send a number of packets in order to broadcast that devices not within + // close proximity must back off. + for (i = 0; i < GZP_MAX_BACKOFF_PACKETS; i++) + { + success = gzp_tx_packet(address_req, GZP_CMD_HOST_ADDRESS_REQ_PAYLOAD_LENGTH, GZP_PAIRING_PIPE); + if (success) + { + nrf_gzp_flush_rx_fifo(GZP_PAIRING_PIPE); + } + else + { + break; + } + } + + gzp_delay_rx_periods(GZP_TX_ACK_WAIT_TIMEOUT); + // Send message for fetching pairing response from host. + address_req[0] = (uint8_t)GZP_CMD_HOST_ADDRESS_FETCH; + + success = gzp_tx_packet(address_req, GZP_CMD_HOST_ADDRESS_REQ_PAYLOAD_LENGTH, GZP_PAIRING_PIPE); + if (success && latest_tx_info.payload_received_in_ack) + { + // If pairing response received + if (nrf_gzll_get_rx_fifo_packet_count(GZP_PAIRING_PIPE) > 0) + { + rx_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; //dummy placeholder + if (nrf_gzll_fetch_packet_from_rx_fifo(GZP_PAIRING_PIPE, rx_payload, &rx_payload_length)) + { + if (rx_payload[0] == (uint8_t)GZP_CMD_HOST_ADDRESS_RESP) + { + memcpy(gzp_system_address, &rx_payload[GZP_CMD_HOST_ADDRESS_RESP_ADDRESS], GZP_SYSTEM_ADDRESS_WIDTH); + gzll_update_ok &= gzp_update_radio_params(&rx_payload[GZP_CMD_HOST_ADDRESS_RESP_ADDRESS]); + #ifndef GZP_NV_STORAGE_DISABLE + (void)gzp_params_store(false); // "False" indicates that only "system address" part of DB element will be stored + #endif + retval = true; + } + } + } + } + else + { + gzp_delay_rx_periods(GZP_NOT_PROXIMITY_BACKOFF_RX_TIMEOUT - GZP_TX_ACK_WAIT_TIMEOUT); + } + gzp_delay_rx_periods(GZP_STEP1_RX_TIMEOUT); + + // Clean-up and restore parameters temporarily modified + nrf_gzp_disable_gzll(); + gzll_update_ok &= nrf_gzll_flush_rx_fifo(GZP_PAIRING_PIPE); + gzll_update_ok &= nrf_gzll_flush_tx_fifo(GZP_PAIRING_PIPE); + nrf_gzll_set_max_tx_attempts(temp_max_tx_attempts); + gzll_update_ok &= nrf_gzll_set_tx_power(temp_power); + gzll_update_ok &= nrf_gzll_enable(); + + if (!gzll_update_ok) + { + /* + The update of the Gazell parameters failed. Use nrf_gzll_get_error_code() + to investigate the cause. + */ + } + + return retval; + //lint -restore +} + +#ifndef GZP_CRYPT_DISABLE + +gzp_id_req_res_t gzp_id_req_send() +{ + uint8_t tx_packet[GZP_CMD_HOST_ID_REQ_PAYLOAD_LENGTH]; + uint8_t rx_packet[GZP_MAX_ACK_PAYLOAD_LENGTH]; + gzp_tx_rx_trans_result_t trans_result; + + // If no ID request is pending, send new "ID request" + if (!gzp_id_req_pending) + { + // Build "Host ID request packet" + tx_packet[0] = (uint8_t)GZP_CMD_HOST_ID_REQ; + + // Generate new session token + gzp_random_numbers_generate(&tx_packet[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN], GZP_SESSION_TOKEN_LENGTH); + + // Send "Host ID request" + if (gzp_tx_packet(tx_packet, GZP_CMD_HOST_ID_REQ_PAYLOAD_LENGTH, GZP_DATA_PIPE)) + { + // Update session token if "Host ID request" was successfully transmitted + gzp_crypt_set_session_token(&tx_packet[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN]); + gzp_id_req_pending = true; + + return GZP_ID_RESP_PENDING; + } + } + else // If "ID request is pending" send "fetch ID" packet + { + // Build "host ID fetch" packet + tx_packet[0] = (uint8_t)GZP_CMD_HOST_ID_FETCH; + gzp_add_validation_id(&tx_packet[GZP_CMD_HOST_ID_FETCH_VALIDATION_ID]); + + // Encrypt "host ID fetch" packet + gzp_crypt_select_key(GZP_ID_EXCHANGE); + gzp_crypt(&tx_packet[1], &tx_packet[1], GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH - 1); + + trans_result = gzp_tx_rx_transaction(tx_packet, GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH, rx_packet, NULL, GZP_DATA_PIPE); + // If packet was successfully sent AND a response packet was received + if (trans_result == GZP_TX_RX_SUCCESS) + { + // Validate response packet + if (rx_packet[0] == (uint8_t)GZP_CMD_HOST_ID_FETCH_RESP) + { + gzp_crypt(&rx_packet[1], &rx_packet[1], GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH - 1); + if (gzp_validate_id(&rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID])) + { + switch (rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_STATUS]) + { + case GZP_ID_RESP_PENDING: + break; + case GZP_ID_RESP_REJECTED: + gzp_id_req_pending = false; + break; + case GZP_ID_RESP_GRANTED: + gzp_set_host_id(&rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID]); + gzp_random_numbers_generate(dyn_key, GZP_DYN_KEY_LENGTH); + gzp_crypt_set_dyn_key(dyn_key); + #ifndef GZP_NV_STORAGE_DISABLE + (void)gzp_params_store(true); + #endif + gzp_id_req_pending = false; + break; + default: + break; + } + + return (gzp_id_req_res_t)rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_STATUS]; + } + else + { + gzp_id_req_pending = false; + return GZP_ID_RESP_REJECTED; + } + } + } + } + + gzp_id_req_pending = false; + return GZP_ID_RESP_FAILED; +} + +void gzp_id_req_cancel() +{ + gzp_id_req_pending = false; +} + +bool gzp_crypt_data_send(const uint8_t *src, uint8_t length) +{ + if (length <= GZP_ENCRYPTED_USER_DATA_MAX_LENGTH) + { + if (gzp_crypt_tx_transaction(src, length)) + { + return true; + } + else + { + //print_string("GZP_CRYPT_TX failed\r\n"); + // Attempt key update if user data transmission failed + // during normal operation (!gzp_id_req_pending) + if (!gzp_id_req_pending) + { + //print_string("KEY UPDATE\r\n"); + if (gzp_key_update()) + { + return gzp_crypt_tx_transaction(src, length); + } + } + return false; + } + } + else + { + return false; + } +} + +#endif +/** @} */ + + +/******************************************************************************/ +// Implementation: Internal (static) functions +/******************************************************************************/ + +static bool gzp_tx_packet(const uint8_t* tx_packet, uint8_t length, uint8_t pipe) +{ + tx_complete = false; + tx_success = false; + + if (nrf_gzll_add_packet_to_tx_fifo(pipe,(uint8_t *)tx_packet, length)) + { + while (tx_complete == false) + { + __WFI(); + } + return tx_success; + } + else + { + return false; + } +} + +static gzp_tx_rx_trans_result_t gzp_tx_rx_transaction(const uint8_t *tx_packet, uint8_t tx_length, uint8_t *rx_dst, uint32_t *rx_length, uint8_t pipe) +{ + + gzp_tx_rx_trans_result_t retval; + uint8_t fetch_packet[GZP_CMD_FETCH_RESP_PAYLOAD_LENGTH]; + bool tx_packet_success; + bool fetch_success; + uint32_t local_rx_length = GZP_MAX_ACK_PAYLOAD_LENGTH; + uint32_t temp_lifetime; + + nrf_gzp_flush_rx_fifo(pipe); + + retval = GZP_TX_RX_FAILED_TO_SEND; + + (void)nrf_gzll_disable(); + while (nrf_gzll_is_enabled()) + {} + temp_lifetime = nrf_gzll_get_sync_lifetime(); + (void)nrf_gzll_set_sync_lifetime(GZP_TX_RX_TRANS_DELAY * 3); // 3 = RXPERIOD * 2 + margin + (void)nrf_gzll_enable(); + + tx_packet_success = gzp_tx_packet(tx_packet, tx_length, pipe); + + if (tx_packet_success) + { + retval = GZP_TX_RX_NO_RESPONSE; + + nrf_gzp_flush_rx_fifo(pipe); + + fetch_packet[0] = (uint8_t)GZP_CMD_FETCH_RESP; + + gzp_tick_sleep_rx_periods(GZP_TX_RX_TRANS_DELAY); + + tx_packet_success = gzp_tx_packet(fetch_packet, GZP_CMD_FETCH_RESP_PAYLOAD_LENGTH, pipe); + + if (tx_packet_success) + { + if (nrf_gzll_get_rx_fifo_packet_count(pipe)) + { + local_rx_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; + fetch_success = nrf_gzll_fetch_packet_from_rx_fifo(pipe, rx_dst, &local_rx_length); + } + else + { + fetch_success = false; + } + + if (fetch_success) + { + retval = GZP_TX_RX_SUCCESS; + } + else + { + //print_string("GZP_TX_FETCH_FAILED\r\n"); + } + } + else + { + //print_string("GZP_TX_FETCH_NO_ACK\r\n"); + } + } + + (void)nrf_gzll_disable(); + while (nrf_gzll_is_enabled()) + {} + (void)nrf_gzll_set_sync_lifetime(temp_lifetime); + (void)nrf_gzll_enable(); + + return retval; +} + +#ifndef GZP_CRYPT_DISABLE + +static bool gzp_crypt_tx_transaction(const uint8_t *src, uint8_t length) +{ + uint8_t tx_packet[GZP_MAX_FW_PAYLOAD_LENGTH]; + uint8_t rx_packet[GZP_MAX_ACK_PAYLOAD_LENGTH]; + uint8_t tx_packet_length; + + gzp_tx_rx_trans_result_t result; + + tx_packet_length = length + (uint8_t)GZP_ENCRYPTED_USER_DATA_PACKET_OVERHEAD; + + // Assemble tx packet + tx_packet[0] = (uint8_t)GZP_CMD_ENCRYPTED_USER_DATA; + gzp_add_validation_id(&tx_packet[GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID]); + memcpy(&tx_packet[GZP_CMD_ENCRYPTED_USER_DATA_PAYLOAD], (uint8_t*)src, length); + + // Encrypt tx packet + if (gzp_id_req_pending) + { + gzp_crypt_select_key(GZP_ID_EXCHANGE); + } + else + { + gzp_crypt_select_key(GZP_DATA_EXCHANGE); + } + gzp_crypt(&tx_packet[1], &tx_packet[1], tx_packet_length - 1); + + // If packet was successfully sent AND a response packet was received + result = gzp_tx_rx_transaction(tx_packet, tx_packet_length, rx_packet, NULL, GZP_DATA_PIPE); + if (result == GZP_TX_RX_SUCCESS) + { + if (rx_packet[0] == (uint8_t)GZP_CMD_ENCRYPTED_USER_DATA_RESP) + { + gzp_crypt(&rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], &rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], GZP_VALIDATION_ID_LENGTH); + + // Validate response in order to know whether packet was correctly decrypted by host + if (gzp_validate_id(&rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID])) + { + // Update session token if normal operation (!gzp_id_req_pending) + if (!gzp_id_req_pending) + { + gzp_crypt_set_session_token(&rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]); + } + return true; + } + else + { + //print_string("GZP_CRYPT_TX_TRANS: Validation ID bad\r\n"); + return false; + } + } + else + { + //print_string("GZP_CRYPT_TX_TRANS: Bad CMD. \r\n"); + return false; + } + } + else + { + //print_string("GZP_CRYPT_TX_TRANS: gzp_tx_rx_trans not SUCCESS\r\n"); + return false; + } +} + +static bool gzp_key_update(void) +{ + uint8_t tx_packet[GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH], rx_packet[GZP_MAX_ACK_PAYLOAD_LENGTH]; + + // Send "prepare packet" to get session token to be used for key update + tx_packet[0] = (uint8_t)GZP_CMD_KEY_UPDATE_PREPARE; + + // If packet was successfully sent AND a response packet was received + if (gzp_tx_rx_transaction(tx_packet, GZP_CMD_KEY_UPDATE_PREPARE_PAYLOAD_LENGTH, rx_packet, NULL, GZP_DATA_PIPE) == GZP_TX_RX_SUCCESS) + { + if (rx_packet[0] == (uint8_t)GZP_CMD_KEY_UPDATE_PREPARE_RESP) + { + gzp_crypt_set_session_token(&rx_packet[GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN]); + + // Build "key update" packet + tx_packet[0] = (uint8_t)GZP_CMD_KEY_UPDATE; + gzp_add_validation_id(&tx_packet[GZP_CMD_KEY_UPDATE_VALIDATION_ID]); + gzp_random_numbers_generate(&tx_packet[GZP_CMD_KEY_UPDATE_NEW_KEY], GZP_DYN_KEY_LENGTH); + gzp_crypt_set_dyn_key(&tx_packet[GZP_CMD_KEY_UPDATE_NEW_KEY]); + + // Encrypt "key update packet" + gzp_crypt_select_key(GZP_KEY_EXCHANGE); + gzp_crypt(&tx_packet[1], &tx_packet[1], GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH - 1); + + // Send "key update" packet + if (gzp_tx_packet(tx_packet, GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH, GZP_DATA_PIPE)) + { + return true; + } + } + } + + return false; +} + +#endif + +void gzp_set_host_id(const uint8_t * id) +{ + memcpy(gzp_host_id, id, GZP_HOST_ID_LENGTH); +} + +void gzp_get_host_id(uint8_t * dst_id) +{ + memcpy(dst_id, gzp_host_id, GZP_HOST_ID_LENGTH); +} + +static void gzp_params_db_add(const uint8_t* src_element, uint8_t index) +{ + nrf_nvmc_write_bytes((GZP_PARAMS_DB_ADR + (index * GZP_PARAMS_DB_ELEMENT_SIZE)), src_element, (uint32_t)GZP_PARAMS_DB_ELEMENT_SIZE); +} + + +static void gzp_params_db_read(uint8_t* dst_element, uint8_t index) +{ + memcpy(dst_element,(uint8_t*)(GZP_PARAMS_DB_ADR + (index * GZP_PARAMS_DB_ELEMENT_SIZE)), GZP_PARAMS_DB_ELEMENT_SIZE); +} + + +static void gzp_index_db_add(uint8_t val) +{ + int16_t i; + uint8_t temp_val; + uint32_t addr; + + // Search for unwritten loacation in index DB + for (i = 0; i < GZP_INDEX_DB_SIZE; i++) + { + temp_val = *(uint8_t*)(GZP_INDEX_DB_ADR + i); + + // Lower nibble + if (i != (GZP_INDEX_DB_SIZE - 1)) + { + if ((temp_val & 0x0f) == 0x0f) + { + temp_val = (temp_val & 0xf0) | val; + break; + } + // Upper nibble + else if ((temp_val & 0xf0) == 0xf0) + { + temp_val = (temp_val & 0x0f) | (val << 4); + break; + } + } + else + { + temp_val = (GZP_PARAMS_DB_MAX_ENTRIES << 4) | val; + break; + } + } + + // Write index DB + addr = (GZP_INDEX_DB_ADR + i); + nrf_nvmc_write_byte(addr, temp_val); +} + +static uint8_t gzp_index_db_read() +{ + uint8_t retval; + int16_t i; + + // Search for previously written location + for (i = (GZP_INDEX_DB_SIZE - 1); i >= 0; i--) + { + retval = *(uint8_t*)(GZP_INDEX_DB_ADR + i); + + if (retval != 0xff) + { + break; + } + } + + if (retval == 0xff) + { + retval = GZP_PARAMS_DB_MAX_ENTRIES; // index db empty + } + else if ((retval & 0xf0) != 0xf0) + { + retval >>= 4; + } + else + { + retval &= 0x0f; + } + + return retval; +} + +int8_t gzp_get_pairing_status(void) +{ + uint8_t db_byte; + int8_t db_index; + int16_t i; + uint8_t temp_element[GZP_PARAMS_DB_ELEMENT_SIZE]; + uint8_t default_host_id[GZP_HOST_ID_LENGTH]; + + db_index = -2; + + // Populate default Host ID with F's. + for (i=0; i< GZP_HOST_ID_LENGTH; i++) + { + default_host_id[i] = 0xFF; + } + + // Search for previously written location + for (i = (GZP_INDEX_DB_SIZE - 1); i >= 0; i--) + { + db_byte = *(uint8_t*)(GZP_INDEX_DB_ADR + i); + + // Check if idx has been written to + if (db_byte != 0xff) + { + // Convert 4-bit nibble to index + if ((db_byte & 0xf0) != 0xf0) + { + db_byte = (db_byte >> 4) & 0x0f; + } + else + { + db_byte = db_byte & 0x0f; + } + + // Retrieve database entry + gzp_params_db_read(temp_element, db_byte); + + // Check if database entry is all F's + if ( memcmp(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID], default_host_id, GZP_HOST_ID_LENGTH) != 0) + { + + db_index = db_byte; + } + else + { + db_index = -1; + } + break; + } + } + + return db_index; +} + + +static bool gzp_index_db_full() +{ +#if (GZP_INDEX_DB_SIZE != 0) + return ((*(uint8_t*)(GZP_INDEX_DB_ADR + (GZP_INDEX_DB_SIZE - 1)) != 0xff)); +#else + return true; +#endif +} + +//lint -save -e506 Constant value boolean +static bool gzp_index_db_empty() +{ +#if (GZP_INDEX_DB_SIZE != 0) + return ((GZP_INDEX_DB_SIZE == 0) || ((*(uint8_t*)(GZP_INDEX_DB_ADR)) == 0xff)); +#else + return true; +#endif +} +//lint -restore + +static bool gzp_array_is_set(const uint8_t* src, uint8_t length) +{ + uint8_t i; + + for (i = 0; i < length; i++) + { + if (*(src++) != 0xff) + { + return false; + } + } + return true; +} + +static bool gzp_params_store(bool store_all) +{ + uint8_t i; + bool write_index_db = false; + bool write_param_db = false; + uint8_t new_db_index = 0; + uint8_t temp_element[GZP_PARAMS_DB_ELEMENT_SIZE]; + + // Search param DB to see if current setup exists + if (store_all) + { + // Search for: Current system address and host ID exists + for (i = 0; i < GZP_PARAMS_DB_MAX_ENTRIES; i++) + { + gzp_params_db_read(temp_element, i); + + if (((memcmp(&temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], gzp_system_address, GZP_SYSTEM_ADDRESS_WIDTH)) == 0) && ((memcmp(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID], gzp_host_id, GZP_HOST_ID_LENGTH)) == 0)) + { + write_index_db = true; + new_db_index = i; + break; // System address + host_id allready exists in database + } + } + + // Search for: Current system address and cleared host ID + if (!write_index_db) + { + for (i = 0; i < GZP_PARAMS_DB_MAX_ENTRIES; i++) + { + gzp_params_db_read(temp_element, i); + + if (((memcmp(&temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], gzp_system_address, GZP_SYSTEM_ADDRESS_WIDTH)) == 0) && \ + (gzp_array_is_set(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID], GZP_HOST_ID_LENGTH))) + { + memcpy(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID], gzp_host_id, GZP_HOST_ID_LENGTH); + new_db_index = i; + write_index_db = true; + write_param_db = true; + break; + } + } + } + + // Search for: Cleared system address and cleared host ID + if (!write_index_db) + { + for (i = 0; i < GZP_PARAMS_DB_MAX_ENTRIES; i++) + { + gzp_params_db_read(temp_element, i); + + if (gzp_array_is_set(temp_element, GZP_PARAMS_DB_ELEMENT_SIZE)) + { + memcpy(&temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], gzp_system_address, GZP_SYSTEM_ADDRESS_WIDTH); + memcpy(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID], gzp_host_id, GZP_HOST_ID_LENGTH); + new_db_index = i; + write_index_db = true; + write_param_db = true; + break; + } + } + } + } + else + { + // Search for: System address + any host ID + for (i = 0; i < GZP_PARAMS_DB_MAX_ENTRIES; i++) + { + gzp_params_db_read(temp_element, i); + + if ((memcmp(&temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], gzp_system_address, GZP_SYSTEM_ADDRESS_WIDTH)) == 0) + { + //memcpy(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID], gzp_host_id, GZP_HOST_ID_LENGTH); + write_index_db = true; + new_db_index = i; + break; + } + } + + // Search for: System address cleared + if (!write_index_db) + { + for (i = 0; i < GZP_PARAMS_DB_MAX_ENTRIES; i++) + { + gzp_params_db_read(temp_element, i); + + if (gzp_array_is_set(&temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], GZP_SYSTEM_ADDRESS_WIDTH)) + { + memcpy(&temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], gzp_system_address, GZP_SYSTEM_ADDRESS_WIDTH); + write_index_db = true; + write_param_db = true; + new_db_index = i; + break; + } + } + } + } + + if (write_param_db) + { + gzp_params_db_add(temp_element, new_db_index); + } + + if (write_index_db) + { + if (!gzp_index_db_full() && (new_db_index != gzp_index_db_read()) && (new_db_index != GZP_PARAMS_DB_MAX_ENTRIES)) + { + gzp_index_db_add(new_db_index); + return true; + } + } + + return false; +} + +static bool gzp_params_restore(void) +{ + uint8_t i; + uint8_t temp_element[GZP_PARAMS_DB_ELEMENT_SIZE]; + + if (!gzp_index_db_full() && !gzp_index_db_empty()) + { + i = gzp_index_db_read(); + + if (i < GZP_PARAMS_DB_MAX_ENTRIES) + { + gzp_params_db_read(temp_element, i); + memcpy(gzp_system_address, &temp_element[GZP_PARAMS_DB_ELEMENT_SYSTEM_ADDRESS], GZP_SYSTEM_ADDRESS_WIDTH); + gzp_set_host_id(&temp_element[GZP_PARAMS_DB_ELEMENT_HOST_ID]); + return true; + } + } + + return false; +} + +void gzp_delay_rx_periods(uint32_t rx_periods) +{ + nrf_delay_us(rx_periods * 2 * nrf_gzll_get_timeslot_period()); +} + +void gzp_tick_sleep_rx_periods(uint32_t rx_periods) +{ + nrf_gzll_clear_tick_count(); + + while (nrf_gzll_get_tick_count() < 2 * rx_periods) + { + __WFI(); + } +} + + +void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) +{ + latest_tx_info = tx_info; + + tx_complete = true; + tx_success = true; +} + +void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) +{ + latest_tx_info = tx_info; + + tx_complete = true; + tx_success = false; +} + +bool nrf_gzp_tx_complete(void) +{ + return tx_complete; +} + +bool nrf_gzp_tx_success(void) +{ + return tx_success; +} + +void nrf_gzp_reset_tx_complete() +{ + tx_complete = false; +} + +void nrf_gzp_reset_tx_success() +{ + tx_success = false; +} + +void nrf_gzll_disabled(void) +{ +} + +void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info) +{ +} + +/** @} */ +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_host.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_host.c new file mode 100644 index 0000000..6e331a9 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_host.c @@ -0,0 +1,821 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @file + * @brief Implementation of Gazell Pairing Library (gzp), Host functions. + * @defgroup gzp_source_host Gazell Pairing Host implementation + * @{ + * @ingroup gzp_04_source + */ + + +#include "nrf_gzp.h" +#include "nrf_gzll.h" +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include "nrf_assert.h" +#include "nrf_ecb.h" +#include "nrf_nvmc.h" + + +//lint -esym(40, GZP_PARAMS_STORAGE_ADR) "Undeclared identifier" +#define GZP_PARAMS_DB_ADR GZP_PARAMS_STORAGE_ADR // Address of the GZP parameters flash page. + + +/******************************************************************************/ +/** @name Typedefs + * @{ */ +/******************************************************************************/ + +/** + * Definition of internal states. + */ +typedef enum +{ + GZP_ID_REQ_IDLE, ///< No Host ID request received from Device. + GZP_ID_REQ_PENDING, ///< Host ID request received and waiting on application to grant/reject. + GZP_ID_REQ_PENDING_AND_GRANTED, ///< Host ID request received and granted by application. + GZP_ID_REQ_PENDING_AND_REJECTED, ///< Host ID request received and rejected by application. +} gzp_id_req_stat_t; + +/** @} */ + + +/******************************************************************************/ +/** @name Internal (static) function prototypes + * @{ */ +/******************************************************************************/ + + +/** + * Function for incrementing internal session counter. + */ +static void gzp_session_counter_inc(void); + + +/** + * Function for reading value of internal session counter. + * @param dst Current session counter. + */ +static void gzp_get_session_counter(uint8_t* dst); + + +/** + * Function processing received "system address request" from Device. + * + * @param gzp_req Pointer to RX payload containing system address request. + */ +static void gzp_process_address_req(uint8_t* gzp_req); + + +/** + * Function to process Host ID request from device. + * + * The Host shall retrieve the Host ID from NVM, or shall generate if + * it does not yet exist. + * + * @param rx_payload Pointer to rx_payload contaning Host ID request. + */ +static void gzp_process_id_req(uint8_t* rx_payload); + +/** + * Function to process Host ID fetch request from Device. + * + * The Device fetches the Host ID after the Host has generated/retrieved + * the Host ID. + * + * @param rx_payload Pointer to rx_payload contaning Host ID fetch request. + */ +static void gzp_process_id_fetch(uint8_t* rx_payload); + + +/** + * Function to process Key Update Prepare packet. + * + * Device requests the Session Token to be used for the Key Update request. + */ +static void gzp_process_key_update_prepare(void); + + +/** + * Function to process Key Update packet. + * + * Device requests a Key Update and sends a new Dynamic Key. The Dynamic Key is + * updated on the Host. + * + * @param rx_payload Pointer to rx_payload containing Key Update request. + */ +static void gzp_process_key_update(uint8_t* rx_payload); + + +/** + * Function to process received Encrypted User packet. + * + * @param rx_payload Pointer to rx_payload containing the encrypted user data. + * @param length Length of encrypted user data. + */ +static void gzp_process_encrypted_user_data(uint8_t* rx_payload, uint8_t length); + + +/** + * Function to preload the payload for the next ACK. + * + * @param src Pointer to source payload. + * @param length Length of source payload. + * @param pipe Pipe for the ACK payload. + */ +static void gzp_preload_ack(uint8_t* src, uint8_t length, uint8_t pipe); + + +/** + * Function for reading the Chip ID from non-volatile memory. + * + * The chip ID is used for the system address. + * + * If the Chip ID is not yet created a random Chip ID is created and + * written to non-volatile memory. Note that the term chip ID is used as + * the factory programmed chip sequence number was used for the system + * address in nRF24LU ICs. + * + * @param dst Address to copy Host ID to. + * @param[in] n Number of bytes in the Host ID. + */ +void gzp_host_chip_id_read(uint8_t *dst, uint8_t n); + + +/** + * Function to set the Host ID. + * + * Writes the Host ID to non-volatile memory. + * @param src Address of the Host ID to copy from. + */ +static void gzp_set_host_id(const uint8_t* src); + + +/** + * Function to request disabling of Gazell and wait for it to be disabled. + * + * Emulates legacy gzll_goto_idle(). + */ +static void gzll_goto_idle(void); + + +/** + * Flush all TX FIFOs. + * + * Emulates legacy gzll_tx_fifo_flush(). + */ +static void gzll_tx_fifo_flush(void); + + +/** + * Flush all RX FIFOs. + * + * Emulates legacy gzll_rx_fifo_flush(). + */ +static void gzll_rx_fifo_flush(void); + + +/** + * Set a timeout for the reception of packets on the Gazell Host. + * + * Emulates legacy Gazell function: gzll_set_param(GZLL_PARAM_RX_TIMEOUT, x). + * + * @param timeout Timeout in number of legacy "RX periods" + * (1 RX period = 2 timeslot periods). + */ +static void gzll_set_rx_timeout(uint32_t timeout); + +/** @} */ + + +/******************************************************************************/ +/** @name Internal (static) variabls + * @{ */ +/******************************************************************************/ + +static gzp_id_req_stat_t gzp_id_req_stat; ///< Current state of Host ID request. +static bool gzp_pairing_enabled_f; ///< True if Host is paired with a device. +static bool gzp_address_exchanged_f; ///< True if Host has exchanged a system address with a device and thus pairing has begun. + +static uint8_t gzp_session_counter[GZP_SESSION_TOKEN_LENGTH]; ///< Session counter used for key generation and update. + +static bool gzp_encrypted_user_data[GZP_ENCRYPTED_USER_DATA_MAX_LENGTH]; ///< Placeholder for encrypted data from Device. +static uint8_t gzp_encrypted_user_data_length; ///< Length of gzp_encrypted_user_data. Zero implies no data received. + +static nrf_gzll_host_rx_info_t prev_gzp_rx_info = {0, 0}; ///< RSSI and status of ACK payload transmission of previous Gazell packet. + +// Define Macro to make array initialization nicer +#define REP4(X) X X X X + +#if defined(__ICCARM__) + #if GZP_PARAMS_DB_ADR == 0x1000 + static const uint32_t database[GZP_DEVICE_PARAMS_STORAGE_SIZE/4] @ "gzp_dev_data" + #elif GZP_PARAMS_DB_ADR == 0x15000 + static const uint32_t database[GZP_DEVICE_PARAMS_STORAGE_SIZE/4] @ "gzp_dev_data_sd" + #else + #error + #endif +#else +static const uint32_t database[GZP_DEVICE_PARAMS_STORAGE_SIZE / 4] __attribute__((at(GZP_PARAMS_DB_ADR))) +#endif += { + #define STATIC_INIT_VALUE 0xFFFFFFFF + #define STATIC_INIT_COUNT (GZP_DEVICE_PARAMS_STORAGE_SIZE / 4) + #define INIT_1 STATIC_INIT_VALUE, + #define INIT_4 REP4(INIT_1) + #define INIT_16 REP4(INIT_4) + #define INIT_64 REP4(INIT_16) + #define INIT_256 REP4(INIT_64) + #define INIT_1024 REP4(INIT_256) + + #if (STATIC_INIT_COUNT == 256) + INIT_256 + #elif (STATIC_INIT_COUNT == 1024) + INIT_1024 + #else + #error Gazell Pairing Library database not initialized properly! + #endif +}; ///< Database for storing keys. + +/** @} */ + + +/******************************************************************************/ +// Implementation: Host-specific API functions +/******************************************************************************/ + +void gzp_init() +{ + uint8_t system_address[GZP_SYSTEM_ADDRESS_WIDTH]; + + // Read "chip id", of which 4 bytes (GZP_SYSTEM_ADDRESS_WIDTH) + // are used as system address + gzp_host_chip_id_read(system_address, GZP_SYSTEM_ADDRESS_WIDTH); + + // Set up radio parameters (addresses and channel subset) from system_address + (void)gzp_update_radio_params(system_address); + + // Only "data pipe" enabled by default + + (void)nrf_gzll_set_rx_pipes_enabled(nrf_gzll_get_rx_pipes_enabled() | (1 << GZP_DATA_PIPE)); + + gzp_pairing_enabled_f = false; + gzp_address_exchanged_f = false; + gzp_id_req_stat = GZP_ID_REQ_IDLE; + gzp_encrypted_user_data_length = 0; + + // Infinite RX timeout + gzll_set_rx_timeout(0); +} + +void gzp_pairing_enable(bool enable) +{ + if (gzp_pairing_enabled_f != enable) + { + gzll_goto_idle(); + + if (enable) + { + (void)nrf_gzll_set_rx_pipes_enabled(nrf_gzll_get_rx_pipes_enabled() | (1 << GZP_PAIRING_PIPE)); + } + else + { + (void)nrf_gzll_set_rx_pipes_enabled(nrf_gzll_get_rx_pipes_enabled() & ~(1 << GZP_PAIRING_PIPE)); + + gzp_id_req_stat = GZP_ID_REQ_IDLE; + } + + gzp_pairing_enabled_f = enable; + + gzll_rx_start(); + } +} + +void gzp_host_execute() +{ + bool gzp_packet_received = false; + uint32_t payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; + uint8_t rx_payload[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; + + gzp_address_exchanged_f = false; + + if (nrf_gzll_get_rx_fifo_packet_count(GZP_PAIRING_PIPE) > 0) + { + gzp_packet_received = nrf_gzll_fetch_packet_from_rx_fifo(GZP_PAIRING_PIPE, rx_payload, &payload_length); + } + + if (!gzp_packet_received && (gzp_encrypted_user_data_length == 0)) + { + if (nrf_gzll_get_rx_fifo_packet_count(GZP_DATA_PIPE) > 0) + { + gzp_packet_received = nrf_gzll_fetch_packet_from_rx_fifo(GZP_DATA_PIPE, rx_payload, &payload_length); + } + } + + if (gzp_packet_received) + { + //lint -save -esym(644,rx_payload) //may not have been initialized + switch (rx_payload[0]) + { + case GZP_CMD_HOST_ADDRESS_REQ: + gzp_process_address_req(rx_payload); + break; + + #ifndef GZP_CRYPT_DISABLE + + case GZP_CMD_HOST_ID_REQ: + gzp_process_id_req(rx_payload); + break; + case GZP_CMD_HOST_ID_FETCH: + gzp_process_id_fetch(rx_payload); + break; + case GZP_CMD_KEY_UPDATE_PREPARE: + gzp_process_key_update_prepare(); + break; + case GZP_CMD_KEY_UPDATE: + gzp_process_key_update(rx_payload); + break; + case GZP_CMD_ENCRYPTED_USER_DATA: + gzp_process_encrypted_user_data(rx_payload, payload_length); + break; + + #endif + + case GZP_CMD_FETCH_RESP: + default: + break; + } + } + + // Restart reception if "not proximity backoff" period has elapsed + if (!nrf_gzll_is_enabled()) + { + gzll_set_rx_timeout(0); + + if (gzp_pairing_enabled_f) + { + (void)nrf_gzll_set_rx_pipes_enabled(nrf_gzll_get_rx_pipes_enabled() | (1 << GZP_PAIRING_PIPE)); + } + + gzll_rx_start(); + } + + #ifndef GZP_CRYPT_DISABLE + gzp_session_counter_inc(); + #endif +} + +void gzll_rx_start(void) +{ + if (nrf_gzll_get_mode() != NRF_GZLL_MODE_HOST) + { + gzll_goto_idle(); + (void)nrf_gzll_set_mode(NRF_GZLL_MODE_HOST); + } + + if (!nrf_gzll_is_enabled()) + { + (void)nrf_gzll_enable(); + } +} + +bool gzp_id_req_received() +{ + return (gzp_id_req_stat != GZP_ID_REQ_IDLE); +} + +void gzp_id_req_reject() +{ + if (gzp_id_req_received()) + { + gzp_id_req_stat = GZP_ID_REQ_PENDING_AND_REJECTED; + } +} + +void gzp_id_req_grant() +{ + if (gzp_id_req_received()) + { + gzp_id_req_stat = GZP_ID_REQ_PENDING_AND_GRANTED; + } +} + +void gzp_id_req_cancel() +{ + if (gzp_id_req_received()) + { + gzp_id_req_stat = GZP_ID_REQ_IDLE; + } +} + +//----------------------------------------------------------------------------- +// Implementation: Static functions +//----------------------------------------------------------------------------- + +static void gzp_process_address_req(uint8_t* gzp_req) +{ + uint8_t temp_rx_pipes; + uint8_t pairing_resp[GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH]; + uint32_t rx_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; + + gzp_address_exchanged_f = false; + + gzll_goto_idle(); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + + temp_rx_pipes = nrf_gzll_get_rx_pipes_enabled(); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + + // If requesting Device within close proximity + if (prev_gzp_rx_info.rssi >= GZP_HOST_RX_POWER_THRESHOLD) + { + (void)nrf_gzll_set_rx_pipes_enabled(0); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + + gzll_set_rx_timeout(GZP_CLOSE_PROXIMITY_BACKOFF_RX_TIMEOUT); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + + gzll_rx_fifo_flush(); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + + // Start "proximity" back off period + gzll_rx_start(); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + + while (nrf_gzll_is_enabled()) + {} + + // Build pairing response packet + pairing_resp[0] = (uint8_t)GZP_CMD_HOST_ADDRESS_RESP; + gzp_host_chip_id_read(&pairing_resp[GZP_CMD_HOST_ADDRESS_RESP_ADDRESS], GZP_SYSTEM_ADDRESS_WIDTH); + + (void)nrf_gzll_add_packet_to_tx_fifo(0, &pairing_resp[0], GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + gzll_set_rx_timeout(GZP_STEP1_RX_TIMEOUT); + + // Enable only pairing pipe when waiting for pairing request step 1 + (void)nrf_gzll_set_rx_pipes_enabled((1 << GZP_PAIRING_PIPE)); + + gzll_rx_start(); + + while (nrf_gzll_is_enabled()) + { + if (nrf_gzll_get_rx_fifo_packet_count(GZP_PAIRING_PIPE)) + { + (void)nrf_gzll_fetch_packet_from_rx_fifo(GZP_PAIRING_PIPE, &gzp_req[0], &rx_payload_length); + + // Validate step 1 of pairing request + if (gzp_req[0] == (uint8_t)GZP_CMD_HOST_ADDRESS_FETCH) + { + gzp_address_exchanged_f = true; + } + } + } + + gzll_tx_fifo_flush(); + gzll_rx_fifo_flush(); + + gzll_set_rx_timeout(0); + + (void)nrf_gzll_set_rx_pipes_enabled(temp_rx_pipes); + + // Return to normal operation + gzll_rx_start(); + } + else + { + (void)nrf_gzll_set_rx_pipes_enabled(temp_rx_pipes & ~(1 << GZP_PAIRING_PIPE)); + + gzll_set_rx_timeout(GZP_NOT_PROXIMITY_BACKOFF_RX_TIMEOUT); + + // Start "not proximity" backoff period + gzll_rx_start(); + } +} + +static void gzp_preload_ack(uint8_t* src, uint8_t length, uint8_t pipe) +{ + gzll_goto_idle(); + + gzll_tx_fifo_flush(); + + (void)nrf_gzll_add_packet_to_tx_fifo(pipe, src, length); + + gzll_rx_start(); +} + +static void gzll_set_rx_timeout(uint32_t timeout) +{ + timeout *= 2; // * 2 as gzll_set_rx_timeout() takes RX_PERIODS as input, which equals 2 timeslots. + nrf_gzll_set_auto_disable(timeout); +} + +bool gzp_address_exchanged() +{ + return gzp_address_exchanged_f; +} + +#ifndef GZP_CRYPT_DISABLE + +bool gzp_crypt_user_data_received() +{ + return (gzp_encrypted_user_data_length > 0); +} + +bool gzp_crypt_user_data_read(uint8_t* dst, uint8_t* length) +{ + if (gzp_encrypted_user_data_length > 0) + { + memcpy(dst, (void*)gzp_encrypted_user_data, gzp_encrypted_user_data_length); + + if (length != NULL) + { + *length = gzp_encrypted_user_data_length; + } + gzp_encrypted_user_data_length = 0; + + return true; + } + else + { + return false; + } +} + +static void gzp_session_counter_inc() +{ + uint8_t i; + + for (i = 0; i < GZP_SESSION_TOKEN_LENGTH; i++) + { + gzp_session_counter[i]++; + if (gzp_session_counter[i] != 0) + { + break; + } + } +} + +static void gzp_get_session_counter(uint8_t* dst) +{ + memcpy(dst, (void*)gzp_session_counter, GZP_SESSION_TOKEN_LENGTH); +} + +static void gzp_set_host_id(const uint8_t* src) +{ + if (*((uint8_t*)database) == 0xff) + { + nrf_nvmc_write_bytes(GZP_PARAMS_STORAGE_ADR + 1, src, GZP_HOST_ID_LENGTH); + nrf_nvmc_write_byte(GZP_PARAMS_STORAGE_ADR, 0x00); + } +} + +void gzp_get_host_id(uint8_t *dst) +{ + memcpy(dst, (uint8_t*)GZP_PARAMS_STORAGE_ADR + 1, GZP_HOST_ID_LENGTH); +} + +static void gzp_process_id_req(uint8_t* rx_payload) +{ + int i; + uint8_t temp_host_id[GZP_HOST_ID_LENGTH]; + + if (gzp_pairing_enabled_f) + { + if (!gzp_id_req_received()) + { + gzp_crypt_set_session_token(&rx_payload[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN]); + gzp_id_req_stat = GZP_ID_REQ_PENDING; + } + + gzp_get_host_id(temp_host_id); + + // Added: + for (i = 0; i < GZP_HOST_ID_LENGTH; i++) + { + if (temp_host_id[i] != 0xFF) + { + break; + } + } + + if (i == GZP_HOST_ID_LENGTH) // If host not generated yet + { + gzp_get_session_counter(temp_host_id); + +#if (GZP_HOST_ID_LENGTH > GZP_SESSION_TOKEN_LENGTH) + gzp_xor_cipher(temp_host_id, temp_host_id, &rx_payload[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN], GZP_SESSION_TOKEN_LENGTH); +#else //(GZP_HOST_ID_LENGTH > GZP_SESSION_TOKEN_LENGTH) + gzp_xor_cipher(temp_host_id, temp_host_id, &rx_payload[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN], GZP_HOST_ID_LENGTH); +#endif //(GZP_HOST_ID_LENGTH > GZP_SESSION_TOKEN_LENGTH) + + gzp_set_host_id(temp_host_id); + } + } +} + +static void gzp_process_id_fetch(uint8_t* rx_payload) +{ + uint8_t tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH]; + + if (gzp_id_req_received()) + { + gzp_crypt_select_key(GZP_ID_EXCHANGE); + gzp_crypt(&rx_payload[1], &rx_payload[1], GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH - 1); + if (gzp_validate_id(&rx_payload[GZP_CMD_HOST_ID_FETCH_VALIDATION_ID])) + { + switch (gzp_id_req_stat) + { + case GZP_ID_REQ_PENDING_AND_GRANTED: + tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = (uint8_t)GZP_ID_RESP_GRANTED; + gzp_get_host_id(&tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID]); + gzp_id_req_stat = GZP_ID_REQ_IDLE; + break; + case GZP_ID_REQ_PENDING_AND_REJECTED: + tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = (uint8_t)GZP_ID_RESP_REJECTED; + gzp_id_req_stat = GZP_ID_REQ_IDLE; + break; + case GZP_ID_REQ_PENDING: + default: + tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = (uint8_t)GZP_ID_RESP_PENDING; + break; + } + + tx_payload[0] = (uint8_t)GZP_CMD_HOST_ID_FETCH_RESP; + gzp_add_validation_id(&tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID]); + gzp_crypt(&tx_payload[1], &tx_payload[1], GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH - 1); + + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + gzp_preload_ack(tx_payload, GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + } + } +} + +static void gzp_process_key_update_prepare() +{ + uint8_t tx_payload[GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH]; + + tx_payload[0] = (uint8_t)GZP_CMD_KEY_UPDATE_PREPARE_RESP; + + gzp_get_session_counter(&tx_payload[GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN]); + + // Update session token if no ID request is pending + if (!gzp_id_req_received()) + { + gzp_crypt_set_session_token(&tx_payload[GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN]); + } + + gzp_preload_ack(tx_payload, GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); +} + +static void gzp_process_key_update(uint8_t* rx_payload) +{ + gzp_crypt_select_key(GZP_KEY_EXCHANGE); + gzp_crypt(&rx_payload[1], &rx_payload[1], GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH - 1); + if (gzp_validate_id(&rx_payload[GZP_CMD_KEY_UPDATE_VALIDATION_ID])) + { + gzp_crypt_set_dyn_key(&rx_payload[GZP_CMD_KEY_UPDATE_NEW_KEY]); + } +} + +static void gzp_process_encrypted_user_data(uint8_t* rx_payload, uint8_t length) +{ + uint8_t tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH]; + + if (gzp_id_req_received()) + { + gzp_crypt_select_key(GZP_ID_EXCHANGE); + } + else + { + gzp_crypt_select_key(GZP_DATA_EXCHANGE); + } + + gzp_crypt(&rx_payload[1], &rx_payload[1], length - 1); + if (gzp_validate_id(&rx_payload[GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID])) + { + gzp_encrypted_user_data_length = length - GZP_ENCRYPTED_USER_DATA_PACKET_OVERHEAD; + memcpy((void*)gzp_encrypted_user_data, &rx_payload[GZP_CMD_ENCRYPTED_USER_DATA_PAYLOAD], gzp_encrypted_user_data_length); + } + + // Build response packet + tx_payload[0] = (uint8_t)GZP_CMD_ENCRYPTED_USER_DATA_RESP; + gzp_add_validation_id(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID]); + gzp_crypt(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], &tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], GZP_VALIDATION_ID_LENGTH); + gzp_get_session_counter(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]); + + // Update "session token" only if no ID request is pending + if (!gzp_id_req_received()) + { + gzp_crypt_set_session_token(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]); + } + + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); + gzp_preload_ack(tx_payload, GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE); + ASSERT(nrf_gzll_get_error_code() == NRF_GZLL_ERROR_CODE_NO_ERROR); +} + +//----------------------------------------------------------------------------- +// Function added during LE1 -> nRF51 port +//----------------------------------------------------------------------------- + +static void gzll_goto_idle() +{ + nrf_gzll_disable(); + while (nrf_gzll_is_enabled()) + {} +} + +static void gzll_tx_fifo_flush(void) +{ + int i; + + for (i = 0; i < NRF_GZLL_CONST_PIPE_COUNT; i++) + { + (void)nrf_gzll_flush_tx_fifo(i); + } +} + +static void gzll_rx_fifo_flush(void) +{ + int i; + + for (i = 0; i < NRF_GZLL_CONST_PIPE_COUNT; i++) + { + (void)nrf_gzll_flush_rx_fifo(i); + } +} + + +/******************************************************************************/ +// Implementation: Gazell callback functions +/******************************************************************************/ + +void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) +{ +} + + +void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) +{ +} + + +void nrf_gzll_disabled(void) +{ +} + + +void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info) +{ + if (pipe == GZP_PAIRING_PIPE) + { + prev_gzp_rx_info = rx_info; + } +} + +/** @} */ +/** @} */ + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_host_nrf5x.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_host_nrf5x.c new file mode 100644 index 0000000..b78c34c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/proprietary_rf/gzll/nrf_gzp_host_nrf5x.c @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "nrf_gzp.h" +#include "nrf_nvmc.h" + +/** + * @file + * @brief Implementation of Gazell Pairing Library (gzp), nRF5x specific Host functions. + * @defgroup gzp_source_host_nrf5x Gazell Pairing Host nRF5x specific implementation + * @{ + * @ingroup gzp_04_source + */ + + +void gzp_host_chip_id_read(uint8_t *dst, uint8_t n) +{ + uint8_t i; + uint8_t random_number; + + if ( *((uint8_t*)(GZP_PARAMS_STORAGE_ADR + GZP_HOST_ID_LENGTH + 1)) == 0xff) + { + nrf_nvmc_write_byte((GZP_PARAMS_STORAGE_ADR + GZP_HOST_ID_LENGTH + 1) , 0x00); + + for (i = 0; i < n; i++) + { + gzp_random_numbers_generate(&random_number, 1); + nrf_nvmc_write_byte((GZP_PARAMS_STORAGE_ADR + GZP_HOST_ID_LENGTH + 2 + i) , random_number); + } + } + + for (i = 0; i < n; i++) + { + *(dst++) = *((uint8_t*)(GZP_PARAMS_STORAGE_ADR + GZP_HOST_ID_LENGTH + 2 + i)); + } +} + +/** @} */ |