49 #if RUUVI_NRF5_SDK15_GATT_ENABLED
61 #include "app_timer.h"
62 #include "ble_advdata.h"
63 #include "ble_types.h"
64 #include "ble_conn_params.h"
69 #include "sdk_errors.h"
70 #include "nrf_error.h"
72 #include "nrf_sdh_soc.h"
73 #include "nrf_sdh_ble.h"
74 #include "nrf_ble_qwr.h"
75 #include "nrf_ble_gatt.h"
76 #include "peer_manager.h"
81 #define CENTRAL_LINK_COUNT 0
82 #define PERIPHERAL_LINK_COUNT 1
84 #define APP_BLE_OBSERVER_PRIO 3
86 #define NEXT_CONN_PARAMS_UPDATE_DELAY_MS (30000)
87 #define FIRST_CONN_PARAMS_UPDATE_DELAY_TICKS APP_TIMER_TICKS(5000)
88 #define NEXT_CONN_PARAMS_UPDATE_DELAY_TICKS APP_TIMER_TICKS(NEXT_CONN_PARAMS_UPDATE_DELAY_MS)
90 #define MAX_CONN_PARAMS_UPDATE_COUNT 3
92 #define SEC_PARAM_BOND 0
93 #define SEC_PARAM_MITM 0
94 #define SEC_PARAM_LESC 0
95 #define SEC_PARAM_KEYPRESS 0
96 #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE
97 #define SEC_PARAM_OOB 0
98 #define SEC_PARAM_MIN_KEY_SIZE 7
99 #define SEC_PARAM_MAX_KEY_SIZE 16
101 #ifndef RUUVI_NRF5_SDK15_COMMUNICATION_BLE4_GATT_LOG_LEVEL
102 #define RUUVI_NRF5_SDK15_COMMUNICATION_BLE4_GATT_LOG_LEVEL RI_LOG_LEVEL_DEBUG
104 #define LOG(msg) ri_log(RUUVI_NRF5_SDK15_COMMUNICATION_BLE4_GATT_LOG_LEVEL, msg)
105 #define LOGD(msg) ri_log(RI_LOG_LEVEL_DEBUG, msg)
106 #define LOGW(msg) ri_log(RI_LOG_LEVEL_WARNING, msg)
107 #define LOGHEX(msg, len) ri_log_hex(RUUVI_NRF5_SDK15_COMMUNICATION_BLE4_GATT_LOG_LEVEL, msg, len)
110 m_conn_param_retry_timer);
112 NRF_BLE_GATT_DEF (m_gatt);
113 NRF_BLE_QWR_DEF (m_qwr);
115 static uint16_t m_conn_handle =
116 BLE_CONN_HANDLE_INVALID;
117 static bool m_gatt_is_init =
false;
121 static ble_gap_conn_params_t m_gatt_params;
123 static uint8_t m_gatt_retries;
126 static ble_gap_phys_t m_phys =
128 .rx_phys = BLE_GAP_PHY_1MBPS,
129 .tx_phys = BLE_GAP_PHY_1MBPS
133 static char const * phy_str (ble_gap_phys_t phys)
135 static char const * str[] =
143 switch (phys.tx_phys)
145 case BLE_GAP_PHY_1MBPS:
148 case BLE_GAP_PHY_2MBPS:
149 case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS:
150 case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED:
153 case BLE_GAP_PHY_CODED:
167 static ret_code_t gap_params_init (
void)
170 ble_gap_conn_params_t gap_conn_params;
171 ble_gap_conn_sec_mode_t sec_mode;
172 BLE_GAP_CONN_SEC_MODE_SET_OPEN (&sec_mode);
173 memset (&gap_conn_params, 0,
sizeof (gap_conn_params));
181 err_code = sd_ble_gap_ppcp_set (&gap_conn_params);
189 static void conn_params_error_handler (uint32_t nrf_error)
206 static void on_conn_params_evt (ble_conn_params_evt_t * p_evt)
210 if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
212 err_code = sd_ble_gap_disconnect (m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
221 static ret_code_t conn_params_init (
void)
224 ble_conn_params_init_t cp_init;
225 memset (&cp_init, 0,
sizeof (cp_init));
226 cp_init.p_conn_params = NULL;
227 cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY_TICKS;
228 cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY_TICKS;
229 cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
230 cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
231 cp_init.disconnect_on_fail =
false;
232 cp_init.evt_handler = on_conn_params_evt;
233 cp_init.error_handler = conn_params_error_handler;
234 err_code = ble_conn_params_init (&cp_init);
247 static void nus_data_handler (ble_nus_evt_t * p_evt)
249 if (NULL == channel || NULL == channel->
on_evt)
256 case BLE_NUS_EVT_RX_DATA:
257 LOGD (
"NUS RX \r\n");
259 (
void *) p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
262 case BLE_NUS_EVT_COMM_STARTED:
263 LOG (
"NUS Started\r\n");
267 case BLE_NUS_EVT_COMM_STOPPED:
268 LOG (
"NUS Finished\r\n");
272 case BLE_NUS_EVT_TX_RDY:
273 LOGD (
"NUS TX Done\r\n");
290 static void ble_evt_handler (ble_evt_t
const * p_ble_evt,
void * p_context)
292 uint32_t err_code = NRF_SUCCESS;
294 switch (p_ble_evt->header.evt_id)
296 case BLE_GAP_EVT_CONNECTED:
297 m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
298 err_code = nrf_ble_qwr_conn_handle_assign (&m_qwr, m_conn_handle);
299 LOG (
"BLE Connected \r\n");
301 sprintf (msg,
"PHY: %s.\r\n", phy_str (m_phys));
307 err_code = sd_ble_gap_phy_update (p_ble_evt->evt.gap_evt.conn_handle, &m_phys);
309 snprintf (msg,
sizeof (msg),
"Request PHY update to %s.\r\n", phy_str (m_phys));
314 case BLE_GAP_EVT_TIMEOUT:
315 LOG (
"BLE GAP timeout \r\n");
318 case BLE_GAP_EVT_DISCONNECTED:
319 LOG (
"BLE Disconnected \r\n");
321 ble_nus_evt_t evt = { 0 };
322 evt.type = BLE_NUS_EVT_COMM_STOPPED;
323 nus_data_handler (&evt);
324 m_conn_handle = BLE_CONN_HANDLE_INVALID;
325 err_code |= app_timer_stop (m_conn_param_retry_timer);
330 case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
331 err_code = sd_ble_gap_phy_update (p_ble_evt->evt.gap_evt.conn_handle, &m_phys);
332 LOG (
"BLE PHY update requested \r\n");
337 case BLE_GAP_EVT_PHY_UPDATE:
339 ble_gap_evt_phy_update_t
const * p_phy_evt = &p_ble_evt->evt.gap_evt.params.phy_update;
341 if (p_phy_evt->status == BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION)
343 LOGW (
"BLE LL transaction collision during PHY update.\r\n");
347 ble_gap_phys_t evt_phys = {0};
348 evt_phys.tx_phys = p_phy_evt->tx_phy;
349 evt_phys.rx_phys = p_phy_evt->rx_phy;
351 snprintf (msg,
sizeof (msg),
"PHY update %s. PHY set to %s.\r\n",
352 (p_phy_evt->status == BLE_HCI_STATUS_CODE_SUCCESS) ?
353 "accepted" :
"rejected",
359 case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
361 LOG (
"BLE security parameters requested - denying \r\n");
362 err_code = sd_ble_gap_sec_params_reply (m_conn_handle,
363 BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
368 if (NRF_ERROR_INVALID_STATE == err_code)
370 err_code = sd_ble_gap_disconnect (p_ble_evt->evt.gattc_evt.conn_handle,
371 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
372 LOG (
"BLE GATT Disconnected\r\n");
377 case BLE_GATTS_EVT_SYS_ATTR_MISSING:
379 LOG (
"BLE System attributes missing\r\n");
380 err_code = sd_ble_gatts_sys_attr_set (m_conn_handle, NULL, 0, 0);
385 case BLE_GATTC_EVT_TIMEOUT:
387 LOG (
"BLE GATT Client timeout\r\n");
388 err_code = sd_ble_gap_disconnect (p_ble_evt->evt.gattc_evt.conn_handle,
389 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
394 case BLE_GATTS_EVT_TIMEOUT:
396 LOG (
"BLE GATT Server timeout\r\n");
397 err_code = sd_ble_gap_disconnect (p_ble_evt->evt.gatts_evt.conn_handle,
398 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
403 case BLE_GATTS_EVT_HVN_TX_COMPLETE:
404 LOGD (
"BLE Notification sent\r\n");
409 LOGD (
"BLE Unknown event\r\n");
415 static void gatt_evt_handler (nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t
const * p_evt)
417 if ( (m_conn_handle == p_evt->conn_handle)
418 && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
421 LOGD (
"Changing MTU size is not supported\r\n");
432 static void nrf_qwr_error_handler (uint32_t nrf_error)
443 static void ble_dfu_evt_handler (ble_dfu_buttonless_evt_type_t event)
447 case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
453 case BLE_DFU_EVT_BOOTLOADER_ENTER:
458 case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
463 case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
477 static void pm_evt_handler (pm_evt_t
const * p_evt)
481 switch (p_evt->evt_id)
483 case PM_EVT_BONDED_PEER_CONNECTED:
487 case PM_EVT_CONN_SEC_SUCCEEDED:
491 case PM_EVT_CONN_SEC_FAILED:
501 case PM_EVT_CONN_SEC_CONFIG_REQ:
504 pm_conn_sec_config_t conn_sec_config = {.allow_repairing =
false};
505 pm_conn_sec_config_reply (p_evt->conn_handle, &conn_sec_config);
509 case PM_EVT_STORAGE_FULL:
520 APP_ERROR_CHECK (err_code);
525 case PM_EVT_PEERS_DELETE_SUCCEEDED:
529 case PM_EVT_PEER_DATA_UPDATE_FAILED:
533 p_evt->params.peer_data_update_failed.error),
RD_SUCCESS);
537 case PM_EVT_PEER_DELETE_FAILED:
541 p_evt->params.peer_delete_failed.error),
RD_SUCCESS);
545 case PM_EVT_PEERS_DELETE_FAILED:
549 p_evt->params.peers_delete_failed_evt.error),
RD_SUCCESS);
553 case PM_EVT_ERROR_UNEXPECTED:
557 p_evt->params.error_unexpected.error),
RD_SUCCESS);
561 case PM_EVT_CONN_SEC_START:
562 case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
563 case PM_EVT_PEER_DELETE_SUCCEEDED:
564 case PM_EVT_LOCAL_DB_CACHE_APPLIED:
565 case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
566 case PM_EVT_SERVICE_CHANGED_IND_SENT:
567 case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
578 static ret_code_t peer_manager_init()
580 ble_gap_sec_params_t sec_param;
581 ret_code_t err_code = NRF_SUCCESS;
582 err_code |= pm_init();
585 if (NRF_SUCCESS != err_code)
591 memset (&sec_param, 0,
sizeof (ble_gap_sec_params_t));
593 sec_param.bond = SEC_PARAM_BOND;
594 sec_param.mitm = SEC_PARAM_MITM;
595 sec_param.lesc = SEC_PARAM_LESC;
596 sec_param.keypress = SEC_PARAM_KEYPRESS;
597 sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
598 sec_param.oob = SEC_PARAM_OOB;
599 sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
600 sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
601 sec_param.kdist_own.enc = 0;
602 sec_param.kdist_own.id = 0;
603 sec_param.kdist_peer.enc = 0;
604 sec_param.kdist_peer.id = 0;
605 err_code = pm_sec_params_set (&sec_param);
606 err_code |= pm_register (pm_evt_handler);
629 m_phys.rx_phys = BLE_GAP_PHY_CODED;
630 m_phys.tx_phys = BLE_GAP_PHY_CODED;
634 m_phys.rx_phys = BLE_GAP_PHY_2MBPS;
635 m_phys.tx_phys = BLE_GAP_PHY_2MBPS;
640 m_phys.rx_phys = BLE_GAP_PHY_1MBPS;
641 m_phys.tx_phys = BLE_GAP_PHY_1MBPS;
654 static void gatt_params_request (
void *
const params)
656 ret_code_t nrf_status = NRF_SUCCESS;
658 if (BLE_CONN_HANDLE_INVALID == m_conn_handle)
661 LOG (
"No connection, ignore param change\r\n");
665 nrf_status = ble_conn_params_change_conn_params (m_conn_handle, params);
666 LOG (
"Requesting param change\r\n");
669 if (NRF_SUCCESS != nrf_status)
671 nrf_status = app_timer_start (m_conn_param_retry_timer,
672 NEXT_CONN_PARAMS_UPDATE_DELAY_TICKS,
677 LOG (
"Param change failed, retry queued\r\n");
680 if (m_gatt_retries > MAX_CONN_PARAMS_UPDATE_COUNT)
683 nrf_status = sd_ble_gap_disconnect (m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
686 LOG (
"Param change errored too many times, cut connection\r\n");
692 ret_code_t err_code = NRF_SUCCESS;
693 static bool qwr_is_init =
false;
708 LOGW (
"NRF5 SDK15 BLE4 GATT module requires initialized timers\r\n");
715 (void) app_timer_stop (m_conn_param_retry_timer);
716 err_code |= app_timer_create (&m_conn_param_retry_timer, APP_TIMER_MODE_SINGLE_SHOT,
717 &gatt_params_request);
722 NRF_SDH_BLE_OBSERVER (m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
723 err_code |= gap_params_init();
724 err_code |= nrf_ble_gatt_init (&m_gatt, gatt_evt_handler);
731 nrf_ble_qwr_init_t qwr_init = {0};
732 qwr_init.error_handler = nrf_qwr_error_handler;
733 err_code |= nrf_ble_qwr_init (&m_qwr, &qwr_init);
734 err_code |= peer_manager_init();
739 err_code |= conn_params_init();
741 err_code |= setup_phys();
744 if ( (NRF_SUCCESS == err_code))
746 m_gatt_is_init =
true;
765 m_gatt_is_init =
false;
775 if (NULL == _channel)
784 if (BLE_CONN_HANDLE_INVALID != m_conn_handle)
786 err_code |= sd_ble_gap_disconnect (m_conn_handle,
787 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
788 m_conn_handle = BLE_CONN_HANDLE_INVALID;
802 ret_code_t nrf_code = NRF_SUCCESS;
808 else if (BLE_NUS_MAX_DATA_LEN < message->data_length)
812 else if (BLE_CONN_HANDLE_INVALID == m_conn_handle)
823 nrf_code |= ble_nus_data_send (&m_nus, message->
data, &data_len, m_conn_handle);
839 ble_nus_init_t nus_init;
841 memset (&nus_init, 0,
sizeof (nus_init));
842 nus_init.data_handler = nus_data_handler;
843 err_code = ble_nus_init (&m_nus, &nus_init);
847 channel->
send = ri_gatt_nus_send;
848 channel->
read = ri_gatt_nus_read;
849 m_gatt_is_init =
true;
853 bool ble_nus_is_connected (
void)
855 ret_code_t err_code = NRF_SUCCESS;
856 ble_nus_client_context_t * p_client;
857 err_code = blcm_link_ctx_get (m_nus.p_link_ctx_storage, m_conn_handle,
860 if (NRF_SUCCESS != err_code)
865 if ( (m_conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
870 if (!p_client->is_notification_enabled)
880 ret_code_t err_code = NRF_SUCCESS;
881 ble_dfu_buttonless_init_t dfus_init = {0};
883 err_code = ble_dfu_buttonless_async_svci_init();
885 if (NRF_SUCCESS != err_code) {}
887 dfus_init.evt_handler = ble_dfu_evt_handler;
888 err_code = ble_dfu_buttonless_init (&dfus_init);
890 if (NRF_SUCCESS != err_code) {}
904 ret_code_t err_code = NRF_SUCCESS;
905 ble_dis_init_t dis_init;
907 memset (&dis_init, 0,
sizeof (dis_init));
908 memcpy (&dis_local, p_dis,
sizeof (dis_local));
909 ble_srv_ascii_to_utf8 (&dis_init.manufact_name_str, dis_local.
manufacturer);
910 ble_srv_ascii_to_utf8 (&dis_init.model_num_str, dis_local.
model);
911 ble_srv_ascii_to_utf8 (&dis_init.serial_num_str, dis_local.
deviceid);
912 ble_srv_ascii_to_utf8 (&dis_init.hw_rev_str, dis_local.
hw_version);
913 ble_srv_ascii_to_utf8 (&dis_init.fw_rev_str, dis_local.
fw_version);
916 dis_init.dis_char_rd_sec = SEC_OPEN;
917 err_code = ble_dis_init (&dis_init);
922 const uint16_t delay_ms)
925 ret_code_t nrf_status = NRF_SUCCESS;
926 ble_gap_conn_params_t gap_conn_params = {0};
933 LOG (
"RI_GATT_TURBO\r\n");
942 LOG (
"RI_GATT_LOW_POWER\r\n");
952 LOG (
"RI_GATT_STANDARD\r\n");
962 memcpy (&m_gatt_params, &gap_conn_params,
sizeof (gap_conn_params));
966 nrf_status = ble_conn_params_change_conn_params (m_conn_handle, &gap_conn_params);
968 if (NRF_SUCCESS != nrf_status)
971 NEXT_CONN_PARAMS_UPDATE_DELAY_TICKS, &m_gatt_params));
974 LOG (
"Retrying new params soon\r\n");
978 LOG (
"Switched to new params\r\n");
984 APP_TIMER_TICKS (delay_ms), &m_gatt_params));
987 LOG (
"New params set after delay\r\n");
#define RD_ERROR_NULL
Null Pointer.
#define RD_ERROR_FATAL
Program should always reset after this.
uint32_t rd_status_t
bitfield for representing errors
rd_status_t ruuvi_nrf5_sdk15_to_ruuvi_error(const ret_code_t error)
convert nrf5 sdk15 error code into Ruuvi error code.
#define RD_ERROR_CHECK(error, mask)
Shorthand macro for calling the rd_error_check with current file & line.
#define RD_ERROR_NOT_IMPLEMENTED
Not implemented yet.
#define RD_ERROR_NOT_SUPPORTED
Not supported.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_DATA_SIZE
Invalid Data size.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
void ri_flash_purge(void)
Purge flash.
rd_status_t ri_radio_get_modulation(ri_radio_modulation_t *const p_modulation)
Get the modulation used by application.
bool ri_radio_is_init()
Check if radio is initialized.
bool ri_radio_supports(ri_radio_modulation_t modulation)
Check if radio supports given modulation.
ri_radio_modulation_t
type of radio modulation to be used.
@ RI_RADIO_BLE_1MBPS
"Normal" BLE 4 modulation
@ RI_RADIO_BLE_2MBPS
"Fast BLE". Advertising uses 1MBPS primary advertisement followed by 2 MBit/s extended advertisement.
@ RI_RADIO_BLE_125KBPS
Also known as BLE Long Range S=8.
ret_code_t fds_gc(void)
Function for running garbage collection.
@ FDS_ERR_NO_SPACE_IN_QUEUES
Error. There is no space in the internal queues.
bool ri_timer_is_init(void)
Check if timer is initialized.
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
@ RI_COMM_CONNECTED
Connection established, OK to send, may receive data.
@ RI_COMM_RECEIVED
New data received, available to read with read function.
@ RI_COMM_SENT
One queued message was sent with all repetitions.
@ RI_COMM_DISCONNECTED
Connection lost, cannot send, may not receive data.
rd_status_t ri_gatt_init(void)
Initializes GATT stack. Uses default values from sdk_config.h, these can be overridden in nrf5_sdk15_...
#define RI_GATT_MIN_INTERVAL_TURBO_MS
#define RI_GATT_SLAVE_LATENCY_STANDARD
#define RI_GATT_SLAVE_LATENCY_TURBO
#define RI_GATT_MAX_INTERVAL_LOW_POWER_MS
rd_status_t ri_gatt_nus_uninit(ri_comm_channel_t *const _channel)
Uninitialize Nordic UART Service as a communication channel.
rd_status_t ri_gatt_dfu_init(void)
Initialize BLE4 Device firmware update service.
#define RI_GATT_SLAVE_LATENCY_LOW_POWER
rd_status_t ri_gatt_uninit(void)
Uninitializes GATT stack.
#define RI_GATT_CONN_SUP_TIMEOUT_MS
rd_status_t ri_gatt_nus_init(ri_comm_channel_t *const channel)
Initialize Nordic UART Service as a communication channel. ri_communication_radio_init(RI_COMMUNICATI...
#define RI_GATT_MIN_INTERVAL_LOW_POWER_MS
#define RI_GATT_MIN_INTERVAL_STANDARD_MS
#define RI_GATT_MAX_INTERVAL_STANDARD_MS
#define RI_GATT_MAX_INTERVAL_TURBO_MS
rd_status_t ri_gatt_params_request(const ri_gatt_params_t params, const uint16_t delay_ms)
Request connection parameter update for current connection.
rd_status_t ri_gatt_dis_init(const ri_comm_dis_init_t *const dis)
Initialize BLE4 Device Information service.
Interface functions to persistent flash storage.
void ri_power_reset(void)
Reset IC.
Interface functions to timer.
#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE
#define NRF_SDH_BLE_TOTAL_LINK_COUNT
control API for communication via outside world
ri_comm_evt_handler_fp_t on_evt
Callback to application-level event handler, must be set in application.
ri_comm_xfer_fp_t send
Asynchronous send function.
ri_comm_init_fp_t init
Initialize and populate channel api control.
ri_comm_init_fp_t uninit
Uninitialize and depopulate channel api control.
ri_comm_xfer_fp_t read
Asynchronous read function.
char fw_version[RI_COMM_DIS_STRLEN]
Human readable firmware version.
char deviceid[RI_COMM_DIS_STRLEN]
Human readable device ID.
char manufacturer[RI_COMM_DIS_STRLEN]
Human readable manufacturer name.
char hw_version[RI_COMM_DIS_STRLEN]
Human readable hardware version.
char model[RI_COMM_DIS_STRLEN]
Human readable board model.
Application message structure used for communication.
uint8_t data[RI_COMM_MESSAGE_MAX_LENGTH]
Data payload.
uint8_t repeat_count
Number of times to repeat the message,.
uint8_t data_length
Length of data.