OSDN Git Service

Remove obsolete LOCAL_MODULE_TAGS
[android-x86/external-bluetooth-bluez.git] / tools / mcaptest.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2014 Intel Corporation
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <getopt.h>
31 #include <unistd.h>
32
33 #include <glib.h>
34
35 #include "lib/bluetooth.h"
36 #include "lib/hci.h"
37 #include "lib/hci_lib.h"
38
39 #include "btio/btio.h"
40 #include "lib/l2cap.h"
41 #include "profiles/health/mcap.h"
42
43 enum {
44         MODE_NONE,
45         MODE_CONNECT,
46         MODE_LISTEN,
47 };
48
49 static GMainLoop *mloop;
50
51 static int ccpsm = 0x1003, dcpsm = 0x1005;
52
53 static struct mcap_instance *mcap = NULL;
54 static struct mcap_mdl *mdl = NULL;
55 static uint16_t mdlid;
56
57 static int control_mode = MODE_LISTEN;
58 static int data_mode = MODE_LISTEN;
59
60 static int mdl_conn_req_result = MCAP_SUCCESS;
61
62 static gboolean send_synccap_req = FALSE;
63 static gboolean mcl_disconnect = FALSE;
64 static gboolean mdl_disconnect = FALSE;
65 static int mcl_disconnect_timeout = -1;
66 static int mdl_disconnect_timeout = -1;
67
68 static struct mcap_mcl *mcl = NULL;
69
70 static gboolean no_close = FALSE;
71
72 #define REQ_CLOCK_ACC 0x1400
73
74 static void mdl_close(struct mcap_mdl *mdl)
75 {
76         int fd = -1;
77
78         printf("%s\n", __func__);
79
80         if (mdl_disconnect_timeout >= 0)
81                 sleep(mdl_disconnect_timeout);
82
83         fd = mcap_mdl_get_fd(mdl);
84
85         if (fd > 0)
86                 close(fd);
87 }
88
89 static void mdl_connected_cb(struct mcap_mdl *mdl, void *data)
90 {
91         printf("%s\n", __func__);
92
93         if (mdl_disconnect)
94                 mdl_close(mdl);
95 }
96
97 static void mdl_closed_cb(struct mcap_mdl *mdl, void *data)
98 {
99         printf("%s\n", __func__);
100
101         if (mcl_disconnect && mcl_disconnect_timeout >= 0) {
102                 sleep(mcl_disconnect_timeout);
103
104                 printf("Closing MCAP communication link\n");
105                 mcap_close_mcl(mcl, TRUE);
106
107                 if (no_close)
108                         return;
109
110                 g_main_loop_quit(mloop);
111         }
112 }
113
114 static void mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
115 {
116         /* TODO */
117         printf("%s\n", __func__);
118
119         /* Disconnecting MDL latency timeout */
120         if (mdl_disconnect_timeout >= 0)
121                 sleep(mdl_disconnect_timeout);
122 }
123
124 static void mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
125 {
126         /* TODO */
127         printf("%s\n", __func__);
128 }
129
130 static uint8_t mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
131                                 uint16_t mdlid, uint8_t *conf, void *data)
132 {
133         int ret;
134
135         printf("%s\n", __func__);
136
137         ret = mdl_conn_req_result;
138
139         mdl_conn_req_result = MCAP_SUCCESS;
140
141         return ret;
142 }
143
144 static uint8_t mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
145 {
146         printf("%s\n", __func__);
147
148         return MCAP_SUCCESS;
149 }
150
151 static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
152                                                                 gpointer data);
153
154 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
155 {
156         GError *gerr = NULL;
157
158         printf("%s\n", __func__);
159
160         if (data_mode == MODE_CONNECT) {
161                 mcap_create_mdl(mcl, 1, 0, create_mdl_cb, NULL, NULL, &gerr);
162                 if (gerr) {
163                         printf("Could not connect MDL: %s\n", gerr->message);
164                         g_error_free(gerr);
165                 }
166         }
167 }
168
169 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
170 {
171         /* TODO */
172         printf("%s\n", __func__);
173
174         if (no_close)
175                 return;
176
177         g_main_loop_quit(mloop);
178 }
179
180 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
181 {
182         /* TODO */
183         printf("%s\n", __func__);
184 }
185
186 static void connect_mdl_cb(struct mcap_mdl *mdl, GError *gerr, gpointer data)
187 {
188         mdlid = mcap_mdl_get_mdlid(mdl);
189
190         printf("%s\n", __func__);
191
192         if (mdlid == MCAP_MDLID_RESERVED)
193                 printf("MCAP mdlid is reserved");
194         else
195                 printf("MDL %d connected\n", mdlid);
196 }
197
198 static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
199                                                                 gpointer data)
200 {
201         GError *err = NULL;
202
203         printf("%s\n", __func__);
204
205         if (gerr) {
206                 printf("MDL error: %s\n", gerr->message);
207
208                 if (!no_close)
209                         g_main_loop_quit(mloop);
210
211                 return;
212         }
213
214         if (mdl)
215                 mcap_mdl_unref(mdl);
216
217         mdl = mcap_mdl_ref(mcap_mdl);
218
219         if (!mcap_connect_mdl(mdl, L2CAP_MODE_ERTM, dcpsm, connect_mdl_cb, NULL,
220                                                                 NULL, &err)) {
221                 printf("Error connecting to mdl: %s\n", err->message);
222                 g_error_free(err);
223
224                 if (no_close)
225                         return;
226
227                 g_main_loop_quit(mloop);
228         }
229 }
230
231 static void sync_cap_cb(struct mcap_mcl *mcl, uint8_t mcap_err,
232                         uint8_t btclockres, uint16_t synclead,
233                         uint16_t tmstampres, uint16_t tmstampacc, GError *err,
234                         gpointer data)
235 {
236         /* TODO */
237         printf("%s\n", __func__);
238 }
239
240 static void trigger_mdl_action(int mode)
241 {
242         GError *gerr = NULL;
243         gboolean ret;
244
245         ret = mcap_mcl_set_cb(mcl, NULL, &gerr,
246                 MCAP_MDL_CB_CONNECTED, mdl_connected_cb,
247                 MCAP_MDL_CB_CLOSED, mdl_closed_cb,
248                 MCAP_MDL_CB_DELETED, mdl_deleted_cb,
249                 MCAP_MDL_CB_ABORTED, mdl_aborted_cb,
250                 MCAP_MDL_CB_REMOTE_CONN_REQ, mdl_conn_req_cb,
251                 MCAP_MDL_CB_REMOTE_RECONN_REQ, mdl_reconn_req_cb,
252                 MCAP_MDL_CB_INVALID);
253
254         if (!ret && gerr) {
255                 printf("MCL cannot handle connection %s\n",
256                                                         gerr->message);
257                 g_error_free(gerr);
258         }
259
260         if (mode == MODE_CONNECT) {
261                 printf("Creating MCAP Data End Point\n");
262                 mcap_create_mdl(mcl, 1, 0, create_mdl_cb, NULL, NULL, &gerr);
263                 if (gerr) {
264                         printf("Could not connect MDL: %s\n", gerr->message);
265                         g_error_free(gerr);
266                 }
267         }
268
269         if (send_synccap_req && mcap->csp_enabled) {
270                 mcap_sync_init(mcl);
271
272                 mcap_sync_cap_req(mcl, REQ_CLOCK_ACC, sync_cap_cb, NULL, &gerr);
273                 if (gerr) {
274                         printf("MCAP Sync req error: %s\n", gerr->message);
275                         g_error_free(gerr);
276                 }
277         }
278 }
279
280 static void mcl_connected(struct mcap_mcl *mcap_mcl, gpointer data)
281 {
282         printf("%s\n", __func__);
283
284         if (mcl) {
285                 mcap_sync_stop(mcl);
286                 mcap_mcl_unref(mcl);
287         }
288
289         mcl = mcap_mcl_ref(mcap_mcl);
290         trigger_mdl_action(data_mode);
291 }
292
293 static void create_mcl_cb(struct mcap_mcl *mcap_mcl, GError *err, gpointer data)
294 {
295         printf("%s\n", __func__);
296
297         if (err) {
298                 printf("Could not connect MCL: %s\n", err->message);
299
300                 if (!no_close)
301                         g_main_loop_quit(mloop);
302
303                 return;
304         }
305
306         if (mcl) {
307                 mcap_sync_stop(mcl);
308                 mcap_mcl_unref(mcl);
309         }
310
311         mcl = mcap_mcl_ref(mcap_mcl);
312         trigger_mdl_action(data_mode);
313 }
314
315 static void usage(void)
316 {
317         printf("mcaptest - MCAP testing ver %s\n", VERSION);
318         printf("Usage:\n"
319                 "\tmcaptest <control_mode> <data_mode> [options]\n");
320         printf("Control Link Mode:\n"
321                 "\t-c connect <dst_addr>\n"
322                 "\t-b close control link after closing data link\n"
323                 "\t-e <timeout> disconnect MCL and quit after MDL is closed\n"
324                 "\t-g send clock sync capability request if MCL connected\n");
325         printf("Data Link Mode:\n"
326                 "\t-d connect\n"
327                 "\t-a close data link immediately after being connected"
328                 "\t-f <timeout> disconnect MDL after it's connected\n"
329                 "\t-u send \'Unavailable\' on first MDL connection request\n");
330         printf("Options:\n"
331                 "\t-n don't exit after mcl disconnect/err receive\n"
332                 "\t-i <hcidev>        HCI device\n"
333                 "\t-C <control_ch>    Control channel PSM\n"
334                 "\t-D <data_ch>       Data channel PSM\n");
335 }
336
337 static struct option main_options[] = {
338         { "help",               0, 0, 'h' },
339         { "device",             1, 0, 'i' },
340         { "connect_cl",         1, 0, 'c' },
341         { "disconnect_cl",      1, 0, 'e' },
342         { "synccap_req",        0, 0, 'g' },
343         { "connect_dl",         0, 0, 'd' },
344         { "disconnect_da",      0, 0, 'a' },
345         { "disconnect_ca",      0, 0, 'b' },
346         { "disconnect_dl",      1, 0, 'f' },
347         { "unavailable_dl",     0, 0, 'u' },
348         { "no exit mcl dis/err",0, 0, 'n' },
349         { "control_ch",         1, 0, 'C' },
350         { "data_ch",            1, 0, 'D' },
351         { 0, 0, 0, 0 }
352 };
353
354 int main(int argc, char *argv[])
355 {
356         GError *err = NULL;
357         bdaddr_t src, dst;
358         int opt;
359         char bdastr[18];
360
361         hci_devba(0, &src);
362         bacpy(&dst, BDADDR_ANY);
363
364         mloop = g_main_loop_new(NULL, FALSE);
365         if (!mloop) {
366                 printf("Cannot create main loop\n");
367
368                 exit(1);
369         }
370
371         while ((opt = getopt_long(argc, argv, "+i:c:C:D:e:f:dghunab",
372                                                 main_options, NULL)) != EOF) {
373                 switch (opt) {
374                 case 'i':
375                         if (!strncmp(optarg, "hci", 3))
376                                 hci_devba(atoi(optarg + 3), &src);
377                         else
378                                 str2ba(optarg, &src);
379
380                         break;
381
382                 case 'c':
383                         control_mode = MODE_CONNECT;
384                         str2ba(optarg, &dst);
385
386                         break;
387
388                 case 'd':
389                         data_mode = MODE_CONNECT;
390
391                         break;
392
393                 case 'a':
394                         mdl_disconnect = TRUE;
395
396                         break;
397
398                 case 'b':
399                         mcl_disconnect = TRUE;
400
401                         break;
402
403                 case 'e':
404                         mcl_disconnect_timeout = atoi(optarg);
405
406                         break;
407
408                 case 'f':
409                         mdl_disconnect_timeout = atoi(optarg);
410
411                         break;
412
413                 case 'g':
414                         send_synccap_req = TRUE;
415
416                         break;
417
418                 case 'u':
419                         mdl_conn_req_result = MCAP_RESOURCE_UNAVAILABLE;
420
421                         break;
422
423                 case 'n':
424                         no_close = TRUE;
425
426                         break;
427
428                 case 'C':
429                         ccpsm = atoi(optarg);
430
431                         break;
432
433                 case 'D':
434                         dcpsm = atoi(optarg);
435
436                         break;
437
438                 case 'h':
439                 default:
440                         usage();
441                         exit(0);
442                 }
443         }
444
445         mcap = mcap_create_instance(&src, BT_IO_SEC_MEDIUM, ccpsm, dcpsm,
446                                         mcl_connected, mcl_reconnected,
447                                         mcl_disconnected, mcl_uncached,
448                                         NULL, /* CSP is not used right now */
449                                         NULL, &err);
450
451         if (!mcap) {
452                 printf("MCAP instance creation failed %s\n", err->message);
453                 g_error_free(err);
454
455                 exit(1);
456         }
457
458         mcap_enable_csp(mcap);
459
460         switch (control_mode) {
461         case MODE_CONNECT:
462                 ba2str(&dst, bdastr);
463                 printf("Connecting to %s\n", bdastr);
464
465                 mcap_create_mcl(mcap, &dst, ccpsm, create_mcl_cb, NULL, NULL,
466                                                                         &err);
467
468                 if (err) {
469                         printf("MCAP create error %s\n", err->message);
470                         g_error_free(err);
471
472                         exit(1);
473                 }
474
475                 break;
476         case MODE_LISTEN:
477                 printf("Listening for control channel connection\n");
478
479                 break;
480         case MODE_NONE:
481         default:
482                 goto done;
483         }
484
485         g_main_loop_run(mloop);
486
487 done:
488         printf("Done\n");
489
490         if (mcap)
491                 mcap_instance_unref(mcap);
492
493         g_main_loop_unref(mloop);
494
495         return 0;
496 }