Added ble payload fragmentation handling depending on the current MTU size, added a few other function to interact with the ble service

This commit is contained in:
anschrammh 2023-03-12 21:50:19 +01:00
parent 2854c45848
commit ef0660c499
2 changed files with 237 additions and 54 deletions

View File

@ -6,10 +6,33 @@
#include "wm_bt_util.h" #include "wm_bt_util.h"
#include "bluetooth_sig_values.h" #include "bluetooth_sig_values.h"
#define USABLE_DEFAULT_MTU (20) //23 - 3 of header bytes
/* ble service internal workings attributes */
static volatile ble_service_state_e _ble_service_state = BLE_SERVICE_MODE_STOPPED;
static nus_data_rx_fn_t _ble_service_nus_data_rx_cb = NULL;
static volatile ble_service_state_t ble_service_state = BLE_SERVICE_MODE_STOPPED;
/* Connection handle to the connected device : only one simultaneous connection */ /* Connection handle to the connected device : only one simultaneous connection */
static uint16_t ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE; static uint16_t ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE;
static uint16_t usable_mtu = USABLE_DEFAULT_MTU;
/**
* @brief Structure used to store the various data to carry out a chunked notification or indication data transfer
*
*/
typedef struct
{
uint16_t length; // The length of the data being sent
uint16_t offset; // The offset used to be ableto send the next chunk of data in the array
uint16_t sent_chunk_size; // The size of the chunk sent
const uint8_t *data; // The address of the data to send
bool transfer_in_progress; // Is a transfer already in progress ?
} data_being_sent_t;
// Only one transfer of a type () can occur at any given time
static data_being_sent_t notification_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false};
static data_being_sent_t indication_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false};
static struct ble_gap_event_listener ble_gap_event_listener; static struct ble_gap_event_listener ble_gap_event_listener;
static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
@ -78,15 +101,38 @@ static bool ble_service_advertise(bool enable);
static int ble_gap_event_cb(struct ble_gap_event *event, void *arg); static int ble_gap_event_cb(struct ble_gap_event *event, void *arg);
static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg); static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg);
static void print_conn_desc(const struct ble_gap_conn_desc *desc); static void print_conn_desc(const struct ble_gap_conn_desc *desc);
// Raw because it doesn't handle payload fragmentation if mtu size is smaller than the payload size
static bool ble_service_send_raw_custom_notification(uint16_t characteristic_handle, const uint8_t *data, uint16_t length);
static bool ble_service_send_custom_notification(uint16_t characteristic_handle, data_being_sent_t * const data);
static void reset_data_being_sent(data_being_sent_t * const data);
// Needed to get the reponse after a mtu exchange request // Needed to get the reponse after a mtu exchange request
static int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t mtu, void *arg); static int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t mtu, void *arg);
const char *ble_service_state_2_str(ble_service_state_e state)
{
switch(state) {
CASE_RETURN_STR(BLE_SERVICE_MODE_STOPPED)
CASE_RETURN_STR(BLE_SERVICE_MODE_IDLE)
CASE_RETURN_STR(BLE_SERVICE_MODE_ADVERTISING)
CASE_RETURN_STR(BLE_SERVICE_MODE_CONNECTED)
CASE_RETURN_STR(BLE_SERVICE_MODE_INDICATING)
CASE_RETURN_STR(BLE_SERVICE_MODE_EXITING)
default:
return "unkown ble service state";
}
}
/**
* PUBLIC FUNCTION DEFINITION
*/
bool ble_service_start(void) bool ble_service_start(void)
{ {
int status = BLE_HS_ENOERR; int status = BLE_HS_ENOERR;
// 1 We first check if the BLE service is stopped // 1 We first check if the BLE service is stopped
if(ble_service_state != BLE_SERVICE_MODE_STOPPED) if(_ble_service_state != BLE_SERVICE_MODE_STOPPED)
{ {
TLS_BT_APPL_TRACE_WARNING("%s, ble service already running"NEW_LINE, __FUNCTION__); TLS_BT_APPL_TRACE_WARNING("%s, ble service already running"NEW_LINE, __FUNCTION__);
return true; return true;
@ -137,7 +183,7 @@ bool ble_service_start(void)
return false; return false;
} }
ble_service_state = BLE_SERVICE_MODE_ADVERTISING; _ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
return true; return true;
} }
@ -147,7 +193,7 @@ bool ble_service_stop(void)
int status = BLE_HS_ENOERR; int status = BLE_HS_ENOERR;
// 1 We first check if the BLE service is not stopped // 1 We first check if the BLE service is not stopped
if(ble_service_state == BLE_SERVICE_MODE_STOPPED) if(_ble_service_state == BLE_SERVICE_MODE_STOPPED)
{ {
TLS_BT_APPL_TRACE_WARNING("%s, ble service already stopped"NEW_LINE, __FUNCTION__); TLS_BT_APPL_TRACE_WARNING("%s, ble service already stopped"NEW_LINE, __FUNCTION__);
return true; return true;
@ -160,19 +206,19 @@ bool ble_service_stop(void)
return false; return false;
} }
switch(ble_service_state) switch(_ble_service_state)
{ {
case BLE_SERVICE_MODE_CONNECTED: case BLE_SERVICE_MODE_CONNECTED:
case BLE_SERVICE_MODE_INDICATING: case BLE_SERVICE_MODE_INDICATING:
status = ble_gap_terminate(ble_device_conn_handle, BLE_ERR_REM_USER_CONN_TERM); status = ble_gap_terminate(ble_device_conn_handle, BLE_ERR_REM_USER_CONN_TERM);
if(status == BLE_HS_ENOERR) if(status == BLE_HS_ENOERR)
{ {
ble_service_state = BLE_SERVICE_MODE_EXITING; _ble_service_state = BLE_SERVICE_MODE_EXITING;
} }
else //BLE_HS_EDISABLED || BLE_HS_ENOTCONN or any other error else //BLE_HS_EDISABLED || BLE_HS_ENOTCONN or any other error
{ {
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_terminate %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_terminate %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
ble_service_state = BLE_SERVICE_MODE_STOPPED; _ble_service_state = BLE_SERVICE_MODE_STOPPED;
//Unregister gap event listener //Unregister gap event listener
if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR) if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR)
{ {
@ -187,7 +233,7 @@ bool ble_service_stop(void)
} }
else else
{ {
ble_service_state = BLE_SERVICE_MODE_STOPPED; _ble_service_state = BLE_SERVICE_MODE_STOPPED;
//Unregister gap event listener //Unregister gap event listener
if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR) if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR)
{ {
@ -199,7 +245,7 @@ bool ble_service_stop(void)
break; break;
} }
if(ble_service_state == BLE_SERVICE_MODE_STOPPED) if(_ble_service_state == BLE_SERVICE_MODE_STOPPED)
{ {
// We finally clean the gatt registered services // We finally clean the gatt registered services
if((status = ble_gatts_reset()) != BLE_HS_ENOERR) if((status = ble_gatts_reset()) != BLE_HS_ENOERR)
@ -212,6 +258,21 @@ bool ble_service_stop(void)
return true; return true;
} }
bool ble_service_is_started(void)
{
return _ble_service_state != BLE_SERVICE_MODE_STOPPED;
}
bool ble_service_is_device_connected(void)
{
return _ble_service_state == BLE_SERVICE_MODE_CONNECTED;
}
ble_service_state_e ble_service_get_state(void)
{
return _ble_service_state;
}
bool ble_service_update_connection_parameters( bool ble_service_update_connection_parameters(
uint16_t itvl_min, uint16_t itvl_min,
uint16_t itvl_max, uint16_t itvl_max,
@ -245,7 +306,51 @@ bool ble_service_update_connection_parameters(
return true; return true;
} }
bool ble_service_send_custom_notification(const uint8_t *data, uint16_t length) bool ble_service_request_mtu_exchange(void)
{
if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle)
{
TLS_BT_APPL_TRACE_ERROR("%s, no active connection" NEW_LINE, __FUNCTION__);
return false;
}
int status = BLE_HS_ENOERR;
if((status = ble_gattc_exchange_mtu(ble_device_conn_handle, &(ble_gatt_mtu_cb), NULL)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, ble_gattc_exchange_mtu %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
return false;
}
return true;
}
bool ble_service_nus_send_data(const uint8_t *data, uint16_t length)
{
// The NUS is TX is using notification
if(notification_data.transfer_in_progress)
{
TLS_BT_APPL_TRACE_WARNING("%s, a transfer is already in progress"NEW_LINE, __FUNCTION__);
return false;
}
notification_data.transfer_in_progress = true;
notification_data.data = data;
notification_data.length = length;
return ble_service_send_custom_notification(gatt_nus_char_tx_handle, &notification_data);
}
void ble_service_nus_register_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb)
{
_ble_service_nus_data_rx_cb = nus_data_rx_cb;
}
/**
* PRIVATE FUNCTION DEFINITION
* Used for the internal workings of the service
*/
static bool ble_service_send_raw_custom_notification(uint16_t characteristic_handle, const uint8_t *data, uint16_t length)
{ {
if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle) if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle)
{ {
@ -268,7 +373,7 @@ bool ble_service_send_custom_notification(const uint8_t *data, uint16_t length)
return false; return false;
} }
if((status = ble_gattc_notify_custom(ble_device_conn_handle, gatt_nus_char_tx_handle, om_buf)) != BLE_HS_ENOERR) if((status = ble_gattc_notify_custom(ble_device_conn_handle, characteristic_handle, om_buf)) != BLE_HS_ENOERR)
{ {
TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_mbuf_from_flat %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_mbuf_from_flat %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
return false; return false;
@ -277,19 +382,22 @@ bool ble_service_send_custom_notification(const uint8_t *data, uint16_t length)
return true; return true;
} }
bool ble_service_request_mtu_exchange(void) static bool ble_service_send_custom_notification(uint16_t characteristic_handle, data_being_sent_t * const notif_data)
{ {
if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle) if(!notif_data)
{ {
TLS_BT_APPL_TRACE_ERROR("%s, no active connection" NEW_LINE, __FUNCTION__); TLS_BT_APPL_TRACE_WARNING("%s, notif_data is NULL"NEW_LINE, __FUNCTION__);
return false; return false;
} }
int status = BLE_HS_ENOERR; // We compute the maximum size of the data we can send:
uint16_t remaining_data_to_send = notif_data->length - notif_data->offset;
notif_data->sent_chunk_size = remaining_data_to_send <= usable_mtu ? remaining_data_to_send : usable_mtu;
if((status = ble_gattc_exchange_mtu(ble_device_conn_handle, &(ble_gatt_mtu_cb), NULL)) != BLE_HS_ENOERR) if(!ble_service_send_raw_custom_notification(characteristic_handle, &notif_data->data[notif_data->offset], notif_data->sent_chunk_size))
{ {
TLS_BT_APPL_TRACE_ERROR("%s, ble_gattc_exchange_mtu %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); //Transfer failed :
reset_data_being_sent(notif_data);
return false; return false;
} }
@ -305,6 +413,7 @@ int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *error, ui
case 0: case 0:
TLS_BT_APPL_TRACE_DEBUG("mtu exchange complete: conn_handle=%d mtu=%d"NEW_LINE, TLS_BT_APPL_TRACE_DEBUG("mtu exchange complete: conn_handle=%d mtu=%d"NEW_LINE,
conn_handle, mtu); conn_handle, mtu);
usable_mtu = mtu - 3;
break; break;
default: default:
TLS_BT_APPL_TRACE_ERROR("Update MTU failed...error->status=%d"NEW_LINE, error->status); TLS_BT_APPL_TRACE_ERROR("Update MTU failed...error->status=%d"NEW_LINE, error->status);
@ -314,20 +423,6 @@ int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *error, ui
return BLE_HS_ENOERR; return BLE_HS_ENOERR;
} }
const char *ble_service_state_2_str(uint8_t state)
{
switch(state) {
CASE_RETURN_STR(BLE_SERVICE_MODE_STOPPED)
CASE_RETURN_STR(BLE_SERVICE_MODE_IDLE)
CASE_RETURN_STR(BLE_SERVICE_MODE_ADVERTISING)
CASE_RETURN_STR(BLE_SERVICE_MODE_CONNECTED)
CASE_RETURN_STR(BLE_SERVICE_MODE_INDICATING)
CASE_RETURN_STR(BLE_SERVICE_MODE_EXITING)
default:
return "unkown ble service state";
}
}
static bool ble_service_define_gatt(const struct ble_gatt_svc_def *gatt_svc) static bool ble_service_define_gatt(const struct ble_gatt_svc_def *gatt_svc)
{ {
int status = BLE_HS_ENOERR; int status = BLE_HS_ENOERR;
@ -459,7 +554,8 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
print_conn_desc(&desc); print_conn_desc(&desc);
if(desc.role == BLE_GAP_ROLE_SLAVE) if(desc.role == BLE_GAP_ROLE_SLAVE)
{ {
ble_service_state = BLE_SERVICE_MODE_CONNECTED; _ble_service_state = BLE_SERVICE_MODE_CONNECTED;
usable_mtu = USABLE_DEFAULT_MTU;
ble_device_conn_handle = event->connect.conn_handle; ble_device_conn_handle = event->connect.conn_handle;
} }
else else
@ -483,24 +579,24 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
TLS_BT_APPL_TRACE_VERBOSE("Remote device failed to connect, advertise again"NEW_LINE); TLS_BT_APPL_TRACE_VERBOSE("Remote device failed to connect, advertise again"NEW_LINE);
if(!ble_service_advertise(true)) if(!ble_service_advertise(true))
{ {
ble_service_state = BLE_SERVICE_MODE_IDLE; _ble_service_state = BLE_SERVICE_MODE_IDLE;
return BLE_HS_EUNKNOWN; return BLE_HS_EUNKNOWN;
} }
ble_service_state = BLE_SERVICE_MODE_ADVERTISING; _ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
} }
break; break;
case BLE_GAP_EVENT_DISCONNECT: case BLE_GAP_EVENT_DISCONNECT:
if(event->disconnect.conn.role != BLE_GAP_ROLE_SLAVE) return 0; if(event->disconnect.conn.role != BLE_GAP_ROLE_SLAVE) return 0;
TLS_BT_APPL_TRACE_DEBUG("Server disconnect reason=%d[0x%02x],state=%s"NEW_LINE, event->disconnect.reason,event->disconnect.reason-0x200, TLS_BT_APPL_TRACE_DEBUG("Server disconnect reason=%d[0x%02x],state=%s"NEW_LINE, event->disconnect.reason,event->disconnect.reason-0x200,
ble_service_state_2_str(ble_service_state)); ble_service_state_2_str(_ble_service_state));
// Don't forget to invalidate the connection handle : // Don't forget to invalidate the connection handle :
ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE; ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE;
if(ble_service_state == BLE_SERVICE_MODE_EXITING) if(_ble_service_state == BLE_SERVICE_MODE_EXITING)
{ {
ble_service_state = BLE_SERVICE_MODE_STOPPED; _ble_service_state = BLE_SERVICE_MODE_STOPPED;
if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR) if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR)
{ {
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_event_listener_unregister %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_event_listener_unregister %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
@ -518,10 +614,10 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
TLS_BT_APPL_TRACE_VERBOSE("Service disconnect event, advertise again"NEW_LINE); TLS_BT_APPL_TRACE_VERBOSE("Service disconnect event, advertise again"NEW_LINE);
if(!ble_service_advertise(true)) if(!ble_service_advertise(true))
{ {
ble_service_state = BLE_SERVICE_MODE_IDLE; _ble_service_state = BLE_SERVICE_MODE_IDLE;
return BLE_HS_EUNKNOWN; return BLE_HS_EUNKNOWN;
} }
ble_service_state = BLE_SERVICE_MODE_ADVERTISING; _ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
} }
break; break;
case BLE_GAP_EVENT_CONN_UPDATE: case BLE_GAP_EVENT_CONN_UPDATE:
@ -550,6 +646,47 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
break; break;
case BLE_GAP_EVENT_MTU: case BLE_GAP_EVENT_MTU:
TLS_BT_APPL_TRACE_VERBOSE("MTU update : %u"NEW_LINE, event->mtu.value); TLS_BT_APPL_TRACE_VERBOSE("MTU update : %u"NEW_LINE, event->mtu.value);
usable_mtu = event->mtu.value - 3;
break;
case BLE_GAP_EVENT_NOTIFY_TX:
if(event->notify_tx.indication == 0) // Notification
{
TLS_BT_APPL_TRACE_VERBOSE("Type : notification"NEW_LINE);
if(event->notify_tx.status != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_WARNING("%s, notify_tx notification error %d, transfer in progress : %u"NEW_LINE, __FUNCTION__, event->notify_tx.status, notification_data.transfer_in_progress);
reset_data_being_sent(&notification_data);
return BLE_HS_EUNKNOWN;
}
TLS_BT_APPL_TRACE_DEBUG("transfer : %u"NEW_LINE"length : %u"NEW_LINE"offset : %u"NEW_LINE,
notification_data.transfer_in_progress,
notification_data.length,
notification_data.offset);
// We update the offset :
notification_data.offset += notification_data.sent_chunk_size;
if(notification_data.offset < notification_data.length) // Still data to send ?
{
if(!ble_service_send_custom_notification(event->notify_tx.attr_handle, &notification_data))
{
TLS_BT_APPL_TRACE_ERROR("Failed to send next notification chunk, aborting"NEW_LINE);
reset_data_being_sent(&notification_data);
return BLE_HS_EUNKNOWN;
}
}
else
{
TLS_BT_APPL_TRACE_VERBOSE("last data chunk sent, end of the transfer"NEW_LINE);
// All data has been sent, end of the transfer
reset_data_being_sent(&notification_data);
}
}
else // Indication
{
TLS_BT_APPL_TRACE_WARNING("Indication not yet handled"NEW_LINE);
}
break; break;
default: default:
TLS_BT_APPL_TRACE_WARNING("unhandled event !"NEW_LINE); TLS_BT_APPL_TRACE_WARNING("unhandled event !"NEW_LINE);
@ -595,16 +732,21 @@ static int gatt_nus_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, s
case BLE_GATT_ACCESS_OP_WRITE_CHR: case BLE_GATT_ACCESS_OP_WRITE_CHR:
{ {
struct os_mbuf *om_buf = ctxt->om; struct os_mbuf *om_buf = ctxt->om;
TLS_BT_APPL_TRACE_VERBOSE("Received data : "NEW_LINE); //TLS_BT_APPL_TRACE_VERBOSE("Received data : "NEW_LINE);
while(om_buf) while(om_buf)
{ {
for(uint16_t i = 0; i < om_buf->om_len; i++) /*for(uint16_t i = 0; i < om_buf->om_len; i++)
{ {
if(om_buf->om_data[i] < 32) if(om_buf->om_data[i] < 32)
printf("[%u]", om_buf->om_data[i]); printf("[%u]", om_buf->om_data[i]);
else else
putchar(om_buf->om_data[i]); putchar(om_buf->om_data[i]);
} }*/
// Call the nus rx cb function if one is registered
if(_ble_service_nus_data_rx_cb)
_ble_service_nus_data_rx_cb(om_buf->om_data, om_buf->om_len);
om_buf = SLIST_NEXT(om_buf, om_next); om_buf = SLIST_NEXT(om_buf, om_next);
} }
printf(NEW_LINE); printf(NEW_LINE);
@ -630,4 +772,12 @@ static void print_conn_desc(const struct ble_gap_conn_desc *desc)
desc->sec_state.encrypted, desc->sec_state.encrypted,
desc->sec_state.authenticated, desc->sec_state.authenticated,
desc->sec_state.bonded); desc->sec_state.bonded);
}
static void reset_data_being_sent(data_being_sent_t * const data)
{
if(data)
{
memset(data, 0, sizeof(data_being_sent_t));
}
} }

View File

@ -7,6 +7,8 @@
#define CASE_RETURN_STR(const) case const: return #const; #define CASE_RETURN_STR(const) case const: return #const;
#endif #endif
typedef void (*nus_data_rx_fn_t)(const uint8_t *data, uint16_t length);
typedef enum typedef enum
{ {
BLE_SERVICE_MODE_STOPPED = 0x00, BLE_SERVICE_MODE_STOPPED = 0x00,
@ -15,7 +17,7 @@ typedef enum
BLE_SERVICE_MODE_CONNECTED, BLE_SERVICE_MODE_CONNECTED,
BLE_SERVICE_MODE_INDICATING, BLE_SERVICE_MODE_INDICATING,
BLE_SERVICE_MODE_EXITING BLE_SERVICE_MODE_EXITING
} ble_service_state_t; } ble_service_state_e;
/** /**
* @brief Resturns the corresponding enum name as a string * @brief Resturns the corresponding enum name as a string
@ -23,7 +25,7 @@ typedef enum
* @param state the enum value * @param state the enum value
* @return const char* the enum name as a string * @return const char* the enum name as a string
*/ */
const char *ble_service_state_2_str(uint8_t state); const char *ble_service_state_2_str(ble_service_state_e state);
/** /**
* @brief Configures and starts the BLE service * @brief Configures and starts the BLE service
@ -41,6 +43,29 @@ bool ble_service_start(void);
*/ */
bool ble_service_stop(void); bool ble_service_stop(void);
/**
* @brief Check whether the ble service is running or not
*
* @return true if it is running
* @return false if it is stopped
*/
bool ble_service_is_started(void);
/**
* @brief Check whether a device is connected to the ble service or not
*
* @return true if a device is connected
* @return false if no device is connected
*/
bool ble_service_is_device_connected(void);
/**
* @brief Returns the current state of the ble service
*
* @return ble_service_state_e
*/
ble_service_state_e ble_service_get_state(void);
/** /**
* @brief Asks to update the current connection parameters * @brief Asks to update the current connection parameters
* /!\ A connection should be already active before calling this function. * /!\ A connection should be already active before calling this function.
@ -62,16 +87,6 @@ bool ble_service_update_connection_parameters(
uint16_t min_ce_len, uint16_t min_ce_len,
uint16_t max_ce_len); uint16_t max_ce_len);
/**
* @brief Sends a custom notification with the provided payload of size length
*
* @param data the data to send in the notification
* @param length the lenght in byte of the data to send
* @return true on success
* @return false on failure
*/
bool ble_service_send_custom_notification(const uint8_t *data, uint16_t length);
/** /**
* @brief Requests a MTU (Maximum Transmission Unit) update in order to hopefully, get something bigger than 20 bytes ... * @brief Requests a MTU (Maximum Transmission Unit) update in order to hopefully, get something bigger than 20 bytes ...
* *
@ -80,4 +95,22 @@ bool ble_service_send_custom_notification(const uint8_t *data, uint16_t length);
*/ */
bool ble_service_request_mtu_exchange(void); bool ble_service_request_mtu_exchange(void);
/**
* @brief Sends the provided payload of size length using the NUS (Nordic UART Service) TX characteristic
*
* @param data the data to send through the NUS
* @param length the lenght in byte of the data to send
* @return true on success
* @return false on failure
*/
bool ble_service_nus_send_data(const uint8_t *data, uint16_t length);
/**
* @brief Registers a function which will be called every time data is received by the nus rx
* @note To unregister a callback, simply pass NULL to the function
*
* @param nus_data_rx_cb a pointer to the function to call of type nus_data_rx_fn_t
*/
void ble_service_nus_register_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb);
#endif //BLE_APP_H #endif //BLE_APP_H