Openwear requires RC oscillator to be used
Fork of nRF51822 by
Revision 46:2bfbbe290083, committed 2014-07-16
- Comitter:
- Rohit Grover
- Date:
- Wed Jul 16 10:54:22 2014 +0100
- Parent:
- 45:3c4df37ed83e
- Child:
- 47:db25ca6ed092
- Commit message:
- get some more app_common ancillary sources from the Nordic SDK
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nordic/app_common/app_gpiote.c Wed Jul 16 10:54:22 2014 +0100 @@ -0,0 +1,360 @@ +/* Copyright (c) 2012 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 "app_gpiote.h" +#include <stdlib.h> +#include <string.h> +#include "app_util.h" +#include "app_util_platform.h" +#include "nrf_error.h" +#include "nrf_gpio.h" + + +/**@brief GPIOTE user type. */ +typedef struct +{ + uint32_t pins_mask; /**< Mask defining which pins user wants to monitor. */ + uint32_t pins_low_to_high_mask; /**< Mask defining which pins will generate events to this user when toggling low->high. */ + uint32_t pins_high_to_low_mask; /**< Mask defining which pins will generate events to this user when toggling high->low. */ + uint32_t sense_high_pins; /**< Mask defining which pins are configured to generate GPIOTE interrupt on transition to high level. */ + app_gpiote_event_handler_t event_handler; /**< Pointer to function to be executed when an event occurs. */ +} gpiote_user_t; + +STATIC_ASSERT(sizeof(gpiote_user_t) <= GPIOTE_USER_NODE_SIZE); +STATIC_ASSERT(sizeof(gpiote_user_t) % 4 == 0); + +static uint32_t m_enabled_users_mask; /**< Mask for tracking which users are enabled. */ +static uint8_t m_user_array_size; /**< Size of user array. */ +static uint8_t m_user_count; /**< Number of registered users. */ +static gpiote_user_t * mp_users = NULL; /**< Array of GPIOTE users. */ + + +/**@brief Function for toggling sense level for specified pins. + * + * @param[in] p_user Pointer to user structure. + * @param[in] pins Bitmask specifying for which pins the sense level is to be toggled. + */ +static void sense_level_toggle(gpiote_user_t * p_user, uint32_t pins) +{ + uint32_t pin_no; + + for (pin_no = 0; pin_no < NO_OF_PINS; pin_no++) + { + uint32_t pin_mask = (1 << pin_no); + + if ((pins & pin_mask) != 0) + { + uint32_t sense; + + // Invert sensing. + if ((p_user->sense_high_pins & pin_mask) == 0) + { + sense = GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos; + p_user->sense_high_pins |= pin_mask; + } + else + { + sense = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos; + p_user->sense_high_pins &= ~pin_mask; + } + + NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk; + NRF_GPIO->PIN_CNF[pin_no] |= sense; + } + } +} + + +/**@brief Function for handling the GPIOTE interrupt. + */ +void GPIOTE_IRQHandler(void) +{ + uint8_t i; + uint32_t pins_changed; + uint32_t pins_state = NRF_GPIO->IN; + + // Clear event. + NRF_GPIOTE->EVENTS_PORT = 0; + + // Check all users. + for (i = 0; i < m_user_count; i++) + { + gpiote_user_t * p_user = &mp_users[i]; + + // Check if user is enabled. + if (((1 << i) & m_enabled_users_mask) != 0) + { + uint32_t transition_pins; + uint32_t event_low_to_high; + uint32_t event_high_to_low; + + // Find set of pins on which there has been a transition. + transition_pins = (pins_state ^ ~p_user->sense_high_pins) & p_user->pins_mask; + + // Toggle SENSE level for all pins that have changed state. + sense_level_toggle(p_user, transition_pins); + + // Second read after setting sense. + // Check if any pins have changed while serving this interrupt. + pins_changed = NRF_GPIO->IN ^ pins_state; + if (pins_changed) + { + // Transition pins detected in late stage. + uint32_t late_transition_pins; + + pins_state |= pins_changed; + + // Find set of pins on which there has been a transition. + late_transition_pins = (pins_state ^ ~p_user->sense_high_pins) & p_user->pins_mask; + + // Toggle SENSE level for all pins that have changed state in last phase. + sense_level_toggle(p_user, late_transition_pins); + + // Update pins that has changed state since the interrupt occurred. + transition_pins |= late_transition_pins; + } + + // Call user event handler if an event has occurred. + event_high_to_low = (~pins_state & p_user->pins_high_to_low_mask) & transition_pins; + event_low_to_high = (pins_state & p_user->pins_low_to_high_mask) & transition_pins; + + if ((event_low_to_high | event_high_to_low) != 0) + { + p_user->event_handler(event_low_to_high, event_high_to_low); + } + } + } +} + + +/**@brief Function for sense disabling for all pins for specified user. + * + * @param[in] user_id User id. + */ +static void pins_sense_disable(app_gpiote_user_id_t user_id) +{ + uint32_t pin_no; + + for (pin_no = 0; pin_no < 32; pin_no++) + { + if ((mp_users[user_id].pins_mask & (1 << pin_no)) != 0) + { + NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk; + NRF_GPIO->PIN_CNF[pin_no] |= GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos; + } + } +} + + +uint32_t app_gpiote_init(uint8_t max_users, void * p_buffer) +{ + if (p_buffer == NULL) + { + return NRF_ERROR_INVALID_PARAM; + } + + // Check that buffer is correctly aligned. + if (!is_word_aligned(p_buffer)) + { + return NRF_ERROR_INVALID_PARAM; + } + + // Initialize file globals. + mp_users = (gpiote_user_t *)p_buffer; + m_user_array_size = max_users; + m_user_count = 0; + m_enabled_users_mask = 0; + + memset(mp_users, 0, m_user_array_size * sizeof(gpiote_user_t)); + + // Initialize GPIOTE interrupt (will not be enabled until app_gpiote_user_enable() is called). + NRF_GPIOTE->INTENCLR = 0xFFFFFFFF; + + NVIC_ClearPendingIRQ(GPIOTE_IRQn); + NVIC_SetPriority(GPIOTE_IRQn, APP_IRQ_PRIORITY_HIGH); + NVIC_EnableIRQ(GPIOTE_IRQn); + + return NRF_SUCCESS; +} + + +uint32_t app_gpiote_user_register(app_gpiote_user_id_t * p_user_id, + uint32_t pins_low_to_high_mask, + uint32_t pins_high_to_low_mask, + app_gpiote_event_handler_t event_handler) +{ + // Check state and parameters. + if (mp_users == NULL) + { + return NRF_ERROR_INVALID_STATE; + } + if (event_handler == NULL) + { + return NRF_ERROR_INVALID_PARAM; + } + if (m_user_count >= m_user_array_size) + { + return NRF_ERROR_NO_MEM; + } + + // Allocate new user. + mp_users[m_user_count].pins_mask = pins_low_to_high_mask | pins_high_to_low_mask; + mp_users[m_user_count].pins_low_to_high_mask = pins_low_to_high_mask; + mp_users[m_user_count].pins_high_to_low_mask = pins_high_to_low_mask; + mp_users[m_user_count].event_handler = event_handler; + + *p_user_id = m_user_count++; + + // Make sure SENSE is disabled for all pins. + pins_sense_disable(*p_user_id); + + return NRF_SUCCESS; +} + + +uint32_t app_gpiote_user_enable(app_gpiote_user_id_t user_id) +{ + uint32_t pin_no; + uint32_t pins_state; + + // Check state and parameters. + if (mp_users == NULL) + { + return NRF_ERROR_INVALID_STATE; + } + if (user_id >= m_user_count) + { + return NRF_ERROR_INVALID_PARAM; + } + + // Clear any pending event. + NRF_GPIOTE->EVENTS_PORT = 0; + pins_state = NRF_GPIO->IN; + + // Enable user. + if (m_enabled_users_mask == 0) + { + NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk; + } + m_enabled_users_mask |= (1 << user_id); + + // Enable sensing for all pins for specified user. + mp_users[user_id].sense_high_pins = 0; + for (pin_no = 0; pin_no < 32; pin_no++) + { + uint32_t pin_mask = (1 << pin_no); + + if ((mp_users[user_id].pins_mask & pin_mask) != 0) + { + uint32_t sense; + + if ((pins_state & pin_mask) != 0) + { + sense = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos; + } + else + { + sense = GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos; + mp_users[user_id].sense_high_pins |= pin_mask; + } + + NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk; + NRF_GPIO->PIN_CNF[pin_no] |= sense; + } + } + + return NRF_SUCCESS; +} + + +uint32_t app_gpiote_user_disable(app_gpiote_user_id_t user_id) +{ + // Check state and parameters. + if (mp_users == NULL) + { + return NRF_ERROR_INVALID_STATE; + } + if (user_id >= m_user_count) + { + return NRF_ERROR_INVALID_PARAM; + } + + // Disable sensing for all pins for specified user. + pins_sense_disable(user_id); + + // Disable user. + m_enabled_users_mask &= ~(1UL << user_id); + if (m_enabled_users_mask == 0) + { + NRF_GPIOTE->INTENCLR = GPIOTE_INTENSET_PORT_Msk; + } + + return NRF_SUCCESS; +} + + +uint32_t app_gpiote_pins_state_get(app_gpiote_user_id_t user_id, uint32_t * p_pins) +{ + gpiote_user_t * p_user; + + // Check state and parameters. + if (mp_users == NULL) + { + return NRF_ERROR_INVALID_STATE; + } + if (user_id >= m_user_count) + { + return NRF_ERROR_INVALID_PARAM; + } + + // Get pins. + p_user = &mp_users[user_id]; + *p_pins = NRF_GPIO->IN & p_user->pins_mask; + + return NRF_SUCCESS; +} + +#if defined(SVCALL_AS_NORMAL_FUNCTION) || defined(SER_CONNECTIVITY) +uint32_t app_gpiote_input_event_handler_register(const uint8_t channel, + const uint32_t pin, + const uint32_t polarity, + app_gpiote_input_event_handler_t event_handler) +{ + (void)sense_level_toggle(NULL, pin); + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t app_gpiote_input_event_handler_unregister(const uint8_t channel) +{ + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t app_gpiote_end_irq_event_handler_register(app_gpiote_input_event_handler_t event_handler) +{ + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t app_gpiote_end_irq_event_handler_unregister(void) +{ + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t app_gpiote_enable_interrupts(void) +{ + return NRF_ERROR_NOT_SUPPORTED; +} + +uint32_t app_gpiote_disable_interrupts(void) +{ + return NRF_ERROR_NOT_SUPPORTED; +} +#endif // SVCALL_AS_NORMAL_FUNCTION || SER_CONNECTIVITY
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nordic/app_common/app_scheduler.c Wed Jul 16 10:54:22 2014 +0100 @@ -0,0 +1,179 @@ +/* Copyright (c) 2012 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 "app_scheduler.h" +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include "nrf_soc.h" +#include "nrf_assert.h" +#include "app_util.h" +#include "app_util_platform.h" + +/**@brief Structure for holding a scheduled event header. */ +typedef struct +{ + app_sched_event_handler_t handler; /**< Pointer to event handler to receive the event. */ + uint16_t event_data_size; /**< Size of event data. */ +} event_header_t; + +STATIC_ASSERT(sizeof(event_header_t) <= APP_SCHED_EVENT_HEADER_SIZE); + +static event_header_t * m_queue_event_headers; /**< Array for holding the queue event headers. */ +static uint8_t * m_queue_event_data; /**< Array for holding the queue event data. */ +static volatile uint8_t m_queue_start_index; /**< Index of queue entry at the start of the queue. */ +static volatile uint8_t m_queue_end_index; /**< Index of queue entry at the end of the queue. */ +static uint16_t m_queue_event_size; /**< Maximum event size in queue. */ +static uint16_t m_queue_size; /**< Number of queue entries. */ + +/**@brief Macro for checking if a queue is full. */ +#define APP_SCHED_QUEUE_FULL() (next_index(m_queue_end_index) == m_queue_start_index) + +/**@brief Macro for checking if a queue is empty. */ +#define APP_SCHED_QUEUE_EMPTY() (m_queue_end_index == m_queue_start_index) + + +/**@brief Function for incrementing a queue index, and handle wrap-around. + * + * @param[in] index Old index. + * + * @return New (incremented) index. + */ +static __INLINE uint8_t next_index(uint8_t index) +{ + return (index < m_queue_size) ? (index + 1) : 0; +} + + +uint32_t app_sched_init(uint16_t event_size, uint16_t queue_size, void * p_event_buffer) +{ + uint16_t data_start_index = (queue_size + 1) * sizeof(event_header_t); + + // Check that buffer is correctly aligned + if (!is_word_aligned(p_event_buffer)) + { + return NRF_ERROR_INVALID_PARAM; + } + + // Initialize event scheduler + m_queue_event_headers = p_event_buffer; + m_queue_event_data = &((uint8_t *)p_event_buffer)[data_start_index]; + m_queue_end_index = 0; + m_queue_start_index = 0; + m_queue_event_size = event_size; + m_queue_size = queue_size; + + return NRF_SUCCESS; +} + + +uint32_t app_sched_event_put(void * p_event_data, + uint16_t event_data_size, + app_sched_event_handler_t handler) +{ + uint32_t err_code; + + if (event_data_size <= m_queue_event_size) + { + uint16_t event_index = 0xFFFF; + + CRITICAL_REGION_ENTER(); + + if (!APP_SCHED_QUEUE_FULL()) + { + event_index = m_queue_end_index; + m_queue_end_index = next_index(m_queue_end_index); + } + + CRITICAL_REGION_EXIT(); + + if (event_index != 0xFFFF) + { + // NOTE: This can be done outside the critical region since the event consumer will + // always be called from the main loop, and will thus never interrupt this code. + m_queue_event_headers[event_index].handler = handler; + if ((p_event_data != NULL) && (event_data_size > 0)) + { + memcpy(&m_queue_event_data[event_index * m_queue_event_size], + p_event_data, + event_data_size); + m_queue_event_headers[event_index].event_data_size = event_data_size; + } + else + { + m_queue_event_headers[event_index].event_data_size = 0; + } + + err_code = NRF_SUCCESS; + } + else + { + err_code = NRF_ERROR_NO_MEM; + } + } + else + { + err_code = NRF_ERROR_INVALID_LENGTH; + } + + return err_code; +} + + +/**@brief Function for reading the next event from specified event queue. + * + * @param[out] pp_event_data Pointer to pointer to event data. + * @param[out] p_event_data_size Pointer to size of event data. + * @param[out] p_event_handler Pointer to event handler function pointer. + * + * @return NRF_SUCCESS if new event, NRF_ERROR_NOT_FOUND if event queue is empty. + */ +static uint32_t app_sched_event_get(void ** pp_event_data, + uint16_t * p_event_data_size, + app_sched_event_handler_t * p_event_handler) +{ + uint32_t err_code = NRF_ERROR_NOT_FOUND; + + if (!APP_SCHED_QUEUE_EMPTY()) + { + uint16_t event_index; + + // NOTE: There is no need for a critical region here, as this function will only be called + // from app_sched_execute() from inside the main loop, so it will never interrupt + // app_sched_event_put(). Also, updating of (i.e. writing to) the start index will be + // an atomic operation. + event_index = m_queue_start_index; + m_queue_start_index = next_index(m_queue_start_index); + + *pp_event_data = &m_queue_event_data[event_index * m_queue_event_size]; + *p_event_data_size = m_queue_event_headers[event_index].event_data_size; + *p_event_handler = m_queue_event_headers[event_index].handler; + + err_code = NRF_SUCCESS; + } + + return err_code; +} + + +void app_sched_execute(void) +{ + void * p_event_data; + uint16_t event_data_size; + app_sched_event_handler_t event_handler; + + // Get next event (if any), and execute handler + while ((app_sched_event_get(&p_event_data, &event_data_size, &event_handler) == NRF_SUCCESS)) + { + event_handler(p_event_data, event_data_size); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nordic/app_common/hci_mem_pool.c Wed Jul 16 10:54:22 2014 +0100 @@ -0,0 +1,235 @@ +/* Copyright (c) 2013 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 "hci_mem_pool.h" +#include "hci_mem_pool_internal.h" +#include <stdbool.h> +#include <stdio.h> + +/**@brief RX buffer element instance structure. + */ +typedef struct +{ + uint8_t rx_buffer[RX_BUF_SIZE]; /**< RX buffer memory array. */ + uint32_t length; /**< Length of the RX buffer memory array. */ +} rx_buffer_elem_t; + +/**@brief RX buffer queue element instance structure. + */ +typedef struct +{ + rx_buffer_elem_t * p_buffer; /**< Pointer to RX buffer element. */ + uint32_t free_window_count; /**< Free space element count. */ + uint32_t free_available_count; /**< Free area element count. */ + uint32_t read_available_count; /**< Read area element count. */ + uint32_t write_index; /**< Write position index. */ + uint32_t read_index; /**< Read position index. */ + uint32_t free_index; /**< Free position index. */ +} rx_buffer_queue_t; + +static bool m_is_tx_allocated; /**< Boolean value to determine if the TX buffer is allocated. */ +static rx_buffer_elem_t m_rx_buffer_elem_queue[RX_BUF_QUEUE_SIZE]; /**< RX buffer element instances. */ +static rx_buffer_queue_t m_rx_buffer_queue; /**< RX buffer queue element instance. */ + + +uint32_t hci_mem_pool_open(void) +{ + m_is_tx_allocated = false; + m_rx_buffer_queue.p_buffer = m_rx_buffer_elem_queue; + m_rx_buffer_queue.free_window_count = RX_BUF_QUEUE_SIZE; + m_rx_buffer_queue.free_available_count = 0; + m_rx_buffer_queue.read_available_count = 0; + m_rx_buffer_queue.write_index = 0; + m_rx_buffer_queue.read_index = 0; + m_rx_buffer_queue.free_index = 0; + + return NRF_SUCCESS; +} + + +uint32_t hci_mem_pool_close(void) +{ + return NRF_SUCCESS; +} + + +uint32_t hci_mem_pool_tx_alloc(void ** pp_buffer) +{ + static uint8_t tx_buffer[TX_BUF_SIZE]; + + uint32_t err_code; + + if (pp_buffer == NULL) + { + return NRF_ERROR_NULL; + } + + if (!m_is_tx_allocated) + { + m_is_tx_allocated = true; + *pp_buffer = tx_buffer; + err_code = NRF_SUCCESS; + } + else + { + err_code = NRF_ERROR_NO_MEM; + } + + return err_code; +} + + +uint32_t hci_mem_pool_tx_free(void) +{ + m_is_tx_allocated = false; + + return NRF_SUCCESS; +} + + +uint32_t hci_mem_pool_rx_produce(uint32_t length, void ** pp_buffer) +{ + uint32_t err_code; + + if (pp_buffer == NULL) + { + return NRF_ERROR_NULL; + } + *pp_buffer = NULL; + + if (m_rx_buffer_queue.free_window_count != 0) + { + if (length <= RX_BUF_SIZE) + { + --(m_rx_buffer_queue.free_window_count); + ++(m_rx_buffer_queue.read_available_count); + + *pp_buffer = + m_rx_buffer_queue.p_buffer[m_rx_buffer_queue.write_index].rx_buffer; + + m_rx_buffer_queue.free_index |= (1u << m_rx_buffer_queue.write_index); + + // @note: Adjust the write_index making use of the fact that the buffer size is of + // power of two and two's complement arithmetic. For details refer example to book + // "Making embedded systems: Elicia White". + m_rx_buffer_queue.write_index = + (m_rx_buffer_queue.write_index + 1u) & (RX_BUF_QUEUE_SIZE - 1u); + + err_code = NRF_SUCCESS; + } + else + { + err_code = NRF_ERROR_DATA_SIZE; + } + } + else + { + err_code = NRF_ERROR_NO_MEM; + } + + return err_code; +} + + +uint32_t hci_mem_pool_rx_consume(uint8_t * p_buffer) +{ + uint32_t err_code; + uint32_t consume_index; + uint32_t start_index; + + if (m_rx_buffer_queue.free_available_count != 0) + { + // Find the buffer that has been freed - + // Start at read_index minus free_available_count and then increment until read index. + err_code = NRF_ERROR_INVALID_ADDR; + consume_index = (m_rx_buffer_queue.read_index - m_rx_buffer_queue.free_available_count) & + (RX_BUF_QUEUE_SIZE - 1u); + start_index = consume_index; + + do + { + if (m_rx_buffer_queue.p_buffer[consume_index].rx_buffer == p_buffer) + { + m_rx_buffer_queue.free_index ^= (1u << consume_index); + err_code = NRF_SUCCESS; + break; + } + else + { + consume_index = (consume_index + 1u) & (RX_BUF_QUEUE_SIZE - 1u); + } + } + while (consume_index != m_rx_buffer_queue.read_index); + + while (!(m_rx_buffer_queue.free_index & (1 << start_index)) && + (m_rx_buffer_queue.free_available_count != 0)) + { + --(m_rx_buffer_queue.free_available_count); + ++(m_rx_buffer_queue.free_window_count); + start_index = (consume_index + 1u) & (RX_BUF_QUEUE_SIZE - 1u); + } + } + else + { + err_code = NRF_ERROR_NO_MEM; + } + + return err_code; +} + + +uint32_t hci_mem_pool_rx_data_size_set(uint32_t length) +{ + // @note: Adjust the write_index making use of the fact that the buffer size is of power + // of two and two's complement arithmetic. For details refer example to book + // "Making embedded systems: Elicia White". + const uint32_t index = (m_rx_buffer_queue.write_index - 1u) & (RX_BUF_QUEUE_SIZE - 1u); + m_rx_buffer_queue.p_buffer[index].length = length; + + return NRF_SUCCESS; +} + + +uint32_t hci_mem_pool_rx_extract(uint8_t ** pp_buffer, uint32_t * p_length) +{ + uint32_t err_code; + + if ((pp_buffer == NULL) || (p_length == NULL)) + { + return NRF_ERROR_NULL; + } + + if (m_rx_buffer_queue.read_available_count != 0) + { + --(m_rx_buffer_queue.read_available_count); + ++(m_rx_buffer_queue.free_available_count); + + *pp_buffer = + m_rx_buffer_queue.p_buffer[m_rx_buffer_queue.read_index].rx_buffer; + *p_length = + m_rx_buffer_queue.p_buffer[m_rx_buffer_queue.read_index].length; + + // @note: Adjust the write_index making use of the fact that the buffer size is of power + // of two and two's complement arithmetic. For details refer example to book + // "Making embedded systems: Elicia White". + m_rx_buffer_queue.read_index = + (m_rx_buffer_queue.read_index + 1u) & (RX_BUF_QUEUE_SIZE - 1u); + + err_code = NRF_SUCCESS; + } + else + { + err_code = NRF_ERROR_NO_MEM; + } + + return err_code; +}