3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2014 Intel Corporation
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.
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.
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
35 #include "lib/bluetooth.h"
37 #include "lib/hci_lib.h"
39 #include "btio/btio.h"
40 #include "lib/l2cap.h"
41 #include "profiles/health/mcap.h"
49 static GMainLoop *mloop;
51 static int ccpsm = 0x1003, dcpsm = 0x1005;
53 static struct mcap_instance *mcap = NULL;
54 static struct mcap_mdl *mdl = NULL;
55 static uint16_t mdlid;
57 static int control_mode = MODE_LISTEN;
58 static int data_mode = MODE_LISTEN;
60 static int mdl_conn_req_result = MCAP_SUCCESS;
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;
68 static struct mcap_mcl *mcl = NULL;
70 static gboolean no_close = FALSE;
72 #define REQ_CLOCK_ACC 0x1400
74 static void mdl_close(struct mcap_mdl *mdl)
78 printf("%s\n", __func__);
80 if (mdl_disconnect_timeout >= 0)
81 sleep(mdl_disconnect_timeout);
83 fd = mcap_mdl_get_fd(mdl);
89 static void mdl_connected_cb(struct mcap_mdl *mdl, void *data)
91 printf("%s\n", __func__);
97 static void mdl_closed_cb(struct mcap_mdl *mdl, void *data)
99 printf("%s\n", __func__);
101 if (mcl_disconnect && mcl_disconnect_timeout >= 0) {
102 sleep(mcl_disconnect_timeout);
104 printf("Closing MCAP communication link\n");
105 mcap_close_mcl(mcl, TRUE);
110 g_main_loop_quit(mloop);
114 static void mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
117 printf("%s\n", __func__);
119 /* Disconnecting MDL latency timeout */
120 if (mdl_disconnect_timeout >= 0)
121 sleep(mdl_disconnect_timeout);
124 static void mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
127 printf("%s\n", __func__);
130 static uint8_t mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
131 uint16_t mdlid, uint8_t *conf, void *data)
135 printf("%s\n", __func__);
137 ret = mdl_conn_req_result;
139 mdl_conn_req_result = MCAP_SUCCESS;
144 static uint8_t mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
146 printf("%s\n", __func__);
151 static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
154 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
158 printf("%s\n", __func__);
160 if (data_mode == MODE_CONNECT) {
161 mcap_create_mdl(mcl, 1, 0, create_mdl_cb, NULL, NULL, &gerr);
163 printf("Could not connect MDL: %s\n", gerr->message);
169 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
172 printf("%s\n", __func__);
177 g_main_loop_quit(mloop);
180 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
183 printf("%s\n", __func__);
186 static void connect_mdl_cb(struct mcap_mdl *mdl, GError *gerr, gpointer data)
188 mdlid = mcap_mdl_get_mdlid(mdl);
190 printf("%s\n", __func__);
192 if (mdlid == MCAP_MDLID_RESERVED)
193 printf("MCAP mdlid is reserved");
195 printf("MDL %d connected\n", mdlid);
198 static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
203 printf("%s\n", __func__);
206 printf("MDL error: %s\n", gerr->message);
209 g_main_loop_quit(mloop);
217 mdl = mcap_mdl_ref(mcap_mdl);
219 if (!mcap_connect_mdl(mdl, L2CAP_MODE_ERTM, dcpsm, connect_mdl_cb, NULL,
221 printf("Error connecting to mdl: %s\n", err->message);
227 g_main_loop_quit(mloop);
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,
237 printf("%s\n", __func__);
240 static void trigger_mdl_action(int mode)
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);
255 printf("MCL cannot handle connection %s\n",
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);
264 printf("Could not connect MDL: %s\n", gerr->message);
269 if (send_synccap_req && mcap->csp_enabled) {
272 mcap_sync_cap_req(mcl, REQ_CLOCK_ACC, sync_cap_cb, NULL, &gerr);
274 printf("MCAP Sync req error: %s\n", gerr->message);
280 static void mcl_connected(struct mcap_mcl *mcap_mcl, gpointer data)
282 printf("%s\n", __func__);
289 mcl = mcap_mcl_ref(mcap_mcl);
290 trigger_mdl_action(data_mode);
293 static void create_mcl_cb(struct mcap_mcl *mcap_mcl, GError *err, gpointer data)
295 printf("%s\n", __func__);
298 printf("Could not connect MCL: %s\n", err->message);
301 g_main_loop_quit(mloop);
311 mcl = mcap_mcl_ref(mcap_mcl);
312 trigger_mdl_action(data_mode);
315 static void usage(void)
317 printf("mcaptest - MCAP testing ver %s\n", VERSION);
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"
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");
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");
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' },
354 int main(int argc, char *argv[])
362 bacpy(&dst, BDADDR_ANY);
364 mloop = g_main_loop_new(NULL, FALSE);
366 printf("Cannot create main loop\n");
371 while ((opt = getopt_long(argc, argv, "+i:c:C:D:e:f:dghunab",
372 main_options, NULL)) != EOF) {
375 if (!strncmp(optarg, "hci", 3))
376 hci_devba(atoi(optarg + 3), &src);
378 str2ba(optarg, &src);
383 control_mode = MODE_CONNECT;
384 str2ba(optarg, &dst);
389 data_mode = MODE_CONNECT;
394 mdl_disconnect = TRUE;
399 mcl_disconnect = TRUE;
404 mcl_disconnect_timeout = atoi(optarg);
409 mdl_disconnect_timeout = atoi(optarg);
414 send_synccap_req = TRUE;
419 mdl_conn_req_result = MCAP_RESOURCE_UNAVAILABLE;
429 ccpsm = atoi(optarg);
434 dcpsm = atoi(optarg);
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 */
452 printf("MCAP instance creation failed %s\n", err->message);
458 mcap_enable_csp(mcap);
460 switch (control_mode) {
462 ba2str(&dst, bdastr);
463 printf("Connecting to %s\n", bdastr);
465 mcap_create_mcl(mcap, &dst, ccpsm, create_mcl_cb, NULL, NULL,
469 printf("MCAP create error %s\n", err->message);
477 printf("Listening for control channel connection\n");
485 g_main_loop_run(mloop);
491 mcap_instance_unref(mcap);
493 g_main_loop_unref(mloop);