1 /**
2 *****************************************************************************************
3 *
4 * @file wechat.c
5 *
6 * @briefWeChat Service API 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 "wechat.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 #define INDEX_0 0
47 #define INDEX_1 1
48 #define INDEX_2 2
49 #define INDEX_3 3
50 /*
51 * ENUMERATIONS
52 *****************************************************************************************
53 */
54 /**@brief WeChat Service Attributes Indexes. */
55 enum wechat_attr_idx_t {
56 WECHAT_IDX_SVC,
57
58 WECHAR_IDX_AIRSYNC_WRITE_CHAR,
59 WECHAR_IDX_AIRSYNC_WRITE_VAL,
60
61 WECHAR_IDX_AIRSYNC_INDICATE_CHAR,
62 WECHAR_IDX_AIRSYNC_INDICATE_VAL,
63 WECHAR_IDX_AIRSYNC_INDICATE_CFG,
64
65 WECHAR_IDX_AIRSYNC_READ_CHAR,
66 WECHAR_IDX_AIRSYNC_READ_VAL,
67
68 WECHAT_IDX_PEDO_MEAS_CHAR,
69 WECHAT_IDX_PEDO_MEAS_VAL,
70 WECHAT_IDX_PEDO_MEAS_CFG,
71
72 WECHAT_IDX_TARGET_CHAR,
73 WECHAT_IDX_TARGET_VAL,
74 WECHAT_IDX_TARGET_CFG,
75
76 WECHAT_IDX_NB,
77 };
78
79 /*
80 * STRUCTURES
81 *****************************************************************************************
82 */
83 /**@brief WeChat service environment variable. */
84 struct wechat_env_t {
85 wechat_evt_handler_t evt_handler; /**< WeChat Service event handler. */
86 uint16_t start_hdl; /**< WeChat Service start handle. */
87 wechat_pedo_meas_t pedo_meas; /**< WeChat pedometer measurement value. */
88 wechat_pedo_target_t pedo_target; /**< WeChat pedometer target value. */
89 uint8_t dev_mac[GAP_ADDR_LEN]; /**< WeChat device mac address. */
90 uint16_t airsync_ind_cfg[WECHAT_CONNECTION_MAX]; /**< Indication configuration for Airsync. */
91 uint16_t
92 pedo_meas_ntf_cfg[WECHAT_CONNECTION_MAX]; /**< Notification configuration for pedometer measurement. */
93 uint16_t
94 pedo_target_ind_cfg[WECHAT_CONNECTION_MAX]; /**< Indication configuration for pedometer target. */
95 };
96
97 /*
98 * LOCAL FUNCTION DECLARATION
99 *****************************************************************************************
100 */
101 static sdk_err_t wechat_init(void);
102 static void wechat_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
103 static void wechat_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
104 static void wechat_gatts_cmpl_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
105 static void wechat_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
106 static uint8_t wechat_pedo_meas_encode(uint8_t *p_buff, wechat_pedo_meas_t *p_pedo_meas);
107 static uint8_t wechat_pedo_target_encode(uint8_t *p_buff, wechat_pedo_target_t *p_pedo_target);
108 static void wechat_pedo_target_set(const uint8_t *p_data, uint8_t length);
109 static sdk_err_t wechat_indicate_data_chunk(uint8_t conn_idx);
110
111 /*
112 * LOCAL VARIABLE DEFINITIONS
113 *****************************************************************************************
114 */
115 static struct wechat_env_t s_wechat_env;
116 static wechat_data_t s_ind_data;
117 static const uint16_t s_char_mask = 0x3FFF;
118
119 static const attm_desc_t wechat_attr_tab[WECHAT_IDX_NB] = {
120 [WECHAT_IDX_SVC] = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
121
122 [WECHAR_IDX_AIRSYNC_WRITE_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
123 [WECHAR_IDX_AIRSYNC_WRITE_VAL] = {WECHAT_WRITE_CHAR_UUID, WRITE_REQ_PERM_UNSEC, ATT_VAL_LOC_USER, WECHAT_DATA_LEN},
124
125 [WECHAR_IDX_AIRSYNC_INDICATE_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
126 [WECHAR_IDX_AIRSYNC_INDICATE_VAL] = {WECHAT_INDICATE_CHAR_UUID, INDICATE_PERM_UNSEC,
127 ATT_VAL_LOC_USER, WECHAT_DATA_LEN},
128 [WECHAR_IDX_AIRSYNC_INDICATE_CFG] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
129
130 [WECHAR_IDX_AIRSYNC_READ_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
131 [WECHAR_IDX_AIRSYNC_READ_VAL] = {WECHAT_READ_CHAR_UUID, READ_PERM_UNSEC, ATT_VAL_LOC_USER, 6},
132
133 [WECHAT_IDX_PEDO_MEAS_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
134 [WECHAT_IDX_PEDO_MEAS_VAL] = {WECHAT_PEDOMETER_MEASUREMENT, READ_PERM_UNSEC | NOTIFY_PERM_UNSEC,
135 ATT_VAL_LOC_USER, WECHAT_DATA_LEN},
136 [WECHAT_IDX_PEDO_MEAS_CFG] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
137
138 [WECHAT_IDX_TARGET_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
139 [WECHAT_IDX_TARGET_VAL] = {WECHAT_TARGET, READ_PERM_UNSEC | INDICATE_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
140 ATT_VAL_LOC_USER, WECHAT_DATA_LEN},
141 [WECHAT_IDX_TARGET_CFG] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
142 };
143
144 /**@brief WeChat interface required by profile manager. */
145 static ble_prf_manager_cbs_t wechat_mgr_cbs = {
146 (prf_init_func_t)wechat_init,
147 NULL,
148 NULL
149 };
150
151 /**@brief WeChat GATT server Callbacks. */
152 static gatts_prf_cbs_t wechat_gatts_cbs = {
153 wechat_read_att_cb,
154 wechat_write_att_cb,
155 NULL,
156 wechat_gatts_cmpl_cb,
157 wechat_cccd_set_cb
158 };
159
160 /**@brief WeChat Information. */
161 static const prf_server_info_t wechat_prf_info = {
162 .max_connection_nb = WECHAT_CONNECTION_MAX,
163 .manager_cbs = &wechat_mgr_cbs,
164 .gatts_prf_cbs = &wechat_gatts_cbs
165 };
166
167 /*
168 * LOCAL FUNCTION DEFINITIONS
169 *******************************************************************************
170 */
171 /**
172 *****************************************************************************************
173 * @brief Initialize WeChat service and create database in ATT.
174 *
175 * @return Error code to know if profile initialization succeed or not.
176 *****************************************************************************************
177 */
wechat_init(void)178 static sdk_err_t wechat_init(void)
179 {
180 // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
181 uint16_t start_hdl = PRF_INVALID_HANDLE;
182 const uint8_t wechat_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(WECHAT_SERVICE_UUID);
183 sdk_err_t error_code;
184 gatts_create_db_t gatts_db;
185
186 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
187 if (error_code < 0) {
188 return error_code;
189 }
190
191 gatts_db.shdl = &start_hdl;
192 gatts_db.uuid = wechat_svc_uuid;
193 gatts_db.attr_tab_cfg = (uint8_t *)&s_char_mask;
194 gatts_db.max_nb_attr = WECHAT_IDX_NB;
195 gatts_db.srvc_perm = 0;
196 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_16;
197 gatts_db.attr_tab.attr_tab_16 = wechat_attr_tab;
198
199 error_code = ble_gatts_srvc_db_create(&gatts_db);
200 if (SDK_SUCCESS == error_code) {
201 s_wechat_env.start_hdl = *gatts_db.shdl;
202 }
203
204 return error_code;
205 }
206
207 /**
208 *****************************************************************************************
209 * @brief Handles reception of the attribute info request message.
210 *
211 * @param[in] conn_idx: Connection index
212 * @param[in] p_param: The parameters of the read request.
213 *****************************************************************************************
214 */
wechat_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)215 static void wechat_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
216 {
217 gatts_read_cfm_t cfm;
218 uint8_t encode_data[WECHAT_DATA_LEN];
219 uint8_t handle = p_param->handle;
220 uint8_t tab_index = prf_find_idx_by_handle(handle,
221 s_wechat_env.start_hdl,
222 WECHAT_IDX_NB,
223 (uint8_t *)&s_char_mask);
224
225 cfm.handle = handle;
226 cfm.status = BLE_SUCCESS;
227
228 switch (tab_index) {
229 case WECHAR_IDX_AIRSYNC_INDICATE_CFG:
230 cfm.length = sizeof(uint16_t);
231 cfm.value = (uint8_t *)&s_wechat_env.airsync_ind_cfg[conn_idx];
232 break;
233
234 case WECHAR_IDX_AIRSYNC_READ_VAL:
235 cfm.length = GAP_ADDR_LEN;
236 cfm.value = s_wechat_env.dev_mac;
237 break;
238
239 case WECHAT_IDX_PEDO_MEAS_VAL:
240 cfm.length = wechat_pedo_meas_encode(encode_data, &s_wechat_env.pedo_meas);
241 cfm.value = encode_data;
242 break;
243
244 case WECHAT_IDX_PEDO_MEAS_CFG:
245 cfm.length = sizeof(uint16_t);
246 cfm.value = (uint8_t *)&s_wechat_env.pedo_meas_ntf_cfg[conn_idx];
247 break;
248
249 case WECHAT_IDX_TARGET_VAL:
250 cfm.length = wechat_pedo_target_encode(encode_data, &s_wechat_env.pedo_target);
251 cfm.value = encode_data;
252 break;
253
254 case WECHAT_IDX_TARGET_CFG:
255 cfm.length = sizeof(uint16_t);
256 cfm.value = (uint8_t *)&s_wechat_env.pedo_target_ind_cfg[conn_idx];
257 break;
258
259 default:
260 cfm.length = 0;
261 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
262 break;
263 }
264
265 ble_gatts_read_cfm(conn_idx, &cfm);
266 }
267
268 /**
269 *******************************************************************************
270 * @brief Handles reception of the write request.
271 *
272 * @param[in] conn_idx: Connection index.
273 * @param[in] p_param: Pointer to the parameters of the write request.
274 *******************************************************************************
275 */
wechat_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)276 static void wechat_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
277 {
278 uint16_t handle = p_param->handle;
279 uint16_t cccd_value = 0;
280 uint8_t tab_index = 0;
281 wechat_evt_t event;
282 gatts_write_cfm_t cfm;
283 uint8_t ret;
284
285 tab_index = prf_find_idx_by_handle(handle,
286 s_wechat_env.start_hdl,
287 WECHAT_IDX_NB,
288 (uint8_t *)&s_char_mask);
289 cfm.handle = handle;
290 cfm.status = BLE_SUCCESS;
291
292 event.conn_idx = conn_idx;
293 event.evt_type = WECHAT_EVT_INVALID;
294
295 switch (tab_index) {
296 case WECHAR_IDX_AIRSYNC_WRITE_VAL:
297 event.evt_type = WECHAT_EVT_AIRSYNC_DATA_RECIEVE;
298 event.param.data.p_data = p_param->value;
299 event.param.data.length = p_param->length;
300 break;
301
302 case WECHAR_IDX_AIRSYNC_INDICATE_CFG:
303 cccd_value = le16toh(&p_param->value[0]);
304 event.evt_type = (PRF_CLI_START_IND == cccd_value ?\
305 WECHAT_EVT_AIRSYNC_IND_ENABLE :\
306 WECHAT_EVT_AIRSYNC_IND_DISABLE);
307 s_wechat_env.airsync_ind_cfg[conn_idx] = cccd_value;
308 break;
309
310 case WECHAT_IDX_PEDO_MEAS_CFG:
311 cccd_value = le16toh(&p_param->value[0]);
312 event.evt_type = (PRF_CLI_START_NTF == cccd_value ?\
313 WECHAT_EVT_PEDO_MEAS_NTF_ENABLE :\
314 WECHAT_EVT_PEDO_MEAS_NTF_DISABLE);
315 s_wechat_env.pedo_meas_ntf_cfg[conn_idx] = cccd_value;
316 break;
317
318 case WECHAT_IDX_TARGET_VAL:
319 wechat_pedo_target_set(p_param->value, p_param->length);
320 event.evt_type = WECHAT_EVT_PEDO_TARGET_UPDATE;
321 ret = memcpy_s(&event.param.pedo_target, sizeof(wechat_pedo_target_t),
322 &s_wechat_env.pedo_target, sizeof(wechat_pedo_target_t));
323 if (ret < 0) {
324 return;
325 }
326 break;
327
328 case WECHAT_IDX_TARGET_CFG:
329 cccd_value = le16toh(&p_param->value[0]);
330 event.evt_type = (PRF_CLI_START_IND == cccd_value ?\
331 WECHAT_EVT_PEDO_TARGET_IND_ENABLE :\
332 WECHAT_EVT_PEDO_TARGET_IND_DISABLE);
333 s_wechat_env.pedo_target_ind_cfg[conn_idx] = cccd_value;
334 break;
335
336 default:
337 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
338 break;
339 }
340
341 ble_gatts_write_cfm(conn_idx, &cfm);
342
343 if (WECHAT_EVT_INVALID != event.evt_type && s_wechat_env.evt_handler) {
344 s_wechat_env.evt_handler(&event);
345 }
346 }
347
348 /**
349 *****************************************************************************************
350 * @brief Handles reception of the cccd recover request.
351 *
352 * @param[in]: conn_idx: Connection index
353 * @param[in]: handle: The handle of cccd attribute.
354 * @param[in]: cccd_value: The value of cccd attribute.
355 *****************************************************************************************
356 */
wechat_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)357 static void wechat_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
358 {
359 uint8_t tab_index = 0;
360 wechat_evt_t event;
361
362 event.conn_idx = conn_idx;
363 event.evt_type = WECHAT_EVT_INVALID;
364
365 if (!prf_is_cccd_value_valid(cccd_value)) {
366 return;
367 }
368
369 tab_index = prf_find_idx_by_handle(handle, s_wechat_env.start_hdl,
370 WECHAT_IDX_NB,
371 (uint8_t *)&s_char_mask);
372
373 switch (tab_index) {
374 case WECHAR_IDX_AIRSYNC_INDICATE_CFG:
375 event.evt_type = (PRF_CLI_START_IND == cccd_value ?\
376 WECHAT_EVT_AIRSYNC_IND_ENABLE :\
377 WECHAT_EVT_AIRSYNC_IND_DISABLE);
378 s_wechat_env.airsync_ind_cfg[conn_idx] = cccd_value;
379 break;
380
381 case WECHAT_IDX_PEDO_MEAS_CFG:
382 event.evt_type = (PRF_CLI_START_NTF == cccd_value ?\
383 WECHAT_EVT_PEDO_MEAS_NTF_ENABLE :\
384 WECHAT_EVT_PEDO_MEAS_NTF_DISABLE);
385 s_wechat_env.pedo_meas_ntf_cfg[conn_idx] = cccd_value;
386 break;
387
388 case WECHAT_IDX_TARGET_CFG:
389 event.evt_type = (PRF_CLI_START_IND == cccd_value ?\
390 WECHAT_EVT_PEDO_TARGET_IND_ENABLE :\
391 WECHAT_EVT_PEDO_TARGET_IND_DISABLE);
392 s_wechat_env.pedo_target_ind_cfg[conn_idx] = cccd_value;
393 break;
394
395 default:
396 break;
397 }
398
399 if (WECHAT_EVT_INVALID != event.evt_type && s_wechat_env.evt_handler) {
400 s_wechat_env.evt_handler(&event);
401 }
402 }
403
404 /**
405 *****************************************************************************************
406 * @brief Handles reception of the complete event.
407 *
408 * @param[in] conn_idx: Connection index.
409 * @param[in] p_param: Pointer to the parameters of the complete event.
410 *****************************************************************************************
411 */
wechat_gatts_cmpl_cb(uint8_t conn_idx,uint8_t status,const ble_gatts_ntf_ind_t * p_ntf_ind)412 static void wechat_gatts_cmpl_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
413 {
414 uint8_t tab_index;
415
416 tab_index = prf_find_idx_by_handle(p_ntf_ind->handle, s_wechat_env.start_hdl,
417 WECHAT_IDX_NB,
418 (uint8_t *)&s_char_mask);
419 if (WECHAR_IDX_AIRSYNC_INDICATE_VAL == tab_index) {
420 wechat_indicate_data_chunk(conn_idx);
421 }
422 }
423
424 /**
425 *****************************************************************************************
426 * @brief Encode WeChat pedometer measurement value.
427 *
428 * @param[in] p_buff: Pointer to encode buffer.
429 * @param[in] p_pedo_meas: Pointer to pedometer measurement value.
430 *
431 * @return Length of encoded.
432 *****************************************************************************************
433 */
wechat_pedo_meas_encode(uint8_t * p_buff,wechat_pedo_meas_t * p_pedo_meas)434 static uint8_t wechat_pedo_meas_encode(uint8_t *p_buff, wechat_pedo_meas_t *p_pedo_meas)
435 {
436 uint8_t encode_length = 0;
437
438 p_buff[encode_length++] = p_pedo_meas->flag;
439
440 // Encode step count
441 if (p_pedo_meas->flag & WECHAT_PEDO_FLAG_STEP_COUNT_BIT) {
442 p_buff[encode_length++] = p_pedo_meas->step_count[INDEX_0];
443 p_buff[encode_length++] = p_pedo_meas->step_count[INDEX_1];
444 p_buff[encode_length++] = p_pedo_meas->step_count[INDEX_2];
445 }
446
447 // Encode step distance
448 if (p_pedo_meas->flag & WECHAT_PEDO_FLAG_STEP_DISTENCE_BIT) {
449 p_buff[encode_length++] = p_pedo_meas->step_dist[INDEX_0];
450 p_buff[encode_length++] = p_pedo_meas->step_dist[INDEX_1];
451 p_buff[encode_length++] = p_pedo_meas->step_dist[INDEX_2];
452 }
453
454 // Encode step calorie
455 if (p_pedo_meas->flag & WECHAT_PEDO_FLAG_STEP_CALORIE_BIT) {
456 p_buff[encode_length++] = p_pedo_meas->step_calorie[INDEX_0];
457 p_buff[encode_length++] = p_pedo_meas->step_calorie[INDEX_1];
458 p_buff[encode_length++] = p_pedo_meas->step_calorie[INDEX_2];
459 }
460
461 return encode_length;
462 }
463
464 /**
465 *****************************************************************************************
466 * @brief Encode WeChat pedometer target value.
467 *
468 * @param[in] p_buff: Pointer to encode buffer.
469 * @param[in] p_pedo_meas: Pointer to pedometer target value.
470 *
471 * @return Length of encoded.
472 *****************************************************************************************
473 */
wechat_pedo_target_encode(uint8_t * p_buff,wechat_pedo_target_t * p_pedo_target)474 static uint8_t wechat_pedo_target_encode(uint8_t *p_buff, wechat_pedo_target_t *p_pedo_target)
475 {
476 uint8_t encode_length = 0;
477
478 if (p_pedo_target->flag & WECHAT_PEDO_FLAG_STEP_COUNT_BIT) {
479 p_buff[encode_length++] = p_pedo_target->flag;
480 p_buff[encode_length++] = p_pedo_target->step_count[INDEX_0];
481 p_buff[encode_length++] = p_pedo_target->step_count[INDEX_1];
482 p_buff[encode_length++] = p_pedo_target->step_count[INDEX_2];
483 }
484
485 return encode_length;
486 }
487
488 /**
489 *****************************************************************************************
490 * @brief Set wechat pedometer target value.
491 *
492 * @param[in] p_data: Pointer to data.
493 * @param[in] length: Length to data.
494 *****************************************************************************************
495 */
wechat_pedo_target_set(const uint8_t * p_data,uint8_t length)496 static void wechat_pedo_target_set(const uint8_t *p_data, uint8_t length)
497 {
498 if ((p_data[INDEX_0] & WECHAT_PEDO_FLAG_STEP_COUNT_BIT) && (WECHAT_PEDO_TARGET_VAL_LEN == length)) {
499 s_wechat_env.pedo_target.flag = WECHAT_PEDO_FLAG_STEP_COUNT_BIT;
500 s_wechat_env.pedo_target.step_count[INDEX_0] = p_data[INDEX_1];
501 s_wechat_env.pedo_target.step_count[INDEX_1] = p_data[INDEX_2];
502 s_wechat_env.pedo_target.step_count[INDEX_2] = p_data[INDEX_3];
503 } else {
504 return;
505 }
506 }
507
508 /**
509 *****************************************************************************************
510 * @brief Handle WeChat Airsync data indicate.
511 *
512 * @param[in] conn_idx: Connection index.
513 *
514 * @return Result of handle.
515 *****************************************************************************************
516 */
wechat_indicate_data_chunk(uint8_t conn_idx)517 static sdk_err_t wechat_indicate_data_chunk(uint8_t conn_idx)
518 {
519 uint16_t chunk_len = 0;
520 gatts_noti_ind_t wechat_ind;
521 sdk_err_t error_code;
522
523 chunk_len = s_ind_data.length - s_ind_data.offset;
524 chunk_len = chunk_len > WECHAT_DATA_LEN ? WECHAT_DATA_LEN : chunk_len;
525
526 if (chunk_len == 0) {
527 s_ind_data.p_data = NULL;
528 s_ind_data.length = 0;
529 s_ind_data.offset = 0;
530
531 return SDK_SUCCESS;
532 }
533
534 wechat_ind.type = BLE_GATT_INDICATION;
535 wechat_ind.handle = prf_find_handle_by_idx(WECHAR_IDX_AIRSYNC_INDICATE_VAL,
536 s_wechat_env.start_hdl,
537 (uint8_t *)&s_char_mask);
538 wechat_ind.length = chunk_len;
539 wechat_ind.value = (uint8_t *)s_ind_data.p_data + s_ind_data.offset;
540
541 error_code = ble_gatts_noti_ind(conn_idx, &wechat_ind);
542 if (SDK_SUCCESS == error_code) {
543 s_ind_data.offset += chunk_len;
544 }
545
546 return error_code;
547 }
548
549 /*
550 * GLOBAL FUNCTION DEFINITIONS
551 *****************************************************************************************
552 */
wechat_service_init(wechat_init_t * p_wechat_init)553 sdk_err_t wechat_service_init(wechat_init_t *p_wechat_init)
554 {
555 sdk_err_t ret;
556 if (p_wechat_init == NULL) {
557 return SDK_ERR_POINTER_NULL;
558 }
559
560 s_wechat_env.evt_handler = p_wechat_init->evt_handler;
561 s_wechat_env.pedo_meas.flag = WECHAT_PEDO_FLAG_ALL_SUP_BIT;
562 s_wechat_env.pedo_target.flag = WECHAT_PEDO_FLAG_STEP_COUNT_BIT;
563 s_wechat_env.pedo_target.step_count[INDEX_0] = LO_UINT32_T(p_wechat_init->step_count_target);
564 s_wechat_env.pedo_target.step_count[INDEX_1] = L2_UINT32_T(p_wechat_init->step_count_target);
565 s_wechat_env.pedo_target.step_count[INDEX_2] = L3_UINT32_T(p_wechat_init->step_count_target);
566 ret = memcpy_s(s_wechat_env.dev_mac, GAP_ADDR_LEN, p_wechat_init->p_dev_mac, GAP_ADDR_LEN);
567 if (ret < 0) {
568 return ret;
569 }
570
571 return ble_server_prf_add(&wechat_prf_info);
572 }
573
wechat_airsync_data_indicate(uint8_t conn_idx,uint8_t * p_data,uint16_t length)574 sdk_err_t wechat_airsync_data_indicate(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
575 {
576 if (p_data == NULL || length == 0) {
577 return SDK_ERR_INVALID_PARAM;
578 }
579
580 s_ind_data.p_data = p_data;
581 s_ind_data.length = length;
582 s_ind_data.offset = 0;
583
584 return wechat_indicate_data_chunk(conn_idx);
585 }
586
wechat_pedo_measurement_send(uint8_t conn_idx,wechat_pedo_meas_t * p_pedo_meas)587 sdk_err_t wechat_pedo_measurement_send(uint8_t conn_idx, wechat_pedo_meas_t *p_pedo_meas)
588 {
589 gatts_noti_ind_t pedo_meas_ntf;
590 uint8_t encode_data[WECHAT_DATA_LEN];
591 uint8_t encode_len = 0;
592 sdk_err_t error_code = SDK_ERR_NTF_DISABLED;
593 uint8_t ret;
594
595 if (p_pedo_meas == NULL) {
596 return SDK_ERR_POINTER_NULL;
597 }
598
599 ret = memcpy_s(&s_wechat_env.pedo_meas, sizeof(wechat_pedo_meas_t), p_pedo_meas, sizeof(wechat_pedo_meas_t));
600 if (ret < 0) {
601 return ret;
602 }
603
604 encode_len = wechat_pedo_meas_encode(encode_data, &s_wechat_env.pedo_meas);
605
606 if (s_wechat_env.pedo_meas_ntf_cfg[conn_idx] & PRF_CLI_START_NTF) {
607 pedo_meas_ntf.type = BLE_GATT_NOTIFICATION;
608 pedo_meas_ntf.handle = prf_find_handle_by_idx(WECHAT_IDX_PEDO_MEAS_VAL,
609 s_wechat_env.start_hdl,
610 (uint8_t *)&s_char_mask);
611 pedo_meas_ntf.length = encode_len;
612 pedo_meas_ntf.value = encode_data;
613
614 error_code = ble_gatts_noti_ind(conn_idx, &pedo_meas_ntf);
615 }
616
617 return error_code;
618 }
619
wechat_pedo_target_send(uint8_t conn_idx)620 sdk_err_t wechat_pedo_target_send(uint8_t conn_idx)
621 {
622 gatts_noti_ind_t pedo_target_ind;
623 uint8_t encode_data[WECHAT_DATA_LEN];
624 uint8_t encode_len = 0;
625 sdk_err_t error_code = SDK_ERR_IND_DISABLED;
626
627 encode_len = wechat_pedo_target_encode(encode_data, &s_wechat_env.pedo_target);
628
629 if (s_wechat_env.pedo_target_ind_cfg[conn_idx] & PRF_CLI_START_IND) {
630 pedo_target_ind.type = BLE_GATT_INDICATION;
631 pedo_target_ind.handle = prf_find_handle_by_idx(WECHAT_IDX_TARGET_VAL,
632 s_wechat_env.start_hdl,
633 (uint8_t *)&s_char_mask);
634 pedo_target_ind.length = encode_len;
635 pedo_target_ind.value = encode_data;
636
637 error_code = ble_gatts_noti_ind(conn_idx, &pedo_target_ind);
638 }
639
640 return error_code;
641 }
642
643