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