• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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