1 /**
2 ****************************************************************************************
3 *
4 * @file lns.c
5 *
6 * @brief Log Notification Service implementation.
7 *
8 ****************************************************************************************
9 * @attention
10 #####Copyright (c) 2019 GOODIX
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 * Neither the name of GOODIX nor the names of its contributors may be used
21 to endorse or promote products derived from this software without
22 specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
35 *****************************************************************************************
36 */
37
38 /*
39 * INCLUDE FILES
40 ****************************************************************************************
41 */
42 #include <string.h>
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 #include "lns.h"
47
48 /*
49 * DEFINES
50 *****************************************************************************************
51 */
52 #define LNS_DEFAULT_GATT_PAYLOAD 20
53 #define LNS_LOG_INFO_CHARACTERISTIC_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, \
54 0x0A, 0x46, 0x44, 0xD3, 0x02, 0x08, 0xED, 0xA6}
55 #define LNS_LOG_CTRL_PT_CHARACTERISTIC_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, \
56 0x0A, 0x46, 0x44, 0xD3, 0x03, 0x08, 0xED, 0xA6}
57
58 /**@brief Macros for conversion of 128bit to 16bit UUID. */
59 #define ATT_128_PRIMARY_SERVICE BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
60 #define ATT_128_CHARACTERISTIC BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
61 #define ATT_128_CLIENT_CHAR_CFG BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)
62
63 /*
64 * ENUMERATIONS
65 ****************************************************************************************
66 */
67 /**@brief Log Notification Service Attributes Indexes. */
68 enum {
69 // Log Notification Service
70 LNS_IDX_SVC,
71
72 // Log Information
73 LNS_IDX_LOG_INFO_CHAR,
74 LNS_IDX_LOG_INFO_VAL,
75 LNS_IDX_LOG_INFO_NTF_CFG,
76
77 // Log Control Point
78 LNS_IDX_LOG_CTRL_PT_CHAR,
79 LNS_IDX_LOG_CTRL_PT_VAL,
80 LNS_IDX_LOG_CTRL_PT_IND_CFG,
81
82 LNS_IDX_NB
83 };
84
85 /*
86 * STRUCTURES
87 *****************************************************************************************
88 */
89 /**@brief Log Notification Service environment variable. */
90 struct lns_env_t {
91 lns_evt_handler_t evt_handler; /**< Log Notification Service event handler. */
92 uint16_t start_hdl; /**< Log Notification Service start handle. */
93 uint16_t payload_len; /**< Length of gatt payload. */
94 uint16_t
95 log_info_ntf_cfg[LNS_CONNECTION_MAX]; /**< The configuration of Log Information Notification \
96 which is configured by the peer devices. */
97 uint16_t
98 log_ctrl_pt_ind_cfg[LNS_CONNECTION_MAX]; /**< The configuration of Log Control Point indication \
99 which is configured by the peer devices. */
100 };
101
102 /*
103 * LOCAL FUNCTION DECLARATION
104 *****************************************************************************************
105 */
106 static sdk_err_t lns_init(void);
107 static void lns_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
108 static void lns_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
109 static void lns_gatts_cplt_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
110 static void lns_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
111 static sdk_err_t lns_log_info_chunk(uint8_t conn_idx);
112 static void lns_evt_handler(lns_evt_t *p_evt);
113
114 /*
115 * LOCAL VARIABLE DEFINITIONS
116 *****************************************************************************************
117 */
118 static struct lns_env_t s_lns_env;
119 static lns_log_data_t s_log_data_ntf;
120 static uint16_t s_lns_char_mask = 0x007f;
121
122 /**@brief Full LNS Database Description - Used to add attributes into the database. */
123 static const attm_desc_128_t lns_attr_tab[LNS_IDX_NB] = {
124 // Log Notification Service Declaration
125 [LNS_IDX_SVC] = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
126
127 // Log Information Characteristic - Declaration
128 [LNS_IDX_LOG_INFO_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
129 // Log Information Characteristic - Value
130 [LNS_IDX_LOG_INFO_VAL] = {
131 LNS_LOG_INFO_CHARACTERISTIC_UUID,
132 NOTIFY_PERM_UNSEC,
133 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128),
134 LNS_LOG_INFO_VAL_LEN
135 },
136 // Log Information Characteristic - Client Characteristic Configuration Descriptor
137 [LNS_IDX_LOG_INFO_NTF_CFG] = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
138
139 // Log Control Point Characteristic - Declaration
140 [LNS_IDX_LOG_CTRL_PT_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
141 // Log Control Point Characteristic - Value
142 [LNS_IDX_LOG_CTRL_PT_VAL] = {
143 LNS_LOG_CTRL_PT_CHARACTERISTIC_UUID,
144 INDICATE_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
145 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128),
146 LNS_LOG_CTRL_PT_VAL_LEN
147 },
148 // Log Control Point Characteristic - Client Characteristic Configuration Descriptor
149 [LNS_IDX_LOG_CTRL_PT_IND_CFG] = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
150 };
151
152 /**@brief LNS Task interface required by profile manager. */
153 static ble_prf_manager_cbs_t lns_task_cbs = {
154 (prf_init_func_t) lns_init,
155 NULL,
156 NULL,
157 };
158
159 /**@brief LNS Task Callbacks. */
160 static gatts_prf_cbs_t lns_cb_func = {
161 lns_read_att_cb,
162 lns_write_att_cb,
163 NULL,
164 lns_gatts_cplt_cb,
165 lns_cccd_set_cb
166 };
167
168 /**@brief LNS Information. */
169 static const prf_server_info_t lns_prf_info = {
170 .max_connection_nb = LNS_CONNECTION_MAX,
171 .manager_cbs = &lns_task_cbs,
172 .gatts_prf_cbs = &lns_cb_func,
173 };
174
175 /*
176 * LOCAL FUNCTION DEFINITIONS
177 *****************************************************************************************
178 */
179 /**
180 *****************************************************************************************
181 * @brief Initialize Log Notification Service and create db in att
182 *
183 * @return Error code to know if profile initialization succeed or not.
184 *****************************************************************************************
185 */
lns_init(void)186 static sdk_err_t lns_init(void)
187 {
188 // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
189 uint16_t start_hdl = PRF_INVALID_HANDLE;
190 const uint8_t lns_svc_uuid[] = {LNS_SERVICE_UUID};
191 sdk_err_t error_code;
192 gatts_create_db_t gatts_db;
193
194 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
195 if (error_code < 0) {
196 return error_code;
197 }
198
199 gatts_db.shdl = &start_hdl;
200 gatts_db.uuid = lns_svc_uuid;
201 gatts_db.attr_tab_cfg = (uint8_t *)&s_lns_char_mask;
202 gatts_db.max_nb_attr = LNS_IDX_NB;
203 gatts_db.srvc_perm = SRVC_UUID_TYPE_SET(UUID_TYPE_128);
204 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_128;
205 gatts_db.attr_tab.attr_tab_128 = lns_attr_tab;
206
207 error_code = ble_gatts_srvc_db_create(&gatts_db);
208 if (SDK_SUCCESS == error_code) {
209 s_lns_env.start_hdl = *gatts_db.shdl;
210 }
211
212 return error_code;
213 }
214
215 /**
216 *****************************************************************************************
217 * @brief Handles reception of the attribute info request message.
218 *
219 * @param[in] conn_idx: Connection index
220 * @param[in] p_param: The parameters of the read request.
221 *****************************************************************************************
222 */
lns_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)223 static void lns_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
224 {
225 gatts_read_cfm_t cfm;
226 uint8_t handle = p_param->handle;
227 uint8_t tab_index = prf_find_idx_by_handle(handle,
228 s_lns_env.start_hdl,
229 LNS_IDX_NB,
230 (uint8_t *)&s_lns_char_mask);
231 cfm.handle = handle;
232 cfm.status = BLE_SUCCESS;
233
234 switch (tab_index) {
235 case LNS_IDX_LOG_INFO_NTF_CFG:
236 cfm.length = sizeof(uint16_t);
237 cfm.value = (uint8_t *)&s_lns_env.log_info_ntf_cfg[conn_idx];
238 break;
239
240 case LNS_IDX_LOG_CTRL_PT_IND_CFG:
241 cfm.length = sizeof(uint16_t);
242 cfm.value = (uint8_t *)&s_lns_env.log_ctrl_pt_ind_cfg[conn_idx];
243 break;
244
245 default:
246 cfm.length = 0;
247 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
248 break;
249 }
250
251 ble_gatts_read_cfm(conn_idx, &cfm);
252 }
253
254 /**
255 *****************************************************************************************
256 * @brief Handles reception of the write request.
257 *
258 * @param[in]: conn_idx: Connection index
259 * @param[in]: p_param: The parameters of the write request.
260 *****************************************************************************************
261 */
lns_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)262 static void lns_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
263 {
264 uint16_t handle = p_param->handle;
265 uint16_t tab_index = 0;
266 uint16_t cccd_value = 0;
267 lns_evt_t event;
268 gatts_write_cfm_t cfm;
269
270 tab_index = prf_find_idx_by_handle(handle,
271 s_lns_env.start_hdl,
272 LNS_IDX_NB,
273 (uint8_t *)&s_lns_char_mask);
274 cfm.handle = handle;
275 cfm.status = BLE_SUCCESS;
276 event.evt_type = LNS_EVT_INVALID;
277 event.conn_idx = conn_idx;
278
279 switch (tab_index) {
280 case LNS_IDX_LOG_INFO_NTF_CFG:
281 cccd_value = le16toh(&p_param->value[0]);
282 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
283 LNS_EVT_LOG_INFO_NTF_ENABLE : \
284 LNS_EVT_LOG_INFO_NTF_DISABLE);
285 s_lns_env.log_info_ntf_cfg[conn_idx] = cccd_value;
286 break;
287
288 case LNS_IDX_LOG_CTRL_PT_IND_CFG:
289 cccd_value = le16toh(&p_param->value[0]);
290 event.evt_type = ((PRF_CLI_START_IND == cccd_value) ? \
291 LNS_EVT_CTRL_PT_IND_ENABLE : \
292 LNS_EVT_CTRL_PT_IND_DISABLE);
293 s_lns_env.log_ctrl_pt_ind_cfg[conn_idx] = cccd_value;
294 break;
295
296 case LNS_IDX_LOG_CTRL_PT_VAL: {
297 switch (p_param->value[0]) {
298 case LNS_CTRL_PT_TRACE_STATUS_GET:
299 event.evt_type = LNS_EVT_TRACE_STATUS_GET;
300 break;
301
302 case LNS_CTRL_PT_TRACE_INFO_DUMP:
303 event.evt_type = LNS_EVT_TRACE_INFO_DUMP;
304 break;
305
306 case LNS_CTRL_PT_TRACE_INFO_CLEAR:
307 event.evt_type = LNS_EVT_TRACE_INFO_CLEAR;
308 break;
309
310 default:
311 break;
312 }
313 }
314 break;
315
316 default:
317 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
318 break;
319 }
320
321 ble_gatts_write_cfm(conn_idx, &cfm);
322
323 if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && LNS_EVT_INVALID != event.evt_type) {
324 lns_evt_handler(&event);
325 }
326 }
327
328 /**
329 *****************************************************************************************
330 * @brief Handles reception of the cccd recover request.
331 *
332 * @param[in]: conn_idx: Connection index
333 * @param[in]: handle: The handle of cccd attribute.
334 * @param[in]: cccd_value: The value of cccd attribute.
335 *****************************************************************************************
336 */
lns_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)337 static void lns_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
338 {
339 uint16_t tab_index = 0;
340 lns_evt_t event;
341
342 if (!prf_is_cccd_value_valid(cccd_value)) {
343 return;
344 }
345
346 tab_index = prf_find_idx_by_handle(handle,
347 s_lns_env.start_hdl,
348 LNS_IDX_NB,
349 (uint8_t *)&s_lns_char_mask);
350
351 event.evt_type = LNS_EVT_INVALID;
352 event.conn_idx = conn_idx;
353
354 switch (tab_index) {
355 case LNS_IDX_LOG_INFO_NTF_CFG:
356 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
357 LNS_EVT_LOG_INFO_NTF_ENABLE : \
358 LNS_EVT_LOG_INFO_NTF_DISABLE);
359 s_lns_env.log_info_ntf_cfg[conn_idx] = cccd_value;
360 break;
361
362 case LNS_IDX_LOG_CTRL_PT_IND_CFG:
363 event.evt_type = ((PRF_CLI_START_IND == cccd_value) ? \
364 LNS_EVT_CTRL_PT_IND_ENABLE : \
365 LNS_EVT_CTRL_PT_IND_DISABLE);
366 s_lns_env.log_ctrl_pt_ind_cfg[conn_idx] = cccd_value;
367 break;
368
369 default:
370 break;
371 }
372
373 if (LNS_EVT_INVALID != event.evt_type && s_lns_env.evt_handler) {
374 s_lns_env.evt_handler(&event);
375 }
376 }
377
378 /**
379 *****************************************************************************************
380 * @brief Handles reception of the complete event.
381 *
382 * @param[in] conn_idx: Connection index.
383 * @param[in] p_param: Pointer to the parameters of the complete event.
384 *****************************************************************************************
385 */
lns_gatts_cplt_cb(uint8_t conn_idx,uint8_t status,const ble_gatts_ntf_ind_t * p_ntf_ind)386 static void lns_gatts_cplt_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
387 {
388 uint8_t tab_index;
389
390 tab_index = prf_find_idx_by_handle(p_ntf_ind->handle,
391 s_lns_env.start_hdl,
392 LNS_IDX_NB,
393 (uint8_t *)&s_lns_char_mask);
394 if (LNS_IDX_LOG_INFO_VAL == tab_index) {
395 if (BLE_SUCCESS == status) {
396 lns_log_info_chunk(conn_idx);
397 } else {
398 s_log_data_ntf.length = 0;
399 s_log_data_ntf.offset = 0;
400
401 sys_free(s_log_data_ntf.p_data);
402 }
403 }
404 }
405
406 /**
407 *****************************************************************************************
408 * @brief Handles lns event.
409 *
410 * @param[in] p_evt: Pointer to event.
411 *****************************************************************************************
412 */
lns_evt_handler(lns_evt_t * p_evt)413 static void lns_evt_handler(lns_evt_t *p_evt)
414 {
415 uint8_t trace_log_num = 0;
416
417 switch (p_evt->evt_type) {
418 case LNS_EVT_TRACE_STATUS_GET:
419 trace_log_num = fault_db_records_num_get();
420 lns_log_status_send(p_evt->conn_idx, trace_log_num);
421 break;
422
423 case LNS_EVT_TRACE_INFO_DUMP:
424 lns_log_info_send(p_evt->conn_idx);
425 break;
426
427 case LNS_EVT_TRACE_INFO_CLEAR:
428 fault_db_record_clear();
429 break;
430 default :
431 break;
432 }
433
434 if (LNS_EVT_INVALID != p_evt->evt_type && s_lns_env.evt_handler) {
435 s_lns_env.evt_handler(p_evt);
436 }
437 }
438
439 /**
440 *****************************************************************************************
441 * @brief Handle Log Information data notify.
442 *
443 * @param[in] conn_idx: Connection index.
444 *
445 * @return Result of handle.
446 *****************************************************************************************
447 */
lns_log_info_chunk(uint8_t conn_idx)448 static sdk_err_t lns_log_info_chunk(uint8_t conn_idx)
449 {
450 uint16_t chunk_len = 0;
451 sdk_err_t error_code = SDK_ERR_NTF_DISABLED;
452 gatts_noti_ind_t data_ntf;
453
454 chunk_len = s_log_data_ntf.length - s_log_data_ntf.offset;
455 chunk_len = chunk_len > s_lns_env.payload_len ? s_lns_env.payload_len : chunk_len;
456
457 if (chunk_len == 0) {
458 s_log_data_ntf.length = 0;
459 s_log_data_ntf.offset = 0;
460
461 sys_free(s_log_data_ntf.p_data);
462
463 return SDK_SUCCESS;
464 }
465
466 if (PRF_CLI_START_NTF == s_lns_env.log_info_ntf_cfg[conn_idx]) {
467 data_ntf.type = BLE_GATT_NOTIFICATION;
468 data_ntf.handle = prf_find_handle_by_idx(LNS_IDX_LOG_INFO_VAL,
469 s_lns_env.start_hdl,
470 (uint8_t *)&s_lns_char_mask);
471 data_ntf.length = chunk_len;
472 data_ntf.value = (uint8_t *)s_log_data_ntf.p_data + s_log_data_ntf.offset;
473
474 error_code = ble_gatts_noti_ind(conn_idx, &data_ntf);
475 }
476
477 if (SDK_SUCCESS == error_code) {
478 s_log_data_ntf.offset += chunk_len;
479 }
480
481 return error_code;
482 }
483
484 /*
485 * GLOBAL FUNCTION DEFINITIONS
486 *****************************************************************************************
487 */
lns_service_init(lns_evt_handler_t evt_handler)488 sdk_err_t lns_service_init(lns_evt_handler_t evt_handler)
489 {
490 s_lns_env.evt_handler = evt_handler;
491 s_lns_env.payload_len = LNS_DEFAULT_GATT_PAYLOAD;
492
493 return ble_server_prf_add(&lns_prf_info);
494 }
495
lns_log_info_send(uint8_t conn_idx)496 sdk_err_t lns_log_info_send(uint8_t conn_idx)
497 {
498 s_log_data_ntf.offset = 0;
499 s_log_data_ntf.length = fault_db_records_total_len_get();
500 s_log_data_ntf.p_data = sys_malloc(s_log_data_ntf.length);
501
502 if (s_log_data_ntf.p_data) {
503 fault_db_records_dump(s_log_data_ntf.p_data, &s_log_data_ntf.length);
504 } else {
505 return SDK_ERR_NO_RESOURCES;
506 }
507
508 return lns_log_info_chunk(conn_idx);
509 }
510
lns_log_status_send(uint8_t conn_idx,const uint8_t log_num)511 sdk_err_t lns_log_status_send(uint8_t conn_idx, const uint8_t log_num)
512 {
513 sdk_err_t error_code = SDK_ERR_IND_DISABLED;
514 gatts_noti_ind_t status_ind;
515
516 if (PRF_CLI_START_IND == s_lns_env.log_ctrl_pt_ind_cfg[conn_idx]) {
517 status_ind.type = BLE_GATT_INDICATION;
518 status_ind.handle = prf_find_handle_by_idx(LNS_IDX_LOG_CTRL_PT_VAL,
519 s_lns_env.start_hdl,
520 (uint8_t *)&s_lns_char_mask);
521 status_ind.length = LNS_LOG_CTRL_PT_VAL_LEN;
522 status_ind.value = (uint8_t *)&log_num;
523
524 error_code = ble_gatts_noti_ind(conn_idx, &status_ind);
525 }
526
527 return error_code;
528 }
529
lns_pay_load_update(uint8_t conn_idx,const uint16_t payload_len)530 sdk_err_t lns_pay_load_update(uint8_t conn_idx, const uint16_t payload_len)
531 {
532 if (s_lns_env.payload_len > LNS_LOG_INFO_VAL_LEN) {
533 s_lns_env.payload_len = LNS_LOG_INFO_VAL_LEN;
534 } else {
535 s_lns_env.payload_len = payload_len;
536 }
537
538 return SDK_SUCCESS;
539 }
540
541