trying to get micro-esb working with nrf51822

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
joshuajnoble
Date:
Mon Mar 23 04:09:41 2015 +0000
Commit message:
trying esb

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
micro_esb.c Show annotated file Show diff for this revision Revisions of this file
micro_esb.h Show annotated file Show diff for this revision Revisions of this file
uesb_error_codes.h Show annotated file Show diff for this revision Revisions of this file
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