• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file mlmr_c.c
5  *
6  * @brief Goodix UART Client 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  * INCLUDE FILES
39  *****************************************************************************************
40  */
41 #include "mlmr_c.h"
42 #include "user_app.h"
43 #include "app_log.h"
44 #define DATA_COPY_LEN 2
45 #define MAX_MTU_OFFSET 3
46 #define UUID_LEN 16
47 #define ATTR_LEN_DEF 2
48 
49 /*
50  * STRUCT DEFINE
51  *****************************************************************************************
52  */
53 /**@brief Goodix UART Service Client environment variable. */
54 struct gus_c_env_t {
55     gus_c_handles_t      handles;            /**< Handles of GUS characteristics which will be got for peer. */
56     gus_c_evt_handler_t  evt_handler;        /**< Handler of GUS client event  */
57     uint8_t              prf_id;             /**< GUS Client profile id. */
58 };
59 
60 /*
61  * LOCAL FUNCTION DECLARATION
62  *****************************************************************************************
63  */
64 static void gus_c_att_write_cb(uint8_t conn_idx, uint8_t status, uint16_t handle);
65 static void gus_c_att_ntf_ind_cb(uint8_t conn_idx, const ble_gattc_ntf_ind_t *p_ntf_ind);
66 static void gus_c_srvc_browse_cb(uint8_t conn_idx, uint8_t status, const ble_gattc_browse_srvc_t *p_browse_srvc);
67 
68 /*
69  * LOCAL VARIABLE DEFINITIONS
70  *****************************************************************************************
71  */
72 static struct gus_c_env_t s_gus_c_env;       /**< GUS Client environment variable. */
73 static uint8_t            s_gus_uuid[16]                = GUS_SVC_UUID;
74 static uint8_t            s_gus_rx_char_uuid[16]        = GUS_RX_CHAR_UUID;
75 static uint8_t            s_gus_tx_char_uuid[16]        = GUS_TX_CHAR_UUID;
76 static uint8_t            s_gus_flow_ctrl_char_uuid[16] = GUS_FLOW_CTRL_UUID;
77 
78 static uint16_t           received_data_len[CFG_BOND_DEVS];
79 static uint16_t           send_data_len[CFG_BOND_DEVS];
80 static uint8_t            adv_header        = 0xA0;
81 static uint8_t            rx_buffer[CFG_BOND_DEVS][516];
82 
83 
84 /**@brief GUS Client interface required by profile manager. */
85 static ble_prf_manager_cbs_t gus_c_mgr_cbs = {
86     NULL,
87     NULL,
88     NULL
89 };
90 
91 /**@brief GUS GATT Client Callbacks. */
92 static gattc_prf_cbs_t gus_c_gattc_cbs = {
93     NULL,
94     NULL,
95     NULL,
96     NULL,
97     NULL,
98     gus_c_att_write_cb,
99     gus_c_att_ntf_ind_cb,
100     gus_c_srvc_browse_cb,
101     NULL,
102 };
103 
104 /**@brief GUS Client Information. */
105 static const prf_client_info_t gus_c_prf_info = {
106     .max_connection_nb = GUS_C_CONNECTION_MAX,
107     .manager_cbs       = &gus_c_mgr_cbs,
108     .gattc_prf_cbs     = &gus_c_gattc_cbs
109 };
110 
111 /*
112  * LOCAL FUNCTION DEFINITIONS
113  *****************************************************************************************
114  */
115 /**
116  *****************************************************************************************
117  * @brief Excute GUS Service Client event handler.
118  *
119  * @param[in] p_evt: Pointer to GUS Service Client event structure.
120  *****************************************************************************************
121  */
gus_c_evt_handler_excute(gus_c_evt_t * p_evt)122 static void gus_c_evt_handler_excute(gus_c_evt_t *p_evt)
123 {
124     if (s_gus_c_env.evt_handler != NULL && GUS_C_EVT_INVALID != p_evt->evt_type) {
125         s_gus_c_env.evt_handler(p_evt);
126     }
127 }
128 
129 /**
130  *****************************************************************************************
131  * @brief This callback function will be called when receiving read response.
132  *
133  * @param[in] conn_idx:   The connection index.
134  * @param[in] status:     The status of GATTC operation.
135  * @param[in] handle:     The handle of attribute.
136  *****************************************************************************************
137  */
gus_c_att_write_cb(uint8_t conn_idx,uint8_t status,uint16_t handle)138 static void gus_c_att_write_cb(uint8_t conn_idx, uint8_t status, uint16_t handle)
139 {
140     gus_c_evt_t gus_c_evt;
141 
142     gus_c_evt.conn_idx = conn_idx;
143     gus_c_evt.evt_type = GUS_C_EVT_INVALID;
144 
145     if (handle == s_gus_c_env.handles.gus_tx_cccd_handle) {
146         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
147                              GUS_C_EVT_TX_NTF_SET_SUCCESS : \
148                              GUS_C_EVT_WRITE_OP_ERR;
149     } else if (handle == s_gus_c_env.handles.gus_flow_ctrl_cccd_handle) {
150         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
151                              GUS_C_EVT_FLOW_CTRL_NTF_SET_SUCCESS : \
152                              GUS_C_EVT_WRITE_OP_ERR;
153     } else if (handle == s_gus_c_env.handles.gus_rx_handle) {
154         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
155                              GUS_C_EVT_TX_CPLT : \
156                              GUS_C_EVT_WRITE_OP_ERR;
157     } else if (handle == s_gus_c_env.handles.gus_flow_ctrl_handle) {
158         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
159                              GUS_C_EVT_RX_FLOW_UPDATE_CPLT : \
160                              GUS_C_EVT_WRITE_OP_ERR;
161     }
162 
163     gus_c_evt_handler_excute(&gus_c_evt);
164 }
165 
combin_received_packet(uint8_t conn_idx,uint16_t length,uint8_t * p_received_data,uint8_t * p_combin_data)166 void combin_received_packet(uint8_t conn_idx, uint16_t length, uint8_t *p_received_data, uint8_t *p_combin_data)
167 {
168     uint8_t *buffer = p_combin_data;
169     uint8_t ret;
170 
171     if (send_data_len[conn_idx] > received_data_len[conn_idx]) {
172         buffer += received_data_len[conn_idx];
173         ret = memcpy_s(buffer, length, p_received_data, length);
174         if (ret < 0) {
175             return;
176         }
177         received_data_len[conn_idx] += length;
178     }
179 }
180 
181 /**
182  *****************************************************************************************
183  * @brief This callback function will be called when receiving notification or indication.
184  *
185  * @param[in] conn_idx:  The connection index.
186  * @param[in] status:    The status of GATTC operation.
187  * @param[in] p_ntf_ind: The information of notification or indication.
188  *****************************************************************************************
189  */
gus_c_att_ntf_ind_cb(uint8_t conn_idx,const ble_gattc_ntf_ind_t * p_ntf_ind)190 static void gus_c_att_ntf_ind_cb(uint8_t conn_idx, const ble_gattc_ntf_ind_t *p_ntf_ind)
191 {
192     gus_c_evt_t gus_c_evt;
193     uint8_t ret;
194     uint16_t data_length;
195 
196     gus_c_evt.conn_idx = conn_idx;
197     gus_c_evt.evt_type = GUS_C_EVT_INVALID;
198 
199     if (p_ntf_ind->handle == s_gus_c_env.handles.gus_flow_ctrl_handle) {
200         if (FLOW_ON == p_ntf_ind->p_value[0]) {
201             gus_c_evt.evt_type = GUS_C_EVT_TX_FLOW_ON;
202         } else if (FLOW_OFF == p_ntf_ind->p_value[0]) {
203             gus_c_evt.evt_type = GUS_C_EVT_TX_FLOW_OFF;
204         }
205     } else if (p_ntf_ind->handle == s_gus_c_env.handles.gus_tx_handle) {
206         gus_c_evt.evt_type = GUS_C_EVT_PEER_DATA_RECEIVE;
207         if (p_ntf_ind->p_value[0] == adv_header) {
208             ret = memcpy_s(&data_length, DATA_COPY_LEN,
209                            sizeof(&(((uint8_t *)p_ntf_ind->p_value)[1]), DATA_COPY_LEN);
210             if (ret <0) {
211                 return;
212             }
213             if (data_length <= (MAX_MTU_DEFUALT - MAX_MTU_OFFSET)) {
214                 gus_c_evt.evt_type = GUS_C_EVT_PEER_DATA_RECEIVE;
215                 gus_c_evt.p_data   = p_ntf_ind->p_value;
216                 gus_c_evt.length   = p_ntf_ind->length;
217                 gus_c_evt_handler_excute(&gus_c_evt);
218             } else {
219                 send_data_len[conn_idx] = data_length;
220                 combin_received_packet(conn_idx, p_ntf_ind->length, p_ntf_ind->p_value, rx_buffer[conn_idx]);
221                 if (received_data_len[conn_idx] == send_data_len[conn_idx]) {
222                     gus_c_evt.p_data = rx_buffer[conn_idx];
223                     gus_c_evt.length = send_data_len[conn_idx];
224                     gus_c_evt_handler_excute(&gus_c_evt);
225                     received_data_len[conn_idx] = 0;
226                 }
227             }
228         } else {
229             combin_received_packet(conn_idx, p_ntf_ind->length, p_ntf_ind->p_value, rx_buffer[conn_idx]);
230             if (received_data_len[conn_idx] == send_data_len[conn_idx]) {
231                 gus_c_evt.p_data = rx_buffer[conn_idx];
232                 gus_c_evt.length = send_data_len[conn_idx];
233                 gus_c_evt_handler_excute(&gus_c_evt);
234                 received_data_len[conn_idx] = 0;
235             }
236         }
237     }
238 }
239 
240 /**
241  *****************************************************************************************
242  * @brief This callback function will be called when receiving browse service indication.
243  *
244  * @param[in] conn_idx:      The connection index.
245  * @param[in] status:        The status of GATTC operation.
246  * @param[in] p_browse_srvc: The information of service browse.
247  *****************************************************************************************
248  */
249 static void gus_c_srvc_browse_cb(uint8_t conn_idx, uint8_t status, const ble_gattc_browse_srvc_t *p_browse_srvc)
250 {
251     gus_c_evt_t  gus_c_evt;
252     uint16_t     handle_disc;
253 
254     gus_c_evt.conn_idx = conn_idx;
255     gus_c_evt.evt_type = GUS_C_EVT_DISCOVERY_FAIL;
256 
257     if (BLE_GATT_ERR_BROWSE_NO_ANY_MORE == status) {
258         return;
259     }
260 
261     if (BLE_SUCCESS == status) {
262         if (p_browse_srvc->uuid_len == UUID_LEN &&
263             memcmp(p_browse_srvc->uuid, s_gus_uuid, UUID_LEN) == 0) {
264             s_gus_c_env.handles.gus_srvc_start_handle = p_browse_srvc->start_hdl;
265             s_gus_c_env.handles.gus_srvc_end_handle   = p_browse_srvc->end_hdl;
266 
267             for (uint32_t i = 0; i < (p_browse_srvc->end_hdl - p_browse_srvc->start_hdl); i++) {
268                 handle_disc = p_browse_srvc->start_hdl + i + 1;
269 
270                 if (BLE_GATTC_BROWSE_ATTR_VAL == p_browse_srvc->info[i].attr_type) {
271                     if (memcmp(p_browse_srvc->info[i].attr.uuid, s_gus_rx_char_uuid, UUID_LEN) == 0) {
272                         s_gus_c_env.handles.gus_rx_handle = handle_disc;
273                     } else if (memcmp(p_browse_srvc->info[i].attr.uuid, s_gus_tx_char_uuid, UUID_LEN) == 0) {
274                         s_gus_c_env.handles.gus_tx_handle      = handle_disc;
275                         s_gus_c_env.handles.gus_tx_cccd_handle = handle_disc + 1;
276                     } else if (memcmp(p_browse_srvc->info[i].attr.uuid, s_gus_flow_ctrl_char_uuid, UUID_LEN) == 0) {
277                         s_gus_c_env.handles.gus_flow_ctrl_handle      = handle_disc;
278                         s_gus_c_env.handles.gus_flow_ctrl_cccd_handle = handle_disc + 1;
279                     }
280                 }
281 
282                 if (p_browse_srvc->info[i].attr_type == BLE_GATTC_BROWSE_NONE) {
283                     break;
284                 }
285             }
286 
287             gus_c_evt.evt_type = GUS_C_EVT_DISCOVERY_COMPLETE;
288         }
289     }
290 
291     gus_c_evt_handler_excute(&gus_c_evt);
292 }
293 
294 /*
295  * GLOBAL FUNCTION DEFINITIONS
296  *****************************************************************************************
297  */
298 sdk_err_t gus_client_init(gus_c_evt_handler_t evt_handler)
299 {
300     sdk_err_t ret;
301     if (evt_handler == NULL) {
302         return SDK_ERR_POINTER_NULL;
303     }
304 
305     ret = memset_s(&s_gus_c_env, sizeof(s_gus_c_env), 0, sizeof(s_gus_c_env));
306     if (ret < 0) {
307         return ret;
308     }
309     s_gus_c_env.evt_handler = evt_handler;
310 
311     return ble_client_prf_add(&gus_c_prf_info, &s_gus_c_env.prf_id);
312 }
313 
314 sdk_err_t gus_c_disc_srvc_start(uint8_t conn_idx)
315 {
316     const ble_uuid_t gus_uuid = {
317         .uuid_len = 16,
318         .uuid     = s_gus_uuid,
319     };
320 
321     return ble_gattc_prf_services_browse(s_gus_c_env.prf_id, conn_idx, &gus_uuid);
322 }
323 
324 sdk_err_t gus_c_tx_notify_set(uint8_t conn_idx, bool is_enable)
325 {
326     gattc_write_attr_value_t write_attr_value;
327     uint16_t ntf_value = is_enable ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND;
328 
329     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_tx_cccd_handle) {
330         return SDK_ERR_INVALID_HANDLE;
331     }
332 
333     write_attr_value.handle  = s_gus_c_env.handles.gus_tx_cccd_handle;
334     write_attr_value.offset  = 0;
335     write_attr_value.length  = ATTR_LEN_DEF;
336     write_attr_value.p_value = (uint8_t *)&ntf_value;
337 
338     return ble_gattc_prf_write(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
339 }
340 
341 sdk_err_t gus_c_flow_ctrl_notify_set(uint8_t conn_idx, bool is_enable)
342 {
343     gattc_write_attr_value_t write_attr_value;
344     uint16_t ntf_value = is_enable ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND;
345 
346     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_flow_ctrl_cccd_handle) {
347         return SDK_ERR_INVALID_HANDLE;
348     }
349 
350     write_attr_value.handle  = s_gus_c_env.handles.gus_flow_ctrl_cccd_handle;
351     write_attr_value.offset  = 0;
352     write_attr_value.length  = ATTR_LEN_DEF;
353     write_attr_value.p_value = (uint8_t *)&ntf_value;
354 
355     return ble_gattc_prf_write(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
356 }
357 
358 sdk_err_t gus_c_tx_data_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
359 {
360     sdk_err_t             error_code;
361     uint8_t               *buffer = p_data;
362     gattc_write_no_resp_t write_attr_value;
363 
364     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_rx_handle) {
365         return SDK_ERR_INVALID_HANDLE;
366     }
367 
368     if (p_data == NULL) {
369         return SDK_ERR_POINTER_NULL;
370     }
371 
372     write_attr_value.signed_write = false;
373     write_attr_value.handle       = s_gus_c_env.handles.gus_rx_handle;
374 
375     if (length > (MAX_MTU_DEFUALT - MAX_MTU_OFFSET)) {
376         while (length > MAX_MTU_DEFUALT - MAX_MTU_OFFSET) {
377             write_attr_value.p_value      = buffer;
378             write_attr_value.length       = MAX_MTU_DEFUALT - MAX_MTU_OFFSET;
379             error_code = ble_gattc_prf_write_no_resp(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
380             buffer += (MAX_MTU_DEFUALT - MAX_MTU_OFFSET);
381             length -= (MAX_MTU_DEFUALT - MAX_MTU_OFFSET);
382         }
383 
384         if (length != 0 && length < (MAX_MTU_DEFUALT - MAX_MTU_OFFSET)) {
385             write_attr_value.length       = length;
386             write_attr_value.p_value      = buffer;
387             error_code = ble_gattc_prf_write_no_resp(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
388         }
389     } else {
390         write_attr_value.p_value      = buffer;
391         write_attr_value.length       = length;
392         error_code = ble_gattc_prf_write_no_resp(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
393     }
394 
395     return error_code;
396 }
397 
398 sdk_err_t gus_c_rx_flow_ctrl_set(uint8_t conn_idx, uint8_t flow_ctrl)
399 {
400     gattc_write_attr_value_t write_attr_value;
401 
402     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_flow_ctrl_handle) {
403         return SDK_ERR_INVALID_HANDLE;
404     }
405 
406     write_attr_value.handle  = s_gus_c_env.handles.gus_flow_ctrl_handle;
407     write_attr_value.offset  = 0;
408     write_attr_value.length  = 1;
409     write_attr_value.p_value = &flow_ctrl;
410 
411     return ble_gattc_prf_write(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
412 }
413