123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- /**
- * Copyright (c) 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)
- }
- }
|