diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte')
4 files changed, 1231 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte.c new file mode 100644 index 0000000..6f44d0b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte.c @@ -0,0 +1,578 @@ +/** + * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "sdk_config.h" +#include "nrf_libuarte.h" +#include "nrfx_ppi.h" +#include "nrf_uarte.h" +#include "nrf_gpio.h" +#include "nrfx_timer.h" + + + +#define NRF_LOG_MODULE_NAME libUARTE +#if NRF_LIBUARTE_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL NRF_LIBUARTE_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR NRF_LIBUARTE_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR NRF_LIBUARTE_CONFIG_DEBUG_COLOR +#else // NRF_LIBUARTE_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL 0 +#endif // NRF_LIBUARTE_CONFIG_LOG_ENABLED +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + + +#define INTERRUPTS_MASK \ + (NRF_UARTE_INT_ENDRX_MASK | NRF_UARTE_INT_RXSTARTED_MASK | NRF_UARTE_INT_ERROR_MASK | \ + NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_TXSTOPPED_MASK) + +#define UART_DRV_UARTE CONCAT_2(NRF_UARTE, NRF_LIBUARTE_CONFIG_UARTE_USED) + +#if NRF_LIBUARTE_CONFIG_UARTE_USED == 0 +#define UART_DRV_IRQn UARTE0_UART0_IRQn +#define UART_DRV_IRQHandler UARTE0_UART0_IRQHandler +#define MAX_DMA_XFER_LEN (1<<UARTE0_EASYDMA_MAXCNT_SIZE) +#elif NRF_LIBUARTE_CONFIG_UARTE_USED == 1 +#define UART_DRV_IRQn UARTE1_UART1_IRQn +#define UART_DRV_IRQHandler UARTE1_IRQHandler +#define MAX_DMA_XFER_LEN (1<<UARTE1_EASYDMA_MAXCNT_SIZE) +#endif + +typedef enum +{ + PPI_CH_EXT_TRIGGER_STARTRX_EN_ENDRX_STARTX, + PPI_CH_RXSTARTED_EXT_TSK, + PPI_CH_EXT_STOP_STOPRX, + PPI_CH_EXT_STOP_GROUPS_EN, + PPI_CH_RXRDY_TIMER_COUNT, + + PPI_CH_RX_MAX, + PPI_CH_ENDRX_STARTRX = PPI_CH_RX_MAX, + PPI_CH_ENDRX_EXT_TSK, + + PPI_CH_RX_GROUP_MAX, + + PPI_CH_ENDTX_STARTTX = PPI_CH_RX_GROUP_MAX, + + PPI_CH_MAX +} nrf_libuarte_ppi_channel_t; + +typedef enum +{ + PPI_GROUP_ENDRX_STARTRX, + PPI_GROUP_ENDRX_EXT_RXDONE_TSK, + PPI_GROUP_MAX +} nrf_libuarte_ppi_group_t; + +static nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(NRF_LIBUARTE_CONFIG_TIMER_USED); + +#if CONCAT_3(NRFX_TIMER, NRF_LIBUARTE_CONFIG_TIMER_USED,_ENABLED) == 0 +#error "Timer instance not enabled" +#endif + +static nrf_ppi_channel_t m_ppi_channels[PPI_CH_MAX]; +static nrf_ppi_channel_group_t m_ppi_groups[PPI_GROUP_MAX]; + +static uint8_t * mp_tx; +static size_t m_tx_len; +static size_t m_tx_cur_idx; + +static uint8_t * mp_cur_rx; +static uint8_t * mp_next_rx; +static uint8_t * mp_next_next_rx; +static nrf_libuarte_evt_handler_t m_evt_handler; +static uint32_t m_last_rx_byte_cnt; +static uint32_t m_last_pin_rx_byte_cnt; +static uint8_t m_tx_chunk8; +static uint32_t m_chunk_size; + +#define PPI_CH_SETUP(_ch, _evt, _tsk, _fork) \ + ret = nrfx_ppi_channel_assign(m_ppi_channels[_ch], _evt, _tsk); \ + if (ret != NRF_SUCCESS) \ + { \ + return NRF_ERROR_INTERNAL; \ + } \ + if (_fork) \ + { \ + ret = nrfx_ppi_channel_fork_assign(m_ppi_channels[_ch], _fork); \ + if (ret != NRF_SUCCESS) \ + { \ + return NRF_ERROR_INTERNAL; \ + } \ + } + +#define PPI_GROUP_SETUP(_ch, _group, _en_tsk, _dis_tsk) \ + ret = nrfx_ppi_channel_include_in_group(m_ppi_channels[_ch], \ + m_ppi_groups[_group]); \ + if (ret != NRF_SUCCESS) \ + { \ + return NRF_ERROR_INTERNAL; \ + } \ + _en_tsk = nrfx_ppi_task_addr_group_enable_get(m_ppi_groups[_group]); \ + _dis_tsk = nrfx_ppi_task_addr_group_disable_get(m_ppi_groups[_group]); + + +static ret_code_t ppi_configure(nrf_libuarte_config_t * p_config) +{ + ret_code_t ret; + +/*lint -save -e666 */ + + /////////////////////////////////////////////////////////////////////////////// + uint32_t group1_en_tsk; + uint32_t group1_dis_tsk; + + PPI_GROUP_SETUP(PPI_CH_ENDRX_STARTRX, PPI_GROUP_ENDRX_STARTRX, group1_en_tsk, group1_dis_tsk); + + PPI_CH_SETUP(PPI_CH_ENDRX_STARTRX, + nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDRX), + nrf_uarte_task_address_get(UART_DRV_UARTE, NRF_UARTE_TASK_STARTRX), + nrfx_timer_capture_task_address_get(&m_timer, 0)); + + + /////////////////////////////////////////////////////////////////////////////// + uint32_t group2_en_tsk; + uint32_t group2_dis_tsk; + + PPI_GROUP_SETUP(PPI_CH_ENDRX_EXT_TSK, PPI_GROUP_ENDRX_EXT_RXDONE_TSK, group2_en_tsk, group2_dis_tsk); + + PPI_CH_SETUP(PPI_CH_ENDRX_EXT_TSK, + nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDRX), + nrfx_timer_capture_task_address_get(&m_timer, 0), + p_config->rxdone_tsk); + + /////////////////////////////////////////////////////////////////////////////// + PPI_CH_SETUP(PPI_CH_EXT_TRIGGER_STARTRX_EN_ENDRX_STARTX, + p_config->startrx_evt, + group1_en_tsk, + nrf_uarte_task_address_get(UART_DRV_UARTE, NRF_UARTE_TASK_STARTRX)); + + /////////////////////////////////////////////////////////////////////////////// + PPI_CH_SETUP(PPI_CH_RXSTARTED_EXT_TSK, + nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_RXSTARTED), + group2_dis_tsk, + p_config->rxstarted_tsk); + + if (p_config->endrx_evt) + { + /////////////////////////////////////////////////////////////////////////////// + PPI_CH_SETUP(PPI_CH_EXT_STOP_STOPRX, + p_config->endrx_evt, + nrf_uarte_task_address_get(UART_DRV_UARTE, NRF_UARTE_TASK_STOPRX), + group2_en_tsk); + + /////////////////////////////////////////////////////////////////////////////// + PPI_CH_SETUP(PPI_CH_EXT_STOP_GROUPS_EN, + p_config->endrx_evt, + group1_dis_tsk, + nrfx_timer_capture_task_address_get(&m_timer, 1)); + } + + ////////////////////////////////TX/////////////////////////////////////////////// + PPI_CH_SETUP(PPI_CH_ENDTX_STARTTX, + nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDTX), + nrf_uarte_task_address_get(UART_DRV_UARTE, NRF_UARTE_TASK_STARTTX), + 0); + + ////////////////////////////////TX/////////////////////////////////////////////// + PPI_CH_SETUP(PPI_CH_RXRDY_TIMER_COUNT, + nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_RXDRDY), + nrfx_timer_task_address_get(&m_timer, NRF_TIMER_TASK_COUNT), + 0); + + if (ret != NRFX_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + return NRF_SUCCESS; +/*lint -restore */ +} + +void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context) +{ + UNUSED_PARAMETER(event_type); + UNUSED_PARAMETER(p_context); +} + +ret_code_t nrf_libuarte_init(nrf_libuarte_config_t * p_config, nrf_libuarte_evt_handler_t evt_handler) +{ + ret_code_t ret; + m_evt_handler = evt_handler; + mp_cur_rx = NULL; + mp_next_rx = NULL; + mp_next_next_rx = NULL; + mp_tx = NULL; + + //UART init + nrf_gpio_pin_set(p_config->tx_pin); + nrf_gpio_cfg_output(p_config->tx_pin); + nrf_gpio_cfg_input(p_config->rx_pin, NRF_GPIO_PIN_NOPULL); + nrf_uarte_baudrate_set(UART_DRV_UARTE, p_config->baudrate); + nrf_uarte_configure(UART_DRV_UARTE, p_config->parity, p_config->hwfc); + nrf_uarte_txrx_pins_set(UART_DRV_UARTE, p_config->tx_pin, p_config->rx_pin); + + if (p_config->hwfc == NRF_UARTE_HWFC_ENABLED) + { + if (p_config->cts_pin != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_input(p_config->cts_pin, NRF_GPIO_PIN_NOPULL); + } + if (p_config->rts_pin != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_pin_set(p_config->rts_pin); + nrf_gpio_cfg_output(p_config->rts_pin); + } + nrf_uarte_hwfc_pins_set(UART_DRV_UARTE, p_config->rts_pin, p_config->cts_pin); + } + + nrf_uarte_int_enable(UART_DRV_UARTE, INTERRUPTS_MASK); + + NVIC_SetPriority(UART_DRV_IRQn, p_config->irq_priority); + NVIC_ClearPendingIRQ(UART_DRV_IRQn); + NVIC_EnableIRQ(UART_DRV_IRQn); + + nrf_uarte_enable(UART_DRV_UARTE); + + nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG; + tmr_config.mode = NRF_TIMER_MODE_COUNTER; + tmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32; + ret = nrfx_timer_init(&m_timer, &tmr_config, tmr_evt_handler); + if (ret != NRFX_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + nrfx_timer_enable(&m_timer); + nrfx_timer_clear(&m_timer); + m_last_rx_byte_cnt = 0; + m_last_pin_rx_byte_cnt = 0; + + uint32_t i; + for (i = 0; i < PPI_CH_MAX; i++) + { + ret = nrfx_ppi_channel_alloc(&m_ppi_channels[i]); + if (ret != NRFX_SUCCESS) + { + //we don't free already allocated channels, system is wrongly configured. + return NRF_ERROR_INTERNAL; + } + } + + for (i = 0; i < PPI_GROUP_MAX; i++) + { + ret = nrfx_ppi_group_alloc(&m_ppi_groups[i]); + if (ret != NRFX_SUCCESS) + { + //we don't free already allocated channels, system is wrongly configured. + return NRF_ERROR_INTERNAL; + } + } + + return ppi_configure(p_config); +} + +void nrf_libuarte_uninit(void) +{ + NVIC_DisableIRQ(UART_DRV_IRQn); + nrf_uarte_int_disable(UART_DRV_UARTE, 0xFFFFFFFF); + nrf_uarte_disable(UART_DRV_UARTE); + + nrfx_timer_disable(&m_timer); + nrfx_timer_uninit(&m_timer); + + uint32_t i; + ret_code_t ret; + for (i = 0; i < PPI_CH_MAX; i++) + { + ret = nrfx_ppi_channel_disable(m_ppi_channels[i]); + ASSERT(ret == NRFX_SUCCESS) + ret = nrfx_ppi_channel_free(m_ppi_channels[i]); + ASSERT(ret == NRFX_SUCCESS) + } + + for (i = 0; i < PPI_GROUP_MAX; i++) + { + ret = nrfx_ppi_group_free(m_ppi_groups[i]); + ASSERT(ret == NRFX_SUCCESS) + } + +} + +ret_code_t nrf_libuarte_tx(uint8_t * p_data, size_t len) +{ + if (mp_tx) + { + return NRF_ERROR_BUSY; + } + mp_tx = p_data; + m_tx_len = len; + m_tx_cur_idx = 0; + uint8_t first_chunk; + + if (len <= MAX_DMA_XFER_LEN) + { + first_chunk = len; + m_tx_chunk8 = 0; + } + else + { + uint32_t num_of_chunks = CEIL_DIV(len, MAX_DMA_XFER_LEN); + m_tx_chunk8 = len/num_of_chunks; + first_chunk = m_tx_chunk8 + len%m_tx_chunk8; + } + + NRF_LOG_DEBUG("Started TX total length:%d, first chunk:%d", len, first_chunk); + nrf_uarte_tx_buffer_set(UART_DRV_UARTE, p_data, first_chunk); + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTARTED); + nrf_uarte_task_trigger(UART_DRV_UARTE, NRF_UARTE_TASK_STARTTX); + + if (len > MAX_DMA_XFER_LEN) + { + while(nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTARTED) == 0) + { + } + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTARTED); + nrfx_err_t err = nrfx_ppi_channel_enable(m_ppi_channels[PPI_CH_ENDTX_STARTTX]); + if (err != NRFX_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + + nrf_uarte_tx_buffer_set(UART_DRV_UARTE, &p_data[first_chunk], m_tx_chunk8); + } + return NRF_SUCCESS; +} + +ret_code_t nrf_libuarte_rx_start(uint8_t * p_data, size_t len, bool ext_trigger_en) +{ + + m_chunk_size = len; + + uint32_t i; + for (i = 0; i < PPI_CH_RX_MAX; i++) + { + nrfx_err_t err = nrfx_ppi_channel_enable(m_ppi_channels[i]); + if (err != NRFX_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + } + + ASSERT(len <= MAX_DMA_XFER_LEN); + + if (p_data) + { + mp_cur_rx = p_data; + nrf_uarte_rx_buffer_set(UART_DRV_UARTE, p_data, len); + } + + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDRX); + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_RXSTARTED); + if (ext_trigger_en) + { + } + else + { + + *(uint32_t *)nrfx_ppi_task_addr_group_enable_get(m_ppi_groups[PPI_GROUP_ENDRX_STARTRX]) = 1; + nrf_uarte_task_trigger(UART_DRV_UARTE, NRF_UARTE_TASK_STARTRX); + } + NRF_LOG_DEBUG("Start continues RX. Provided buffer:0x%08X", p_data); + return NRF_SUCCESS; +} + +void nrf_libuarte_rx_buf_rsp(uint8_t * p_data, size_t len) +{ + if (mp_next_rx == NULL) + { + mp_next_rx = p_data; + NRF_LOG_DEBUG("RX buf response (next). Provided buffer:0x%08X", p_data); + nrf_uarte_rx_buffer_set(UART_DRV_UARTE, p_data, len); + } + else + { + NRF_LOG_DEBUG("RX buf response (mp_next_rx not NULL:0x%08X), Provided buffer:0x%08X", + mp_next_rx, + p_data); + mp_next_next_rx = p_data; + } +} + +void nrf_libuarte_rx_stop(void) +{ + uint32_t i; + for (i = 0; i < PPI_CH_RX_MAX; i++) + { + nrfx_err_t err = nrfx_ppi_channel_disable(m_ppi_channels[i]); + ASSERT(err == NRFX_SUCCESS); + } + + NRF_LOG_DEBUG("RX stopped."); + nrf_uarte_task_trigger(UART_DRV_UARTE, NRF_UARTE_TASK_STOPRX); +} + +void UART_DRV_IRQHandler(void) +{ + if (nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_ERROR)) + { + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_ERROR); + nrf_libuarte_evt_t evt = { + .type = NRF_LIBUARTE_EVT_ERROR + }; + m_evt_handler(&evt); + } + + if (nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_RXSTARTED)) + { + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_RXSTARTED); + + nrf_libuarte_evt_t evt = { + .type = NRF_LIBUARTE_EVT_RX_BUF_REQ, + }; + m_evt_handler(&evt); + } + + if (nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDRX)) + { + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDRX); + + uint32_t endrx_byte_cnt = nrfx_timer_capture_get(&m_timer, NRF_TIMER_CC_CHANNEL0); + uint32_t stop_byte_cnt = nrfx_timer_capture_get(&m_timer, NRF_TIMER_CC_CHANNEL1); + + uint32_t dma_amount = endrx_byte_cnt - m_last_rx_byte_cnt; + uint32_t pin_amount = stop_byte_cnt - m_last_pin_rx_byte_cnt; + NRF_LOG_DEBUG("(evt) RX dma_cnt:%d, endrx_cnt:%d, stop_cnt:%d", + dma_amount, + endrx_byte_cnt, + stop_byte_cnt); + m_last_rx_byte_cnt = endrx_byte_cnt; + m_last_pin_rx_byte_cnt = stop_byte_cnt; + + if (dma_amount || pin_amount) + { + uint32_t chunk0 = (dma_amount > m_chunk_size) ? m_chunk_size : dma_amount; + uint32_t chunk1 = dma_amount - chunk0; + + NRF_LOG_DEBUG("RX END chunk0:%d, chunk1:%d, data[0]=%d %d", + chunk0, + chunk1, + mp_cur_rx[0], + mp_cur_rx[1]); + nrf_libuarte_evt_t evt = { + .type = NRF_LIBUARTE_EVT_RX_DATA, + .data = { + .rxtx = { + .p_data = mp_cur_rx, + .length = chunk0 + } + } + }; + mp_cur_rx = mp_next_rx; + mp_next_rx = NULL; + if (mp_next_next_rx) + { + mp_next_rx = mp_next_next_rx; + mp_next_next_rx = NULL; + nrf_uarte_rx_buffer_set(UART_DRV_UARTE, mp_next_rx, m_chunk_size); + } + m_evt_handler(&evt); + + if ( chunk1 || + ((dma_amount == m_chunk_size) && (endrx_byte_cnt == stop_byte_cnt))) + { + NRF_LOG_WARNING("RX END Chunk1:%d", chunk1); + + evt.data.rxtx.length = chunk1; + evt.data.rxtx.p_data = mp_cur_rx; + + mp_cur_rx = mp_next_rx; + mp_next_rx = NULL; + m_evt_handler(&evt); + } + } + } + + if (nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTOPPED)) + { + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTOPPED); + nrf_libuarte_evt_t evt = { + .type = NRF_LIBUARTE_EVT_TX_DONE, + .data = { + .rxtx = { + .p_data = mp_tx, + .length = m_tx_len + } + } + }; + mp_tx = NULL; + m_evt_handler(&evt); + } + + if (nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDTX)) + { + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDTX); + uint8_t amount = nrf_uarte_tx_amount_get(UART_DRV_UARTE); + NRF_LOG_DEBUG("(evt) TX completed (%d)", amount); + m_tx_cur_idx += amount; + if (m_tx_cur_idx == m_tx_len) + { + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTOPPED); + nrf_uarte_task_trigger(UART_DRV_UARTE, NRF_UARTE_TASK_STOPTX); + } + else + { + size_t rem_len = (m_tx_len - m_tx_cur_idx); + if ( rem_len <= MAX_DMA_XFER_LEN) + { + nrfx_err_t err = nrfx_ppi_channel_disable(m_ppi_channels[PPI_CH_ENDTX_STARTTX]); + ASSERT(err == NRFX_SUCCESS); + } + else + { + if (nrf_uarte_event_check(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTARTED) == 0) + { + NRF_LOG_ERROR("Tx not started yet!"); + ASSERT(false); + } + nrf_uarte_event_clear(UART_DRV_UARTE, NRF_UARTE_EVENT_TXSTARTED); + nrf_uarte_tx_buffer_set(UART_DRV_UARTE, &mp_tx[m_tx_cur_idx + m_tx_chunk8], m_tx_chunk8); + } + } + + } +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte.h new file mode 100644 index 0000000..0c9d97b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte.h @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_LIBUARTE_H +#define NRF_LIBUARTE_H + +#include "sdk_errors.h" +#include "nrf_uarte.h" +#include <stdint.h> +#include <stdbool.h> + +/** + * @defgroup nrf_libuarte libUARTE + * @ingroup app_common + * + * @brief Module for reliable communication over UARTE. + * + * @{ + */ + +typedef enum +{ + NRF_LIBUARTE_EVT_RX_DATA, ///< Data received. + NRF_LIBUARTE_EVT_RX_BUF_REQ, ///< Requesting new buffer for receiving data. + NRF_LIBUARTE_EVT_TX_DONE, ///< Requested TX transfer completed. + NRF_LIBUARTE_EVT_ERROR ///< Error reported by the UARTE peripheral. +} nrf_libuarte_evt_type_t; + +typedef struct +{ + uint8_t * p_data; ///< Pointer to the data to be sent or received. + size_t length; ///< Length of the data. +} nrf_libuarte_data_t; + +typedef struct +{ + nrf_libuarte_evt_type_t type; ///< Event type. + union { + nrf_libuarte_data_t rxtx; ///< Data provided for transfer completion events. + } data; +} nrf_libuarte_evt_t; + +typedef struct { + uint32_t tx_pin; ///< TXD pin number. + uint32_t rx_pin; ///< RXD pin number. + uint32_t cts_pin; ///< CTS pin number. + uint32_t rts_pin; ///< RTS pin number. + uint32_t startrx_evt; ///< Event to trigger STARTRX task in UARTE. + uint32_t endrx_evt; ///< Event to trigger STOPRX task in UARTE. + uint32_t rxstarted_tsk; ///< Task to be triggered when RXSTARTED UARTE event occurs. + uint32_t rxdone_tsk; ///< Task to be triggered when ENDRX UARTE event occurs. + nrf_uarte_hwfc_t hwfc; ///< Flow control configuration. + nrf_uarte_parity_t parity; ///< Parity configuration. + nrf_uarte_baudrate_t baudrate; ///< Baud rate. + uint8_t irq_priority; ///< Interrupt priority. +} nrf_libuarte_config_t; + +typedef void (*nrf_libuarte_evt_handler_t)(nrf_libuarte_evt_t * p_evt); + +/** + * @brief Function for initializing the libUARTE library. + * + * @param[in] p_config Pointer to the structure with initial configuration. + * @param[in] evt_handler Event handler provided by the user. Must not be NULL. + * + * @return NRF_SUCCESS when properly initialized. NRF_ERROR_INTERNAL otherwise. + */ +ret_code_t nrf_libuarte_init(nrf_libuarte_config_t * p_config, nrf_libuarte_evt_handler_t evt_handler); + +/** @brief Function for uninitializing the libUARTE library. */ +void nrf_libuarte_uninit(void); + +/** + * @brief Function for sending data over UARTE using EasyDMA. + * + * @param[in] p_data Pointer to data. + * @param[in] len Number of bytes to send. + * + * @retval NRF_ERROR_BUSY Data is transferring. + * @retval NRF_ERROR_INTERNAL Error during PPI channel configuration. + * @retval NRF_SUCCESS Buffer set for sending. + */ +ret_code_t nrf_libuarte_tx(uint8_t * p_data, size_t len); + +/** + * @brief Function for starting receiving data with additional configuration of external + * trigger to start receiving. + * + * @param p_data Pointer to data. + * @param len Number of bytes to receive. Maximum possible length is + * dependent on the used SoC (see the MAXCNT register + * description in the Product Specification). The library + * checks it with an assertion. + * @param ext_trigger_en True to disable immediate start. + * + * @retval NRF_ERROR_INTERNAL Error during PPI channel configuration. + * @retval NRF_SUCCESS Buffer set for receiving. + */ +ret_code_t nrf_libuarte_rx_start(uint8_t * p_data, size_t len, bool ext_trigger_en); + +/** + * @brief Function for setting a buffer for data that will be later received in UARTE. + * + * @param p_data Pointer to data. + * @param len Number of bytes to receive. Maximum possible length is + * dependent on the used SoC (see the MAXCNT register + * description in the Product Specification). The library + * checks it with an assertion. + */ +void nrf_libuarte_rx_buf_rsp(uint8_t * p_data, size_t len); + +/** @brief Function for stopping receiving data over UARTE. */ +void nrf_libuarte_rx_stop(void); + +/** @} */ + +#endif //NRF_libuarte_H diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte_async.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte_async.c new file mode 100644 index 0000000..5c5a639 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte_async.c @@ -0,0 +1,365 @@ +/** + * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "sdk_config.h" +#include "nrf_libuarte_async.h" +#include "nrf_libuarte.h" +#include "app_error.h" +#include "nrf_balloc.h" +#include "nrfx_timer.h" +#include "nrfx_ppi.h" +#include "nrf_uart.h" +#include "nrf_queue.h" + +#define NRF_LOG_MODULE_NAME libUARTE_async +#if NRF_LIBUARTE_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL NRF_LIBUARTE_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR NRF_LIBUARTE_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR NRF_LIBUARTE_CONFIG_DEBUG_COLOR +#else // NRF_LIBUARTE_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL 0 +#endif // NRF_LIBUARTE_CONFIG_LOG_ENABLED +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +static nrf_libuarte_async_evt_handler m_evt_handler; +#define POOL_SZ 3UL +#define MAX_CHUNK_SZ 255UL + +NRF_BALLOC_DEF(m_rx_pool, MAX_CHUNK_SZ, POOL_SZ); + +NRF_QUEUE_DEF(uint8_t *, m_rxdata_queue, 3, NRF_QUEUE_MODE_NO_OVERFLOW); + +#define UART_DRV_TIMER CONCAT_2(NRF_TIMER, NRF_LIBUARTE_CONFIG_TIMER_USED) +#define UART_DRV_UARTE CONCAT_2(NRF_UARTE, NRF_LIBUARTE_CONFIG_UARTE_USED) + +static nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(NRF_LIBUARTE_ASYNC_CONFIG_TIMER_USED); + +#if CONCAT_3(NRFX_TIMER, NRF_LIBUARTE_ASYNC_CONFIG_TIMER_USED,_ENABLED) == 0 +#error "Timer instance not enabled" +#endif + +typedef enum +{ + PPI_CH_RXRDY_CLEAR, + PPI_CH_COMPARE_SHUTDOWN, + PPI_CH_MAX +} nrf_libuarte_async_ppi_channel_t; + +static nrf_ppi_channel_t m_ppi_channels[PPI_CH_MAX]; +static int32_t m_alloc_cnt; +static uint32_t m_rx_count; +static uint32_t m_sub_rx_count; +static uint8_t * mp_curr_rx_buf; +static uint32_t m_rx_free_cnt; +static size_t m_rx_chunk_size; + +#define PPI_CH_SETUP(_ch, _evt, _tsk, _fork) \ + ret = nrfx_ppi_channel_assign(m_ppi_channels[_ch], _evt, _tsk); \ + if (ret != NRF_SUCCESS) \ + { \ + return NRF_ERROR_INTERNAL; \ + } \ + if (_fork) \ + { \ + ret = nrfx_ppi_channel_fork_assign(m_ppi_channels[_ch], _fork); \ + if (ret != NRF_SUCCESS) \ + { \ + return NRF_ERROR_INTERNAL; \ + } \ + } + +static void uart_evt_handler(nrf_libuarte_evt_t * p_evt) +{ + ret_code_t ret; + switch (p_evt->type) + { + case NRF_LIBUARTE_EVT_TX_DONE: + { + NRF_LOG_DEBUG("(evt) TX completed (%d)", p_evt->data.rxtx.length); + nrf_libuarte_async_evt_t evt = { + .type = NRF_LIBUARTE_ASYNC_EVT_TX_DONE, + .data.rxtx.p_data = p_evt->data.rxtx.p_data, + .data.rxtx.length = p_evt->data.rxtx.length, + }; + m_evt_handler(&evt); + break; + } + case NRF_LIBUARTE_EVT_RX_BUF_REQ: + { + uint8_t * p_data = nrf_balloc_alloc(&m_rx_pool); + if (p_data) + { + ret = nrf_queue_push(&m_rxdata_queue, &p_data); + if (ret != NRF_SUCCESS) + { + NRF_LOG_ERROR("(evt) RX buffer queue full."); + APP_ERROR_CHECK_BOOL(false); + } + + m_alloc_cnt++; + nrf_libuarte_rx_buf_rsp(p_data, m_rx_chunk_size); + } + else + { + NRF_LOG_ERROR("(evt) Failed to allocate buffer for RX."); + APP_ERROR_CHECK_BOOL(false); + } + break; + } + case NRF_LIBUARTE_EVT_RX_DATA: + { + + uint32_t rx_amount = p_evt->data.rxtx.length - m_sub_rx_count; + if (rx_amount) + { + m_rx_count += rx_amount; + nrf_libuarte_async_evt_t evt = { + .type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA, + .data.rxtx.p_data = &p_evt->data.rxtx.p_data[m_sub_rx_count], + .data.rxtx.length = rx_amount, + }; + NRF_LOG_DEBUG("(evt) RX: %d (addr:0x%08X, internal index: %d)", + rx_amount, + p_evt->data.rxtx.p_data, + m_sub_rx_count); + + m_sub_rx_count = 0; + + if(p_evt->data.rxtx.p_data != mp_curr_rx_buf) + { + NRF_LOG_ERROR("(evt) RX buffer address mismatch"); + } + + ret = nrf_queue_pop(&m_rxdata_queue, &mp_curr_rx_buf); + if (ret != NRF_SUCCESS) + { + NRF_LOG_ERROR("RX buffer queue empty."); + APP_ERROR_CHECK_BOOL(false); + } + + m_evt_handler(&evt); + } + else + { + NRF_LOG_ERROR("(evt) RX with 0 length: 0x%08X", p_evt->data.rxtx.p_data); + //zero length packet is freed immediately and not forwarded to the application. + APP_ERROR_CHECK_BOOL(false); + } + break; + } + default: + APP_ERROR_CHECK_BOOL(false); + break; + } +} + +static void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context) +{ + uint32_t capt_rx_count = UART_DRV_TIMER->CC[2]; + + if (capt_rx_count > m_rx_count) + { + uint32_t rx_amount = capt_rx_count - m_rx_count; + nrf_libuarte_async_evt_t evt = { + .type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA, + .data.rxtx.p_data = &mp_curr_rx_buf[m_sub_rx_count], + .data.rxtx.length = rx_amount, + }; + NRF_LOG_DEBUG("(tmr evt) RX: %d (addr:0x%08X, internal index: %d)", + rx_amount, + evt.data.rxtx.p_data, + m_sub_rx_count); + + m_sub_rx_count += rx_amount; + m_rx_count = capt_rx_count; + m_evt_handler(&evt); + } +} + +ret_code_t nrf_libuarte_async_init(nrf_libuarte_async_config_t const * p_config, nrf_libuarte_async_evt_handler evt_handler) +{ + ret_code_t ret; + + m_evt_handler = evt_handler; + m_rx_count = 0; + mp_curr_rx_buf = NULL; + m_rx_free_cnt = 0; + m_sub_rx_count = 0; + m_alloc_cnt = 0; + + nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG; + tmr_config.frequency = NRF_TIMER_FREQ_1MHz; + ret = nrfx_timer_init(&m_timer, &tmr_config, tmr_evt_handler); + if (ret != NRFX_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + nrfx_timer_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, p_config->timeout_us, true); + + uint32_t i; + for (i = 0; i < PPI_CH_MAX; i++) + { + ret = nrfx_ppi_channel_alloc(&m_ppi_channels[i]); + if (ret != NRFX_SUCCESS) + { + //we don't free already allocated channels, system is wrongly configured. + return NRF_ERROR_INTERNAL; + } + } + +/*lint -save -e666 */ + PPI_CH_SETUP(m_ppi_channels[PPI_CH_RXRDY_CLEAR], + nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_RXDRDY), + nrfx_timer_task_address_get(&m_timer, NRF_TIMER_TASK_START), + nrfx_timer_task_address_get(&m_timer, NRF_TIMER_TASK_CLEAR)); + + PPI_CH_SETUP(m_ppi_channels[PPI_CH_COMPARE_SHUTDOWN], + nrfx_timer_compare_event_address_get(&m_timer, 0), + nrfx_timer_task_address_get(&m_timer, NRF_TIMER_TASK_SHUTDOWN), + (uint32_t)&UART_DRV_TIMER->TASKS_CAPTURE[2]); + +/*lint -restore */ + + nrf_libuarte_config_t uart_config = { + .tx_pin = p_config->tx_pin, + .rx_pin = p_config->rx_pin, + .cts_pin = p_config->cts_pin, + .rts_pin = p_config->rts_pin, + .startrx_evt = nrf_uarte_event_address_get(UART_DRV_UARTE, NRF_UARTE_EVENT_ENDRX), + .endrx_evt = 0, + .rxstarted_tsk = 0, + .rxdone_tsk = 0, + .hwfc = p_config->hwfc, + .parity = p_config->parity, + .baudrate = p_config->baudrate, + .irq_priority = 7, + }; + + ret = nrf_libuarte_init(&uart_config, uart_evt_handler); + if (ret != NRF_SUCCESS) + { + return ret; + } + + ret = nrf_balloc_init(&m_rx_pool); + if (ret != NRF_SUCCESS) + { + return ret; + } + + nrf_queue_reset(&m_rxdata_queue); + + return ret; +} + +void nrf_libuarte_async_uninit(void) +{ + nrfx_err_t err = nrfx_ppi_channel_disable(m_ppi_channels[PPI_CH_RXRDY_CLEAR]); + APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS); + nrf_libuarte_uninit(); + nrfx_timer_disable(&m_timer); + nrfx_timer_uninit(&m_timer); + + uint32_t i; + ret_code_t ret; + for (i = 0; i < PPI_CH_MAX; i++) + { + ret = nrfx_ppi_channel_disable(m_ppi_channels[i]); + ASSERT(ret == NRF_SUCCESS) + ret = nrfx_ppi_channel_free(m_ppi_channels[i]); + ASSERT(ret == NRF_SUCCESS) + } +} + +void nrf_libuarte_async_enable(size_t chunk_size) +{ + ASSERT(chunk_size <= MAX_CHUNK_SZ); + uint8_t * p_data; + p_data = nrf_balloc_alloc(&m_rx_pool); + m_alloc_cnt++; + if (p_data == NULL) + { + APP_ERROR_CHECK_BOOL(false); + } + nrfx_timer_clear(&m_timer); + nrfx_err_t err = nrfx_ppi_channel_enable(m_ppi_channels[PPI_CH_RXRDY_CLEAR]); + APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS); + err = nrfx_ppi_channel_enable(m_ppi_channels[PPI_CH_COMPARE_SHUTDOWN]); + APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS); + + mp_curr_rx_buf = p_data; + m_rx_chunk_size = chunk_size; + ret_code_t ret = nrf_libuarte_rx_start(p_data, chunk_size, false); + APP_ERROR_CHECK_BOOL(ret == NRF_SUCCESS); +} + +ret_code_t nrf_libuarte_async_tx(uint8_t * p_data, size_t length) +{ + return nrf_libuarte_tx(p_data, length); +} + +void nrf_libuarte_async_rx_free(uint8_t * p_data, size_t length) +{ + m_rx_free_cnt += length; + if (m_rx_free_cnt == m_rx_chunk_size) + { + p_data -= (m_rx_free_cnt - length); + m_rx_free_cnt = 0; + nrf_balloc_free(&m_rx_pool, p_data); + + m_alloc_cnt--; + if (m_alloc_cnt<0) + { + NRF_LOG_ERROR("Freeing more RX buffers than allocated."); + APP_ERROR_CHECK_BOOL(false); + } + NRF_LOG_INFO("Freeing full buffer 0x%08X, %d, (currently allocated:%d).",p_data, length, m_alloc_cnt); + } + else if (m_rx_free_cnt > m_rx_chunk_size) + { + NRF_LOG_ERROR("Unexpected RX free input parameter.") + APP_ERROR_CHECK_BOOL(false); + } + else + { + NRF_LOG_INFO("Freeing partial buffer: 0x%08X, length:%d", p_data, length) + } + +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte_async.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte_async.h new file mode 100644 index 0000000..9930a81 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/experimental_libuarte/nrf_libuarte_async.h @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef UART_ASYNC_H +#define UART_ASYNC_H +#include <stdint.h> +#include "sdk_errors.h" +#include <hal/nrf_uarte.h> + +/** @brief Types of libuarte driver events. */ +typedef enum +{ + NRF_LIBUARTE_ASYNC_EVT_RX_DATA, ///< Requested TX transfer completed. + NRF_LIBUARTE_ASYNC_EVT_TX_DONE, ///< Requested RX transfer completed. + NRF_LIBUARTE_ASYNC_EVT_ERROR ///< Error reported by UARTE peripheral. +} nrf_libuarte_async_evt_type_t; + +/** @brief Structure for libuarte async transfer completion event. */ +typedef struct +{ + uint8_t * p_data; ///< Pointer to memory used for transfer. + size_t length; ///< Number of bytes transfered. +} nrf_libuarte_async_data_t; + +/** @brief Structure for libuarte async configuration. */ +typedef struct +{ + uint32_t rx_pin; ///< RXD pin number. + uint32_t tx_pin; ///< TXD pin number. + uint32_t cts_pin; ///< CTS pin number. + uint32_t rts_pin; ///< RTS pin number. + uint32_t timeout_us; ///< Receiver timeout in us unit. + nrf_uarte_hwfc_t hwfc; ///< Flow control configuration. + nrf_uarte_parity_t parity; ///< Parity configuration. + nrf_uarte_baudrate_t baudrate; ///< Baudrate. +} nrf_libuarte_async_config_t; + +/** @brief Structure for libuarte error event. */ +typedef struct +{ + nrf_libuarte_async_evt_type_t type; ///< Event type. + union { + nrf_libuarte_async_data_t rxtx; ///< RXD/TXD data. + } data; ///< Union with data. +} nrf_libuarte_async_evt_t; + +/** + * @brief Interrupt event handler. + * + * @param[in] p_evt Pointer to event structure. Event is allocated on the stack so it is available + * only within the context of the event handler. + */ +typedef void (*nrf_libuarte_async_evt_handler)(nrf_libuarte_async_evt_t * p_evt); + +/** + * @brief Function for initializing the libuarte async library. + * + * @param[in] p_config Pointer to the structure with initial configuration. + * @param[in] evt_handler Event handler provided by the user. Must not be NULL. + * + * @return NRF_SUCCESS when properly initialized. NRF_ERROR_INTERNAL otherwise. + */ +ret_code_t nrf_libuarte_async_init(nrf_libuarte_async_config_t const * p_config, + nrf_libuarte_async_evt_handler evt_handler); + +/** @brief Function for uninitializing the libuarte async library */ +void nrf_libuarte_async_uninit(void); + +/** + * @brief Funtrion for setting buffer and its size for received data. + * + * @param chunk_size Number of bytes in chunk of data + */ +void nrf_libuarte_async_enable(size_t chunk_size); + +/** + * @brief Function for sending data asynchronously over UARTE. + * + * @param[in] p_data Pointer to data. + * @param[in] length Number of bytes to send. Maximum possible length is + * dependent on the used SoC (see the MAXCNT register + * description in the Product Specification). The library + * checks it with assertion. + * + * @retval NRF_ERROR_BUSY Data is transferring. + * @retval NRF_ERROR_INTERNAL Error during configuration. + * @retval NRF_SUCCESS Buffer set for sending. + */ +ret_code_t nrf_libuarte_async_tx(uint8_t * p_data, size_t length); + +/** + * @brief Function for deallocating received buffer data. + * + * @param[in] p_data Pointer to data. + * @param[in] length Number of bytes to free. + */ +void nrf_libuarte_async_rx_free(uint8_t * p_data, size_t length); + +#endif //UART_ASYNC_H |