/** * Copyright (c) 2014 - 2017, 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 #include #include "app_error.h" #include "ser_config.h" #include "ser_phy.h" #include "ser_hal_transport.h" /** * @brief States of the RX state machine. */ typedef enum { HAL_TRANSP_RX_STATE_CLOSED = 0, HAL_TRANSP_RX_STATE_IDLE, HAL_TRANSP_RX_STATE_RECEIVING, HAL_TRANSP_RX_STATE_DROPPING, HAL_TRANSP_RX_STATE_RECEIVED, HAL_TRANSP_RX_STATE_RECEIVED_PENDING_BUF_REQ, HAL_TRANSP_RX_STATE_RECEIVED_DROPPING, HAL_TRANSP_RX_STATE_MAX }ser_hal_transp_rx_states_t; /** * @brief States of the TX state machine. */ typedef enum { HAL_TRANSP_TX_STATE_CLOSED = 0, HAL_TRANSP_TX_STATE_IDLE, HAL_TRANSP_TX_STATE_TX_ALLOCATED, HAL_TRANSP_TX_STATE_TRANSMITTING, HAL_TRANSP_TX_STATE_TRANSMITTED, HAL_TRANSP_TX_STATE_MAX }ser_hal_transp_tx_states_t; /** * @brief RX state. */ static ser_hal_transp_rx_states_t m_rx_state = HAL_TRANSP_RX_STATE_CLOSED; /** * @brief TX state. */ static ser_hal_transp_tx_states_t m_tx_state = HAL_TRANSP_TX_STATE_CLOSED; /** * @brief Transmission buffer. */ static uint8_t m_tx_buffer[SER_HAL_TRANSPORT_TX_MAX_PKT_SIZE]; /** * @brief Reception buffer. */ static uint8_t m_rx_buffer[SER_HAL_TRANSPORT_RX_MAX_PKT_SIZE]; /** * @brief Callback function handler for Serialization HAL Transport layer events. */ static ser_hal_transport_events_handler_t m_events_handler = NULL; /** * @brief A callback function to be used to handle a PHY module events. This function is called in * an interrupt context. */ static void phy_events_handler(ser_phy_evt_t phy_event) { uint32_t err_code = 0; ser_hal_transport_evt_t hal_transp_event; memset(&hal_transp_event, 0, sizeof (ser_hal_transport_evt_t)); hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_TYPE_MAX; switch (phy_event.evt_type) { case SER_PHY_EVT_TX_PKT_SENT: { if (HAL_TRANSP_TX_STATE_TRANSMITTING == m_tx_state) { m_tx_state = HAL_TRANSP_TX_STATE_TRANSMITTED; err_code = ser_hal_transport_tx_pkt_free(m_tx_buffer); APP_ERROR_CHECK(err_code); /* An event to an upper layer that a packet has been transmitted. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_TX_PKT_SENT; m_events_handler(hal_transp_event); } else { /* Lower layer should not generate this event in current state. */ APP_ERROR_CHECK_BOOL(false); } break; } case SER_PHY_EVT_RX_BUF_REQUEST: { /* An event to an upper layer that a packet is being scheduled to receive or to drop. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_RX_PKT_RECEIVING; /* Receive or drop a packet. */ if (phy_event.evt_params.rx_buf_request.num_of_bytes <= sizeof (m_rx_buffer)) { if (HAL_TRANSP_RX_STATE_IDLE == m_rx_state) { m_events_handler(hal_transp_event); err_code = ser_phy_rx_buf_set(m_rx_buffer); APP_ERROR_CHECK(err_code); m_rx_state = HAL_TRANSP_RX_STATE_RECEIVING; } else if (HAL_TRANSP_RX_STATE_RECEIVED == m_rx_state) { /* It is OK to get know higher layer at this point that we are going to receive * a new packet even though we will start receiving when rx buffer is freed. */ m_events_handler(hal_transp_event); m_rx_state = HAL_TRANSP_RX_STATE_RECEIVED_PENDING_BUF_REQ; } else { /* Lower layer should not generate this event in current state. */ APP_ERROR_CHECK_BOOL(false); } } else { /* There is not enough memory but packet has to be received to dummy location. */ if (HAL_TRANSP_RX_STATE_IDLE == m_rx_state) { m_events_handler(hal_transp_event); err_code = ser_phy_rx_buf_set(NULL); APP_ERROR_CHECK(err_code); m_rx_state = HAL_TRANSP_RX_STATE_DROPPING; } else if (HAL_TRANSP_RX_STATE_RECEIVED == m_rx_state) { m_events_handler(hal_transp_event); err_code = ser_phy_rx_buf_set(NULL); APP_ERROR_CHECK(err_code); m_rx_state = HAL_TRANSP_RX_STATE_RECEIVED_DROPPING; } else { /* Lower layer should not generate this event in current state. */ APP_ERROR_CHECK_BOOL(false); } } break; } case SER_PHY_EVT_RX_PKT_RECEIVED: { if (HAL_TRANSP_RX_STATE_RECEIVING == m_rx_state) { m_rx_state = HAL_TRANSP_RX_STATE_RECEIVED; /* Generate the event to an upper layer. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_RX_PKT_RECEIVED; hal_transp_event.evt_params.rx_pkt_received.p_buffer = phy_event.evt_params.rx_pkt_received.p_buffer; hal_transp_event.evt_params.rx_pkt_received.num_of_bytes = phy_event.evt_params.rx_pkt_received.num_of_bytes; m_events_handler(hal_transp_event); } else { /* Lower layer should not generate this event in current state. */ APP_ERROR_CHECK_BOOL(false); } break; } case SER_PHY_EVT_RX_PKT_DROPPED: { if (HAL_TRANSP_RX_STATE_DROPPING == m_rx_state) { /* Generate the event to an upper layer. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_RX_PKT_DROPPED; m_events_handler(hal_transp_event); m_rx_state = HAL_TRANSP_RX_STATE_IDLE; } else if (HAL_TRANSP_RX_STATE_RECEIVED_DROPPING == m_rx_state) { /* Generate the event to an upper layer. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_RX_PKT_DROPPED; m_events_handler(hal_transp_event); m_rx_state = HAL_TRANSP_RX_STATE_RECEIVED; } else { /* Lower layer should not generate this event in current state. */ APP_ERROR_CHECK_BOOL(false); } break; } case SER_PHY_EVT_RX_OVERFLOW_ERROR: { /* Generate the event to an upper layer. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_PHY_ERROR; hal_transp_event.evt_params.phy_error.error_type = SER_HAL_TRANSP_PHY_ERROR_RX_OVERFLOW; m_events_handler(hal_transp_event); break; } case SER_PHY_EVT_TX_OVERREAD_ERROR: { /* Generate the event to an upper layer. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_PHY_ERROR; hal_transp_event.evt_params.phy_error.error_type = SER_HAL_TRANSP_PHY_ERROR_TX_OVERREAD; m_events_handler(hal_transp_event); break; } case SER_PHY_EVT_HW_ERROR: { /* Generate the event to an upper layer. */ hal_transp_event.evt_type = SER_HAL_TRANSP_EVT_PHY_ERROR; hal_transp_event.evt_params.phy_error.error_type = SER_HAL_TRANSP_PHY_ERROR_HW_ERROR; hal_transp_event.evt_params.phy_error.hw_error_code = phy_event.evt_params.hw_error.error_code; if (HAL_TRANSP_TX_STATE_TRANSMITTING == m_tx_state) { m_tx_state = HAL_TRANSP_TX_STATE_TRANSMITTED; err_code = ser_hal_transport_tx_pkt_free(phy_event.evt_params.hw_error.p_buffer); APP_ERROR_CHECK(err_code); /* An event to an upper layer that a packet has been transmitted. */ } else if (HAL_TRANSP_RX_STATE_RECEIVING == m_rx_state) { m_rx_state = HAL_TRANSP_RX_STATE_RECEIVED; err_code = ser_hal_transport_rx_pkt_free(phy_event.evt_params.hw_error.p_buffer); APP_ERROR_CHECK(err_code); } m_events_handler(hal_transp_event); break; } default: { APP_ERROR_CHECK_BOOL(false); break; } } } uint32_t ser_hal_transport_open(ser_hal_transport_events_handler_t events_handler) { uint32_t err_code = NRF_SUCCESS; if ((HAL_TRANSP_RX_STATE_CLOSED != m_rx_state) || (HAL_TRANSP_TX_STATE_CLOSED != m_tx_state)) { err_code = NRF_ERROR_INVALID_STATE; } else if (NULL == events_handler) { err_code = NRF_ERROR_NULL; } else { /* We have to change states before calling lower layer because ser_phy_open() function is * going to enable interrupts. On success an event from PHY layer can be emitted immediately * after return from ser_phy_open(). */ m_rx_state = HAL_TRANSP_RX_STATE_IDLE; m_tx_state = HAL_TRANSP_TX_STATE_IDLE; m_events_handler = events_handler; /* Initialize a PHY module. */ err_code = ser_phy_open(phy_events_handler); if (NRF_SUCCESS != err_code) { m_rx_state = HAL_TRANSP_RX_STATE_CLOSED; m_tx_state = HAL_TRANSP_TX_STATE_CLOSED; m_events_handler = NULL; if (NRF_ERROR_INVALID_PARAM != err_code) { err_code = NRF_ERROR_INTERNAL; } } } return err_code; } void ser_hal_transport_close(void) { /* Reset generic handler for all events, reset internal states and close PHY module. */ ser_phy_interrupts_disable(); m_rx_state = HAL_TRANSP_RX_STATE_CLOSED; m_tx_state = HAL_TRANSP_TX_STATE_CLOSED; m_events_handler = NULL; ser_phy_close(); } uint32_t ser_hal_transport_rx_pkt_free(uint8_t * p_buffer) { uint32_t err_code = NRF_SUCCESS; ser_phy_interrupts_disable(); if (NULL == p_buffer) { err_code = NRF_ERROR_NULL; } else if (p_buffer != m_rx_buffer) { err_code = NRF_ERROR_INVALID_ADDR; } else if (HAL_TRANSP_RX_STATE_RECEIVED == m_rx_state) { m_rx_state = HAL_TRANSP_RX_STATE_IDLE; } else if (HAL_TRANSP_RX_STATE_RECEIVED_DROPPING == m_rx_state) { m_rx_state = HAL_TRANSP_RX_STATE_DROPPING; } else if (HAL_TRANSP_RX_STATE_RECEIVED_PENDING_BUF_REQ == m_rx_state) { err_code = ser_phy_rx_buf_set(m_rx_buffer); if (NRF_SUCCESS == err_code) { m_rx_state = HAL_TRANSP_RX_STATE_RECEIVING; } else { err_code = NRF_ERROR_INTERNAL; } } else { /* Upper layer should not call this function in current state. */ err_code = NRF_ERROR_INVALID_STATE; } ser_phy_interrupts_enable(); return err_code; } uint32_t ser_hal_transport_tx_pkt_alloc(uint8_t * * pp_memory, uint16_t * p_num_of_bytes) { uint32_t err_code = NRF_SUCCESS; if ((NULL == pp_memory) || (NULL == p_num_of_bytes)) { err_code = NRF_ERROR_NULL; } else if (HAL_TRANSP_TX_STATE_CLOSED == m_tx_state) { err_code = NRF_ERROR_INVALID_STATE; } else if (HAL_TRANSP_TX_STATE_IDLE == m_tx_state) { m_tx_state = HAL_TRANSP_TX_STATE_TX_ALLOCATED; *pp_memory = &m_tx_buffer[0]; *p_num_of_bytes = (uint16_t)sizeof (m_tx_buffer); } else { err_code = NRF_ERROR_NO_MEM; } return err_code; } uint32_t ser_hal_transport_tx_pkt_send(const uint8_t * p_buffer, uint16_t num_of_bytes) { uint32_t err_code = NRF_SUCCESS; /* The buffer provided to this function must be allocated through ser_hal_transport_tx_alloc() * function - this assures correct state and that correct memory buffer is used. */ if (NULL == p_buffer) { err_code = NRF_ERROR_NULL; } else if (0 == num_of_bytes) { err_code = NRF_ERROR_INVALID_PARAM; } else if (p_buffer != m_tx_buffer) { err_code = NRF_ERROR_INVALID_ADDR; } else if (num_of_bytes > sizeof (m_tx_buffer)) { err_code = NRF_ERROR_DATA_SIZE; } else if (HAL_TRANSP_TX_STATE_TX_ALLOCATED == m_tx_state) { ser_phy_interrupts_disable(); err_code = ser_phy_tx_pkt_send(p_buffer, num_of_bytes); if (NRF_SUCCESS == err_code) { m_tx_state = HAL_TRANSP_TX_STATE_TRANSMITTING; } else { if (NRF_ERROR_BUSY != err_code) { err_code = NRF_ERROR_INTERNAL; } } ser_phy_interrupts_enable(); } else { err_code = NRF_ERROR_INVALID_STATE; } return err_code; } uint32_t ser_hal_transport_tx_pkt_free(uint8_t * p_buffer) { uint32_t err_code = NRF_SUCCESS; if (NULL == p_buffer) { err_code = NRF_ERROR_NULL; } else if (p_buffer != m_tx_buffer) { err_code = NRF_ERROR_INVALID_ADDR; } else if ((HAL_TRANSP_TX_STATE_TX_ALLOCATED == m_tx_state) || (HAL_TRANSP_TX_STATE_TRANSMITTED == m_tx_state)) { /* Release TX buffer for use. */ m_tx_state = HAL_TRANSP_TX_STATE_IDLE; } else { err_code = NRF_ERROR_INVALID_STATE; } return err_code; }