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