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