1 /**
2  ****************************************************************************************
3  *
4  * @file prf_utils.c
5  *
6  * @brief Implementation of Profile Utilities
7  *
8  * Copyright (C) RivieraWaves 2009-2016
9  *
10  *
11  ****************************************************************************************
12  */
13 
14 
15 /**
16  ****************************************************************************************
17  * @addtogroup PRF_UTILS
18  * @{
19  ****************************************************************************************
20  */
21 
22 /*
23  * INCLUDE FILES
24  ****************************************************************************************
25  */
26 #include "rwip_config.h"
27 #if (BLE_PROFILES)
28 #if (BLE_SERVER_PRF || BLE_CLIENT_PRF)
29 
30 #include <stdint.h>
31 #include <stdbool.h>
32 #include "ke_task.h"
33 #include "attm.h"
34 #include "gattc_task.h"
35 #include "prf_utils.h"
36 #include "gap.h"
37 #include "gapc.h"
38 
39 #include "ke_mem.h"
40 #include "co_utils.h"
41 #include "co_error.h"
42 
43 #endif /* (BLE_SERVER_PRF || BLE_CLIENT_PRF) */
44 
45 /*
46  * LOCAL FUNCTIONS DEFINITIONS
47  ****************************************************************************************
48  */
49 
50 /*
51  * EXPORTED FUNCTIONS DEFINITIONS
52  ****************************************************************************************
53  */
54 
55 #if (BLE_BATT_SERVER)
prf_pack_char_pres_fmt(uint8_t * packed_val,const struct prf_char_pres_fmt * char_pres_fmt)56 void prf_pack_char_pres_fmt(uint8_t *packed_val, const struct prf_char_pres_fmt* char_pres_fmt)
57 {
58     *packed_val =               char_pres_fmt->format;
59     *(packed_val + 1) =         char_pres_fmt->exponent;
60     co_write16p(packed_val + 2, char_pres_fmt->unit);
61     *(packed_val + 4) =         char_pres_fmt->name_space;
62     co_write16p(packed_val + 5, char_pres_fmt->description);
63 }
64 #endif // (BLE_BATT_SERVER)
65 
66 #if (BLE_BATT_CLIENT)
prf_unpack_char_pres_fmt(const uint8_t * packed_val,struct prf_char_pres_fmt * char_pres_fmt)67 void prf_unpack_char_pres_fmt(const uint8_t *packed_val, struct prf_char_pres_fmt* char_pres_fmt)
68 {
69 
70     char_pres_fmt->format       = *packed_val;
71     char_pres_fmt->exponent     = *(packed_val + 1);
72     char_pres_fmt->unit         = co_read16p(packed_val + 2);
73     char_pres_fmt->name_space    = *(packed_val + 4);
74     char_pres_fmt->description  = co_read16p(packed_val + 5);
75 }
76 #endif // (BLE_BATT_CLIENT)
77 
78 
79 #if (BLE_CLIENT_PRF)
prf_read_char_send(prf_env_t * prf_env,uint8_t conidx,uint16_t shdl,uint16_t ehdl,uint16_t valhdl)80 void prf_read_char_send(prf_env_t *prf_env, uint8_t conidx,
81                         uint16_t shdl, uint16_t ehdl, uint16_t valhdl)
82 {
83     struct gattc_read_cmd * req  = KE_MSG_ALLOC(GATTC_READ_CMD, KE_BUILD_ID(TASK_GATTC, conidx),
84             prf_src_task_get(prf_env, conidx), gattc_read_cmd);
85     //request type
86     req->operation                       = GATTC_READ;
87     req->nb                             = 1;
88     req->req.simple.offset              = 0;
89     req->req.simple.length              = 0;
90     req->req.simple.handle              = valhdl;
91 
92     //send request to GATT
93     ke_msg_send(req);
94 }
95 
prf_register_atthdl2gatt(prf_env_t * prf_env,uint8_t conidx,struct prf_svc * svc)96 void prf_register_atthdl2gatt(prf_env_t *prf_env, uint8_t conidx, struct prf_svc *svc)
97 {
98     if (svc->shdl != ATT_INVALID_HANDLE)
99     {
100         //register profile task in gatt for indication/notifications
101         struct gattc_reg_to_peer_evt_cmd * reg = KE_MSG_ALLOC(GATTC_REG_TO_PEER_EVT_CMD,
102                 KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
103                 gattc_reg_to_peer_evt_cmd);
104 
105         reg->operation =  GATTC_REGISTER;
106         reg->start_hdl = svc->shdl;
107         reg->end_hdl =   svc->ehdl;
108 
109         ke_msg_send(reg);
110     }
111 }
112 
prf_unregister_atthdl2gatt(prf_env_t * prf_env,uint8_t conidx,struct prf_svc * svc)113 void prf_unregister_atthdl2gatt(prf_env_t *prf_env, uint8_t conidx, struct prf_svc *svc)
114 {
115     if (svc->shdl != ATT_INVALID_HANDLE)
116     {
117         //un register profile task in gatt for indication/notifications
118         struct gattc_reg_to_peer_evt_cmd * reg = KE_MSG_ALLOC(GATTC_REG_TO_PEER_EVT_CMD,
119                 KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
120                 gattc_reg_to_peer_evt_cmd);
121 
122         reg->operation =  GATTC_UNREGISTER;
123         reg->start_hdl = svc->shdl;
124         reg->end_hdl =   svc->ehdl;
125 
126         ke_msg_send(reg);
127     }
128 }
129 
130 
prf_disc_svc_send(prf_env_t * prf_env,uint8_t conidx,uint16_t uuid)131 void prf_disc_svc_send(prf_env_t *prf_env, uint8_t conidx, uint16_t uuid)
132 {
133     //send GATT discover primary services by UUID request
134     struct gattc_sdp_svc_disc_cmd * svc_req = KE_MSG_ALLOC_DYN(GATTC_SDP_SVC_DISC_CMD,
135             KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
136             gattc_sdp_svc_disc_cmd, ATT_UUID_16_LEN);
137 
138     //gatt request type: by UUID
139     svc_req->operation         = GATTC_SDP_DISC_SVC;
140     //start handle;
141     svc_req->start_hdl        = ATT_1ST_REQ_START_HDL;
142     //end handle
143     svc_req->end_hdl          = ATT_1ST_REQ_END_HDL;
144 
145     // UUID search
146     svc_req->uuid_len = ATT_UUID_16_LEN;
147 
148     //set the first two bytes to the value array, LSB to MSB:Health Thermometer Service UUID first
149     co_write16p(&(svc_req->uuid[0]), uuid);
150 
151     //send the message to GATT, which will send back the response when it gets it
152     ke_msg_send(svc_req);
153 }
154 
155 
156 
prf_gatt_write(prf_env_t * prf_env,uint8_t conidx,uint16_t handle,uint8_t * value,uint16_t length,uint8_t operation)157 void prf_gatt_write(prf_env_t *prf_env, uint8_t conidx,
158                     uint16_t handle, uint8_t* value, uint16_t length, uint8_t operation)
159 {
160     if (handle != ATT_INVALID_HANDLE)
161     {
162         struct gattc_write_cmd *wr_char = KE_MSG_ALLOC_DYN(GATTC_WRITE_CMD,
163                 KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
164                 gattc_write_cmd, length);
165 
166         // Offset
167         wr_char->offset         = 0x0000;
168         // cursor always 0
169         wr_char->cursor         = 0x0000;
170         // Write Type
171         wr_char->operation       = operation;
172         // Characteristic Value attribute handle
173         wr_char->handle         = handle;
174         // Value Length
175         wr_char->length         = length;
176         // Auto Execute
177         wr_char->auto_execute   = true;
178         // Value
179         memcpy(&wr_char->value[0], value, length);
180 
181         // Send the message
182         ke_msg_send(wr_char);
183     }
184 }
185 
prf_gatt_write_ntf_ind(prf_env_t * prf_env,uint8_t conidx,uint16_t handle,uint16_t ntf_ind_cfg)186 void prf_gatt_write_ntf_ind(prf_env_t *prf_env, uint8_t conidx, uint16_t handle, uint16_t ntf_ind_cfg)
187 {
188     uint8_t value[2];
189 
190     // put value in air format
191     co_write16p((&value[0]), ntf_ind_cfg);
192     // write value over GATT
193     prf_gatt_write(prf_env, conidx, handle, value, 2, GATTC_WRITE);
194 }
195 
prf_check_svc_char_validity(uint8_t nb_chars,const struct prf_char_inf * chars,const struct prf_char_def * chars_req)196 uint8_t prf_check_svc_char_validity(uint8_t nb_chars,
197                                     const struct prf_char_inf* chars,
198                                     const struct prf_char_def* chars_req)
199 {
200     uint8_t status = GAP_ERR_NO_ERROR;
201     uint8_t i;
202 
203     for(i = 0; ((i < nb_chars) && (status == GAP_ERR_NO_ERROR)); i++)
204     {
205         if (chars[i].char_hdl == ATT_INVALID_HANDLE)
206         {
207             //If Characteristic is not present, check requirements
208             if (chars_req[i].req_flag == ATT_MANDATORY)
209             {
210                 status = PRF_ERR_STOP_DISC_CHAR_MISSING;
211             }
212         }
213         else
214         {
215             //If Characteristic is present, check properties
216             if ((chars[i].prop & chars_req[i].prop_mand) != chars_req[i].prop_mand)
217             {
218                 status = PRF_ERR_STOP_DISC_WRONG_CHAR_PROP;
219             }
220         }
221     }
222 
223     return (status);
224 }
225 
226 
prf_check_svc_char_uuid128_validity(uint8_t nb_chars,const struct prf_char_inf * chars,const struct prf_char_uuid128_def * chars_req)227 uint8_t prf_check_svc_char_uuid128_validity(uint8_t nb_chars,
228                                     const struct prf_char_inf* chars,
229                                     const struct prf_char_uuid128_def* chars_req)
230 {
231     uint8_t status = GAP_ERR_NO_ERROR;
232     uint8_t i;
233 
234     for(i = 0; ((i < nb_chars) && (status == GAP_ERR_NO_ERROR)); i++)
235     {
236         if (chars[i].char_hdl == ATT_INVALID_HANDLE)
237         {
238             //If Characteristic is not present, check requirements
239             if (chars_req[i].req_flag == ATT_MANDATORY)
240             {
241                 status = PRF_ERR_STOP_DISC_CHAR_MISSING;
242             }
243         }
244         else
245         {
246             //If Characteristic is present, check properties
247             if ((chars[i].prop & chars_req[i].prop_mand) != chars_req[i].prop_mand)
248             {
249                 status = PRF_ERR_STOP_DISC_WRONG_CHAR_PROP;
250             }
251         }
252     }
253 
254     return (status);
255 }
256 
257 
prf_check_svc_char_desc_validity(uint8_t descs_size,const struct prf_char_desc_inf * descs,const struct prf_char_desc_def * descs_req,const struct prf_char_inf * chars)258 uint8_t prf_check_svc_char_desc_validity(uint8_t descs_size,
259                                          const struct prf_char_desc_inf* descs,
260                                          const struct prf_char_desc_def* descs_req,
261                                          const struct prf_char_inf* chars)
262 {
263     uint8_t status = GAP_ERR_NO_ERROR;
264     uint8_t i;
265 
266     for(i = 0; ((i < descs_size) && (status == GAP_ERR_NO_ERROR)) ; i++)
267     {
268         if (descs[i].desc_hdl == ATT_INVALID_HANDLE)
269         {
270             //If Descriptor is missing, check if it is mandatory
271             if (descs_req[i].req_flag == ATT_MANDATORY)
272             {
273                 //Check if Char is present
274                 if (chars[descs_req[i].char_code].char_hdl != ATT_INVALID_HANDLE)
275                 {
276                     //Char. is present and descriptor not, error
277                     status = PRF_ERR_STOP_DISC_CHAR_MISSING;
278                 }
279             }
280         }
281     }
282 
283     return (status);
284 }
285 
286 
prf_check_svc_char_desc_uuid128_validity(uint8_t descs_size,const struct prf_char_desc_inf * descs,const struct prf_char_desc_uuid128_def * descs_req,const struct prf_char_inf * chars)287 uint8_t prf_check_svc_char_desc_uuid128_validity(uint8_t descs_size,
288                                          const struct prf_char_desc_inf* descs,
289                                          const struct prf_char_desc_uuid128_def* descs_req,
290                                          const struct prf_char_inf* chars)
291 {
292     uint8_t status = GAP_ERR_NO_ERROR;
293     uint8_t i;
294 
295     for(i = 0; ((i < descs_size) && (status == GAP_ERR_NO_ERROR)) ; i++)
296     {
297         if (descs[i].desc_hdl == ATT_INVALID_HANDLE)
298         {
299             //If Descriptor is missing, check if it is mandatory
300             if (descs_req[i].req_flag == ATT_MANDATORY)
301             {
302                 //Check if Char is present
303                 if (chars[descs_req[i].char_code].char_hdl != ATT_INVALID_HANDLE)
304                 {
305                     //Char. is present and descriptor not, error
306                     status = PRF_ERR_STOP_DISC_CHAR_MISSING;
307                 }
308             }
309         }
310     }
311 
312     return (status);
313 }
314 
prf_extract_svc_info(const struct gattc_sdp_svc_ind * param,uint8_t nb_chars,const struct prf_char_def * chars_req,struct prf_char_inf * chars,uint8_t nb_descs,const struct prf_char_desc_def * descs_req,struct prf_char_desc_inf * descs)315 void prf_extract_svc_info(const struct gattc_sdp_svc_ind* param,
316         uint8_t nb_chars, const struct prf_char_def* chars_req, struct prf_char_inf* chars,
317         uint8_t nb_descs, const struct prf_char_desc_def* descs_req, struct prf_char_desc_inf* descs)
318 {
319     //Counters
320     uint8_t svc_char;
321     uint8_t svc_desc;
322     uint8_t fnd_att;
323 
324     for (fnd_att=0; fnd_att< (param->end_hdl - param->start_hdl); fnd_att++)
325     {
326         if (param->info[fnd_att].att_type == GATTC_SDP_ATT_CHAR)
327         {
328             uint16_t char_hdl = param->start_hdl+ 1 + fnd_att;
329             uint16_t val_hdl  = param->info[fnd_att].att_char.handle;
330             uint8_t  val_prop = param->info[fnd_att].att_char.prop;
331             uint8_t  char_idx = fnd_att;
332 
333             // check that value handle is in a valid range
334             if ((val_hdl <= param->end_hdl) && (val_hdl > (param->start_hdl + fnd_att)))
335             {
336                 // retrieve value index
337                 uint8_t val_idx = (val_hdl - param->start_hdl - 1);
338 
339                 //Look over requested characteristics
340                 for (svc_char=0; svc_char<nb_chars ; svc_char++)
341                 {
342                     // check if attribute is valid
343                     if ((chars[svc_char].char_hdl == ATT_INVALID_HDL)
344                             && attm_uuid16_comp((uint8_t*)param->info[val_idx].att.uuid,
345                                                 param->info[val_idx].att.uuid_len, chars_req[svc_char].uuid))
346                     {
347                         //Save properties and handles
348                         chars[svc_char].char_hdl       = char_hdl;
349                         chars[svc_char].val_hdl        = val_hdl;
350                         chars[svc_char].prop           = val_prop;
351 
352                         // find end of characteristic handle and discover descriptors
353                         do
354                         {
355                             fnd_att++;
356 
357                             // found a descriptor
358                             if (param->info[fnd_att].att_type == GATTC_SDP_ATT_DESC)
359                             {
360                                 //Retrieve characteristic descriptor handle using UUID
361                                 for(svc_desc = 0; svc_desc<nb_descs; svc_desc++)
362                                 {
363                                     // check if it's expected descriptor
364                                     if ((descs[svc_desc].desc_hdl == ATT_INVALID_HANDLE)
365                                         && (descs_req[svc_desc].char_code == svc_char)
366                                         && (attm_uuid16_comp((uint8_t*)param->info[fnd_att].att.uuid,
367                                                 param->info[fnd_att].att.uuid_len, descs_req[svc_desc].uuid)))
368                                     {
369                                         descs[svc_desc].desc_hdl = param->start_hdl + 1 + fnd_att;
370                                         // search for next descriptor
371                                         break;
372                                     }
373                                 }
374                             }
375                         } while (((param->start_hdl+ 1 + fnd_att) <= param->end_hdl)
376                                 && (param->info[fnd_att].att_type != GATTC_SDP_ATT_CHAR)
377                                 && (param->info[fnd_att].att_type != GATTC_SDP_INC_SVC));
378 
379                         // return to previous valid value
380                         fnd_att--;
381                         // previous handle was end of the characteristic
382                         chars[svc_char].char_ehdl_off    = fnd_att - char_idx;
383 
384                         // search next characteristic
385                         break;
386                     }
387                 }
388             }
389         }
390     }
391 }
392 
393 
prf_extract_svc_uuid128_info(const struct gattc_sdp_svc_ind * param,uint8_t nb_chars,const struct prf_char_uuid128_def * chars_uuid128_req,struct prf_char_inf * chars,uint8_t nb_descs,const struct prf_char_desc_uuid128_def * descs_uuid128_req,struct prf_char_desc_inf * descs)394 void prf_extract_svc_uuid128_info(const struct gattc_sdp_svc_ind* param,
395         uint8_t nb_chars, const struct prf_char_uuid128_def* chars_uuid128_req, struct prf_char_inf* chars,
396         uint8_t nb_descs, const struct prf_char_desc_uuid128_def* descs_uuid128_req, struct prf_char_desc_inf* descs)
397 {
398     //Counters
399     uint8_t svc_char;
400     uint8_t svc_desc;
401     uint8_t fnd_att;
402 
403     for (fnd_att=0; fnd_att< (param->end_hdl - param->start_hdl); fnd_att++)
404     {
405         if (param->info[fnd_att].att_type == GATTC_SDP_ATT_CHAR)
406         {
407             uint16_t char_hdl = param->start_hdl+ 1 + fnd_att;
408             uint16_t val_hdl  = param->info[fnd_att].att_char.handle;
409             uint8_t  val_prop = param->info[fnd_att].att_char.prop;
410             uint8_t  char_idx = fnd_att;
411 
412             // check that value handle is in a valid range
413             if ((val_hdl <= param->end_hdl) && (val_hdl > (param->start_hdl + fnd_att)))
414             {
415                 // retrieve value index
416                 uint8_t val_idx = (val_hdl - param->start_hdl - 1);
417 
418                 //Look over requested characteristics
419                 for (svc_char=0; svc_char<nb_chars ; svc_char++)
420                 {
421                     // check if attribute is valid
422                     if ((chars[svc_char].char_hdl == ATT_INVALID_HDL)
423                             && attm_uuid_comp((uint8_t*)param->info[val_idx].att.uuid,
424                                                 param->info[val_idx].att.uuid_len, &chars_uuid128_req[svc_char].uuid[0], chars_uuid128_req[svc_char].uuid_len))
425                     {
426                         //Save properties and handles
427                         chars[svc_char].char_hdl       = char_hdl;
428                         chars[svc_char].val_hdl        = val_hdl;
429                         chars[svc_char].prop           = val_prop;
430 
431                         // find end of characteristic handle and discover descriptors
432                         do
433                         {
434                             fnd_att++;
435 
436                             // found a descriptor
437                             if (param->info[fnd_att].att_type == GATTC_SDP_ATT_DESC)
438                             {
439                                 //Retrieve characteristic descriptor handle using UUID
440                                 for(svc_desc = 0; svc_desc<nb_descs; svc_desc++)
441                                 {
442                                     // check if it's expected descriptor
443                                     if ((descs[svc_desc].desc_hdl == ATT_INVALID_HANDLE)
444                                         && (descs_uuid128_req[svc_desc].char_code == svc_char)
445                                         && (attm_uuid_comp((uint8_t*)param->info[fnd_att].att.uuid,
446                                                 param->info[fnd_att].att.uuid_len, descs_uuid128_req[svc_desc].uuid, descs_uuid128_req[svc_desc].uuid_len)))
447                                     {
448                                         descs[svc_desc].desc_hdl = param->start_hdl + 1 + fnd_att;
449                                         // search for next descriptor
450                                         break;
451                                     }
452                                 }
453                             }
454                         } while (((param->start_hdl+ 1 + fnd_att) <= param->end_hdl)
455                                 && (param->info[fnd_att].att_type != GATTC_SDP_ATT_CHAR)
456                                 && (param->info[fnd_att].att_type != GATTC_SDP_INC_SVC));
457 
458                         // return to previous valid value
459                         fnd_att--;
460                         // previous handle was end of the characteristic
461                         chars[svc_char].char_ehdl_off    = fnd_att - char_idx;
462 
463                         // search next characteristic
464                         break;
465                     }
466                 }
467             }
468         }
469     }
470 }
471 
472 
473 #endif //(BLE_CLIENT_PRF)
474 
475 #if (BLE_CLIENT_PRF || BLE_TIP_SERVER || BLE_AN_SERVER || BLE_PAS_SERVER)
476 
prf_client_att_info_rsp(prf_env_t * prf_env,uint8_t conidx,uint16_t msg_id,uint8_t status,struct gattc_read_ind const * read_ind)477 void prf_client_att_info_rsp(prf_env_t *prf_env, uint8_t conidx, uint16_t msg_id,
478                              uint8_t status, struct gattc_read_ind const* read_ind)
479 {
480     // retrieve value length
481     uint16_t length = 0;
482     if (status == GAP_ERR_NO_ERROR)
483     {
484         length = read_ind->length;
485     }
486 
487     // prepare response
488     struct prf_att_info *rsp = KE_MSG_ALLOC_DYN(msg_id,
489             prf_dst_task_get(prf_env, conidx), prf_src_task_get(prf_env, conidx),
490             prf_att_info, length);
491 
492     rsp->status     = status;
493     rsp->handle     = ATT_INVALID_HDL;
494     rsp->length     = length;
495 
496     // set value array
497     if (read_ind != NULL)
498     {
499         rsp->handle = read_ind->handle;
500         memcpy(&(rsp->value[0]), &(read_ind->value[0]), length);
501     }
502 
503     ke_msg_send(rsp);
504 }
505 #endif //(BLE_CLIENT_PRF || BLE_TIP_SERVER || BLE_AN_SERVER || BLE_PAS_SERVER)
506 
507 
508 #if ((BLE_SERVER_PRF || BLE_CLIENT_PRF))
509 
prf_pack_date_time(uint8_t * packed_date,const struct prf_date_time * date_time)510 uint8_t prf_pack_date_time(uint8_t *packed_date, const struct prf_date_time* date_time)
511 {
512     co_write16p(packed_date, date_time->year);
513     *(packed_date + 2) = date_time->month;
514     *(packed_date + 3) = date_time->day;
515     *(packed_date + 4) = date_time->hour;
516     *(packed_date + 5) = date_time->min;
517     *(packed_date + 6) = date_time->sec;
518 
519     return 7;
520 }
prf_unpack_date_time(uint8_t * packed_date,struct prf_date_time * date_time)521 uint8_t prf_unpack_date_time(uint8_t *packed_date, struct prf_date_time* date_time)
522 {
523     date_time->year = co_read16p(&(packed_date[0]));
524     date_time->month = packed_date[2];
525     date_time->day   = packed_date[3];
526     date_time->hour  = packed_date[4];
527     date_time->min   = packed_date[5];
528     date_time->sec   = packed_date[6];
529 
530     return 7;
531 }
532 
533 
534 #endif /* ((BLE_SERVER_PRF || BLE_CLIENT_PRF)) */
535 #endif // (BLE_PROFILES)
536 /// @} PRF_UTILS
537 
538