xref: /nrf52832-nimble/packages/NimBLE-latest/apps/btshell/src/cmd_gatt.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <inttypes.h>
21 #include <errno.h>
22 
23 #include "host/ble_hs_mbuf.h"
24 #include "host/ble_gap.h"
25 #include "services/gatt/ble_svc_gatt.h"
26 #include "btshell.h"
27 #include "cmd.h"
28 #include "cmd_gatt.h"
29 
30 #include "nimble/npl_shell.h"
31 
32 #define CMD_BUF_SZ      256
33 static bssnz_t uint8_t cmd_buf[CMD_BUF_SZ];
34 
35 /*****************************************************************************
36  * $gatt-discover                                                            *
37  *****************************************************************************/
38 
39 int
cmd_gatt_discover_characteristic(int argc,char ** argv)40 cmd_gatt_discover_characteristic(int argc, char **argv)
41 {
42     uint16_t start_handle;
43     uint16_t conn_handle;
44     uint16_t end_handle;
45     ble_uuid_any_t uuid;
46     int rc;
47 
48     rc = parse_arg_all(argc - 1, argv + 1);
49     if (rc != 0) {
50         return rc;
51     }
52 
53     rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle);
54     if (rc != 0) {
55         console_printf("invalid 'conn start end' parameter\n");
56         return rc;
57     }
58 
59     rc = parse_arg_uuid("uuid", &uuid);
60     if (rc == 0) {
61         rc = btshell_disc_chrs_by_uuid(conn_handle, start_handle, end_handle,
62                                        &uuid.u);
63     } else if (rc == ENOENT) {
64         rc = btshell_disc_all_chrs(conn_handle, start_handle, end_handle);
65     } else  {
66         console_printf("invalid 'uuid' parameter\n");
67         return rc;
68     }
69     if (rc != 0) {
70         console_printf("error discovering characteristics; rc=%d\n", rc);
71         return rc;
72     }
73 
74     return 0;
75 }
76 
77 int
cmd_gatt_discover_descriptor(int argc,char ** argv)78 cmd_gatt_discover_descriptor(int argc, char **argv)
79 {
80     uint16_t start_handle;
81     uint16_t conn_handle;
82     uint16_t end_handle;
83     int rc;
84 
85     rc = parse_arg_all(argc - 1, argv + 1);
86     if (rc != 0) {
87         return rc;
88     }
89 
90     rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle);
91     if (rc != 0) {
92         console_printf("invalid 'conn start end' parameter\n");
93         return rc;
94     }
95 
96     rc = btshell_disc_all_dscs(conn_handle, start_handle, end_handle);
97     if (rc != 0) {
98         console_printf("error discovering descriptors; rc=%d\n", rc);
99         return rc;
100     }
101 
102     return 0;
103 }
104 
105 int
cmd_gatt_discover_service(int argc,char ** argv)106 cmd_gatt_discover_service(int argc, char **argv)
107 {
108     ble_uuid_any_t uuid;
109     int conn_handle;
110     int rc;
111 
112     rc = parse_arg_all(argc - 1, argv + 1);
113     if (rc != 0) {
114         return rc;
115     }
116 
117     conn_handle = parse_arg_uint16("conn", &rc);
118     if (rc != 0) {
119         console_printf("invalid 'conn' parameter\n");
120         return rc;
121     }
122 
123     rc = parse_arg_uuid("uuid", &uuid);
124     if (rc == 0) {
125         rc = btshell_disc_svc_by_uuid(conn_handle, &uuid.u);
126     } else if (rc == ENOENT) {
127         rc = btshell_disc_svcs(conn_handle);
128     } else  {
129         console_printf("invalid 'uuid' parameter\n");
130         return rc;
131     }
132 
133     if (rc != 0) {
134         console_printf("error discovering services; rc=%d\n", rc);
135         return rc;
136     }
137 
138     return 0;
139 }
140 
141 int
cmd_gatt_discover_full(int argc,char ** argv)142 cmd_gatt_discover_full(int argc, char **argv)
143 {
144     int conn_handle;
145     int rc;
146 
147     rc = parse_arg_all(argc - 1, argv + 1);
148     if (rc != 0) {
149         return rc;
150     }
151 
152     conn_handle = parse_arg_uint16("conn", &rc);
153     if (rc != 0) {
154         console_printf("invalid 'conn' parameter\n");
155         return rc;
156     }
157 
158     rc = btshell_disc_full(conn_handle);
159     if (rc != 0) {
160         console_printf("error discovering all; rc=%d\n", rc);
161         return rc;
162     }
163 
164     return 0;
165 }
166 
167 /*****************************************************************************
168  * $gatt-exchange-mtu                                                        *
169  *****************************************************************************/
170 
171 int
cmd_gatt_exchange_mtu(int argc,char ** argv)172 cmd_gatt_exchange_mtu(int argc, char **argv)
173 {
174     uint16_t conn_handle;
175     int rc;
176 
177     rc = parse_arg_all(argc - 1, argv + 1);
178     if (rc != 0) {
179         return rc;
180     }
181 
182     conn_handle = parse_arg_uint16("conn", &rc);
183     if (rc != 0) {
184         console_printf("invalid 'conn' parameter\n");
185         return rc;
186     }
187 
188     rc = btshell_exchange_mtu(conn_handle);
189     if (rc != 0) {
190         console_printf("error exchanging mtu; rc=%d\n", rc);
191         return rc;
192     }
193 
194     return 0;
195 }
196 
197 /*****************************************************************************
198  * $gatt-notify                                                              *
199  *****************************************************************************/
200 
201 int
cmd_gatt_notify(int argc,char ** argv)202 cmd_gatt_notify(int argc, char **argv)
203 {
204     uint16_t attr_handle;
205     int rc;
206 
207     rc = parse_arg_all(argc - 1, argv + 1);
208     if (rc != 0) {
209         return rc;
210     }
211 
212     attr_handle = parse_arg_uint16("attr", &rc);
213     if (rc != 0) {
214         console_printf("invalid 'attr' parameter\n");
215         return rc;
216     }
217 
218     btshell_notify(attr_handle);
219 
220     return 0;
221 }
222 
223 /*****************************************************************************
224  * $gatt-read                                                                *
225  *****************************************************************************/
226 
227 #define CMD_READ_MAX_ATTRS  8
228 
229 int
cmd_gatt_read(int argc,char ** argv)230 cmd_gatt_read(int argc, char **argv)
231 {
232     static uint16_t attr_handles[CMD_READ_MAX_ATTRS];
233     uint16_t conn_handle;
234     uint16_t start;
235     uint16_t end;
236     uint16_t offset;
237     ble_uuid_any_t uuid;
238     uint8_t num_attr_handles;
239     int is_uuid;
240     int is_long;
241     int rc;
242 
243     rc = parse_arg_all(argc - 1, argv + 1);
244     if (rc != 0) {
245         return rc;
246     }
247 
248     conn_handle = parse_arg_uint16("conn", &rc);
249     if (rc != 0) {
250         console_printf("invalid 'conn' parameter\n");
251         return rc;
252     }
253 
254     is_long = parse_arg_long("long", &rc);
255     if (rc == ENOENT) {
256         is_long = 0;
257     } else if (rc != 0) {
258         console_printf("invalid 'long' parameter\n");
259         return rc;
260     }
261 
262     for (num_attr_handles = 0;
263          num_attr_handles < CMD_READ_MAX_ATTRS;
264          num_attr_handles++) {
265 
266         attr_handles[num_attr_handles] = parse_arg_uint16("attr", &rc);
267         if (rc == ENOENT) {
268             break;
269         } else if (rc != 0) {
270             console_printf("invalid 'attr' parameter\n");
271             return rc;
272         }
273     }
274 
275     rc = parse_arg_uuid("uuid", &uuid);
276     if (rc == ENOENT) {
277         is_uuid = 0;
278     } else if (rc == 0) {
279         is_uuid = 1;
280     } else {
281         console_printf("invalid 'uuid' parameter\n");
282         return rc;
283     }
284 
285     start = parse_arg_uint16("start", &rc);
286     if (rc == ENOENT) {
287         start = 0;
288     } else if (rc != 0) {
289         console_printf("invalid 'start' parameter\n");
290         return rc;
291     }
292 
293     end = parse_arg_uint16("end", &rc);
294     if (rc == ENOENT) {
295         end = 0;
296     } else if (rc != 0) {
297         console_printf("invalid 'end' parameter\n");
298         return rc;
299     }
300 
301     offset = parse_arg_uint16("offset", &rc);
302     if (rc == ENOENT) {
303         offset = 0;
304     } else if (rc != 0) {
305         console_printf("invalid 'offset' parameter\n");
306         return rc;
307     }
308 
309     if (num_attr_handles == 1) {
310         if (is_long) {
311             rc = btshell_read_long(conn_handle, attr_handles[0], offset);
312         } else {
313             rc = btshell_read(conn_handle, attr_handles[0]);
314         }
315     } else if (num_attr_handles > 1) {
316         rc = btshell_read_mult(conn_handle, attr_handles, num_attr_handles);
317     } else if (is_uuid) {
318         if (start == 0 || end == 0) {
319             rc = EINVAL;
320         } else {
321             rc = btshell_read_by_uuid(conn_handle, start, end, &uuid.u);
322         }
323     } else {
324         rc = EINVAL;
325     }
326 
327     if (rc != 0) {
328         console_printf("error reading characteristic; rc=%d\n", rc);
329         return rc;
330     }
331 
332     return 0;
333 }
334 
335 
336 /*****************************************************************************
337  * $gatt-service-changed                                                     *
338  *****************************************************************************/
339 
340 int
cmd_gatt_service_changed(int argc,char ** argv)341 cmd_gatt_service_changed(int argc, char **argv)
342 {
343     uint16_t start;
344     uint16_t end;
345     int rc;
346 
347     rc = parse_arg_all(argc - 1, argv + 1);
348     if (rc != 0) {
349         return rc;
350     }
351 
352     start = parse_arg_uint16("start", &rc);
353     if (rc != 0) {
354         console_printf("invalid 'start' parameter\n");
355         return rc;
356     }
357 
358     end = parse_arg_uint16("end", &rc);
359     if (rc != 0) {
360         console_printf("invalid 'end' parameter\n");
361         return rc;
362     }
363 
364     ble_svc_gatt_changed(start, end);
365 
366     return 0;
367 }
368 
369 /*****************************************************************************
370  * $gatt-service-visibility                                                  *
371  *****************************************************************************/
372 
373 int
cmd_gatt_service_visibility(int argc,char ** argv)374 cmd_gatt_service_visibility(int argc, char **argv)
375 {
376     uint16_t handle;
377     bool vis;
378     int rc;
379 
380     rc = parse_arg_all(argc - 1, argv + 1);
381     if (rc != 0) {
382         return rc;
383     }
384 
385     handle = parse_arg_uint16("handle", &rc);
386     if (rc != 0) {
387         console_printf("invalid 'handle' parameter\n");
388         return rc;
389     }
390 
391     vis = parse_arg_bool("visibility", &rc);
392     if (rc != 0) {
393         console_printf("invalid 'visibility' parameter\n");
394         return rc;
395     }
396 
397     ble_gatts_svc_set_visibility(handle, vis);
398 
399     return 0;
400 }
401 
402 /*****************************************************************************
403  * $gatt-find-included-services                                              *
404  *****************************************************************************/
405 
406 int
cmd_gatt_find_included_services(int argc,char ** argv)407 cmd_gatt_find_included_services(int argc, char **argv)
408 {
409     uint16_t start_handle;
410     uint16_t conn_handle;
411     uint16_t end_handle;
412     int rc;
413 
414     rc = parse_arg_all(argc - 1, argv + 1);
415     if (rc != 0) {
416         return rc;
417     }
418 
419     rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle);
420     if (rc != 0) {
421         console_printf("invalid 'conn start end' parameter\n");
422         return rc;
423     }
424 
425     rc = btshell_find_inc_svcs(conn_handle, start_handle, end_handle);
426     if (rc != 0) {
427         console_printf("error finding included services; rc=%d\n", rc);
428         return rc;
429     }
430 
431     return 0;
432 }
433 
434 /*****************************************************************************
435  * $gatt-show                                                                *
436  *****************************************************************************/
437 
438 int
cmd_gatt_show(int argc,char ** argv)439 cmd_gatt_show(int argc, char **argv)
440 {
441     struct btshell_conn *conn;
442     struct btshell_svc *svc;
443     int i;
444 
445     for (i = 0; i < btshell_num_conns; i++) {
446         conn = btshell_conns + i;
447 
448         console_printf("CONNECTION: handle=%d\n", conn->handle);
449 
450         SLIST_FOREACH(svc, &conn->svcs, next) {
451             print_svc(svc);
452         }
453     }
454 
455     return 0;
456 }
457 
458 int
cmd_gatt_show_local(int argc,char ** argv)459 cmd_gatt_show_local(int argc, char **argv)
460 {
461     gatt_svr_print_svcs();
462     return 0;
463 }
464 
465 /*****************************************************************************
466  * $gatt-write                                                               *
467  *****************************************************************************/
468 
469 int
cmd_gatt_write(int argc,char ** argv)470 cmd_gatt_write(int argc, char **argv)
471 {
472     struct ble_gatt_attr attrs[MYNEWT_VAL(BLE_GATT_WRITE_MAX_ATTRS)] = { { 0 } };
473     uint16_t attr_handle;
474     uint16_t conn_handle;
475     uint16_t offset;
476     int total_attr_len;
477     int num_attrs;
478     int attr_len;
479     int is_long;
480     int no_rsp;
481     int rc;
482     int i;
483 
484     rc = parse_arg_all(argc - 1, argv + 1);
485     if (rc != 0) {
486         return rc;
487     }
488 
489     conn_handle = parse_arg_uint16("conn", &rc);
490     if (rc != 0) {
491         console_printf("invalid 'conn' parameter\n");
492         return rc;
493     }
494 
495     no_rsp = parse_arg_bool_dflt("no_rsp", 0, &rc);
496     if (rc != 0) {
497         console_printf("invalid 'no_rsp' parameter\n");
498         return rc;
499     }
500 
501     is_long = parse_arg_bool_dflt("long", 0, &rc);
502     if (rc != 0) {
503         console_printf("invalid 'long' parameter\n");
504         return rc;
505     }
506 
507     total_attr_len = 0;
508     num_attrs = 0;
509     while (1) {
510         attr_handle = parse_arg_uint16("attr", &rc);
511         if (rc == ENOENT) {
512             break;
513         } else if (rc != 0) {
514             rc = -rc;
515             console_printf("invalid 'attr' parameter\n");
516             goto done;
517         }
518 
519         rc = parse_arg_byte_stream("value", sizeof cmd_buf - total_attr_len,
520                                    cmd_buf + total_attr_len, &attr_len);
521         if (rc == ENOENT) {
522             break;
523         } else if (rc != 0) {
524             console_printf("invalid 'value' parameter\n");
525             goto done;
526         }
527 
528         offset = parse_arg_uint16("offset", &rc);
529         if (rc == ENOENT) {
530             offset = 0;
531         } else if (rc != 0) {
532             console_printf("invalid 'offset' parameter\n");
533             return rc;
534         }
535 
536         if (num_attrs >= sizeof attrs / sizeof attrs[0]) {
537             rc = -EINVAL;
538             goto done;
539         }
540 
541         attrs[num_attrs].handle = attr_handle;
542         attrs[num_attrs].offset = offset;
543         attrs[num_attrs].om = ble_hs_mbuf_from_flat(cmd_buf + total_attr_len,
544                                                     attr_len);
545         if (attrs[num_attrs].om == NULL) {
546             goto done;
547         }
548 
549         total_attr_len += attr_len;
550         num_attrs++;
551     }
552 
553     if (no_rsp) {
554         if (num_attrs != 1) {
555             rc = -EINVAL;
556             goto done;
557         }
558         rc = btshell_write_no_rsp(conn_handle, attrs[0].handle, attrs[0].om);
559         attrs[0].om = NULL;
560     } else if (is_long) {
561         if (num_attrs != 1) {
562             rc = -EINVAL;
563             goto done;
564         }
565         rc = btshell_write_long(conn_handle, attrs[0].handle,
566                                 attrs[0].offset, attrs[0].om);
567         attrs[0].om = NULL;
568     } else if (num_attrs > 1) {
569         rc = btshell_write_reliable(conn_handle, attrs, num_attrs);
570     } else if (num_attrs == 1) {
571         rc = btshell_write(conn_handle, attrs[0].handle, attrs[0].om);
572         attrs[0].om = NULL;
573     } else {
574         rc = -EINVAL;
575     }
576 
577 done:
578     for (i = 0; i < sizeof attrs / sizeof attrs[0]; i++) {
579         os_mbuf_free_chain(attrs[i].om);
580     }
581 
582     if (rc != 0) {
583         console_printf("error writing characteristic; rc=%d\n", rc);
584     }
585 
586     return rc;
587 }
588