ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_task_gatt.c
Go to the documentation of this file.
1
14#include "ruuvi_interface_log.h"
15#include "ruuvi_interface_rtc.h"
19#include "ruuvi_task_gatt.h"
20#if RT_GATT_ENABLED
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25
26#ifndef TASK_GATT_LOG_LEVEL
27#define TASK_GATT_LOG_LEVEL RI_LOG_LEVEL_INFO
28#endif
29
30static inline void LOGD (const char * const msg)
31{
33}
34
35static inline void LOGDHEX (const uint8_t * const msg, const size_t len)
36{
38}
39
40static ri_comm_channel_t m_channel;
41static bool m_is_init;
42static bool m_nus_is_init;
43static bool m_dis_is_init;
44static bool m_dfu_is_init;
45static bool m_nus_is_connected;
46static char m_name[SCAN_RSP_NAME_MAX_LEN + 1] = { 0 };
47
48static ri_comm_cb_t m_on_connected;
49static ri_comm_cb_t m_on_disconnected;
50static ri_comm_cb_t m_on_received;
51static ri_comm_cb_t m_on_sent;
52
53// https://github.com/arm-embedded/gcc-arm-none-eabi.debian/blob/master/src/libiberty/strnlen.c
54// Not included when compiled with std=c99.
55static inline size_t safe_strlen (const char * s, size_t maxlen)
56{
57 size_t i;
58
59 for (i = 0; (i < maxlen) && ('\0' != s[i]); ++i);
60
61 return i;
62}
63
64#ifdef CEEDLING
65void rt_gatt_mock_state_reset()
66{
67 m_on_connected = NULL;
68 m_on_disconnected = NULL;
69 m_on_received = NULL;
70 m_on_sent = NULL;
71 m_is_init = false;
72 m_nus_is_init = false;
73 m_dfu_is_init = false;
74 m_dis_is_init = false;
75 m_nus_is_connected = false;
76 memset (&m_channel, 0, sizeof (ri_comm_channel_t));
77 memset (m_name, 0, sizeof (m_name));
78}
79#endif
80
99#ifndef CEEDLING
100static
101#endif
102rd_status_t rt_gatt_on_nus_isr (ri_comm_evt_t evt,
103 void * p_data, size_t data_len)
104{
105 switch (evt)
106 {
107 // Note: This gets called only after the NUS notifications have been registered.
109 m_nus_is_connected = true;
110 (NULL != m_on_connected) ? m_on_connected (p_data, data_len) : false;
111 break;
112
114 m_nus_is_connected = false;
115 (NULL != m_on_disconnected) ? m_on_disconnected (p_data, data_len) : false;
116 break;
117
118 case RI_COMM_SENT:
119 (NULL != m_on_sent) ? m_on_sent (p_data, data_len) : false;
120 break;
121
122 case RI_COMM_RECEIVED:
123 LOGD ("<<<;");
124 LOGDHEX (p_data, data_len);
125 LOGD (";\r\n");
126 (NULL != m_on_received) ? m_on_received (p_data, data_len) : false;
127 break;
128
129 default:
130 break;
131 }
132
133 return RD_SUCCESS;
134}
135
137{
138 rd_status_t err_code = RD_SUCCESS;
139
140 if (NULL == p_dis)
141 {
142 err_code |= RD_ERROR_NULL;
143 }
144 else if (rt_gatt_is_init() && (!m_dis_is_init))
145 {
146 err_code |= ri_gatt_dis_init (p_dis);
147 m_dis_is_init = (RD_SUCCESS == err_code);
148 }
149 else
150 {
151 err_code |= RD_ERROR_INVALID_STATE;
152 }
153
154 return err_code;
155}
156
158{
159 rd_status_t err_code = RD_SUCCESS;
160
161 if (rt_gatt_is_init() && (!m_nus_is_init))
162 {
163 err_code |= ri_gatt_nus_init (&m_channel);
164
165 if (RD_SUCCESS == err_code)
166 {
167 m_channel.on_evt = rt_gatt_on_nus_isr;
168 m_nus_is_init = true;
169 }
170 }
171 else
172 {
173 err_code |= RD_ERROR_INVALID_STATE;
174 }
175
176 return err_code;
177}
178
180{
181 rd_status_t err_code = RD_SUCCESS;
182
183 if (rt_gatt_is_init() && (!m_dfu_is_init))
184 {
185 err_code |= ri_gatt_dfu_init();
186 m_dfu_is_init = (RD_SUCCESS == err_code);
187 }
188 else
189 {
190 err_code |= RD_ERROR_INVALID_STATE;
191 }
192
193 return err_code;
194}
195
196rd_status_t rt_gatt_init (const char * const name)
197{
198 rd_status_t err_code = RD_SUCCESS;
199
200 if (NULL == name)
201 {
202 err_code |= RD_ERROR_NULL;
203 }
204 else if (rt_adv_is_init() && (!rt_gatt_is_init()))
205 {
206 const size_t name_length = safe_strlen (name, sizeof (m_name));
207
208 if (sizeof (m_name) > name_length)
209 {
210 err_code |= ri_gatt_init();
211 memcpy (m_name, name, name_length);
212 m_name[name_length] = '\0';
213 }
214 else
215 {
216 err_code |= RD_ERROR_INVALID_LENGTH;
217 }
218 }
219 else
220 {
221 err_code |= RD_ERROR_INVALID_STATE;
222 }
223
224 if (RD_SUCCESS == err_code)
225 {
226 m_is_init = true;
227 }
228
229 return err_code;
230}
231
233{
234 rd_status_t err_code = RD_SUCCESS;
235
236 if (rt_adv_is_init())
237 {
238 err_code |= RD_ERROR_INVALID_STATE;
239 }
240 else
241 {
243 err_code |= ri_radio_get_modulation (&modulation);
248 err_code |= ri_radio_uninit();
249 err_code |= ri_gatt_uninit();
250 memset (&m_channel, 0, sizeof (m_channel));
251 err_code |= ri_radio_init (modulation);
252 m_is_init = false;
253 m_dis_is_init = false;
254 m_nus_is_init = false;
255 m_dfu_is_init = false;
256 }
257
258 return err_code;
259}
260
262{
263 rd_status_t err_code = RD_SUCCESS;
264
265 if (rt_gatt_is_init())
266 {
267 err_code |= rt_adv_connectability_set (true, m_name);
268 }
269 else
270 {
271 err_code |= RD_ERROR_INVALID_STATE;
272 }
273
274 return err_code;
275}
276
278{
279 rd_status_t err_code = RD_SUCCESS;
280
281 if (rt_gatt_is_init())
282 {
283 err_code |= rt_adv_connectability_set (false, NULL);
284 }
285 else
286 {
287 err_code |= RD_ERROR_INVALID_STATE;
288 }
289
290 return err_code;
291}
292
293bool rt_gatt_is_init (void)
294{
295 return m_is_init;
296}
297
303bool rt_gatt_nus_is_connected (void)
304{
305 return m_nus_is_connected && (NULL != m_channel.send);
306}
307
309 * const p_msg)
310{
311 rd_status_t err_code = RD_SUCCESS;
312
313 // State, input check
314 if (NULL == p_msg)
315 {
316 err_code |= RD_ERROR_NULL;
317 }
318 else if (!rt_gatt_nus_is_connected())
319 {
320 err_code |= RD_ERROR_INVALID_STATE;
321 }
322 else
323 {
324 // Try to put data to SD
325 err_code |= m_channel.send (p_msg);
326
327 // If success, return. Else put data to ringbuffer
328 if (RD_SUCCESS == err_code)
329 {
330 LOGD (">>>;");
331 LOGDHEX (p_msg->data, p_msg->data_length);
332 LOGD (";\r\n");
333 }
334 else if (RD_ERROR_RESOURCES == err_code)
335 {
336 err_code = RD_ERROR_NO_MEM;
337 }
338 // If the error code is something else than buffer full, return error.
339 else
340 {
341 RD_ERROR_CHECK (err_code, ~RD_ERROR_FATAL);
342 }
343 }
344
345 return err_code;
346}
347
349{
350 m_on_connected = cb;
351}
352
353
355{
356 m_on_disconnected = cb;
357}
358
360{
361 m_on_received = cb;
362}
363
365{
366 m_on_sent = cb;
367}
368
369bool rt_gatt_is_nus_enabled (void)
370{
371 return m_nus_is_init;
372}
373
374#else
380
385
387{
389}
390
395
396rd_status_t rt_gatt_init (const char * const name)
397{
399}
400
405
410
412{
413 return false;
414}
415
417{
418 // No implementation needed
419}
420
421
423{
424 // No implementation needed
425}
426
428{
429 // No implementation needed
430}
431
433{
434 // No implementation needed
435}
436
438{
439 return false;
440}
441
442#endif
#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
#define RD_ERROR_INVALID_LENGTH
Invalid Length.
#define RD_ERROR_CHECK(error, mask)
Shorthand macro for calling the rd_error_check with current file & line.
#define RD_ERROR_NOT_ENABLED
Driver is not enabled.
#define RD_ERROR_RESOURCES
Not enough resources for operation.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_NO_MEM
No Memory for operation.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
void ri_log_hex(const ri_log_severity_t severity, const uint8_t *const bytes, size_t byte_length)
Queues bytes to be logged out as a hex string.
void ri_log(const ri_log_severity_t severity, const char *const message)
Queues messages into log.
@ RI_LOG_LEVEL_DEBUG
rd_status_t ri_radio_get_modulation(ri_radio_modulation_t *const p_modulation)
Get the modulation used by application.
rd_status_t ri_radio_init(const ri_radio_modulation_t modulation)
Enable radio stack for an user. This function also starts radio activity callbacks internally.
rd_status_t ri_radio_uninit()
Release radio stack.
ri_radio_modulation_t
type of radio modulation to be used.
@ RI_RADIO_BLE_1MBPS
"Normal" BLE 4 modulation
rd_status_t rt_adv_connectability_set(const bool enable, const char *const device_name)
Start advertising BLE GATT connection.
bool rt_adv_is_init(void)
check if advertisement is initialized
#define SCAN_RSP_NAME_MAX_LEN
Longer name gets truncated when advertised with UUID.
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
void(* ri_comm_cb_t)(void *p_data, size_t data_len)
ri_comm_evt_t
Communication event type.
@ 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_...
rd_status_t ri_gatt_dfu_init(void)
Initialize BLE4 Device firmware update service.
rd_status_t ri_gatt_uninit(void)
Uninitializes GATT stack.
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...
rd_status_t ri_gatt_dis_init(const ri_comm_dis_init_t *const dis)
Initialize BLE4 Device Information service.
#define LOGD(fmt,...)
Interface functions to scheduler.
Helper functions for communication.
rd_status_t rt_gatt_dfu_init(void)
Initialize Device Firmware Update service.
bool rt_gatt_is_nus_enabled(void)
Check if Nordic UART Service is enabled.
void rt_gatt_set_on_disconn_isr(const ri_comm_cb_t cb)
Setup disconnection event handler.
rd_status_t rt_gatt_adv_enable()
Start advertising GATT connection to devices.
rd_status_t rt_gatt_dis_init(const ri_comm_dis_init_t *const dis)
Initialize Device Information Update service.
rd_status_t rt_gatt_adv_disable()
Stop advertising GATT connection to devices.
rd_status_t rt_gatt_init(const char *const name)
Initialize GATT. Must be called as a first function in rt_gatt.
void rt_gatt_set_on_sent_isr(const ri_comm_cb_t cb)
Setup data sent event handler.
bool rt_gatt_is_init()
check if GATT task is initialized
void rt_gatt_set_on_connected_isr(const ri_comm_cb_t cb)
Setup connection event handler.
rd_status_t rt_gatt_nus_init()
Initialize Nordic UART Service.
rd_status_t rt_gatt_send_asynchronous(ri_comm_message_t *const p_msg)
Send given message via NUS.
void rt_gatt_set_on_received_isr(const ri_comm_cb_t cb)
Setup data received event handler.
bool rt_gatt_nus_is_connected()
check if NUS is connected, i.e. central has registered to TX notifications.
rd_status_t rt_gatt_uninit(void)
Uninitialize GATT.
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.
Application message structure used for communication.
uint8_t data[RI_COMM_MESSAGE_MAX_LENGTH]
Data payload.
uint8_t data_length
Length of data.