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