Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling and propagation of UART errors #4

Open
wants to merge 4 commits into
base: gsdk_4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion protocol/bluetooth/inc/sl_bt_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -9538,7 +9538,7 @@ sl_status_t sl_bt_pop_event(sl_bt_msg_t* event);
* Check whether events are in queue pending for processing.
* Call @ref sl_bt_pop_event to process pending events.
*
* @return true if event is pending; false otherwise
* @return true if event is pending or error occurred; false otherwise
*/
bool sl_bt_event_pending(void);

Expand Down
32 changes: 21 additions & 11 deletions protocol/bluetooth/inc/sl_bt_ncp_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,11 @@ sl_status_t sli_bgapi_get_event(int block, sl_bt_msg_t *event, bgapi_device_type
/**
* Function that sends a message to the serial port.
*
* @param msg_len Length of the message
* @param msg_data The message data
* @param msg_len[in] Length of the message.
* @param msg_data[in] The message data.
* @return The amount of bytes sent or -1 on failure.
*/
typedef void(*tx_func)(uint32_t msg_len, uint8_t* msg_data);
typedef int32_t(*tx_func)(uint32_t msg_len, uint8_t* msg_data);

/**
* @brief Function that reads data from serial port.
Expand All @@ -134,6 +135,12 @@ typedef int32_t(*rx_func)(uint32_t dataLength, uint8_t* data);
*/
typedef int32_t(*rx_peek_func)(void);

/**
* @brief Function for retrieving current time, used for timeouts.
* @return Returns the number of milliseconds, monotonically increasing since an undefined point in time.
*/
typedef int64_t(*time_ms_func)(void);

/**
* Initialize NCP host Bluetooth API.
*
Expand All @@ -149,17 +156,20 @@ sl_status_t sl_bt_api_initialize(tx_func ofunc, rx_func ifunc);
* @param ofunc The function for sending api messages
* @param ifunc The function for receiving api messages
* @param pfunc The function for getting the number of bytes in the input buffer
* @param tfunc Optional function for getting current monotonic time in ms, used for timeouts
* @param rx_timeout_ms Timeout for receiving command responses, only used if tfunc is provided
* @return Status code
*/
sl_status_t sl_bt_api_initialize_nonblock(tx_func ofunc, rx_func ifunc, rx_peek_func pfunc);

extern void(*sl_bt_api_output)(uint32_t len1, uint8_t* data1);
extern int32_t (*sl_bt_api_input)(uint32_t len1, uint8_t* data1);
extern int32_t(*sl_bt_api_peek)(void);
void sl_bt_host_handle_command();
void sl_bt_host_handle_command_noresponse();
sl_status_t sl_bt_api_initialize_nonblock(tx_func ofunc, rx_func ifunc, rx_peek_func pfunc,
time_ms_func tfunc, uint32_t rx_timeout_ms);

extern tx_func sl_bt_api_output;
extern rx_func sl_bt_api_input;
extern rx_peek_func sl_bt_api_peek;
sl_status_t sl_bt_host_handle_command(void);
sl_status_t sl_bt_host_handle_command_noresponse(void);
sl_status_t sl_bt_wait_event(sl_bt_msg_t *p);

sl_bt_msg_t* sli_wait_for_bgapi_message(sl_bt_msg_t *response_buf);
sl_status_t sli_wait_for_bgapi_message(sl_bt_msg_t *response_buf);

#endif
4 changes: 2 additions & 2 deletions protocol/bluetooth/inc/sl_btmesh_ncp_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ extern bgapi_device_type_queue_t sl_btmesh_api_queue;
#define SL_BTMESH_API_REGISTER() \
do { sli_bgapi_register_device(&sl_btmesh_api_queue); } while (0);

void sl_btmesh_host_handle_command();
void sl_btmesh_host_handle_command_noresponse();
sl_status_t sl_btmesh_host_handle_command(void);
sl_status_t sl_btmesh_host_handle_command_noresponse(void);
sl_status_t sl_btmesh_wait_event(sl_btmesh_msg_t *p);

#endif
114 changes: 74 additions & 40 deletions protocol/bluetooth/src/sl_bt_ncp_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ sl_bt_msg_t _sl_bt_cmd_msg;
sl_bt_msg_t _sl_bt_rsp_msg;
sl_bt_msg_t *sl_bt_cmd_msg = &_sl_bt_cmd_msg;
sl_bt_msg_t *sl_bt_rsp_msg = &_sl_bt_rsp_msg;
void (*sl_bt_api_output)(uint32_t len1, uint8_t* data1);
int32_t (*sl_bt_api_input)(uint32_t len1, uint8_t* data1);
int32_t (*sl_bt_api_peek)(void);
tx_func sl_bt_api_output;
rx_func sl_bt_api_input;
rx_peek_func sl_bt_api_peek;
time_ms_func sl_bt_api_time;
uint32_t sl_bt_rx_timeout = 0;
uint8_t _sl_bt_queue_buffer[SL_BT_API_QUEUE_LEN * (SL_BGAPI_MSG_HEADER_LEN + SL_BGAPI_MAX_PAYLOAD_SIZE)];

bgapi_device_type_queue_t sl_bt_api_queue = {
Expand Down Expand Up @@ -61,17 +63,21 @@ sl_status_t sl_bt_api_initialize(tx_func ofunc, rx_func ifunc)
sl_bt_api_output = ofunc;
sl_bt_api_input = ifunc;
sl_bt_api_peek = NULL;
sl_bt_api_time = NULL;
return sli_bgapi_register_device(&sl_bt_api_queue);
}

sl_status_t sl_bt_api_initialize_nonblock(tx_func ofunc, rx_func ifunc, rx_peek_func pfunc)
sl_status_t sl_bt_api_initialize_nonblock(tx_func ofunc, rx_func ifunc, rx_peek_func pfunc,
time_ms_func tfunc, uint32_t rx_timeout_ms)
{
if (!ofunc || !ifunc || !pfunc) {
return SL_STATUS_INVALID_PARAMETER;
}
sl_bt_api_output = ofunc;
sl_bt_api_input = ifunc;
sl_bt_api_peek = pfunc;
sl_bt_api_time == tfunc;
sl_bt_rx_timeout = rx_timeout_ms;
return sli_bgapi_register_device(&sl_bt_api_queue);
}

Expand Down Expand Up @@ -107,28 +113,33 @@ bool sli_bgapi_other_events_in_queue(enum sl_bgapi_dev_types my_device_type)
/**
* This function attempts to read a BGAPI event or response from the input data pipe.
*
* If there is no data, or a proper header cannot be recognized, returns NULL and
* discards any read data.
* In case of data input callback function error, returns SL_STATUS_RECEIVE. This error
* shall be handler by the caller.
*
* If there is no data, or a proper header cannot be recognized, returns SL_STATUS_FAIL
* and discards any read data.
*
* If an event is found, it is put into the corresponding event queue, as indicated
* by the registered event queue struct device type. Then NULL is returned.
* by the registered event queue struct device type. Then SL_STATUS_FULL is returned
* if queue is full and packet was in fact discarded, otherwise SL_STATUS_BUSY.
*
* If a response is found, it is copied into the response_buffer parameter.
* Then a pointer to response_buffer is returned.
* If a response is found, it is copied into the response_buffer parameter and
* SL_STATUS_OK is returned.
*/
sl_bt_msg_t* sli_wait_for_bgapi_message(sl_bt_msg_t *response_buffer)
sl_status_t sli_wait_for_bgapi_message(sl_bt_msg_t *response_buffer)
{
uint32_t msg_length;
uint32_t header;
uint8_t *payload;
sl_bt_msg_t *packet_ptr, *retVal = NULL;
sl_bt_msg_t *packet_ptr;
sl_status_t ret_val = SL_STATUS_BUSY;
int ret;
size_t i;
bgapi_device_type_queue_t *queue = NULL;
//sync to header byte
ret = sl_bt_api_input(1, (uint8_t*)&header);
if (ret < 0) {
return 0; // Failed to read header byte
return SL_STATUS_BUSY; // Failed to read header byte
}
for (i = 0; i < SL_BGAPI_DEVICE_TYPES; i++) {
if ((device_event_queues[i] != NULL)
Expand All @@ -138,17 +149,17 @@ sl_bt_msg_t* sli_wait_for_bgapi_message(sl_bt_msg_t *response_buffer)
}
}
if (queue == NULL) {
return 0; // Unrecognized device
return SL_STATUS_FAIL; // Unrecognized device
}
ret = sl_bt_api_input(SL_BGAPI_MSG_HEADER_LEN - 1, &((uint8_t*)&header)[1]);
if (ret < 0) {
return 0;
return SL_STATUS_RECEIVE;
}

msg_length = SL_BT_MSG_LEN(header);

if (msg_length > SL_BGAPI_MAX_PAYLOAD_SIZE) {
return 0;
return SL_STATUS_FAIL;
}

if ((header & 0xf8) == ( (uint32_t)(queue->device_type) | (uint32_t)sl_bgapi_msg_type_evt)) {
Expand All @@ -158,9 +169,12 @@ sl_bt_msg_t* sli_wait_for_bgapi_message(sl_bt_msg_t *response_buffer)
if (msg_length) {
// Discard payload if it exists
uint8_t discard_buf[SL_BGAPI_MAX_PAYLOAD_SIZE];
sl_bt_api_input(msg_length, discard_buf);
ret = sl_bt_api_input(msg_length, discard_buf);
if (ret < 0) {
return SL_STATUS_RECEIVE;
}
}
return 0;
return SL_STATUS_FULL;
}
packet_ptr = &queue->buffer[queue->write_offset];
// Move write offset to next slot or wrap around to beginning.
Expand All @@ -169,10 +183,11 @@ sl_bt_msg_t* sli_wait_for_bgapi_message(sl_bt_msg_t *response_buffer)
// Note that in the case of a response we don't need to split it into two buffer types,
// because we can't have multiple pending commands and responses in parallel.
// Whoever sent the last command will wait for the response.
retVal = packet_ptr = response_buffer;
packet_ptr = response_buffer;
ret_val = SL_STATUS_OK;
} else {
//fail
return 0;
return SL_STATUS_FAIL;
}
packet_ptr->header = header;
payload = (uint8_t*)&packet_ptr->data.payload;
Expand All @@ -186,10 +201,10 @@ sl_bt_msg_t* sli_wait_for_bgapi_message(sl_bt_msg_t *response_buffer)
}
}

// Using retVal avoid double handling of event msg types in outer function.
// If retVal is non-null we got a response packet. If null, an event was placed
// in one of the event queues.
return retVal;
// Using ret_val avoids double handling of event msg types in outer function.
// If ret_val is SL_STATUS_OK we got a response packet. Otherwise, an event
// was placed in one of the event queues.
return ret_val;
}

bool sl_bt_event_pending(void)
Expand All @@ -198,8 +213,8 @@ bool sl_bt_event_pending(void)
return true;
}

//something in uart waiting to be read
if (sl_bt_api_peek && sl_bt_api_peek()) {
//something in uart waiting to be read (or error occurred)
if (sl_bt_api_peek && (sl_bt_api_peek() != 0)) {
return true;
}

Expand All @@ -219,7 +234,7 @@ bool sl_bt_event_pending(void)
**/
sl_status_t sli_bgapi_get_event(int block, sl_bt_msg_t *event, bgapi_device_type_queue_t *device_queue)
{
sl_bt_msg_t *rsp;
sl_status_t rc;
while (1) {
// First check if we already have events waiting for us.
if (sli_bgapi_device_queue_has_events(device_queue)) {
Expand All @@ -235,17 +250,27 @@ sl_status_t sli_bgapi_get_event(int block, sl_bt_msg_t *event, bgapi_device_type
}

//if not blocking and nothing in uart -> out
if (!block && sl_bt_api_peek && sl_bt_api_peek() == 0) {
return SL_STATUS_WOULD_BLOCK;
if (!block && sl_bt_api_peek) {
int ret = sl_bt_api_peek();
if (ret < 0) {
return SL_STATUS_RECEIVE;
}
else if (ret == 0) {
return SL_STATUS_WOULD_BLOCK;
}
}

//read more messages from device
if ( (rsp = sli_wait_for_bgapi_message(sl_bt_rsp_msg)) ) {
rc = sli_wait_for_bgapi_message(sl_bt_rsp_msg);
if (rc == SL_STATUS_OK) {
// Note that we copy the event to the event pointer here only if it is a response.
// Regular events are handled in the above blocks.
memcpy(event, rsp, sizeof(sl_bt_msg_t));
memcpy(event, sl_bt_rsp_msg, sizeof(sl_bt_msg_t));
return SL_STATUS_OK;
}
else if (rc == SL_STATUS_RECEIVE) {
return SL_STATUS_RECEIVE;
}
}
}

Expand All @@ -264,26 +289,35 @@ sl_status_t sl_bt_pop_event(sl_bt_msg_t* event)
* Any events that arrive before the response will be put into their corresponding
* event queues.
*/
sl_bt_msg_t* sl_bt_wait_response(void)
sl_status_t sl_bt_wait_response(void)
{
sl_bt_msg_t* rsp;
sl_status_t rc;
const int64_t t_start = (sl_bt_api_time ? sl_bt_api_time() : 0);
while (1) {
rsp = sli_wait_for_bgapi_message(sl_bt_rsp_msg); // Will return a valid pointer only if we got a response.
if (rsp) {
return rsp;
rc = sli_wait_for_bgapi_message(sl_bt_rsp_msg);
if ((rc == SL_STATUS_OK) || (rc == SL_STATUS_RECEIVE)) {
return rc;
}
if (sl_bt_api_time && ((sl_bt_api_time() - t_start) >= sl_bt_rx_timeout)) {
return SL_STATUS_IO_TIMEOUT;
}
}
}

void sl_bt_host_handle_command()
sl_status_t sl_bt_host_handle_command(void)
{
//packet in sl_bt_cmd_msg is waiting for output
sl_bt_api_output(SL_BGAPI_MSG_HEADER_LEN + SL_BT_MSG_LEN(sl_bt_cmd_msg->header), (uint8_t*)sl_bt_cmd_msg);
sl_bt_wait_response();
if (sl_bt_api_output(SL_BGAPI_MSG_HEADER_LEN + SL_BT_MSG_LEN(sl_bt_cmd_msg->header), (uint8_t*)sl_bt_cmd_msg) < 0) {
return SL_STATUS_TRANSMIT;
}
return sl_bt_wait_response();
}

void sl_bt_host_handle_command_noresponse()
sl_status_t sl_bt_host_handle_command_noresponse(void)
{
//packet in sl_bt_cmd_msg is waiting for output
sl_bt_api_output(SL_BGAPI_MSG_HEADER_LEN + SL_BT_MSG_LEN(sl_bt_cmd_msg->header), (uint8_t*)sl_bt_cmd_msg);
if (sl_bt_api_output(SL_BGAPI_MSG_HEADER_LEN + SL_BT_MSG_LEN(sl_bt_cmd_msg->header), (uint8_t*)sl_bt_cmd_msg) < 0) {
return SL_STATUS_TRANSMIT;
}
return SL_STATUS_OK;
}
Loading