2018-02-15 09:27:51 +00:00
/**
* Copyright ( c ) 2013 - 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 .
*
2018-02-07 16:32:49 +00:00
*/
2018-02-15 09:27:51 +00:00
# include "sdk_common.h"
# if NRF_MODULE_ENABLED(HCI_TRANSPORT)
2018-02-07 16:32:49 +00:00
# include "hci_transport.h"
# include "hci_slip.h"
# include "crc16.h"
# include "hci_mem_pool.h"
# include "app_timer.h"
# include "app_error.h"
# include <stdio.h>
# define PKT_HDR_SIZE 4u /**< Packet header size in number of bytes. */
# define PKT_CRC_SIZE 2u /**< Packet CRC size in number of bytes. */
# define PKT_TYPE_VENDOR_SPECIFIC 14u /**< Packet type vendor specific. */
# define PKT_TYPE_ACK 0 /**< Packet type acknowledgement. */
# define DATA_INTEGRITY_MASK (1u << 6u) /**< Mask for data integrity bit in the packet header. */
# define RELIABLE_PKT_MASK (1u << 7u) /**< Mask for reliable packet bit in the packet header. */
# define INITIAL_ACK_NUMBER_EXPECTED 1u /**< Initial acknowledge number expected. */
# define INITIAL_ACK_NUMBER_TX INITIAL_ACK_NUMBER_EXPECTED /**< Initial acknowledge number transmitted. */
# define INVALID_PKT_TYPE 0xFFFFFFFFu /**< Internal invalid packet type value. */
2018-02-15 09:27:51 +00:00
# define HCI_UART_REG_VALUE_TO_BAUDRATE(BAUDRATE) ((BAUDRATE) / 268) /**< Estimated relation between UART baudrate register value and actual baudrate */
# define MAX_TRANSMISSION_TIME \
( ROUNDED_DIV ( ( HCI_MAX_PACKET_SIZE_IN_BITS * 1000u ) , \
HCI_UART_REG_VALUE_TO_BAUDRATE ( HCI_UART_BAUDRATE ) ) ) /**< Max transmission time of a single application packet over UART in units of mseconds. */
# define RETRANSMISSION_TIMEOUT_IN_MS (3u * MAX_TRANSMISSION_TIME) /**< Retransmission timeout for application packet in units of mseconds. */
# define RETRANSMISSION_TIMEOUT_IN_TICKS APP_TIMER_TICKS(RETRANSMISSION_TIMEOUT_IN_MS) /**< Retransmission timeout for application packet in units of timer ticks. */
2018-02-07 16:32:49 +00:00
# define MAX_RETRY_COUNT 5u /**< Max retransmission retry count for application packets. */
# define ACK_BUF_SIZE 5u /**< Length of module internal RX buffer which is big enough to hold an acknowledgement packet. */
/**@brief States of the TX state machine. */
typedef enum
{
2018-02-15 09:27:51 +00:00
TX_STATE_IDLE , /**< State for: no application transmission packet processing in progress. */
2018-02-07 16:32:49 +00:00
TX_STATE_PENDING , /**< State for: TX in progress in slip layer and TX-done event is waited for to signal the end of transmission. */
TX_STATE_ACTIVE /**< State for: application packet has been delivered to slip for transmission and peer transport entity acknowledgement packet is waited for. */
} tx_state_t ;
/**@brief TX state machine events. */
typedef enum
{
2018-02-15 09:27:51 +00:00
TX_EVENT_STATE_ENTRY , /**< Event for: state entry use case. */
2018-02-07 16:32:49 +00:00
TX_EVENT_SLIP_TX_DONE , /**< Event for: HCI_SLIP_TX_DONE event use case. */
TX_EVENT_TIMEOUT , /**< Event for: retransmission timeout use case. */
TX_EVENT_VALID_RX_ACK /**< Event for: valid acknowledgement received for TX packet use case. */
} tx_event_t ;
static void tx_sm_state_change ( tx_state_t new_state ) ;
static tx_state_t m_tx_state ; /**< Current TX state. */
static hci_transport_tx_done_handler_t m_transport_tx_done_handle ; /**< TX done event callback function. */
static hci_transport_event_handler_t m_transport_event_handle ; /**< Event handler callback function. */
static uint8_t * mp_slip_used_rx_buffer ; /**< Reference to RX buffer used by the slip layer. */
2018-02-15 09:27:51 +00:00
static uint32_t m_packet_expected_seq_number ; /**< Sequence number counter of the packet expected to be received . */
static uint32_t m_packet_transmit_seq_number ; /**< Sequence number counter of the transmitted packet for which acknowledgement packet is waited for. */
2018-02-07 16:32:49 +00:00
static uint8_t * mp_tx_buffer ; /**< Pointer to TX application buffer to be transmitted. */
static uint32_t m_tx_buffer_length ; /**< Length of application TX packet data to be transmitted in bytes. */
static bool m_is_slip_decode_ready ; /**< Boolean to determine has slip decode been completed or not. */
APP_TIMER_DEF ( m_app_timer_id ) ; /**< Application timer id. */
static uint32_t m_tx_retry_counter ; /**< Application packet retransmission counter. */
static hci_transport_tx_done_result_t m_tx_done_result_code ; /**< TX done event callback function result code. */
static uint8_t m_rx_ack_buffer [ ACK_BUF_SIZE ] ; /**< RX buffer big enough to hold an acknowledgement packet and which is taken in use upon receiving HCI_SLIP_RX_OVERFLOW event. */
/**@brief Function for validating a received packet.
*
* @ param [ in ] p_buffer Pointer to the packet data .
2018-02-15 09:27:51 +00:00
* @ param [ in ] length Length of packet data in bytes .
2018-02-07 16:32:49 +00:00
*
* @ return true if received packet is valid , false in other case .
*/
static bool is_rx_pkt_valid ( const uint8_t * p_buffer , uint32_t length )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
// Executed packet filtering algorithm order:
// - verify packet overall length
// - verify data integrity bit set
// - verify reliable packet bit set
// - verify supported packet type
// - verify header checksum
// - verify payload length field
// - verify CRC
if ( length < = PKT_HDR_SIZE )
{
2018-02-15 09:27:51 +00:00
return false ;
2018-02-07 16:32:49 +00:00
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
if ( ! ( p_buffer [ 0 ] & DATA_INTEGRITY_MASK ) )
{
return false ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
if ( ! ( p_buffer [ 0 ] & RELIABLE_PKT_MASK ) )
{
return false ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
if ( ( p_buffer [ 1 ] & 0x0Fu ) ! = PKT_TYPE_VENDOR_SPECIFIC )
2018-02-15 09:27:51 +00:00
{
return false ;
2018-02-07 16:32:49 +00:00
}
2018-02-15 09:27:51 +00:00
const uint32_t expected_checksum =
2018-02-07 16:32:49 +00:00
( ( p_buffer [ 0 ] + p_buffer [ 1 ] + p_buffer [ 2 ] + p_buffer [ 3 ] ) ) & 0xFFu ;
if ( expected_checksum ! = 0 )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
return false ;
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
const uint16_t crc_calculated = crc16_compute ( p_buffer , ( length - PKT_CRC_SIZE ) , NULL ) ;
const uint16_t crc_received = uint16_decode ( & p_buffer [ length - PKT_CRC_SIZE ] ) ;
if ( crc_calculated ! = crc_received )
{
return false ;
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return true ;
}
/**@brief Function for getting the sequence number of the next reliable packet expected.
*
* @ return sequence number of the next reliable packet expected .
*/
static __INLINE uint8_t packet_number_expected_get ( void )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
return ( uint8_t ) m_packet_expected_seq_number ;
}
/**@brief Function for calculating a packet header checksum.
*
* @ param [ in ] p_hdr Pointer to the packet header .
*
* @ return Calculated checksum .
*/
static uint8_t header_checksum_calculate ( const uint8_t * p_hdr )
{
// @note: no pointer validation check needed as already checked by calling function.
uint32_t checksum ;
2018-02-15 09:27:51 +00:00
checksum = p_hdr [ 0 ] ;
checksum + = p_hdr [ 1 ] ;
checksum + = p_hdr [ 2 ] ;
2018-02-07 16:32:49 +00:00
checksum & = 0xFFu ;
checksum = ( ~ checksum + 1u ) ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return ( uint8_t ) checksum ;
}
/**@brief Function for writing an acknowledgment packet for transmission.
*/
static void ack_transmit ( void )
{
static uint8_t ack_packet [ PKT_HDR_SIZE ] ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
// TX ACK packet format:
// - Unreliable Packet type
// - Payload Length set to 0
// - Sequence Number set to 0
// - Header checksum calculated
2018-02-15 09:27:51 +00:00
// - Acknowledge Number set correctly
2018-02-07 16:32:49 +00:00
ack_packet [ 0 ] = ( packet_number_expected_get ( ) < < 3u ) ;
2018-02-15 09:27:51 +00:00
ack_packet [ 1 ] = 0 ;
ack_packet [ 2 ] = 0 ;
ack_packet [ 3 ] = header_checksum_calculate ( ack_packet ) ;
2018-02-07 16:32:49 +00:00
2018-02-15 09:27:51 +00:00
// @note: no return value check needed for hci_slip_write(...) call as acknowledgement packets
// are considered to be from system design point of view unreliable packets.Use case where
2018-02-07 16:32:49 +00:00
// underlying slip layer does not accept a packet for transmission is managed either by:
2018-02-15 09:27:51 +00:00
// - acknowledged by possible future application packet as acknowledgement number header field
// is included
// - protocol peer entity will retransmit the packet
UNUSED_VARIABLE ( hci_slip_write ( ack_packet , sizeof ( ack_packet ) ) ) ;
2018-02-07 16:32:49 +00:00
}
/**@brief Function for validating a received packet.
*
2018-02-15 09:27:51 +00:00
* @ param [ in ] p_buffer Pointer to the packet data .
2018-02-07 16:32:49 +00:00
*
* @ return sequence number field of the packet header with unrelated data masked out .
*/
static __INLINE uint8_t packet_seq_nmbr_extract ( const uint8_t * p_buffer )
{
return ( p_buffer [ 0 ] & 0x07u ) ;
}
/**@brief Function for incrementing the sequence number counter for next reliable packet expected.
*/
static __INLINE void packet_number_expected_inc ( void )
{
+ + m_packet_expected_seq_number ;
2018-02-15 09:27:51 +00:00
m_packet_expected_seq_number & = 0x07u ;
2018-02-07 16:32:49 +00:00
}
/**@brief Function for decoding a packet type field.
*
2018-02-15 09:27:51 +00:00
* @ param [ in ] p_buffer Pointer to the packet data .
* @ param [ in ] length Length of packet data in bytes .
2018-02-07 16:32:49 +00:00
*
* @ return Packet type field or INVALID_PKT_TYPE in case of decode error .
*/
static __INLINE uint32_t packet_type_decode ( const uint8_t * p_buffer , uint32_t length )
{
// @note: no pointer validation check needed as allready checked by calling function.
uint32_t return_value ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
if ( length > = PKT_HDR_SIZE )
{
return_value = ( p_buffer [ 1 ] & 0x0Fu ) ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
else
{
return_value = INVALID_PKT_TYPE ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
return return_value ;
}
/**@brief Function for processing a received vendor specific packet.
*
2018-02-15 09:27:51 +00:00
* @ param [ in ] p_buffer Pointer to the packet data .
* @ param [ in ] length Length of packet data in bytes .
2018-02-07 16:32:49 +00:00
*/
static void rx_vendor_specific_pkt_type_handle ( const uint8_t * p_buffer , uint32_t length )
{
// @note: no pointer validation check needed as allready checked by calling function.
uint32_t err_code ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
if ( is_rx_pkt_valid ( p_buffer , length ) )
{
// RX packet is valid: validate sequence number.
const uint8_t rx_seq_number = packet_seq_nmbr_extract ( p_buffer ) ;
if ( packet_number_expected_get ( ) = = rx_seq_number )
{
// Sequence number is valid: transmit acknowledgement.
2018-02-15 09:27:51 +00:00
packet_number_expected_inc ( ) ;
ack_transmit ( ) ;
m_is_slip_decode_ready = true ;
2018-02-07 16:32:49 +00:00
err_code = hci_mem_pool_rx_data_size_set ( length ) ;
APP_ERROR_CHECK ( err_code ) ;
2018-02-15 09:27:51 +00:00
err_code = hci_mem_pool_rx_produce ( HCI_RX_BUF_SIZE , ( void * * ) & mp_slip_used_rx_buffer ) ;
2018-02-07 16:32:49 +00:00
APP_ERROR_CHECK_BOOL ( ( err_code = = NRF_SUCCESS ) | | ( err_code = = NRF_ERROR_NO_MEM ) ) ;
2018-02-15 09:27:51 +00:00
// If memory pool RX buffer produce succeeded we register that buffer to slip layer
// otherwise we register the internal acknowledgement buffer.
2018-02-07 16:32:49 +00:00
err_code = hci_slip_rx_buffer_register (
2018-02-15 09:27:51 +00:00
( err_code = = NRF_SUCCESS ) ? mp_slip_used_rx_buffer : m_rx_ack_buffer ,
( err_code = = NRF_SUCCESS ) ? HCI_RX_BUF_SIZE : ACK_BUF_SIZE ) ;
APP_ERROR_CHECK ( err_code ) ;
2018-02-07 16:32:49 +00:00
if ( m_transport_event_handle ! = NULL )
{
// Send application event of RX packet reception.
const hci_transport_evt_t evt = { HCI_TRANSPORT_RX_RDY } ;
m_transport_event_handle ( evt ) ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
}
else
{
2018-02-15 09:27:51 +00:00
// RX packet discarded: sequence number not valid, set the same buffer to slip layer in
// order to avoid buffer overrun.
err_code = hci_slip_rx_buffer_register ( mp_slip_used_rx_buffer , HCI_RX_BUF_SIZE ) ;
APP_ERROR_CHECK ( err_code ) ;
// As packet did not have expected sequence number: send acknowledgement with the
2018-02-07 16:32:49 +00:00
// current expected sequence number.
ack_transmit ( ) ;
}
}
else
{
// RX packet discarded: reset the same buffer to slip layer in order to avoid buffer
2018-02-15 09:27:51 +00:00
// overrun.
err_code = hci_slip_rx_buffer_register ( mp_slip_used_rx_buffer , HCI_RX_BUF_SIZE ) ;
APP_ERROR_CHECK ( err_code ) ;
}
2018-02-07 16:32:49 +00:00
}
2018-02-15 09:27:51 +00:00
/**@brief Function for getting the sequence number of a reliable TX packet for which peer protocol
2018-02-07 16:32:49 +00:00
* entity acknowledgment is pending .
*
* @ return sequence number of a reliable TX packet for which peer protocol entity acknowledgement
* is pending .
*/
static __INLINE uint8_t packet_number_to_transmit_get ( void )
{
return m_packet_transmit_seq_number ;
}
/**@brief Function for getting the expected acknowledgement number.
*
* @ return expected acknowledgement number .
*/
static __INLINE uint8_t expected_ack_number_get ( void )
{
2018-02-15 09:27:51 +00:00
uint8_t seq_nmbr = packet_number_to_transmit_get ( ) ;
2018-02-07 16:32:49 +00:00
+ + seq_nmbr ;
seq_nmbr & = 0x07u ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return seq_nmbr ;
}
/**@brief Function for processing a received acknowledgement packet.
*
2018-02-15 09:27:51 +00:00
* Verifies does the received acknowledgement packet has the expected acknowledgement number and
* that the header checksum is correct .
2018-02-07 16:32:49 +00:00
*
2018-02-15 09:27:51 +00:00
* @ param [ in ] p_buffer Pointer to the packet data .
2018-02-07 16:32:49 +00:00
*
* @ return true if valid acknowledgement packet received .
*/
static __INLINE bool rx_ack_pkt_type_handle ( const uint8_t * p_buffer )
{
// @note: no pointer validation check needed as allready checked by calling function.
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
// Verify header checksum.
2018-02-15 09:27:51 +00:00
const uint32_t expected_checksum =
2018-02-07 16:32:49 +00:00
( ( p_buffer [ 0 ] + p_buffer [ 1 ] + p_buffer [ 2 ] + p_buffer [ 3 ] ) ) & 0xFFu ;
if ( expected_checksum ! = 0 )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
return false ;
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
const uint8_t ack_number = ( p_buffer [ 0 ] > > 3u ) & 0x07u ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
// Verify expected acknowledgment number.
return ( ack_number = = expected_ack_number_get ( ) ) ;
}
2018-02-15 09:27:51 +00:00
/**@brief Function for incrementing the sequence number counter of the TX packet.
2018-02-07 16:32:49 +00:00
*/
static __INLINE void packet_number_tx_inc ( void )
{
+ + m_packet_transmit_seq_number ;
m_packet_transmit_seq_number & = 0x07u ;
}
/**@brief Function for TX state machine event processing in a state centric manner.
*
* @ param [ in ] event Type of event occurred .
*/
static void tx_sm_event_handle ( tx_event_t event )
{
uint32_t err_code ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
switch ( m_tx_state )
{
case TX_STATE_IDLE :
if ( event = = TX_EVENT_STATE_ENTRY )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
err_code = app_timer_stop ( m_app_timer_id ) ;
APP_ERROR_CHECK ( err_code ) ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
// Send TX-done event if registered handler exists.
2018-02-15 09:27:51 +00:00
if ( m_transport_tx_done_handle ! = NULL )
2018-02-07 16:32:49 +00:00
{
m_transport_tx_done_handle ( m_tx_done_result_code ) ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
}
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case TX_STATE_PENDING :
if ( event = = TX_EVENT_SLIP_TX_DONE )
2018-02-15 09:27:51 +00:00
{
// @note: this call should always succeed as called from HCI_SLIP_TX_DONE context
2018-02-07 16:32:49 +00:00
// and error cases are managed by dedicated error event from the slip layer.
2018-02-15 09:27:51 +00:00
err_code = hci_slip_write ( mp_tx_buffer ,
( m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE ) ) ;
APP_ERROR_CHECK ( err_code ) ;
tx_sm_state_change ( TX_STATE_ACTIVE ) ;
}
2018-02-07 16:32:49 +00:00
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case TX_STATE_ACTIVE :
switch ( event )
{
2018-02-15 09:27:51 +00:00
case TX_EVENT_VALID_RX_ACK :
// Tx sequence number counter incremented as packet transmission
2018-02-07 16:32:49 +00:00
// acknowledged by peer transport entity.
2018-02-15 09:27:51 +00:00
packet_number_tx_inc ( ) ;
2018-02-07 16:32:49 +00:00
tx_sm_state_change ( TX_STATE_IDLE ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case TX_EVENT_STATE_ENTRY :
m_tx_retry_counter = 0 ;
2018-02-15 09:27:51 +00:00
err_code = app_timer_start ( m_app_timer_id ,
RETRANSMISSION_TIMEOUT_IN_TICKS ,
2018-02-07 16:32:49 +00:00
NULL ) ;
APP_ERROR_CHECK ( err_code ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case TX_EVENT_TIMEOUT :
if ( m_tx_retry_counter ! = MAX_RETRY_COUNT )
{
+ + m_tx_retry_counter ;
2018-02-15 09:27:51 +00:00
// @note: no return value check done for hci_slip_write(...) call as current
// system design allows use case where retransmission is not accepted by the
// slip layer due to existing acknowledgement packet transmission in the
// slip layer.
UNUSED_VARIABLE ( hci_slip_write ( mp_tx_buffer ,
( m_tx_buffer_length +
PKT_HDR_SIZE +
PKT_CRC_SIZE ) ) ) ;
}
2018-02-07 16:32:49 +00:00
else
{
2018-02-15 09:27:51 +00:00
// Application packet retransmission count reached:
2018-02-07 16:32:49 +00:00
// - set correct TX done event callback function result code
2018-02-15 09:27:51 +00:00
// - execute state change
2018-02-07 16:32:49 +00:00
// @note: m_tx_retry_counter is reset in TX_STATE_ACTIVE state entry.
2018-02-15 09:27:51 +00:00
m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE ;
2018-02-07 16:32:49 +00:00
tx_sm_state_change ( TX_STATE_IDLE ) ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
default :
// No implementation needed.
break ;
}
break ;
2018-02-15 09:27:51 +00:00
default :
2018-02-07 16:32:49 +00:00
// No implementation needed.
break ;
}
}
/**@brief Function for changing the state of the TX state machine.
*
* @ param [ in ] new_state State TX state machine transits to .
*/
static void tx_sm_state_change ( tx_state_t new_state )
{
m_tx_state = new_state ;
tx_sm_event_handle ( TX_EVENT_STATE_ENTRY ) ;
}
/**@brief Function for handling slip events.
*
* @ param [ in ] event The event structure .
*/
void slip_event_handle ( hci_slip_evt_t event )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
uint32_t return_code ;
2018-02-15 09:27:51 +00:00
uint32_t err_code ;
2018-02-07 16:32:49 +00:00
switch ( event . evt_type )
{
2018-02-15 09:27:51 +00:00
case HCI_SLIP_TX_DONE :
2018-02-07 16:32:49 +00:00
tx_sm_event_handle ( TX_EVENT_SLIP_TX_DONE ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case HCI_SLIP_RX_RDY :
return_code = packet_type_decode ( event . packet , event . packet_length ) ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
switch ( return_code )
{
case PKT_TYPE_VENDOR_SPECIFIC :
rx_vendor_specific_pkt_type_handle ( event . packet , event . packet_length ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case PKT_TYPE_ACK :
if ( rx_ack_pkt_type_handle ( event . packet ) )
{
2018-02-15 09:27:51 +00:00
// Valid expected acknowledgement packet received: set correct TX done event
2018-02-07 16:32:49 +00:00
// callback function result code and execute state change.
2018-02-15 09:27:51 +00:00
m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_SUCCESS ;
2018-02-07 16:32:49 +00:00
tx_sm_event_handle ( TX_EVENT_VALID_RX_ACK ) ;
}
2018-02-15 09:27:51 +00:00
/* fall-through */
2018-02-07 16:32:49 +00:00
default :
2018-02-15 09:27:51 +00:00
// RX packet dropped: reset memory buffer to slip in order to avoid RX buffer
// overflow.
// If existing mem pool produced RX buffer exists reuse that one. If existing
// mem pool produced RX buffer does not exist try to produce new one. If
// producing fails use the internal acknowledgement buffer.
2018-02-07 16:32:49 +00:00
if ( mp_slip_used_rx_buffer ! = NULL )
{
2018-02-15 09:27:51 +00:00
err_code = hci_slip_rx_buffer_register ( mp_slip_used_rx_buffer , HCI_RX_BUF_SIZE ) ;
APP_ERROR_CHECK ( err_code ) ;
2018-02-07 16:32:49 +00:00
}
else
{
2018-02-15 09:27:51 +00:00
err_code = hci_mem_pool_rx_produce ( HCI_RX_BUF_SIZE ,
( void * * ) & mp_slip_used_rx_buffer ) ;
APP_ERROR_CHECK_BOOL ( ( err_code = = NRF_SUCCESS ) | |
2018-02-07 16:32:49 +00:00
( err_code = = NRF_ERROR_NO_MEM ) ) ;
err_code = hci_slip_rx_buffer_register (
2018-02-15 09:27:51 +00:00
( err_code = = NRF_SUCCESS ) ? mp_slip_used_rx_buffer : m_rx_ack_buffer ,
( err_code = = NRF_SUCCESS ) ? HCI_RX_BUF_SIZE : ACK_BUF_SIZE ) ;
APP_ERROR_CHECK ( err_code ) ;
2018-02-07 16:32:49 +00:00
}
break ;
}
break ;
case HCI_SLIP_RX_OVERFLOW :
2018-02-15 09:27:51 +00:00
err_code = hci_slip_rx_buffer_register ( m_rx_ack_buffer , ACK_BUF_SIZE ) ;
APP_ERROR_CHECK ( err_code ) ;
2018-02-07 16:32:49 +00:00
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case HCI_SLIP_ERROR :
APP_ERROR_HANDLER ( event . evt_type ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
default :
2018-02-15 09:27:51 +00:00
APP_ERROR_HANDLER ( event . evt_type ) ;
2018-02-07 16:32:49 +00:00
break ;
}
}
uint32_t hci_transport_evt_handler_reg ( hci_transport_event_handler_t event_handler )
{
2018-02-15 09:27:51 +00:00
uint32_t err_code ;
2018-02-07 16:32:49 +00:00
m_transport_event_handle = event_handler ;
2018-02-15 09:27:51 +00:00
err_code = hci_slip_evt_handler_register ( slip_event_handle ) ;
APP_ERROR_CHECK ( err_code ) ;
return ( event_handler ! = NULL ) ? NRF_SUCCESS : NRF_ERROR_NULL ;
2018-02-07 16:32:49 +00:00
}
uint32_t hci_transport_tx_done_register ( hci_transport_tx_done_handler_t event_handler )
{
2018-02-15 09:27:51 +00:00
uint32_t err_code ;
2018-02-07 16:32:49 +00:00
m_transport_tx_done_handle = event_handler ;
2018-02-15 09:27:51 +00:00
err_code = hci_slip_evt_handler_register ( slip_event_handle ) ;
APP_ERROR_CHECK ( err_code ) ;
return ( event_handler ! = NULL ) ? NRF_SUCCESS : NRF_ERROR_NULL ;
2018-02-07 16:32:49 +00:00
}
/**@brief Function for handling the application packet retransmission timeout.
*
2018-02-15 09:27:51 +00:00
* This function is registered in the @ ref app_timer module when a timer is created on
* @ ref hci_transport_open .
*
* @ note This function must be executed in APP - LO context otherwise retransmission behaviour is
2018-02-07 16:32:49 +00:00
* undefined , see @ ref nrf51_system_integration_serialization .
2018-02-15 09:27:51 +00:00
*
2018-02-07 16:32:49 +00:00
* @ param [ in ] p_context The timeout context .
*/
void hci_transport_timeout_handle ( void * p_context )
{
tx_sm_event_handle ( TX_EVENT_TIMEOUT ) ;
}
uint32_t hci_transport_open ( void )
{
mp_tx_buffer = NULL ;
m_tx_buffer_length = 0 ;
m_tx_retry_counter = 0 ;
m_is_slip_decode_ready = false ;
m_tx_state = TX_STATE_IDLE ;
m_packet_expected_seq_number = INITIAL_ACK_NUMBER_EXPECTED ;
m_packet_transmit_seq_number = INITIAL_ACK_NUMBER_TX ;
m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE ;
2018-02-15 09:27:51 +00:00
uint32_t err_code = app_timer_create ( & m_app_timer_id ,
APP_TIMER_MODE_REPEATED ,
2018-02-07 16:32:49 +00:00
hci_transport_timeout_handle ) ;
if ( err_code ! = NRF_SUCCESS )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
// @note: conduct required interface adjustment.
return NRF_ERROR_INTERNAL ;
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
err_code = hci_mem_pool_open ( ) ;
VERIFY_SUCCESS ( err_code ) ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
err_code = hci_slip_open ( ) ;
VERIFY_SUCCESS ( err_code ) ;
2018-02-15 09:27:51 +00:00
err_code = hci_mem_pool_rx_produce ( HCI_RX_BUF_SIZE , ( void * * ) & mp_slip_used_rx_buffer ) ;
2018-02-07 16:32:49 +00:00
if ( err_code ! = NRF_SUCCESS )
{
// @note: conduct required interface adjustment.
return NRF_ERROR_INTERNAL ;
2018-02-15 09:27:51 +00:00
}
err_code = hci_slip_rx_buffer_register ( mp_slip_used_rx_buffer , HCI_RX_BUF_SIZE ) ;
return err_code ;
2018-02-07 16:32:49 +00:00
}
uint32_t hci_transport_close ( void )
{
uint32_t err_code ;
m_transport_tx_done_handle = NULL ;
m_transport_event_handle = NULL ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
err_code = hci_mem_pool_close ( ) ;
2018-02-15 09:27:51 +00:00
APP_ERROR_CHECK ( err_code ) ;
2018-02-07 16:32:49 +00:00
err_code = hci_slip_close ( ) ;
2018-02-15 09:27:51 +00:00
APP_ERROR_CHECK ( err_code ) ;
2018-02-07 16:32:49 +00:00
// @note: NRF_ERROR_NO_MEM is the only return value which should never be returned.
err_code = app_timer_stop ( m_app_timer_id ) ;
APP_ERROR_CHECK_BOOL ( err_code ! = NRF_ERROR_NO_MEM ) ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return NRF_SUCCESS ;
2018-02-15 09:27:51 +00:00
}
2018-02-07 16:32:49 +00:00
uint32_t hci_transport_tx_alloc ( uint8_t * * pp_memory )
{
2018-02-15 09:27:51 +00:00
const uint32_t err_code = hci_mem_pool_tx_alloc ( ( void * * ) pp_memory ) ;
2018-02-07 16:32:49 +00:00
if ( err_code = = NRF_SUCCESS )
{
2018-02-15 09:27:51 +00:00
// @note: no need to validate pp_memory against null as validation has already been done
2018-02-07 16:32:49 +00:00
// by hci_mem_pool_tx_alloc(...) and visible to us from the method return code.
2018-02-15 09:27:51 +00:00
//lint -e(413) "Likely use of null pointer"
* pp_memory + = PKT_HDR_SIZE ;
2018-02-07 16:32:49 +00:00
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return err_code ;
}
uint32_t hci_transport_tx_free ( void )
{
return hci_mem_pool_tx_free ( ) ;
}
/**@brief Function for constructing 1st byte of the packet header of the packet to be transmitted.
*
* @ return 1 st byte of the packet header of the packet to be transmitted
*/
static __INLINE uint8_t tx_packet_byte_zero_construct ( void )
{
2018-02-15 09:27:51 +00:00
const uint32_t value = DATA_INTEGRITY_MASK |
RELIABLE_PKT_MASK |
( packet_number_expected_get ( ) < < 3u ) |
packet_number_to_transmit_get ( ) ;
2018-02-07 16:32:49 +00:00
return ( uint8_t ) value ;
}
/**@brief Function for handling the application packet write request in tx-idle state.
*/
static uint32_t pkt_write_handle ( void )
2018-02-15 09:27:51 +00:00
{
uint32_t err_code ;
2018-02-07 16:32:49 +00:00
// Set packet header fields.
mp_tx_buffer - = PKT_HDR_SIZE ;
mp_tx_buffer [ 0 ] = tx_packet_byte_zero_construct ( ) ;
2018-02-15 09:27:51 +00:00
const uint16_t type_and_length_fields = ( ( m_tx_buffer_length < < 4u ) | PKT_TYPE_VENDOR_SPECIFIC ) ;
2018-02-07 16:32:49 +00:00
// @note: no use case for uint16_encode(...) return value.
UNUSED_VARIABLE ( uint16_encode ( type_and_length_fields , & ( mp_tx_buffer [ 1 ] ) ) ) ;
mp_tx_buffer [ 3 ] = header_checksum_calculate ( mp_tx_buffer ) ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
// Calculate, append CRC to the packet and write it.
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
const uint16_t crc = crc16_compute ( mp_tx_buffer , ( PKT_HDR_SIZE + m_tx_buffer_length ) , NULL ) ;
// @note: no use case for uint16_encode(...) return value.
2018-02-15 09:27:51 +00:00
UNUSED_VARIABLE ( uint16_encode ( crc , & ( mp_tx_buffer [ PKT_HDR_SIZE + m_tx_buffer_length ] ) ) ) ;
err_code = hci_slip_write ( mp_tx_buffer , ( m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE ) ) ;
2018-02-07 16:32:49 +00:00
switch ( err_code )
{
case NRF_SUCCESS :
tx_sm_state_change ( TX_STATE_ACTIVE ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
case NRF_ERROR_NO_MEM :
2018-02-15 09:27:51 +00:00
tx_sm_state_change ( TX_STATE_PENDING ) ;
2018-02-07 16:32:49 +00:00
err_code = NRF_SUCCESS ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
default :
// No implementation needed.
break ;
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return err_code ;
}
uint32_t hci_transport_pkt_write ( const uint8_t * p_buffer , uint16_t length )
{
uint32_t err_code ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
if ( p_buffer )
2018-02-15 09:27:51 +00:00
{
2018-02-07 16:32:49 +00:00
switch ( m_tx_state )
{
case TX_STATE_IDLE :
mp_tx_buffer = ( uint8_t * ) p_buffer ;
2018-02-15 09:27:51 +00:00
m_tx_buffer_length = length ;
2018-02-07 16:32:49 +00:00
err_code = pkt_write_handle ( ) ;
break ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
default :
err_code = NRF_ERROR_NO_MEM ;
break ;
}
}
else
{
err_code = NRF_ERROR_NULL ;
}
2018-02-15 09:27:51 +00:00
return err_code ;
2018-02-07 16:32:49 +00:00
}
uint32_t hci_transport_rx_pkt_extract ( uint8_t * * pp_buffer , uint16_t * p_length )
{
uint32_t err_code ;
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
if ( pp_buffer ! = NULL & & p_length ! = NULL )
{
2018-02-15 09:27:51 +00:00
uint32_t length = 0 ;
2018-02-07 16:32:49 +00:00
if ( m_is_slip_decode_ready )
{
m_is_slip_decode_ready = false ;
err_code = hci_mem_pool_rx_extract ( pp_buffer , & length ) ;
length - = ( PKT_HDR_SIZE + PKT_CRC_SIZE ) ;
2018-02-15 09:27:51 +00:00
* p_length = ( uint16_t ) length ;
2018-02-07 16:32:49 +00:00
* pp_buffer + = PKT_HDR_SIZE ;
}
else
{
err_code = NRF_ERROR_NO_MEM ;
}
}
else
{
err_code = NRF_ERROR_NULL ;
}
2018-02-15 09:27:51 +00:00
2018-02-07 16:32:49 +00:00
return err_code ;
}
uint32_t hci_transport_rx_pkt_consume ( uint8_t * p_buffer )
{
2018-02-15 09:27:51 +00:00
return ( hci_mem_pool_rx_consume ( p_buffer - PKT_HDR_SIZE ) ) ;
2018-02-07 16:32:49 +00:00
}
2018-02-15 09:27:51 +00:00
# endif //NRF_MODULE_ENABLED(HCI_TRANSPORT)