• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file mlmr.c
5  *
6  * @brief Goodix UART 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 "mlmr.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 #include "user_app.h"
47 #include "app_log.h"
48 #define MTU_DEF_OFFSET 3
49 #define DATA_COPY_LEN 2
50 /*
51  * DEFINES
52  *****************************************************************************************
53  */
54 /**@brief The UUIDs of GUS characteristics. */
55 #define GUS_SERVER_TX_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75,
56                             0x80, 0x0A, 0x46, 0x44, 0xD3, 0x02, 0x02, 0xED, 0xA6}
57 #define GUS_SERVER_RX_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75,
58                             0x80, 0x0A, 0x46, 0x44, 0xD3, 0x03, 0x02, 0xED, 0xA6}
59 #define GUS_FLOW_CTRL_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75,
60                             0x80, 0x0A, 0x46, 0x44, 0xD3, 0x04, 0x02, 0xED, 0xA6}
61 
62 /**@brief Macros for conversion of 128bit to 16bit UUID. */
63 #define ATT_128_PRIMARY_SERVICE BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
64 #define ATT_128_CHARACTERISTIC  BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
65 #define ATT_128_CLIENT_CHAR_CFG BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)
66 
67 /*
68  * ENUMERATIONS
69  *****************************************************************************************
70  */
71 /**@brief Goodix UART Service Attributes Indexes. */
72 enum gus_attr_idx_t {
73     GUS_IDX_SVC,
74 
75     GUS_IDX_TX_CHAR,
76     GUS_IDX_TX_VAL,
77     GUS_IDX_TX_CFG,
78 
79     GUS_IDX_RX_CHAR,
80     GUS_IDX_RX_VAL,
81 
82     GUS_IDX_FLOW_CTRL_CHAR,
83     GUS_IDX_FLOW_CTRL_VAL,
84     GUS_IDX_FLOW_CTRL_CFG,
85 
86     GUS_IDX_NB,
87 };
88 
89 /*
90  * STRUCTURES
91  *****************************************************************************************
92  */
93 /**@brief Goodix UART Service environment variable. */
94 struct gus_env_t {
95     gus_init_t gus_init;                               /**< Goodix UART Service initialization variables. */
96     uint16_t   start_hdl;                              /**< Start handle of services */
97     uint16_t   tx_ntf_cfg[GUS_CONNECTION_MAX];         /**< TX Characteristic Notification configuration of
98                                                         the peers. */
99     uint16_t
100     flow_ctrl_ntf_cfg[GUS_CONNECTION_MAX];  /**< Flow Control Characteristic Notification configuration of the peers. */
101 };
102 
103 /*
104  * LOCAL FUNCTION DECLARATION
105  *****************************************************************************************
106  */
107 static sdk_err_t   gus_init(void);
108 static void        gus_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
109 static void        gus_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
110 static void        gus_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
111 static void        gus_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
112 
113 /*
114  * LOCAL VARIABLE DEFINITIONS
115  *****************************************************************************************
116  */
117 static struct gus_env_t s_gus_env;
118 static const uint16_t   s_char_mask = 0x003F;
119 
120 static uint16_t         received_data_len[CFG_BOND_DEVS];
121 static uint16_t         send_data_len[CFG_BOND_DEVS];
122 static uint8_t          adv_header           = 0xA0;
123 static uint8_t          rx_buffer[CFG_BOND_DEVS][516];
124 
125 /**@brief Full GUS Database Description which is used to add attributes into the ATT database. */
126 static const attm_desc_128_t gus_att_db[GUS_IDX_NB] = {
127     // GUS service
128     [GUS_IDX_SVC]            = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
129 
130     // GUS TX Characteristic Declaration
131     [GUS_IDX_TX_CHAR]        = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
132     // GUS TX Characteristic Value
133     [GUS_IDX_TX_VAL]         = {
134         GUS_SERVER_TX_UUID,
135         NOTIFY_PERM_UNSEC,
136         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
137         GUS_MAX_DATA_LEN
138     },
139     // GUS TX Characteristic - Client Characteristic Configuration Descriptor
140     [GUS_IDX_TX_CFG]         = {
141         ATT_128_CLIENT_CHAR_CFG,
142         READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
143         0,
144         0
145     },
146 
147     // GUS RX Characteristic Declaration
148     [GUS_IDX_RX_CHAR]        = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
149     // GUS RX Characteristic Value
150     [GUS_IDX_RX_VAL]         = {
151         GUS_SERVER_RX_UUID,
152         WRITE_REQ_PERM_UNSEC | WRITE_CMD_PERM_UNSEC,
153         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
154         GUS_MAX_DATA_LEN
155     },
156 
157     // GUS FLOW_CTRL Characteristic Declaration
158     [GUS_IDX_FLOW_CTRL_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
159     // GUS FLOW_CTRL Characteristic Value
160     [GUS_IDX_FLOW_CTRL_VAL]  = {
161         GUS_FLOW_CTRL_UUID,
162         NOTIFY_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
163         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
164         GUS_MAX_DATA_LEN
165     },
166     // GUS FLOW_CTRL Characteristic - Client Characteristic Configuration Descriptor
167     [GUS_IDX_FLOW_CTRL_CFG]  = {
168         ATT_128_CLIENT_CHAR_CFG,
169         READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
170         0,
171         0
172     },
173 };
174 
175 /**@brief GUS Service interface required by profile manager. */
176 static ble_prf_manager_cbs_t gus_mgr_cbs = {
177     (prf_init_func_t)gus_init,
178     NULL,
179     NULL,
180 };
181 
182 /**@brief GUS GATT Server Callbacks. */
183 static gatts_prf_cbs_t gus_gatts_cbs = {
184     gus_read_att_cb,
185     gus_write_att_cb,
186     NULL,
187     gus_ntf_ind_cb,
188     gus_cccd_set_cb
189 };
190 
191 /**@brief GUS Server Information. */
192 static const prf_server_info_t gus_prf_info = {
193     .max_connection_nb = GUS_CONNECTION_MAX,
194     .manager_cbs       = &gus_mgr_cbs,
195     .gatts_prf_cbs     = &gus_gatts_cbs
196 };
197 
198 /*
199  * LOCAL FUNCTION DEFINITIONS
200  *****************************************************************************************
201  */
202 /**
203  *****************************************************************************************
204  * @brief Initialize GUS and create DB in ATT.
205  *
206  * @return Error code to know if service initialization succeed or not.
207  *****************************************************************************************
208  */
209 static sdk_err_t gus_init(void)
210 {
211     const uint8_t     gus_svc_uuid[] = {GUS_SERVICE_UUID};
212     uint16_t          start_hdl      = PRF_INVALID_HANDLE;
213     sdk_err_t         error_code;
214     gatts_create_db_t gatts_db;
215 
216     error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
217     if (error_code < 0) {
218         return;
219     }
220 
221     gatts_db.shdl                  = &start_hdl;
222     gatts_db.uuid                  = gus_svc_uuid;
223     gatts_db.attr_tab_cfg          = (uint8_t *)&s_char_mask;
224     gatts_db.max_nb_attr           = GUS_IDX_NB;
225     gatts_db.srvc_perm             = SRVC_UUID_TYPE_SET(UUID_TYPE_128);
226     gatts_db.attr_tab_type         = SERVICE_TABLE_TYPE_128;
227     gatts_db.attr_tab.attr_tab_128 = gus_att_db;
228 
229     error_code = ble_gatts_srvc_db_create(&gatts_db);
230     if (SDK_SUCCESS == error_code) {
231         s_gus_env.start_hdl = *gatts_db.shdl;
232     }
233 
234     return error_code;
235 }
236 
237 /**
238  *****************************************************************************************
239  * @brief Handles reception of the attribute info request message.
240  *
241  * @param[in] conn_idx: Index of the connection.
242  * @param[in] p_param:  Pointer to the parameters of the read request.
243  *****************************************************************************************
244  */
245 static void gus_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
246 {
247     gatts_read_cfm_t cfm;
248     uint16_t         handle    = p_param->handle;
249     uint8_t          tab_index = 0;
250 
251     tab_index  = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
252     cfm.handle = handle;
253     cfm.status = BLE_SUCCESS;
254 
255     switch (tab_index) {
256         case GUS_IDX_TX_CFG:
257             cfm.length = sizeof(uint16_t);
258             cfm.value  = (uint8_t *)&s_gus_env.tx_ntf_cfg[conn_idx];
259             cfm.status = BLE_SUCCESS;
260             break;
261 
262         case GUS_IDX_FLOW_CTRL_CFG:
263             cfm.length = sizeof(uint16_t);
264             cfm.value  = (uint8_t *)&s_gus_env.flow_ctrl_ntf_cfg[conn_idx];
265             cfm.status = BLE_SUCCESS;
266             break;
267 
268         default:
269             cfm.length = 0;
270             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
271             break;
272     }
273 
274     ble_gatts_read_cfm(conn_idx, &cfm);
275 }
276 
277 void gus_combin_received_packet(uint8_t conn_idx, uint16_t length, uint8_t *p_received_data, uint8_t *p_combin_data)
278 {
279     uint8_t *buffer = p_combin_data;
280     uint8_t ret;
281 
282     if (send_data_len[conn_idx] > received_data_len[conn_idx]) {
283         buffer += received_data_len[conn_idx];
284         ret = memcpy_s(buffer, length, p_received_data, length);
285         if (ret < 0) {
286             return;
287         }
288         received_data_len[conn_idx] += length;
289     }
290 }
291 
292 /**
293  *****************************************************************************************
294  * @brief Handles reception of the write request.
295  *
296  * @param[in] conn_idx: Index of the connection.
297  * @param[in] p_param:  Point to the parameters of the write request.
298  *****************************************************************************************
299  */
300 static void   gus_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
301 {
302     uint8_t           handle    = p_param->handle;
303     uint8_t           tab_index = 0;
304     uint16_t          cccd_value;
305     gus_evt_t         event;
306     gatts_write_cfm_t cfm;
307     uint8_t           ret;
308 
309     tab_index      = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
310     event.conn_idx = conn_idx;
311     cfm.handle     = handle;
312     cfm.status     = BLE_SUCCESS;
313 
314     switch (tab_index) {
315         case GUS_IDX_RX_VAL:
316             event.evt_type       = GUS_EVT_RX_DATA_RECEIVED;
317             if (((uint8_t *)p_param->value)[0] == adv_header) {
318                 uint16_t data_len;
319                 ret = memcpy(&data_len, DATA_COPY_LEN, &(((uint8_t *)p_param->value)[1]), DATA_COPY_LEN);
320                 if (ret < 0) {
321                     return;
322                 }
323 
324                 if (data_len <= (MAX_MTU_DEFUALT - MTU_DEF_OFFSET)) {
325                     event.p_data = (uint8_t *)p_param->value;
326                     event.length = p_param->length;
327                     s_gus_env.gus_init.evt_handler(&event);
328                 } else {
329                     send_data_len[conn_idx] = data_len;
330                     gus_combin_received_packet(conn_idx, p_param->length,
331                                                (uint8_t *)p_param->value, rx_buffer[conn_idx]);
332                     if (received_data_len[conn_idx] == send_data_len[conn_idx]) {
333                         event.p_data = rx_buffer[conn_idx];
334                         event.length = send_data_len[conn_idx];
335                         s_gus_env.gus_init.evt_handler(&event);
336                         received_data_len[conn_idx] = 0;
337                     }
338                 }
339             } else {
340                 gus_combin_received_packet(conn_idx, p_param->length, (uint8_t *)p_param->value, rx_buffer[conn_idx]);
341 
342                 if (received_data_len[conn_idx] == send_data_len[conn_idx]) {
343                     event.p_data = rx_buffer[conn_idx];
344                     event.length = send_data_len[conn_idx];
345                     s_gus_env.gus_init.evt_handler(&event);
346                     received_data_len[conn_idx] = 0;
347                 }
348             }
349 
350             break;
351 
352         case GUS_IDX_TX_CFG:
353             cccd_value     = le16toh(&p_param->value[0]);
354             event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_TX_PORT_OPENED : GUS_EVT_TX_PORT_CLOSED;
355             s_gus_env.tx_ntf_cfg[conn_idx] = cccd_value;
356             s_gus_env.gus_init.evt_handler(&event);
357             break;
358 
359         default:
360             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
361             s_gus_env.gus_init.evt_handler(&event);
362             break;
363     }
364 
365     ble_gatts_write_cfm(conn_idx, &cfm);
366 }
367 
368 /**
369  *****************************************************************************************
370  * @brief Handles reception of the cccd recover request.
371  *
372  * @param[in]: conn_idx:   Connection index
373  * @param[in]: handle:     The handle of cccd attribute.
374  * @param[in]: cccd_value: The value of cccd attribute.
375  *****************************************************************************************
376  */
377 static void gus_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
378 {
379     uint8_t           tab_index = 0;
380     gus_evt_t         event;
381 
382     if (!prf_is_cccd_value_valid(cccd_value)) {
383         return;
384     }
385 
386     tab_index      = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
387     event.conn_idx = conn_idx;
388     event.evt_type = GUS_EVT_INVALID;
389 
390     switch (tab_index) {
391         case GUS_IDX_TX_CFG:
392             event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_TX_PORT_OPENED : GUS_EVT_TX_PORT_CLOSED;
393             s_gus_env.tx_ntf_cfg[conn_idx] = cccd_value;
394             break;
395 
396         case GUS_IDX_FLOW_CTRL_CFG:
397             event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_FLOW_CTRL_ENABLE : GUS_EVT_FLOW_CTRL_DISABLE;
398             s_gus_env.flow_ctrl_ntf_cfg[conn_idx] = cccd_value;
399             break;
400 
401         default:
402             break;
403     }
404 
405     if (GUS_EVT_INVALID != event.evt_type && s_gus_env.gus_init.evt_handler) {
406         s_gus_env.gus_init.evt_handler(&event);
407     }
408 }
409 
410 /**
411  *****************************************************************************************
412  * @brief Handles reception of the complete event.
413  *
414  * @param[in] conn_idx:   Connection index.
415  * @param[in] status:     The status of GATTC operation.
416  * @param[in] p_ntf_ind:  Pointer to the parameters of the complete event.
417  *****************************************************************************************
418  */
419 static void gus_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
420 {
421     if (s_gus_env.gus_init.evt_handler != NULL) {
422         gus_evt_t event;
423         event.conn_idx = conn_idx;
424 
425         if (BLE_SUCCESS == status && BLE_GATT_NOTIFICATION == p_ntf_ind->type) {
426             event.evt_type = GUS_EVT_TX_DATA_SENT;
427             s_gus_env.gus_init.evt_handler(&event);
428         }
429     }
430 }
431 
432 /*
433  * GLOBAL FUNCTION DEFINITIONS
434  *****************************************************************************************
435  */
436 sdk_err_t gus_tx_data_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
437 {
438     sdk_err_t        error_code = SDK_ERR_NTF_DISABLED;
439     gatts_noti_ind_t send_cmd;
440     uint8_t          *buffer    = p_data;
441 
442     if (PRF_CLI_START_NTF == s_gus_env.tx_ntf_cfg[conn_idx]) {
443         send_cmd.type   = BLE_GATT_NOTIFICATION;
444         send_cmd.handle = prf_find_handle_by_idx(GUS_IDX_TX_VAL, s_gus_env.start_hdl, (uint8_t *)&s_char_mask);
445 
446         if (length > (MAX_MTU_DEFUALT - MTU_DEF_OFFSET)) {
447             while length > MAX_MTU_DEFUALT - MTU_DEF_OFFSET) {
448                 send_cmd.value  = buffer;
449                 send_cmd.length = MAX_MTU_DEFUALT - MTU_DEF_OFFSET;
450                 error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);
451                 buffer += (MAX_MTU_DEFUALT - MTU_DEF_OFFSET);
452                 length -= (MAX_MTU_DEFUALT - MTU_DEF_OFFSET);
453             }
454 
455             if (length != 0 && length < (MAX_MTU_DEFUALT - MTU_DEF_OFFSET)) {
456                 send_cmd.length = length;
457                 send_cmd.value  = buffer;
458                 error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);
459             }
460         } else {
461             send_cmd.value  = buffer;
462             send_cmd.length = length;
463             error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);
464         }
465     }
466 
467     return error_code;
468 }
469 
470 sdk_err_t gus_rx_flow_ctrl_set(uint8_t conn_idx, uint8_t flow_ctrl)
471 {
472     sdk_err_t        error_code = BLE_SUCCESS;
473     gatts_noti_ind_t send_cmd;
474 
475     if (PRF_CLI_START_NTF == s_gus_env.flow_ctrl_ntf_cfg[conn_idx]) {
476         // Fill in the parameter structure
477         send_cmd.type   = BLE_GATT_NOTIFICATION;
478         send_cmd.handle = prf_find_handle_by_idx(GUS_IDX_FLOW_CTRL_VAL, s_gus_env.start_hdl, (uint8_t *)&s_char_mask);
479 
480         // Pack measured value in database
481         send_cmd.length = 1;
482         send_cmd.value  = &flow_ctrl;
483 
484         // Send notification to peer device
485         error_code      = ble_gatts_noti_ind(conn_idx, &send_cmd);
486     }
487 
488     return error_code;
489 }
490 
491 sdk_err_t gus_service_init(gus_init_t *p_gus_init)
492 {
493     sdk_err_t ret;
494     if (p_gus_init == NULL) {
495         return SDK_ERR_POINTER_NULL;
496     }
497 
498     ret = memcpy_s(&s_gus_env.gus_init, sizeof(gus_init_t), p_gus_init, sizeof(gus_init_t));
499     if (ret < 0) {
500         return ret;
501     }
502     return ble_server_prf_add(&gus_prf_info);
503 }
504