diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/hci/hci_slip.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/hci/hci_slip.c | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/hci/hci_slip.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/hci/hci_slip.c new file mode 100644 index 0000000..ab70b82 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/hci/hci_slip.c @@ -0,0 +1,457 @@ +/** + * Copyright (c) 2013 - 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_common.h" +#if NRF_MODULE_ENABLED(HCI_SLIP) +#include "hci_slip.h" +#include <stdlib.h> +#include "app_uart.h" +#include "nrf_error.h" + +#define APP_SLIP_END 0xC0 /**< SLIP code for identifying the beginning and end of a packet frame.. */ +#define APP_SLIP_ESC 0xDB /**< SLIP escape code. This code is used to specify that the following character is specially encoded. */ +#define APP_SLIP_ESC_END 0xDC /**< SLIP special code. When this code follows 0xDB, this character is interpreted as payload data 0xC0.. */ +#define APP_SLIP_ESC_ESC 0xDD /**< SLIP special code. When this code follows 0xDB, this character is interpreted as payload data 0xDB. */ + +/** @brief States for the SLIP state machine. */ +typedef enum +{ + SLIP_OFF, /**< SLIP state OFF. */ + SLIP_READY, /**< SLIP state ON. */ + SLIP_TRANSMITTING, /**< SLIP state is transmitting indicating write() has been called but data transmission has not completed. */ +} slip_states_t; + +static slip_states_t m_current_state = SLIP_OFF; /** Current state for the SLIP TX state machine. */ + +static hci_slip_event_handler_t m_slip_event_handler; /** Event callback function for handling of SLIP events, @ref hci_slip_evt_type_t . */ + +static const uint8_t * mp_tx_buffer; /** Pointer to the current TX buffer that is in transmission. */ +static uint32_t m_tx_buffer_length; /** Length of the current TX buffer that is in transmission. */ +static volatile uint32_t m_tx_buffer_index; /** Current index for next byte to transmit in the mp_tx_buffer. */ + +static uint8_t * mp_rx_buffer; /** Pointer to the current RX buffer where the next SLIP decoded packet will be stored. */ +static uint32_t m_rx_buffer_length; /** Length of the current RX buffer. */ +static uint32_t m_rx_received_count; /** Number of SLIP decoded bytes received and stored in mp_rx_buffer. */ + + +/**@brief Function for parsing bytes received on the UART until a SLIP escape byte is received. + * + * @param[in] byte Byte received in UART module. + */ +static void handle_rx_byte_default(uint8_t byte); + +/**@brief Function for parsing bytes received on the UART until SLIP end byte is received. + * + * @param[in] byte Byte received in UART module. + */ +static void handle_rx_byte_wait_start(uint8_t byte); + +/**@brief Function for decoding a received SLIP escape byte. + * It will ensure correct decoding of the byte following the SLIP escape byte. + * + * @param[in] byte Byte received in UART module. + */ +static void handle_rx_byte_esc(uint8_t byte); + +/**@brief Function pointer for parsing and decoding SLIP bytes from the UART module. + * + * @param[in] byte Byte received in UART module. + */ +static void (*handle_rx_byte) (uint8_t byte) = handle_rx_byte_wait_start; + +/**@brief Function pointer for sending a byte through the UART module. + */ +static uint32_t send_tx_byte_default(void); + +/**@brief Function for transferring a SLIP escape byte (0xDB) when special bytes are transferred, + * that is 0xC0 and 0xDB. + */ +static uint32_t send_tx_byte_esc(void); + +/**@brief Function for transferring a byte when it collides with SLIP commands and follows the SLIP + * escape byte, that is 0xC0 => 0xDC and 0xDB => 0xDD. + */ +static uint32_t send_tx_byte_encoded(void); + +/**@brief Function for transferring the SLIP end frame byte, 0xC0. + */ +static uint32_t send_tx_byte_end(void); + +/**@brief Function pointer for sending a byte through the UART module. + */ +uint32_t (*send_tx_byte) (void) = send_tx_byte_default; + + +static uint32_t send_tx_byte_end(void) +{ + uint32_t err_code = app_uart_put(APP_SLIP_END); + + if ((err_code == NRF_SUCCESS) && (m_tx_buffer_index == 0)) + { + // Packet transmission started. + send_tx_byte = send_tx_byte_default; + } + + return err_code; +} + + +static uint32_t send_tx_byte_default(void) +{ + uint32_t err_code = app_uart_put(mp_tx_buffer[m_tx_buffer_index]); + + if (err_code == NRF_SUCCESS) + { + m_tx_buffer_index++; + } + + return err_code; +} + + +static uint32_t send_tx_byte_encoded(void) +{ + uint32_t err_code; + + switch (mp_tx_buffer[m_tx_buffer_index]) + { + case APP_SLIP_END: + err_code = app_uart_put(APP_SLIP_ESC_END); + break; + + case APP_SLIP_ESC: + err_code = app_uart_put(APP_SLIP_ESC_ESC); + break; + + default: + err_code = NRF_ERROR_NO_MEM; + break; + } + + if (err_code == NRF_SUCCESS) + { + m_tx_buffer_index++; + send_tx_byte = send_tx_byte_default; + } + + return err_code; +} + + +static uint32_t send_tx_byte_esc(void) +{ + uint32_t err_code = app_uart_put(APP_SLIP_ESC); + + if (err_code == NRF_SUCCESS) + { + send_tx_byte = send_tx_byte_encoded; + } + + return err_code; +} + + +/** @brief Function for transferring the content of the mp_tx_buffer to the UART. + * It continues to transfer bytes until the UART buffer is full or the complete buffer is + * transferred. + */ +static void transmit_buffer(void) +{ + uint32_t err_code = NRF_SUCCESS; + + while (m_tx_buffer_index < m_tx_buffer_length) + { + if ((mp_tx_buffer[m_tx_buffer_index] == APP_SLIP_END || + mp_tx_buffer[m_tx_buffer_index] == APP_SLIP_ESC) && + send_tx_byte == send_tx_byte_default) + { + send_tx_byte = send_tx_byte_esc; + } + + err_code = send_tx_byte(); + + if (err_code == NRF_ERROR_NO_MEM || err_code == NRF_ERROR_BUSY) + { + // No memory left in UART TX buffer. Abort and wait for APP_UART_TX_EMPTY to continue. + return; + } + } + + send_tx_byte = send_tx_byte_end; + + err_code = send_tx_byte(); + + if (err_code == NRF_SUCCESS) + { + // Packet transmission ended. Notify higher level. + m_current_state = SLIP_READY; + + if (m_slip_event_handler != NULL) + { + hci_slip_evt_t event = {HCI_SLIP_TX_DONE, mp_tx_buffer, m_tx_buffer_index}; + + m_slip_event_handler(event); + } + } +} + + +/** @brief Function for handling the reception of a SLIP end byte. + * If the number of bytes received is greater than zero it will call m_slip_event_handler + * with number of bytes received and invalidate the mp_rx_buffer to protect against data + * corruption. + * No new bytes can be received until a new RX buffer is supplied. + */ +static void handle_slip_end(void) +{ + if (m_rx_received_count > 0) + { + // Full packet received, push it up. + if (m_slip_event_handler != NULL) + { + hci_slip_evt_t event = {HCI_SLIP_RX_RDY, mp_rx_buffer, m_rx_received_count}; + + m_rx_received_count = 0; + mp_rx_buffer = NULL; + + m_slip_event_handler(event); + } + } +} + + +static void handle_rx_byte_esc(uint8_t byte) +{ + switch (byte) + { + case APP_SLIP_END: + handle_slip_end(); + break; + + case APP_SLIP_ESC_END: + mp_rx_buffer[m_rx_received_count++] = APP_SLIP_END; + break; + + case APP_SLIP_ESC_ESC: + mp_rx_buffer[m_rx_received_count++] = APP_SLIP_ESC; + break; + + default: + mp_rx_buffer[m_rx_received_count++] = byte; + break; + } + + handle_rx_byte = handle_rx_byte_default; +} + + +static void handle_rx_byte_default(uint8_t byte) +{ + switch (byte) + { + case APP_SLIP_END: + handle_slip_end(); + break; + + case APP_SLIP_ESC: + handle_rx_byte = handle_rx_byte_esc; + break; + + default: + mp_rx_buffer[m_rx_received_count++] = byte; + break; + } +} + + +static void handle_rx_byte_wait_start(uint8_t byte) +{ + if (byte == APP_SLIP_END) + { + handle_rx_byte = handle_rx_byte_default; + } +} + + +/** @brief Function for checking the current index and length of the RX buffer to determine if the + * buffer is full. If an event handler has been registered, the callback function will + * be executed.. + * + * @retval true If RX buffer has overflowed. + * @retval false otherwise. + * + */ +static bool rx_buffer_overflowed(void) +{ + if (mp_rx_buffer == NULL || m_rx_received_count >= m_rx_buffer_length) + { + if (m_slip_event_handler != NULL) + { + hci_slip_evt_t event = {HCI_SLIP_RX_OVERFLOW, mp_rx_buffer, m_rx_received_count}; + m_slip_event_handler(event); + } + + return true; + } + + return false; +} + + +/** @brief Function for handling the UART module event. It parses events from the UART when + * bytes are received/transmitted. + * + * @param[in] uart_event Event received from app_uart module. + */ +static void slip_uart_eventhandler(app_uart_evt_t * uart_event) +{ + if (uart_event->evt_type == APP_UART_TX_EMPTY && m_current_state == SLIP_TRANSMITTING) + { + transmit_buffer(); + } + + if ((uart_event->evt_type == APP_UART_DATA) && (!rx_buffer_overflowed())) + { + handle_rx_byte(uart_event->data.value); + } +} + + +/** @brief Function for enabling the UART module when the SLIP layer is opened. + */ +static uint32_t slip_uart_open(void) +{ + uint32_t err_code; + + app_uart_comm_params_t comm_params = + { + HCI_UART_RX_PIN, + HCI_UART_TX_PIN, + HCI_UART_RTS_PIN, + HCI_UART_CTS_PIN, + (app_uart_flow_control_t)HCI_UART_FLOW_CONTROL, + false, + HCI_UART_BAUDRATE + }; + + err_code = app_uart_init(&comm_params, + NULL, + slip_uart_eventhandler, + APP_IRQ_PRIORITY_LOWEST); + + if (err_code == NRF_SUCCESS) + { + m_current_state = SLIP_READY; + } + + return err_code; +} + + +uint32_t hci_slip_evt_handler_register(hci_slip_event_handler_t event_handler) +{ + m_slip_event_handler = event_handler; + + return NRF_SUCCESS; +} + + +uint32_t hci_slip_open() +{ + switch (m_current_state) + { + case SLIP_OFF: + return slip_uart_open(); + + default: + // Do nothing. + break; + } + + return NRF_SUCCESS; +} + + +uint32_t hci_slip_close() +{ + m_current_state = SLIP_OFF; + uint32_t err_code = app_uart_close(); + + return err_code; +} + + +uint32_t hci_slip_write(const uint8_t * p_buffer, uint32_t length) +{ + if (p_buffer == NULL) + { + return NRF_ERROR_INVALID_ADDR; + } + + switch (m_current_state) + { + case SLIP_READY: + m_tx_buffer_index = 0; + m_tx_buffer_length = length; + mp_tx_buffer = p_buffer; + m_current_state = SLIP_TRANSMITTING; + send_tx_byte = send_tx_byte_end; + + transmit_buffer(); + return NRF_SUCCESS; + + case SLIP_TRANSMITTING: + return NRF_ERROR_NO_MEM; + + case SLIP_OFF: + default: + return NRF_ERROR_INVALID_STATE; + } +} + + +uint32_t hci_slip_rx_buffer_register(uint8_t * p_buffer, uint32_t length) +{ + mp_rx_buffer = p_buffer; + m_rx_buffer_length = length; + m_rx_received_count = 0; + handle_rx_byte = handle_rx_byte_wait_start; + return NRF_SUCCESS; +} +#endif //NRF_MODULE_ENABLED(HCI_SLIP) |