
trying to get micro-esb working with nrf51822
Revision 0:a01a54c0dc90, committed 2015-03-23
- Comitter:
- joshuajnoble
- Date:
- Mon Mar 23 04:09:41 2015 +0000
- Commit message:
- trying esb
Changed in this revision
diff -r 000000000000 -r a01a54c0dc90 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Mar 23 04:09:41 2015 +0000 @@ -0,0 +1,89 @@ +#include "mbed.h" + +DigitalOut myled(LED1); + +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +//#include "nrf.h" +#include "micro_esb.h" +#include "uesb_error_codes.h" +#include "nrf_delay.h" +//#include "nrf_gpio.h" + +static uesb_payload_t tx_payload, rx_payload; + +void uesb_event_handler() +{ + static uint32_t rf_interrupts; + static uint32_t tx_attempts; + + uesb_get_clear_interrupts(&rf_interrupts); + + if(rf_interrupts & UESB_INT_TX_SUCCESS_MSK) + { + } + + if(rf_interrupts & UESB_INT_TX_FAILED_MSK) + { + uesb_flush_tx(); + } + + if(rf_interrupts & UESB_INT_RX_DR_MSK) + { + uesb_read_rx_payload(&rx_payload); + NRF_GPIO->OUTCLR = 0xFUL << 8; + NRF_GPIO->OUTSET = (uint32_t)((rx_payload.data[2] & 0x0F) << 8); + } + + uesb_get_tx_attempts(&tx_attempts); + NRF_GPIO->OUTCLR = 0xFUL << 12; + NRF_GPIO->OUTSET = (tx_attempts & 0x0F) << 12; +} + +int main(void) +{ + uint8_t rx_addr_p0[] = {0x12, 0x34, 0x56, 0x78, 0x9A}; + uint8_t rx_addr_p1[] = {0xBC, 0xDE, 0xF0, 0x12, 0x23}; + uint8_t rx_addr_p2 = 0x66; + + //nrf_gpio_range_cfg_output(8, 15); + + NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; + NRF_CLOCK->TASKS_HFCLKSTART = 1; + while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); + + uesb_config_t uesb_config = UESB_DEFAULT_CONFIG; + uesb_config.rf_channel = 5; + uesb_config.crc = UESB_CRC_16BIT; + uesb_config.retransmit_count = 6; + uesb_config.retransmit_delay = 500; + uesb_config.dynamic_ack_enabled = 0; + uesb_config.protocol = UESB_PROTOCOL_ESB_DPL; + uesb_config.bitrate = UESB_BITRATE_2MBPS; + uesb_config.event_handler = uesb_event_handler; + + uesb_init(&uesb_config); + + uesb_set_address(UESB_ADDRESS_PIPE0, rx_addr_p0); + uesb_set_address(UESB_ADDRESS_PIPE1, rx_addr_p1); + uesb_set_address(UESB_ADDRESS_PIPE2, &rx_addr_p2); + + tx_payload.length = 8; + tx_payload.pipe = 0; + tx_payload.data[0] = 0x01; + tx_payload.data[1] = 0x00; + tx_payload.data[2] = 0x00; + tx_payload.data[3] = 0x00; + tx_payload.data[4] = 0x11; + + while (true) + { + if(uesb_write_tx_payload(&tx_payload) == UESB_SUCCESS) + { + tx_payload.data[1]++; + } + nrf_delay_us(10000); + } +} +
diff -r 000000000000 -r a01a54c0dc90 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Mar 23 04:09:41 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/487b796308b0 \ No newline at end of file
diff -r 000000000000 -r a01a54c0dc90 micro_esb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/micro_esb.c Mon Mar 23 04:09:41 2015 +0000 @@ -0,0 +1,871 @@ +/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#include "micro_esb.h" +#include "uesb_error_codes.h" +//#include "nrf_gpio.h" +#include <string.h> + + +static uesb_event_handler_t m_event_handler; + +// RF parameters +static uesb_config_t m_config_local; + +// TX FIFO +static uesb_payload_t m_tx_fifo_payload[UESB_CORE_TX_FIFO_SIZE]; +static uesb_payload_tx_fifo_t m_tx_fifo; + +// RX FIFO +static uesb_payload_t m_rx_fifo_payload[UESB_CORE_RX_FIFO_SIZE]; +static uesb_payload_rx_fifo_t m_rx_fifo; + +static uint8_t m_tx_payload_buffer[UESB_CORE_MAX_PAYLOAD_LENGTH + 2]; +static uint8_t m_rx_payload_buffer[UESB_CORE_MAX_PAYLOAD_LENGTH + 2]; + +// Run time variables +static volatile uint32_t m_interrupt_flags = 0; +static uint32_t m_pid = 0; +static volatile uint32_t m_retransmits_remaining; +static volatile uint32_t m_last_tx_attempts; +static volatile uint8_t m_last_rx_packet_pid = 0xFF; +static volatile uint32_t m_last_rx_packet_crc = 0xFFFFFFFF; +static volatile uint32_t m_wait_for_ack_timeout_us; + +static uesb_payload_t *current_payload; + +static uesb_mainstate_t m_uesb_mainstate = UESB_STATE_UNINITIALIZED; + +// Constant parameters +#define RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS 48 // Smallest reliable value - 43 +#define RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS 64 // Smallest reliable value - 59 +#define RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS 250 + +// Macros +#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 ) + +// 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_esb_dpl_tx_noack(void); +static void on_radio_disabled_esb_dpl_tx(void); +static void on_radio_disabled_esb_dpl_tx_wait_for_ack(void); +static void on_radio_disabled_esb_dpl_rx(void); +static void on_radio_disabled_esb_dpl_rx_ack(void); + +static void on_radio_end_sb_tx(void); +static void on_radio_end_sb_rx(void); + +static void update_rf_payload_format_esb_dpl(uint32_t payload_length) +{ +#if(UESB_CORE_MAX_PAYLOAD_LENGTH <= 32) + NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (6 << RADIO_PCNF0_LFLEN_Pos) | (3 << RADIO_PCNF0_S1LEN_Pos); +#else + 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_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | + (0 << RADIO_PCNF1_STATLEN_Pos) | + (UESB_CORE_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_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | + (payload_length << RADIO_PCNF1_STATLEN_Pos) | + (payload_length << RADIO_PCNF1_MAXLEN_Pos); +} + +static void update_rf_payload_format_sb(uint32_t payload_length) +{ + NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (0 << RADIO_PCNF0_LFLEN_Pos) | (0 << RADIO_PCNF0_S1LEN_Pos); + NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | + (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | + ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | + (payload_length << RADIO_PCNF1_STATLEN_Pos) | + (payload_length << RADIO_PCNF1_MAXLEN_Pos); +} + +// Function that swaps the bits within each byte in a uint32. Used to convert from nRF24L type addressing to nRF51 type addressing +static uint32_t bytewise_bit_swap(uint32_t inp) +{ + inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4; + inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2; + return (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1; +} + +static void update_radio_parameters() +{ + // Protocol + switch(m_config_local.protocol) + { + case UESB_PROTOCOL_ESB_DPL: + update_rf_payload_format = update_rf_payload_format_esb_dpl; + break; + case UESB_PROTOCOL_ESB: + update_rf_payload_format = update_rf_payload_format_esb; + break; + case UESB_PROTOCOL_SB: + update_rf_payload_format = update_rf_payload_format_sb; + on_radio_end = (m_config_local.mode == UESB_MODE_PTX ? on_radio_end_sb_tx : on_radio_end_sb_rx); + break; + } + // TX power + NRF_RADIO->TXPOWER = m_config_local.tx_output_power << RADIO_TXPOWER_TXPOWER_Pos; + + // RF bitrate + NRF_RADIO->MODE = m_config_local.bitrate << RADIO_MODE_MODE_Pos; + switch(m_config_local.bitrate) + { + case UESB_BITRATE_2MBPS: + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS; + break; + case UESB_BITRATE_1MBPS: + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS; + break; + case UESB_BITRATE_250KBPS: + m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS; + break; + } + + // CRC configuration + NRF_RADIO->CRCCNF = m_config_local.crc << RADIO_CRCCNF_LEN_Pos; + if(m_config_local.crc == RADIO_CRCCNF_LEN_Two) + { + NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value + NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1 + } + else if(m_config_local.crc == RADIO_CRCCNF_LEN_One) + { + NRF_RADIO->CRCINIT = 0xFFUL; // Initial value + NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8+x^2^x^1+1 + } + + // Packet format + update_rf_payload_format(m_config_local.payload_length); + + // Radio address config + NRF_RADIO->PREFIX0 = bytewise_bit_swap(m_config_local.rx_address_p3 << 24 | m_config_local.rx_address_p2 << 16 | m_config_local.rx_address_p1[0] << 8 | m_config_local.rx_address_p0[0]); + NRF_RADIO->PREFIX1 = bytewise_bit_swap(m_config_local.rx_address_p7 << 24 | m_config_local.rx_address_p6 << 16 | m_config_local.rx_address_p5 << 8 | m_config_local.rx_address_p4); + NRF_RADIO->BASE0 = bytewise_bit_swap(m_config_local.rx_address_p0[1] << 24 | m_config_local.rx_address_p0[2] << 16 | m_config_local.rx_address_p0[3] << 8 | m_config_local.rx_address_p0[4]); + NRF_RADIO->BASE1 = bytewise_bit_swap(m_config_local.rx_address_p1[1] << 24 | m_config_local.rx_address_p1[2] << 16 | m_config_local.rx_address_p1[3] << 8 | m_config_local.rx_address_p1[4]); +} + +static void initialize_fifos() +{ + m_tx_fifo.entry_point = 0; + m_tx_fifo.exit_point = 0; + m_tx_fifo.count = 0; + for(int i = 0; i < UESB_CORE_TX_FIFO_SIZE; i++) + { + m_tx_fifo.payload_ptr[i] = &m_tx_fifo_payload[i]; + } + + m_rx_fifo.entry_point = 0; + m_rx_fifo.exit_point = 0; + m_rx_fifo.count = 0; + for(int i = 0; i < UESB_CORE_RX_FIFO_SIZE; i++) + { + m_rx_fifo.payload_ptr[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--; + m_tx_fifo.exit_point++; + if(m_tx_fifo.exit_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.exit_point = 0; + ENABLE_RF_IRQ; + } +} + +static bool rx_fifo_push_rfbuf(uint8_t pipe) +{ + if(m_rx_fifo.count < UESB_CORE_RX_FIFO_SIZE) + { + if(m_config_local.protocol == UESB_PROTOCOL_ESB_DPL) + { + if(m_rx_payload_buffer[0] > UESB_CORE_MAX_PAYLOAD_LENGTH) return false; + m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length = m_rx_payload_buffer[0]; + } + else + { + m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length = m_config_local.payload_length; + } + if(m_config_local.protocol == UESB_PROTOCOL_SB) + { + memcpy(m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->data, &m_rx_payload_buffer[0], m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length); + } + else + { + memcpy(m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->data, &m_rx_payload_buffer[2], m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length); + } + m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->pipe = pipe; + m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->rssi = NRF_RADIO->RSSISAMPLE; + if(++m_rx_fifo.entry_point >= UESB_CORE_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 + UESB_SYS_TIMER->PRESCALER = 4; + UESB_SYS_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit; + UESB_SYS_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk; +} + +static void ppi_init() +{ + NRF_PPI->CH[UESB_PPI_TIMER_START].EEP = (uint32_t)&NRF_RADIO->EVENTS_READY; + NRF_PPI->CH[UESB_PPI_TIMER_START].TEP = (uint32_t)&UESB_SYS_TIMER->TASKS_START; + NRF_PPI->CH[UESB_PPI_TIMER_STOP].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS; + NRF_PPI->CH[UESB_PPI_TIMER_STOP].TEP = (uint32_t)&UESB_SYS_TIMER->TASKS_STOP; + NRF_PPI->CH[UESB_PPI_RX_TIMEOUT].EEP = (uint32_t)&UESB_SYS_TIMER->EVENTS_COMPARE[0]; + NRF_PPI->CH[UESB_PPI_RX_TIMEOUT].TEP = (uint32_t)&NRF_RADIO->TASKS_DISABLE; + NRF_PPI->CH[UESB_PPI_TX_START].EEP = (uint32_t)&UESB_SYS_TIMER->EVENTS_COMPARE[1]; + NRF_PPI->CH[UESB_PPI_TX_START].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN; +} + +uint32_t uesb_init(uesb_config_t *parameters) +{ + if(m_uesb_mainstate != UESB_STATE_UNINITIALIZED) return UESB_ERROR_ALREADY_INITIALIZED; + m_event_handler = parameters->event_handler; + memcpy(&m_config_local, parameters, sizeof(uesb_config_t)); + + m_interrupt_flags = 0; + m_pid = 0; + m_last_rx_packet_pid = 0xFF; + m_last_rx_packet_crc = 0xFFFFFFFF; + + update_radio_parameters(); + + initialize_fifos(); + + sys_timer_init(); + + ppi_init(); + + NVIC_SetPriority(RADIO_IRQn, m_config_local.radio_irq_priority & 0x03); + + //m_uesb_initialized = true; + m_uesb_mainstate = UESB_STATE_IDLE; + + return UESB_SUCCESS; +} + +uint32_t uesb_disable(void) +{ + if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; + NRF_PPI->CHENCLR = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_TIMER_STOP) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TX_START); + m_uesb_mainstate = UESB_STATE_UNINITIALIZED; + return UESB_SUCCESS; +} + +static void start_tx_transaction() +{ + bool ack; + m_last_tx_attempts = 1; + // Prepare the payload + current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; + m_pid = (m_pid + 1) % 4; + switch(m_config_local.protocol) + { + case UESB_PROTOCOL_SB: + update_rf_payload_format(current_payload->length); + memcpy(&m_tx_payload_buffer[0], current_payload->data, current_payload->length); + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; + on_radio_disabled = on_radio_disabled_esb_dpl_tx_noack; + m_uesb_mainstate = UESB_STATE_PTX_TX; + break; + + case UESB_PROTOCOL_ESB: + update_rf_payload_format(current_payload->length); + m_tx_payload_buffer[0] = 0xCC | m_pid; + m_tx_payload_buffer[1] = 0; + memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); + + NRF_RADIO->SHORTS = 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_esb_dpl_tx; + m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; + break; + + case UESB_PROTOCOL_ESB_DPL: + ack = current_payload->noack == 0 || m_config_local.dynamic_ack_enabled == 0; + m_tx_payload_buffer[0] = current_payload->length; + m_tx_payload_buffer[1] = m_pid << 1 | ((current_payload->noack == 0 && m_config_local.dynamic_ack_enabled) ? 0x01 : 0x00); + memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); + if(ack) + { + NRF_RADIO->SHORTS = 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_esb_dpl_tx; + m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; + } + else + { + NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + on_radio_disabled = on_radio_disabled_esb_dpl_tx_noack; + m_uesb_mainstate = UESB_STATE_PTX_TX; + } + break; + } + + NRF_RADIO->TXADDRESS = current_payload->pipe; + NRF_RADIO->RXADDRESSES = 1 << current_payload->pipe; + + NRF_RADIO->FREQUENCY = m_config_local.rf_channel; + + NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; + + NVIC_ClearPendingIRQ(RADIO_IRQn); + NVIC_EnableIRQ(RADIO_IRQn); + + NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = NRF_RADIO->EVENTS_DISABLED = 0; + DEBUG_PIN_SET(DEBUGPIN4); + NRF_RADIO->TASKS_TXEN = 1; +} + +static uint32_t write_tx_payload(uesb_payload_t *payload, bool noack) // ~50us @ 61 bytes SB +{ + if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; + if(m_tx_fifo.count >= UESB_CORE_TX_FIFO_SIZE) return UESB_ERROR_TX_FIFO_FULL; + + DISABLE_RF_IRQ; + if(noack && m_config_local.dynamic_ack_enabled) payload->noack = 1; + else payload->noack = 0; + memcpy(m_tx_fifo.payload_ptr[m_tx_fifo.entry_point], payload, sizeof(uesb_payload_t)); + m_tx_fifo.entry_point++; + if(m_tx_fifo.entry_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.entry_point = 0; + m_tx_fifo.count++; + ENABLE_RF_IRQ; + + if(m_config_local.tx_mode == UESB_TXMODE_AUTO && m_uesb_mainstate == UESB_STATE_IDLE) + { + start_tx_transaction(); + } + + return UESB_SUCCESS; +} + +uint32_t uesb_write_tx_payload(uesb_payload_t *payload) +{ + return write_tx_payload(payload, false); +} + +uint32_t uesb_write_tx_payload_noack(uesb_payload_t *payload) +{ + if(m_config_local.dynamic_ack_enabled == 0) return UESB_ERROR_DYN_ACK_NOT_ENABLED; + return write_tx_payload(payload, true); +} + +uint32_t uesb_write_ack_payload(uesb_payload_t *payload) +{ + if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; + if((m_uesb_mainstate != UESB_STATE_PRX) && + (m_uesb_mainstate != UESB_STATE_PRX_SEND_ACK) && + (m_uesb_mainstate != UESB_STATE_PRX_SEND_ACK_PAYLOAD)) + { + return UESB_ERROR_NOT_IN_RX_MODE; + } + if(m_tx_fifo.count >= UESB_CORE_TX_FIFO_SIZE) return UESB_ERROR_TX_FIFO_FULL; + + DISABLE_RF_IRQ; + memcpy(m_tx_fifo.payload_ptr[m_tx_fifo.entry_point], payload, sizeof(uesb_payload_t)); + m_tx_fifo.entry_point++; + if(m_tx_fifo.entry_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.entry_point = 0; + m_tx_fifo.count++; + ENABLE_RF_IRQ; + + return UESB_SUCCESS; +} + +uint32_t uesb_read_rx_payload(uesb_payload_t *payload) +{ + if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; + if(m_rx_fifo.count == 0) return UESB_ERROR_RX_FIFO_EMPTY; + + DISABLE_RF_IRQ; + payload->length = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->length; + payload->pipe = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->pipe; + payload->rssi = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->rssi; + memcpy(payload->data, m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->data, payload->length); + if(++m_rx_fifo.exit_point >= UESB_CORE_RX_FIFO_SIZE) m_rx_fifo.exit_point = 0; + m_rx_fifo.count--; + ENABLE_RF_IRQ; + + return UESB_SUCCESS; +} + +uint32_t uesb_start_tx() +{ + if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; + if(m_tx_fifo.count == 0) return UESB_ERROR_TX_FIFO_EMPTY; + start_tx_transaction(); + return UESB_SUCCESS; +} + +uint32_t uesb_start_rx(void) +{ + if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; + + NRF_RADIO->INTENCLR = 0xFFFFFFFF; + NRF_RADIO->EVENTS_DISABLED = 0; + on_radio_disabled = on_radio_disabled_esb_dpl_rx; + switch(m_config_local.protocol) + { + case UESB_PROTOCOL_SB: + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_START_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; + m_uesb_mainstate = UESB_STATE_PRX; + break; + case UESB_PROTOCOL_ESB: + NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + m_uesb_mainstate = UESB_STATE_PRX; + break; + case UESB_PROTOCOL_ESB_DPL: + NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + m_uesb_mainstate = UESB_STATE_PRX; + break; + } + + NRF_RADIO->RXADDRESSES = m_config_local.rx_pipes_enabled; + + NRF_RADIO->FREQUENCY = m_config_local.rf_channel; + + NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; + + NVIC_ClearPendingIRQ(RADIO_IRQn); + NVIC_EnableIRQ(RADIO_IRQn); + + NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->TASKS_RXEN = 1; + return UESB_SUCCESS; +} + +uint32_t uesb_stop_rx(void) +{ + if((m_uesb_mainstate == UESB_STATE_PRX) || (m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK_PAYLOAD)) + { + 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_uesb_mainstate = UESB_STATE_IDLE; + return UESB_SUCCESS; + } + return UESB_ERROR_NOT_IN_RX_MODE; +} + +uint32_t uesb_get_tx_attempts(uint32_t *attempts) +{ + if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; + *attempts = m_last_tx_attempts; + return UESB_SUCCESS; +} + +uint32_t uesb_flush_tx(void) +{ + if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; + DISABLE_RF_IRQ; + m_tx_fifo.count = 0; + m_tx_fifo.entry_point = m_tx_fifo.exit_point = 0; + ENABLE_RF_IRQ; + return UESB_SUCCESS; +} + +uint32_t uesb_flush_rx(void) +{ + DISABLE_RF_IRQ; + m_rx_fifo.count = 0; + m_rx_fifo.entry_point = 0; + ENABLE_RF_IRQ; + return UESB_SUCCESS; +} + +uint32_t uesb_get_clear_interrupts(uint32_t *interrupts) +{ + DISABLE_RF_IRQ; + *interrupts = m_interrupt_flags; + m_interrupt_flags = 0; + ENABLE_RF_IRQ; + return UESB_SUCCESS; +} + +uint32_t uesb_set_address(uesb_address_type_t address, const uint8_t *data_ptr) +{ + if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; + switch(address) + { + case UESB_ADDRESS_PIPE0: + memcpy(m_config_local.rx_address_p0, data_ptr, m_config_local.rf_addr_length); + break; + case UESB_ADDRESS_PIPE1: + memcpy(m_config_local.rx_address_p1, data_ptr, m_config_local.rf_addr_length); + break; + case UESB_ADDRESS_PIPE2: + m_config_local.rx_address_p2 = *data_ptr; + break; + case UESB_ADDRESS_PIPE3: + m_config_local.rx_address_p3 = *data_ptr; + break; + case UESB_ADDRESS_PIPE4: + m_config_local.rx_address_p4 = *data_ptr; + break; + case UESB_ADDRESS_PIPE5: + m_config_local.rx_address_p5 = *data_ptr; + break; + case UESB_ADDRESS_PIPE6: + m_config_local.rx_address_p6 = *data_ptr; + break; + case UESB_ADDRESS_PIPE7: + m_config_local.rx_address_p7 = *data_ptr; + break; + default: + return UESB_ERROR_INVALID_PARAMETERS; + } + update_radio_parameters(); + return UESB_SUCCESS; +} + +uint32_t uesb_set_rf_channel(uint32_t channel) +{ + if(channel > 125) return UESB_ERROR_INVALID_PARAMETERS; + m_config_local.rf_channel = channel; + return UESB_SUCCESS; +} + +uint32_t uesb_set_tx_power(uesb_tx_power_t tx_output_power) +{ + if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; + if ( m_config_local.tx_output_power == tx_output_power ) return UESB_SUCCESS; + m_config_local.tx_output_power = tx_output_power; + update_radio_parameters(); + return UESB_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); +} + +static void on_radio_disabled_esb_dpl_tx_noack() +{ + m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; + tx_fifo_remove_last(); + + if(m_tx_fifo.count == 0) + { + m_uesb_mainstate = UESB_STATE_IDLE; + if(m_event_handler != 0) m_event_handler(); + } + else + { + if(m_event_handler != 0) m_event_handler(); + start_tx_transaction(); + } +} + +static void on_radio_disabled_esb_dpl_tx() +{ + // Remove the DISABLED -> RXEN shortcut, to make sure the radio stays disabled after the RX window + NRF_RADIO->SHORTS = 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 + UESB_SYS_TIMER->CC[0] = m_wait_for_ack_timeout_us; + UESB_SYS_TIMER->CC[1] = m_config_local.retransmit_delay - 130; + UESB_SYS_TIMER->TASKS_CLEAR = 1; + UESB_SYS_TIMER->EVENTS_COMPARE[0] = 0; + UESB_SYS_TIMER->EVENTS_COMPARE[1] = 0; + NRF_PPI->CHENSET = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TIMER_STOP); + NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); + NRF_RADIO->EVENTS_END = 0; + if(m_config_local.protocol == UESB_PROTOCOL_ESB) + { + update_rf_payload_format(0); + } + NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; + on_radio_disabled = on_radio_disabled_esb_dpl_tx_wait_for_ack; + m_uesb_mainstate = UESB_STATE_PTX_RX_ACK; +} + +static void on_radio_disabled_esb_dpl_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 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_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) + { + UESB_SYS_TIMER->TASKS_STOP = 1; + NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); + m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; + m_last_tx_attempts = m_config_local.retransmit_count - m_retransmits_remaining + 1; + tx_fifo_remove_last(); + if(m_rx_payload_buffer[0] > 0) + { + if(rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS)) + { + m_interrupt_flags |= UESB_INT_RX_DR_MSK; + } + } + + if((m_tx_fifo.count == 0) || (m_config_local.tx_mode == UESB_TXMODE_MANUAL)) + { + m_uesb_mainstate = UESB_STATE_IDLE; + if(m_event_handler != 0) m_event_handler(); + } + else + { + if(m_event_handler != 0) m_event_handler(); + start_tx_transaction(); + } + } + else + { + if(m_retransmits_remaining-- == 0) + { + UESB_SYS_TIMER->TASKS_STOP = 1; + NRF_PPI->CHENCLR = (1 << UESB_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 |= UESB_INT_TX_FAILED_MSK; + + m_uesb_mainstate = UESB_STATE_IDLE; + if(m_event_handler != 0) m_event_handler(); + } + else + { + // We still have more retransmits left, and we should enter TX mode again as soon as the system timer reaches CC[1] + NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; + update_rf_payload_format(current_payload->length); + NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; + on_radio_disabled = on_radio_disabled_esb_dpl_tx; + m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; + UESB_SYS_TIMER->TASKS_START = 1; + NRF_PPI->CHENSET = (1 << UESB_PPI_TX_START); + if(UESB_SYS_TIMER->EVENTS_COMPARE[1]) + { + NRF_RADIO->TASKS_TXEN = 1; + } + } + } +} + +static void on_radio_disabled_esb_dpl_rx(void) +{ + bool send_ack = false; + bool set_rx_interrupt = false; + if(NRF_RADIO->CRCSTATUS != 0 && m_rx_fifo.count < UESB_CORE_RX_FIFO_SIZE) + { + send_ack = true; + } + if(send_ack) + { + NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; + + // For a packet to be considered new (and not a retransmit) the PID or the CRC has to be different + if(NRF_RADIO->RXCRC != m_last_rx_packet_crc || (m_rx_payload_buffer[1] >> 1) != m_last_rx_packet_pid) + { + if((m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK_PAYLOAD) && (m_tx_fifo.count > 0)) + { + // It is assumed that the last ACK payload was recieved. + if(++m_tx_fifo.exit_point >= UESB_CORE_RX_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 |= UESB_INT_TX_SUCCESS_MSK; + } + + set_rx_interrupt = true; + m_last_rx_packet_pid = m_rx_payload_buffer[1] >> 1; + m_last_rx_packet_crc = NRF_RADIO->RXCRC; + } + + if(m_config_local.protocol == UESB_PROTOCOL_ESB_DPL) + { + if(m_tx_fifo.count > 0) + { + current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; + + update_rf_payload_format(current_payload->length); + m_tx_payload_buffer[0] = current_payload->length; + memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); + + m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK_PAYLOAD; + } + else + { + update_rf_payload_format(0); + m_tx_payload_buffer[0] = 0; + + m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK; + } + + m_tx_payload_buffer[1] = m_rx_payload_buffer[1]; + } + else if(m_config_local.protocol == UESB_PROTOCOL_ESB) + { + m_tx_payload_buffer[0] = m_rx_payload_buffer[0]; + m_tx_payload_buffer[1] = 0; + + m_uesb_mainstate = UESB_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_esb_dpl_rx_ack; + } + else + { + NRF_RADIO->SHORTS = 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 = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; + NRF_RADIO->TASKS_RXEN = 1; + } + if(set_rx_interrupt) + { + rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH); + m_interrupt_flags |= UESB_INT_RX_DR_MSK; + if(m_event_handler != 0) m_event_handler(); + } +} + +static void on_radio_disabled_esb_dpl_rx_ack(void) +{ + NRF_RADIO->SHORTS = 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_esb_dpl_rx; + + if(m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK) + { + // In the case of UESB_STATE_PRX_SEND_ACK_PAYLOAD the state will be updated when the next packet is received. + m_uesb_mainstate = UESB_STATE_PRX; + } +} + +static void on_radio_end_sb_tx(void) +{ + m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; + tx_fifo_remove_last(); + if(m_config_local.tx_mode == UESB_TXMODE_MANUAL || m_tx_fifo.count == 0) + { + // No more packets to send. Disable the radio and set the state to idle. + NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->TASKS_DISABLE = 1; + while(!NRF_RADIO->EVENTS_DISABLED); + NRF_RADIO->EVENTS_DISABLED = 0; + m_uesb_mainstate = UESB_STATE_IDLE; + if(m_event_handler != 0) m_event_handler(); + } + else + { + // Send another packet automatically without disabling the radio first. + current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; + + update_rf_payload_format(current_payload->length); + memcpy(&m_tx_payload_buffer[0], current_payload->data, current_payload->length); + + NRF_RADIO->TXADDRESS = current_payload->pipe; + + NVIC_ClearPendingIRQ(RADIO_IRQn); + NVIC_EnableIRQ(RADIO_IRQn); + + NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = 0; + NRF_RADIO->TASKS_START = 1; + + } +} + +static void on_radio_end_sb_rx(void) +{ + if(NRF_RADIO->CRCSTATUS != 0 && rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH)) + { + m_interrupt_flags |= UESB_INT_RX_DR_MSK; + if(m_event_handler != 0) m_event_handler(); + } +}
diff -r 000000000000 -r a01a54c0dc90 micro_esb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/micro_esb.h Mon Mar 23 04:09:41 2015 +0000 @@ -0,0 +1,240 @@ +/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#ifndef __MICRO_ESB_H +#define __MICRO_ESB_H + +#include <stdbool.h> +#include <stdint.h> +//#include "nrf.h" +#include "nrf51.h" +#include "nrf51_bitfields.h" + +#define DEBUGPIN1 12 +#define DEBUGPIN2 13 +#define DEBUGPIN3 14 +#define DEBUGPIN4 15 + +#ifdef UESB_DEBUG +#define DEBUG_PIN_SET(a) (NRF_GPIO->OUTSET = (1 << (a))) +#define DEBUG_PIN_CLR(a) (NRF_GPIO->OUTCLR = (1 << (a))) +#else +#define DEBUG_PIN_SET(a) +#define DEBUG_PIN_CLR(a) +#endif + +// Hard coded parameters - change if necessary +#define UESB_CORE_MAX_PAYLOAD_LENGTH 32 +#define UESB_CORE_TX_FIFO_SIZE 8 +#define UESB_CORE_RX_FIFO_SIZE 8 + +#define UESB_SYS_TIMER NRF_TIMER2 +#define UESB_SYS_TIMER_IRQ_Handler TIMER2_IRQHandler + +#define UESB_PPI_TIMER_START 4 +#define UESB_PPI_TIMER_STOP 5 +#define UESB_PPI_RX_TIMEOUT 6 +#define UESB_PPI_TX_START 7 + +// Interrupt flags +#define UESB_INT_TX_SUCCESS_MSK 0x01 +#define UESB_INT_TX_FAILED_MSK 0x02 +#define UESB_INT_RX_DR_MSK 0x04 + +// Configuration parameter definitions +typedef enum { + UESB_PROTOCOL_SB, // Legacy ShockBurst mode - No ACK or retransmit functionality (CURRENTLY NOT IMPLEMENTED!) + UESB_PROTOCOL_ESB, // Enhanced ShockBurst with fixed payload length + UESB_PROTOCOL_ESB_DPL // Enhanced ShockBurst with dynamic payload length +} uesb_protocol_t; + +typedef enum { + UESB_MODE_PTX, // Primary transmitter + UESB_MODE_PRX // Primary receiver (CURRENTLY NOT IMPLEMENTED) +} uesb_mode_t; + +typedef enum { + UESB_BITRATE_2MBPS = RADIO_MODE_MODE_Nrf_2Mbit, + UESB_BITRATE_1MBPS = RADIO_MODE_MODE_Nrf_1Mbit, + UESB_BITRATE_250KBPS = RADIO_MODE_MODE_Nrf_250Kbit +} uesb_bitrate_t; + +typedef enum { + UESB_CRC_16BIT = RADIO_CRCCNF_LEN_Two, + UESB_CRC_8BIT = RADIO_CRCCNF_LEN_One, + UESB_CRC_OFF = RADIO_CRCCNF_LEN_Disabled +} uesb_crc_t; + +typedef enum { + UESB_TX_POWER_4DBM = RADIO_TXPOWER_TXPOWER_Pos4dBm, + UESB_TX_POWER_0DBM = RADIO_TXPOWER_TXPOWER_0dBm, + UESB_TX_POWER_NEG4DBM = RADIO_TXPOWER_TXPOWER_Neg4dBm, + UESB_TX_POWER_NEG8DBM = RADIO_TXPOWER_TXPOWER_Neg8dBm, + UESB_TX_POWER_NEG12DBM = RADIO_TXPOWER_TXPOWER_Neg12dBm, + UESB_TX_POWER_NEG16DBM = RADIO_TXPOWER_TXPOWER_Neg16dBm, + UESB_TX_POWER_NEG20DBM = RADIO_TXPOWER_TXPOWER_Neg20dBm, + UESB_TX_POWER_NEG30DBM = RADIO_TXPOWER_TXPOWER_Neg30dBm +} uesb_tx_power_t; + +typedef enum { + UESB_TXMODE_AUTO, // Automatic TX mode - When the TX fifo is non-empty and the radio is idle packets will be sent automatically. + UESB_TXMODE_MANUAL, // Manual TX mode - Packets will not be sent until uesb_start_tx() is called. Can be used to ensure consistent packet timing. + UESB_TXMODE_MANUAL_START // Manual start TX mode - Packets will not be sent until uesb_start_tx() is called, but transmission will continue automatically until the TX FIFO is empty. +} uesb_tx_mode_t; + +// Internal state definition +typedef enum { + UESB_STATE_UNINITIALIZED, + UESB_STATE_IDLE, + UESB_STATE_PTX_TX, + UESB_STATE_PTX_TX_ACK, + UESB_STATE_PTX_RX_ACK, + UESB_STATE_PRX, + UESB_STATE_PRX_SEND_ACK, + UESB_STATE_PRX_SEND_ACK_PAYLOAD +} uesb_mainstate_t; + +typedef void (*uesb_event_handler_t)(void); + +// Main UESB configuration struct, contains all radio parameters +typedef struct +{ + uesb_protocol_t protocol; + uesb_mode_t mode; + uesb_event_handler_t event_handler; + + // General RF parameters + uesb_bitrate_t bitrate; + uesb_crc_t crc; + uint8_t rf_channel; + uint8_t payload_length; + uint8_t rf_addr_length; + + uesb_tx_power_t tx_output_power; + uint8_t tx_address[5]; + uint8_t rx_address_p0[5]; + uint8_t rx_address_p1[5]; + uint8_t rx_address_p2; + uint8_t rx_address_p3; + uint8_t rx_address_p4; + uint8_t rx_address_p5; + uint8_t rx_address_p6; + uint8_t rx_address_p7; + uint8_t rx_pipes_enabled; + + // ESB specific features + uint8_t dynamic_payload_length_enabled; + uint8_t dynamic_ack_enabled; + uint16_t retransmit_delay; + uint16_t retransmit_count; + + // Control settings + uesb_tx_mode_t tx_mode; + + uint8_t radio_irq_priority; +}uesb_config_t; + +// Default radio parameters, roughly equal to nRF24L default parameters (except CRC which is set to 16-bit, and protocol set to DPL) +#define UESB_DEFAULT_CONFIG {.mode = UESB_MODE_PTX, \ + .protocol = UESB_PROTOCOL_ESB_DPL, \ + .event_handler = 0, \ + .rf_channel = 2, \ + .payload_length = 61, \ + .rf_addr_length = 5, \ + .bitrate = UESB_BITRATE_2MBPS, \ + .crc = UESB_CRC_16BIT, \ + .tx_output_power = UESB_TX_POWER_0DBM, \ + .rx_address_p0 = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}, \ + .rx_address_p1 = {0xC2, 0xC2, 0xC2, 0xC2, 0xC2}, \ + .rx_address_p2 = 0xC3, \ + .rx_address_p3 = 0xC4, \ + .rx_address_p4 = 0xC5, \ + .rx_address_p5 = 0xC6, \ + .rx_address_p6 = 0xC7, \ + .rx_address_p7 = 0xC8, \ + .rx_pipes_enabled = 0x3F, \ + .dynamic_payload_length_enabled = 1, \ + .dynamic_ack_enabled = 0, \ + .retransmit_delay = 250, \ + .retransmit_count = 3, \ + .tx_mode = UESB_TXMODE_AUTO, \ + .radio_irq_priority = 1} + +enum uesb_event_type_t {UESB_EVENT_TX_SUCCESS, UESB_EVENT_TX_FAILED, UESB_EVENT_RX_RECEIVED}; + +typedef enum {UESB_ADDRESS_PIPE0, UESB_ADDRESS_PIPE1, UESB_ADDRESS_PIPE2, UESB_ADDRESS_PIPE3, UESB_ADDRESS_PIPE4, UESB_ADDRESS_PIPE5, UESB_ADDRESS_PIPE6, UESB_ADDRESS_PIPE7} uesb_address_type_t; + +typedef struct +{ + enum uesb_event_type_t type; +}uesb_event_t; + +typedef struct +{ + uint8_t length; + uint8_t pipe; + int8_t rssi; + uint8_t noack; + uint8_t data[UESB_CORE_MAX_PAYLOAD_LENGTH]; +}uesb_payload_t; + +typedef struct +{ + uesb_payload_t *payload_ptr[UESB_CORE_TX_FIFO_SIZE]; + uint32_t entry_point; + uint32_t exit_point; + uint32_t count; +}uesb_payload_tx_fifo_t; + +typedef struct +{ + uesb_payload_t *payload_ptr[UESB_CORE_RX_FIFO_SIZE]; + uint32_t entry_point; + uint32_t exit_point; + uint32_t count; +}uesb_payload_rx_fifo_t; + +uint32_t uesb_init(uesb_config_t *parameters); + +uint32_t uesb_disable(void); + +bool uesb_is_idle(void); + +uint32_t uesb_write_tx_payload(uesb_payload_t *payload); + +uint32_t uesb_write_tx_payload_noack(uesb_payload_t *payload); + +uint32_t uesb_write_ack_payload(uesb_payload_t *payload); + +uint32_t uesb_read_rx_payload(uesb_payload_t *payload); + +uint32_t uesb_start_tx(void); + +uint32_t uesb_start_rx(void); + +uint32_t uesb_stop_rx(void); + +uint32_t uesb_get_tx_attempts(uint32_t *attempts); + +uint32_t uesb_flush_tx(void); + +uint32_t uesb_flush_rx(void); + +uint32_t uesb_get_clear_interrupts(uint32_t *interrupts); + +uint32_t uesb_set_address(uesb_address_type_t address, const uint8_t *data_ptr); + +uint32_t uesb_set_rf_channel(uint32_t channel); + +uint32_t uesb_set_tx_power(uesb_tx_power_t tx_output_power); + +#endif
diff -r 000000000000 -r a01a54c0dc90 uesb_error_codes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uesb_error_codes.h Mon Mar 23 04:09:41 2015 +0000 @@ -0,0 +1,21 @@ +#ifndef __UESB_ERROR_CODES_H__ +#define __UESB_ERROR_CODES_H__ + +#define UESB_SUCCESS 0x0000 + +// State related errors +#define UESB_ERROR_NOT_INITIALIZED 0x0101 +#define UESB_ERROR_ALREADY_INITIALIZED 0x0102 +#define UESB_ERROR_NOT_IDLE 0x0103 +#define UESB_ERROR_NOT_IN_RX_MODE 0x0104 + +// Invalid parameter errors +#define UESB_ERROR_INVALID_PARAMETERS 0x0200 +#define UESB_ERROR_DYN_ACK_NOT_ENABLED 0x0201 + +// FIFO related errors +#define UESB_ERROR_TX_FIFO_FULL 0x0301 +#define UESB_ERROR_TX_FIFO_EMPTY 0x0302 +#define UESB_ERROR_RX_FIFO_EMPTY 0x0303 + +#endif