diff options
author | Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com> | 2014-10-01 16:45:34 +0300 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2014-10-02 14:24:28 +0300 |
commit | c2a70e6b9d0c2257a3ae579d62faa1d60e4962bd (patch) | |
tree | b56126ee8caa66813af2b847a174d2e86f141608 /profiles/health | |
parent | 88adaba587bc53c795a2bebab95058f804412ab4 (diff) | |
download | bluez-c2a70e6b9d0c2257a3ae579d62faa1d60e4962bd.tar.gz |
mcap: Unify libmcap usage for Android and non-Android versions
Now profiles/health/ , android/health and mcaptest will use
profiles/health/mcap-lib.
Diffstat (limited to 'profiles/health')
-rw-r--r-- | profiles/health/hdp.c | 3 | ||||
-rw-r--r-- | profiles/health/hdp_util.c | 3 | ||||
-rw-r--r-- | profiles/health/mcap-lib.c (renamed from profiles/health/mcap.c) | 1047 | ||||
-rw-r--r-- | profiles/health/mcap-lib.h | 437 | ||||
-rw-r--r-- | profiles/health/mcap.h | 164 | ||||
-rw-r--r-- | profiles/health/mcap_internal.h | 137 | ||||
-rw-r--r-- | profiles/health/mcap_lib.h | 224 | ||||
-rw-r--r-- | profiles/health/mcap_sync.c | 1009 |
8 files changed, 1457 insertions, 1567 deletions
diff --git a/profiles/health/hdp.c b/profiles/health/hdp.c index 8ffcd9149..d2e634ae7 100644 --- a/profiles/health/hdp.c +++ b/profiles/health/hdp.c @@ -42,11 +42,10 @@ #include "src/sdpd.h" #include "btio/btio.h" -#include "mcap_lib.h" #include "hdp_types.h" #include "hdp_util.h" #include "hdp.h" -#include "mcap.h" +#include "mcap-lib.h" #define ECHO_TIMEOUT 1 /* second */ #define HDP_ECHO_LEN 15 diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c index e3e0830d1..c524054ad 100644 --- a/profiles/health/hdp_util.c +++ b/profiles/health/hdp_util.c @@ -48,8 +48,7 @@ #include "src/log.h" #include "src/dbus-common.h" -#include "mcap.h" -#include "mcap_lib.h" +#include "mcap-lib.h" #include "hdp_types.h" #include "hdp.h" #include "hdp_util.h" diff --git a/profiles/health/mcap.c b/profiles/health/mcap-lib.c index 102ec85b5..1706d9f6c 100644 --- a/profiles/health/mcap.c +++ b/profiles/health/mcap-lib.c @@ -1,8 +1,10 @@ /* * - * MCAP for BlueZ - Bluetooth protocol stack for Linux + * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. + * Copyright (C) 2010 Signove + * Copyright (C) 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,16 +33,19 @@ #include <glib.h> -#include <bluetooth/bluetooth.h> -#include <bluetooth/l2cap.h> - +#include "lib/bluetooth.h" +#include "bluetooth/l2cap.h" #include "btio/btio.h" #include "src/log.h" -#include "src/error.h" -#include "mcap.h" -#include "mcap_lib.h" -#include "mcap_internal.h" +#include "mcap-lib.h" + +#define MCAP_BTCLOCK_HALF (MCAP_BTCLOCK_FIELD / 2) +#define CLK CLOCK_MONOTONIC + +#define MCAP_CSP_ERROR g_quark_from_static_string("mcap-csp-error-quark") +#define MAX_RETRIES 10 +#define SAMPLE_COUNT 20 #define RESPONSE_TIMER 6 /* seconds */ #define MAX_CACHED 10 /* 10 devices */ @@ -54,6 +59,46 @@ } \ } while(0) +struct mcap_csp { + uint64_t base_tmstamp; /* CSP base timestamp */ + struct timespec base_time; /* CSP base time when timestamp set */ + guint local_caps; /* CSP-Master: have got remote caps */ + guint remote_caps; /* CSP-Slave: remote master got caps */ + guint rem_req_acc; /* CSP-Slave: accuracy required by master */ + guint ind_expected; /* CSP-Master: indication expected */ + uint8_t csp_req; /* CSP-Master: Request control flag */ + guint ind_timer; /* CSP-Slave: indication timer */ + guint set_timer; /* CSP-Slave: delayed set timer */ + void *set_data; /* CSP-Slave: delayed set data */ + void *csp_priv_data; /* CSP-Master: In-flight request data */ +}; + +struct mcap_sync_cap_cbdata { + mcap_sync_cap_cb cb; + gpointer user_data; +}; + +struct mcap_sync_set_cbdata { + mcap_sync_set_cb cb; + gpointer user_data; +}; + +struct csp_caps { + int ts_acc; /* timestamp accuracy */ + int ts_res; /* timestamp resolution */ + int latency; /* Read BT clock latency */ + int preempt_thresh; /* Preemption threshold for latency */ + int syncleadtime_ms; /* SyncLeadTime in ms */ +}; + +struct sync_set_data { + uint8_t update; + uint32_t sched_btclock; + uint64_t timestamp; + int ind_freq; + gboolean role; +}; + struct connect_mcl { struct mcap_mcl *mcl; /* MCL for this operation */ mcap_mcl_connect_cb connect_cb; /* Connect callback */ @@ -85,6 +130,9 @@ static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = { proc_req_active }; +static gboolean csp_caps_initialized = FALSE; +struct csp_caps _caps; + static void mcap_cache_mcl(struct mcap_mcl *mcl); static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data) @@ -793,8 +841,10 @@ static void mcap_cache_mcl(struct mcap_mcl *mcl) mcl->mi->cached = g_slist_remove(mcl->mi->cached, last); last->ctrl &= ~MCAP_CTRL_CACHED; if (last->ctrl & MCAP_CTRL_CONN) { - /* We have to release this MCL if */ - /* connection is not successful */ + /* + * We have to release this MCL if connection is not + * successful + */ last->ctrl |= MCAP_CTRL_FREE; } else { mcap_mcl_release(last); @@ -957,10 +1007,10 @@ static void mcap_del_mdl(gpointer elem, gpointer user_data) struct mcap_mdl *mdl = elem; gboolean notify = *(gboolean *) user_data; - shutdown_mdl(mdl); if (notify) mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data); + shutdown_mdl(mdl); mcap_mdl_unref(mdl); } @@ -1016,8 +1066,10 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd, mdl = get_mdl(mcl, mdl_id); if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) { - /* Creation request arrives for a MDL that is being managed - * at current moment */ + /* + * Creation request arrives for a MDL that is being managed + * at current moment + */ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id, NULL, 0); return; @@ -1033,9 +1085,11 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd, } if (cfga != 0 && cfga != conf) { - /* Remote device set default configuration but upper profile */ - /* has changed it. Protocol Error: force closing the MCL by */ - /* remote device using UNSPECIFIED_ERROR response */ + /* + * Remote device set default configuration but upper profile + * has changed it. Protocol Error: force closing the MCL by + * remote device using UNSPECIFIED_ERROR response + */ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0); return; @@ -1053,8 +1107,10 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd, mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl), compare_mdl); } else if (mdl->state == MDL_CONNECTED) { - /* MCAP specification says that we should close the MCL if - * it is open when we receive a MD_CREATE_MDL_REQ */ + /* + * MCAP specification says that we should close the MCL if + * it is open when we receive a MD_CREATE_MDL_REQ + */ shutdown_mdl(mdl); } @@ -1087,8 +1143,10 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd, mdl_id, NULL, 0); return; } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) { - /* Creation request arrives for a MDL that is being managed - * at current moment */ + /* + * Creation request arrives for a MDL that is being managed + * at current moment + */ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY, mdl_id, NULL, 0); return; @@ -1173,13 +1231,11 @@ static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd, req = cmd; mdlid = ntohs(req->mdl); if (mdlid == MCAP_ALL_MDLIDS) { - notify = FALSE; + notify = TRUE; g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); g_slist_free(mcl->mdls); mcl->mdls = NULL; mcl->state = MCL_CONNECTED; - /* NULL mdl means ALL_MDLS */ - mcl->cb->mdl_deleted(NULL, mcl->cb->user_data); goto resp; } @@ -1219,8 +1275,10 @@ static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) error("Invalid cmd received (op code = %d) in state %d", cmd[0], mcl->state); - /* Get previously mdlid sent to generate an appropriate - * response if it is possible */ + /* + * Get previously mdlid sent to generate an appropriate + * response if it is possible + */ mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED : ntohs(((mcap_md_req *) cmd)->mdl); mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0); @@ -1509,12 +1567,16 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp, static void post_process_rsp(struct mcap_mcl *mcl, struct mcap_mdl_op_cb *op) { if (mcl->priv_data != op) { - /* Queued MCAP request in some callback. */ - /* We should not delete the mcl private data */ + /* + * Queued MCAP request in some callback. + * We should not delete the mcl private data + */ free_mcap_mdl_op(op); } else { - /* This is not a queued request. It's safe */ - /* delete the mcl private data here. */ + /* + * This is not a queued request. It's safe + * delete the mcl private data here. + */ free_mcl_priv_data(mcl); } } @@ -2190,3 +2252,930 @@ void mcap_mdl_unref(struct mcap_mdl *mdl) free_mdl(mdl); } + + +static int send_sync_cmd(struct mcap_mcl *mcl, const void *buf, uint32_t size) +{ + int sock; + + if (mcl->cc == NULL) + return -1; + + sock = g_io_channel_unix_get_fd(mcl->cc); + return mcap_send_data(sock, buf, size); +} + +static int send_unsupported_cap_req(struct mcap_mcl *mcl) +{ + mcap_md_sync_cap_rsp *cmd; + int sent; + + cmd = g_new0(mcap_md_sync_cap_rsp, 1); + cmd->op = MCAP_MD_SYNC_CAP_RSP; + cmd->rc = MCAP_REQUEST_NOT_SUPPORTED; + + sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); + g_free(cmd); + + return sent; +} + +static int send_unsupported_set_req(struct mcap_mcl *mcl) +{ + mcap_md_sync_set_rsp *cmd; + int sent; + + cmd = g_new0(mcap_md_sync_set_rsp, 1); + cmd->op = MCAP_MD_SYNC_SET_RSP; + cmd->rc = MCAP_REQUEST_NOT_SUPPORTED; + + sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); + g_free(cmd); + + return sent; +} + +static void reset_tmstamp(struct mcap_csp *csp, struct timespec *base_time, + uint64_t new_tmstamp) +{ + csp->base_tmstamp = new_tmstamp; + if (base_time) + csp->base_time = *base_time; + else + clock_gettime(CLK, &csp->base_time); +} + +void mcap_sync_init(struct mcap_mcl *mcl) +{ + if (!mcl->mi->csp_enabled) { + mcl->csp = NULL; + return; + } + + mcl->csp = g_new0(struct mcap_csp, 1); + + mcl->csp->rem_req_acc = 10000; /* safe divisor */ + mcl->csp->set_data = NULL; + mcl->csp->csp_priv_data = NULL; + + reset_tmstamp(mcl->csp, NULL, 0); +} + +void mcap_sync_stop(struct mcap_mcl *mcl) +{ + if (!mcl->csp) + return; + + if (mcl->csp->ind_timer) + g_source_remove(mcl->csp->ind_timer); + + if (mcl->csp->set_timer) + g_source_remove(mcl->csp->set_timer); + + if (mcl->csp->set_data) + g_free(mcl->csp->set_data); + + if (mcl->csp->csp_priv_data) + g_free(mcl->csp->csp_priv_data); + + mcl->csp->ind_timer = 0; + mcl->csp->set_timer = 0; + mcl->csp->set_data = NULL; + mcl->csp->csp_priv_data = NULL; + + g_free(mcl->csp); + mcl->csp = NULL; +} + +static uint64_t time_us(struct timespec *tv) +{ + return tv->tv_sec * 1000000ll + tv->tv_nsec / 1000ll; +} + +static int64_t bt2us(int bt) +{ + return bt * 312.5; +} + +static int bt2ms(int bt) +{ + return bt * 312.5 / 1000; +} + +static int btoffset(uint32_t btclk1, uint32_t btclk2) +{ + int offset = btclk2 - btclk1; + + if (offset <= -MCAP_BTCLOCK_HALF) + offset += MCAP_BTCLOCK_FIELD; + else if (offset > MCAP_BTCLOCK_HALF) + offset -= MCAP_BTCLOCK_FIELD; + + return offset; +} + +static int btdiff(uint32_t btclk1, uint32_t btclk2) +{ + return btoffset(btclk1, btclk2); +} + +static gboolean valid_btclock(uint32_t btclk) +{ + return btclk <= MCAP_BTCLOCK_MAX; +} + +/* This call may fail; either deal with retry or use read_btclock_retry */ +static gboolean read_btclock(struct mcap_mcl *mcl, uint32_t *btclock, + uint16_t *btaccuracy) +{ + /* + * FIXME: btd_adapter_read_clock(...) always return FALSE, current + * code doesn't support CSP (Clock Synchronization Protocol). To avoid + * build dependancy on struct 'btd_adapter', removing this code. + */ + + return FALSE; +} + +static gboolean read_btclock_retry(struct mcap_mcl *mcl, uint32_t *btclock, + uint16_t *btaccuracy) +{ + int retries = 5; + + while (--retries >= 0) { + if (read_btclock(mcl, btclock, btaccuracy)) + return TRUE; + DBG("CSP: retrying to read bt clock..."); + } + + return FALSE; +} + +static gboolean get_btrole(struct mcap_mcl *mcl) +{ + int sock, flags; + socklen_t len; + + if (mcl->cc == NULL) + return -1; + + sock = g_io_channel_unix_get_fd(mcl->cc); + len = sizeof(flags); + + if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len)) + DBG("CSP: could not read role"); + + return flags & L2CAP_LM_MASTER; +} + +uint64_t mcap_get_timestamp(struct mcap_mcl *mcl, + struct timespec *given_time) +{ + struct timespec now; + uint64_t tmstamp; + + if (!mcl->csp) + return MCAP_TMSTAMP_DONTSET; + + if (given_time) + now = *given_time; + else + if (clock_gettime(CLK, &now) < 0) + return MCAP_TMSTAMP_DONTSET; + + tmstamp = time_us(&now) - time_us(&mcl->csp->base_time) + + mcl->csp->base_tmstamp; + + return tmstamp; +} + +uint32_t mcap_get_btclock(struct mcap_mcl *mcl) +{ + uint32_t btclock; + uint16_t accuracy; + + if (!mcl->csp) + return MCAP_BTCLOCK_IMMEDIATE; + + if (!read_btclock_retry(mcl, &btclock, &accuracy)) + btclock = 0xffffffff; + + return btclock; +} + +static gboolean initialize_caps(struct mcap_mcl *mcl) +{ + struct timespec t1, t2; + int latencies[SAMPLE_COUNT]; + int latency, avg, dev; + uint32_t btclock; + uint16_t btaccuracy; + int i; + int retries; + + clock_getres(CLK, &t1); + + _caps.ts_res = time_us(&t1); + if (_caps.ts_res < 1) + _caps.ts_res = 1; + + _caps.ts_acc = 20; /* ppm, estimated */ + + /* A little exercise before measuing latency */ + clock_gettime(CLK, &t1); + read_btclock_retry(mcl, &btclock, &btaccuracy); + + /* Read clock a number of times and measure latency */ + avg = 0; + i = 0; + retries = MAX_RETRIES; + while (i < SAMPLE_COUNT && retries > 0) { + clock_gettime(CLK, &t1); + if (!read_btclock(mcl, &btclock, &btaccuracy)) { + retries--; + continue; + } + clock_gettime(CLK, &t2); + + latency = time_us(&t2) - time_us(&t1); + latencies[i] = latency; + avg += latency; + i++; + } + + if (retries <= 0) + return FALSE; + + /* Calculate average and deviation */ + avg /= SAMPLE_COUNT; + dev = 0; + for (i = 0; i < SAMPLE_COUNT; ++i) + dev += abs(latencies[i] - avg); + dev /= SAMPLE_COUNT; + + /* Calculate corrected average, without 'freak' latencies */ + latency = 0; + for (i = 0; i < SAMPLE_COUNT; ++i) { + if (latencies[i] > (avg + dev * 6)) + latency += avg; + else + latency += latencies[i]; + } + latency /= SAMPLE_COUNT; + + _caps.latency = latency; + _caps.preempt_thresh = latency * 4; + _caps.syncleadtime_ms = latency * 50 / 1000; + + csp_caps_initialized = TRUE; + return TRUE; +} + +static struct csp_caps *caps(struct mcap_mcl *mcl) +{ + if (!csp_caps_initialized) + if (!initialize_caps(mcl)) { + /* Temporary failure in reading BT clock */ + return NULL; + } + + return &_caps; +} + +static int send_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t rspcode, + uint8_t btclockres, uint16_t synclead, + uint16_t tmstampres, uint16_t tmstampacc) +{ + mcap_md_sync_cap_rsp *rsp; + int sent; + + rsp = g_new0(mcap_md_sync_cap_rsp, 1); + + rsp->op = MCAP_MD_SYNC_CAP_RSP; + rsp->rc = rspcode; + + rsp->btclock = btclockres; + rsp->sltime = htons(synclead); + rsp->timestnr = htons(tmstampres); + rsp->timestna = htons(tmstampacc); + + sent = send_sync_cmd(mcl, rsp, sizeof(*rsp)); + g_free(rsp); + + return sent; +} + +static void proc_sync_cap_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + mcap_md_sync_cap_req *req; + uint16_t required_accuracy; + uint16_t our_accuracy; + uint32_t btclock; + uint16_t btres; + + if (len != sizeof(mcap_md_sync_cap_req)) { + send_sync_cap_rsp(mcl, MCAP_INVALID_PARAM_VALUE, + 0, 0, 0, 0); + return; + } + + if (!caps(mcl)) { + send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, + 0, 0, 0, 0); + return; + } + + req = (mcap_md_sync_cap_req *) cmd; + required_accuracy = ntohs(req->timest); + our_accuracy = caps(mcl)->ts_acc; + btres = 0; + + if (required_accuracy < our_accuracy || required_accuracy < 1) { + send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, + 0, 0, 0, 0); + return; + } + + if (!read_btclock_retry(mcl, &btclock, &btres)) { + send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, + 0, 0, 0, 0); + return; + } + + mcl->csp->remote_caps = 1; + mcl->csp->rem_req_acc = required_accuracy; + + send_sync_cap_rsp(mcl, MCAP_SUCCESS, btres, + caps(mcl)->syncleadtime_ms, + caps(mcl)->ts_res, our_accuracy); +} + +static int send_sync_set_rsp(struct mcap_mcl *mcl, uint8_t rspcode, + uint32_t btclock, uint64_t timestamp, + uint16_t tmstampres) +{ + mcap_md_sync_set_rsp *rsp; + int sent; + + rsp = g_new0(mcap_md_sync_set_rsp, 1); + + rsp->op = MCAP_MD_SYNC_SET_RSP; + rsp->rc = rspcode; + rsp->btclock = htonl(btclock); + rsp->timestst = hton64(timestamp); + rsp->timestsa = htons(tmstampres); + + sent = send_sync_cmd(mcl, rsp, sizeof(*rsp)); + g_free(rsp); + + return sent; +} + +static gboolean get_all_clocks(struct mcap_mcl *mcl, uint32_t *btclock, + struct timespec *base_time, + uint64_t *timestamp) +{ + int latency; + int retry = 5; + uint16_t btres; + struct timespec t0; + + if (!caps(mcl)) + return FALSE; + + latency = caps(mcl)->preempt_thresh + 1; + + while (latency > caps(mcl)->preempt_thresh && --retry >= 0) { + + if (clock_gettime(CLK, &t0) < 0) + return FALSE; + + if (!read_btclock(mcl, btclock, &btres)) + continue; + + if (clock_gettime(CLK, base_time) < 0) + return FALSE; + + /* + * Tries to detect preemption between clock_gettime + * and read_btclock by measuring transaction time + */ + latency = time_us(base_time) - time_us(&t0); + } + + if (retry < 0) + return FALSE; + + *timestamp = mcap_get_timestamp(mcl, base_time); + + return TRUE; +} + +static gboolean sync_send_indication(gpointer user_data) +{ + struct mcap_mcl *mcl; + mcap_md_sync_info_ind *cmd; + uint32_t btclock; + uint64_t tmstamp; + struct timespec base_time; + int sent; + + if (!user_data) + return FALSE; + + btclock = 0; + mcl = user_data; + + if (!caps(mcl)) + return FALSE; + + if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) + return FALSE; + + cmd = g_new0(mcap_md_sync_info_ind, 1); + + cmd->op = MCAP_MD_SYNC_INFO_IND; + cmd->btclock = htonl(btclock); + cmd->timestst = hton64(tmstamp); + cmd->timestsa = htons(caps(mcl)->latency); + + sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); + g_free(cmd); + + return !sent; +} + +static gboolean proc_sync_set_req_phase2(gpointer user_data) +{ + struct mcap_mcl *mcl; + struct sync_set_data *data; + uint8_t update; + uint32_t sched_btclock; + uint64_t new_tmstamp; + int ind_freq; + int role; + uint32_t btclock; + uint64_t tmstamp; + struct timespec base_time; + uint16_t tmstampacc; + gboolean reset; + int delay; + + if (!user_data) + return FALSE; + + mcl = user_data; + + if (!mcl->csp->set_data) + return FALSE; + + btclock = 0; + data = mcl->csp->set_data; + update = data->update; + sched_btclock = data->sched_btclock; + new_tmstamp = data->timestamp; + ind_freq = data->ind_freq; + role = data->role; + + if (!caps(mcl)) { + send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); + return FALSE; + } + + if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) { + send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); + return FALSE; + } + + if (get_btrole(mcl) != role) { + send_sync_set_rsp(mcl, MCAP_INVALID_OPERATION, 0, 0, 0); + return FALSE; + } + + reset = (new_tmstamp != MCAP_TMSTAMP_DONTSET); + + if (reset) { + if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE) { + delay = bt2us(btdiff(sched_btclock, btclock)); + if (delay >= 0 || ((new_tmstamp - delay) > 0)) { + new_tmstamp += delay; + DBG("CSP: reset w/ delay %dus, compensated", + delay); + } else + DBG("CSP: reset w/ delay %dus, uncompensated", + delay); + } + + reset_tmstamp(mcl->csp, &base_time, new_tmstamp); + tmstamp = new_tmstamp; + } + + tmstampacc = caps(mcl)->latency + caps(mcl)->ts_acc; + + if (mcl->csp->ind_timer) { + g_source_remove(mcl->csp->ind_timer); + mcl->csp->ind_timer = 0; + } + + if (update) { + int when = ind_freq + caps(mcl)->syncleadtime_ms; + mcl->csp->ind_timer = g_timeout_add(when, + sync_send_indication, + mcl); + } + + send_sync_set_rsp(mcl, MCAP_SUCCESS, btclock, tmstamp, tmstampacc); + + /* First indication after set is immediate */ + if (update) + sync_send_indication(mcl); + + return FALSE; +} + +static void proc_sync_set_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + mcap_md_sync_set_req *req; + uint32_t sched_btclock, cur_btclock; + uint16_t btres; + uint8_t update; + uint64_t timestamp; + struct sync_set_data *set_data; + int phase2_delay, ind_freq, when; + + if (len != sizeof(mcap_md_sync_set_req)) { + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); + return; + } + + req = (mcap_md_sync_set_req *) cmd; + sched_btclock = ntohl(req->btclock); + update = req->timestui; + timestamp = ntoh64(req->timestst); + cur_btclock = 0; + + if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE && + !valid_btclock(sched_btclock)) { + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); + return; + } + + if (update > 1) { + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); + return; + } + + if (!mcl->csp->remote_caps) { + /* Remote side did not ask our capabilities yet */ + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); + return; + } + + if (!caps(mcl)) { + send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); + return; + } + + if (!read_btclock_retry(mcl, &cur_btclock, &btres)) { + send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); + return; + } + + if (sched_btclock == MCAP_BTCLOCK_IMMEDIATE) + phase2_delay = 0; + else { + phase2_delay = btdiff(cur_btclock, sched_btclock); + + if (phase2_delay < 0) { + /* can not reset in the past tense */ + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, + 0, 0, 0); + return; + } + + /* Convert to miliseconds */ + phase2_delay = bt2ms(phase2_delay); + + if (phase2_delay > 61*1000) { + /* More than 60 seconds in the future */ + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, + 0, 0, 0); + return; + } else if (phase2_delay < caps(mcl)->latency / 1000) { + /* Too fast for us to do in time */ + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, + 0, 0, 0); + return; + } + } + + if (update) { + /* + * Indication frequency: required accuracy divided by ours + * Converted to milisseconds + */ + ind_freq = (1000 * mcl->csp->rem_req_acc) / caps(mcl)->ts_acc; + + if (ind_freq < MAX(caps(mcl)->latency * 2 / 1000, 100)) { + /* Too frequent, we can't handle */ + send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, + 0, 0, 0); + return; + } + + DBG("CSP: indication every %dms", ind_freq); + } else + ind_freq = 0; + + if (mcl->csp->ind_timer) { + /* Old indications are no longer sent */ + g_source_remove(mcl->csp->ind_timer); + mcl->csp->ind_timer = 0; + } + + if (!mcl->csp->set_data) + mcl->csp->set_data = g_new0(struct sync_set_data, 1); + + set_data = (struct sync_set_data *) mcl->csp->set_data; + + set_data->update = update; + set_data->sched_btclock = sched_btclock; + set_data->timestamp = timestamp; + set_data->ind_freq = ind_freq; + set_data->role = get_btrole(mcl); + + /* + * TODO is there some way to schedule a call based directly on + * a BT clock value, instead of this estimation that uses + * the SO clock? + */ + + if (phase2_delay > 0) { + when = phase2_delay + caps(mcl)->syncleadtime_ms; + mcl->csp->set_timer = g_timeout_add(when, + proc_sync_set_req_phase2, + mcl); + } else + proc_sync_set_req_phase2(mcl); + + /* First indication is immediate */ + if (update) + sync_send_indication(mcl); +} + +static void proc_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + mcap_md_sync_cap_rsp *rsp; + uint8_t mcap_err; + uint8_t btclockres; + uint16_t synclead; + uint16_t tmstampres; + uint16_t tmstampacc; + struct mcap_sync_cap_cbdata *cbdata; + mcap_sync_cap_cb cb; + gpointer user_data; + + if (mcl->csp->csp_req != MCAP_MD_SYNC_CAP_REQ) { + DBG("CSP: got unexpected cap respose"); + return; + } + + if (!mcl->csp->csp_priv_data) { + DBG("CSP: no priv data for cap respose"); + return; + } + + cbdata = mcl->csp->csp_priv_data; + cb = cbdata->cb; + user_data = cbdata->user_data; + g_free(cbdata); + + mcl->csp->csp_priv_data = NULL; + mcl->csp->csp_req = 0; + + if (len != sizeof(mcap_md_sync_cap_rsp)) { + DBG("CSP: got corrupted cap respose"); + return; + } + + rsp = (mcap_md_sync_cap_rsp *) cmd; + mcap_err = rsp->rc; + btclockres = rsp->btclock; + synclead = ntohs(rsp->sltime); + tmstampres = ntohs(rsp->timestnr); + tmstampacc = ntohs(rsp->timestna); + + if (!mcap_err) + mcl->csp->local_caps = TRUE; + + cb(mcl, mcap_err, btclockres, synclead, tmstampres, tmstampacc, NULL, + user_data); +} + +static void proc_sync_set_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + mcap_md_sync_set_rsp *rsp; + uint8_t mcap_err; + uint32_t btclock; + uint64_t timestamp; + uint16_t accuracy; + struct mcap_sync_set_cbdata *cbdata; + mcap_sync_set_cb cb; + gpointer user_data; + + if (mcl->csp->csp_req != MCAP_MD_SYNC_SET_REQ) { + DBG("CSP: got unexpected set respose"); + return; + } + + if (!mcl->csp->csp_priv_data) { + DBG("CSP: no priv data for set respose"); + return; + } + + cbdata = mcl->csp->csp_priv_data; + cb = cbdata->cb; + user_data = cbdata->user_data; + g_free(cbdata); + + mcl->csp->csp_priv_data = NULL; + mcl->csp->csp_req = 0; + + if (len != sizeof(mcap_md_sync_set_rsp)) { + DBG("CSP: got corrupted set respose"); + return; + } + + rsp = (mcap_md_sync_set_rsp *) cmd; + mcap_err = rsp->rc; + btclock = ntohl(rsp->btclock); + timestamp = ntoh64(rsp->timestst); + accuracy = ntohs(rsp->timestsa); + + if (!mcap_err && !valid_btclock(btclock)) + mcap_err = MCAP_ERROR_INVALID_ARGS; + + cb(mcl, mcap_err, btclock, timestamp, accuracy, NULL, user_data); +} + +static void proc_sync_info_ind(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + mcap_md_sync_info_ind *req; + struct sync_info_ind_data data; + uint32_t btclock; + + if (!mcl->csp->ind_expected) { + DBG("CSP: received unexpected info indication"); + return; + } + + if (len != sizeof(mcap_md_sync_info_ind)) + return; + + req = (mcap_md_sync_info_ind *) cmd; + + btclock = ntohl(req->btclock); + + if (!valid_btclock(btclock)) + return; + + data.btclock = btclock; + data.timestamp = ntoh64(req->timestst); + data.accuracy = ntohs(req->timestsa); + + if (mcl->mi->mcl_sync_infoind_cb) + mcl->mi->mcl_sync_infoind_cb(mcl, &data); +} + +void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + if (!mcl->mi->csp_enabled || !mcl->csp) { + switch (cmd[0]) { + case MCAP_MD_SYNC_CAP_REQ: + send_unsupported_cap_req(mcl); + break; + case MCAP_MD_SYNC_SET_REQ: + send_unsupported_set_req(mcl); + break; + } + return; + } + + switch (cmd[0]) { + case MCAP_MD_SYNC_CAP_REQ: + proc_sync_cap_req(mcl, cmd, len); + break; + case MCAP_MD_SYNC_CAP_RSP: + proc_sync_cap_rsp(mcl, cmd, len); + break; + case MCAP_MD_SYNC_SET_REQ: + proc_sync_set_req(mcl, cmd, len); + break; + case MCAP_MD_SYNC_SET_RSP: + proc_sync_set_rsp(mcl, cmd, len); + break; + case MCAP_MD_SYNC_INFO_IND: + proc_sync_info_ind(mcl, cmd, len); + break; + } +} + +void mcap_sync_cap_req(struct mcap_mcl *mcl, uint16_t reqacc, + mcap_sync_cap_cb cb, gpointer user_data, + GError **err) +{ + struct mcap_sync_cap_cbdata *cbdata; + mcap_md_sync_cap_req *cmd; + + if (!mcl->mi->csp_enabled || !mcl->csp) { + g_set_error(err, + MCAP_CSP_ERROR, + MCAP_ERROR_RESOURCE_UNAVAILABLE, + "CSP not enabled for the instance"); + return; + } + + if (mcl->csp->csp_req) { + g_set_error(err, + MCAP_CSP_ERROR, + MCAP_ERROR_RESOURCE_UNAVAILABLE, + "Pending CSP request"); + return; + } + + mcl->csp->csp_req = MCAP_MD_SYNC_CAP_REQ; + cmd = g_new0(mcap_md_sync_cap_req, 1); + + cmd->op = MCAP_MD_SYNC_CAP_REQ; + cmd->timest = htons(reqacc); + + cbdata = g_new0(struct mcap_sync_cap_cbdata, 1); + cbdata->cb = cb; + cbdata->user_data = user_data; + mcl->csp->csp_priv_data = cbdata; + + send_sync_cmd(mcl, cmd, sizeof(*cmd)); + + g_free(cmd); +} + +void mcap_sync_set_req(struct mcap_mcl *mcl, uint8_t update, uint32_t btclock, + uint64_t timestamp, mcap_sync_set_cb cb, + gpointer user_data, GError **err) +{ + mcap_md_sync_set_req *cmd; + struct mcap_sync_set_cbdata *cbdata; + + if (!mcl->mi->csp_enabled || !mcl->csp) { + g_set_error(err, + MCAP_CSP_ERROR, + MCAP_ERROR_RESOURCE_UNAVAILABLE, + "CSP not enabled for the instance"); + return; + } + + if (!mcl->csp->local_caps) { + g_set_error(err, + MCAP_CSP_ERROR, + MCAP_ERROR_RESOURCE_UNAVAILABLE, + "Did not get CSP caps from slave yet"); + return; + } + + if (mcl->csp->csp_req) { + g_set_error(err, + MCAP_CSP_ERROR, + MCAP_ERROR_RESOURCE_UNAVAILABLE, + "Pending CSP request"); + return; + } + + mcl->csp->csp_req = MCAP_MD_SYNC_SET_REQ; + cmd = g_new0(mcap_md_sync_set_req, 1); + + cmd->op = MCAP_MD_SYNC_SET_REQ; + cmd->timestui = update; + cmd->btclock = htonl(btclock); + cmd->timestst = hton64(timestamp); + + mcl->csp->ind_expected = update; + + cbdata = g_new0(struct mcap_sync_set_cbdata, 1); + cbdata->cb = cb; + cbdata->user_data = user_data; + mcl->csp->csp_priv_data = cbdata; + + send_sync_cmd(mcl, cmd, sizeof(*cmd)); + + g_free(cmd); +} + +void mcap_enable_csp(struct mcap_instance *mi) +{ + mi->csp_enabled = TRUE; +} + +void mcap_disable_csp(struct mcap_instance *mi) +{ + mi->csp_enabled = FALSE; +} diff --git a/profiles/health/mcap-lib.h b/profiles/health/mcap-lib.h new file mode 100644 index 000000000..548d67259 --- /dev/null +++ b/profiles/health/mcap-lib.h @@ -0,0 +1,437 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. + * Copyright (C) 2010 Signove + * Copyright (C) 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define MCAP_VERSION 0x0100 /* current version 01.00 */ + +/* bytes to get MCAP Supported Procedures */ +#define MCAP_SUP_PROC 0x06 + +/* maximum transmission unit for channels */ +#define MCAP_CC_MTU 48 +#define MCAP_DC_MTU 65535 + +/* MCAP Standard Op Codes */ +#define MCAP_ERROR_RSP 0x00 +#define MCAP_MD_CREATE_MDL_REQ 0x01 +#define MCAP_MD_CREATE_MDL_RSP 0x02 +#define MCAP_MD_RECONNECT_MDL_REQ 0x03 +#define MCAP_MD_RECONNECT_MDL_RSP 0x04 +#define MCAP_MD_ABORT_MDL_REQ 0x05 +#define MCAP_MD_ABORT_MDL_RSP 0x06 +#define MCAP_MD_DELETE_MDL_REQ 0x07 +#define MCAP_MD_DELETE_MDL_RSP 0x08 + +/* MCAP Clock Sync Op Codes */ +#define MCAP_MD_SYNC_CAP_REQ 0x11 +#define MCAP_MD_SYNC_CAP_RSP 0x12 +#define MCAP_MD_SYNC_SET_REQ 0x13 +#define MCAP_MD_SYNC_SET_RSP 0x14 +#define MCAP_MD_SYNC_INFO_IND 0x15 + +/* MCAP Response codes */ +#define MCAP_SUCCESS 0x00 +#define MCAP_INVALID_OP_CODE 0x01 +#define MCAP_INVALID_PARAM_VALUE 0x02 +#define MCAP_INVALID_MDEP 0x03 +#define MCAP_MDEP_BUSY 0x04 +#define MCAP_INVALID_MDL 0x05 +#define MCAP_MDL_BUSY 0x06 +#define MCAP_INVALID_OPERATION 0x07 +#define MCAP_RESOURCE_UNAVAILABLE 0x08 +#define MCAP_UNSPECIFIED_ERROR 0x09 +#define MCAP_REQUEST_NOT_SUPPORTED 0x0A +#define MCAP_CONFIGURATION_REJECTED 0x0B + +/* MDL IDs */ +#define MCAP_MDLID_RESERVED 0x0000 +#define MCAP_MDLID_INITIAL 0x0001 +#define MCAP_MDLID_FINAL 0xFEFF +#define MCAP_ALL_MDLIDS 0xFFFF + +/* MDEP IDs */ +#define MCAP_MDEPID_INITIAL 0x00 +#define MCAP_MDEPID_FINAL 0x7F + +/* CSP special values */ +#define MCAP_BTCLOCK_IMMEDIATE 0xffffffffUL +#define MCAP_TMSTAMP_DONTSET 0xffffffffffffffffULL +#define MCAP_BTCLOCK_MAX 0x0fffffff +#define MCAP_BTCLOCK_FIELD (MCAP_BTCLOCK_MAX + 1) + +#define MCAP_CTRL_CACHED 0x01 /* MCL is cached */ +#define MCAP_CTRL_STD_OP 0x02 /* Support for standard op codes */ +#define MCAP_CTRL_SYNC_OP 0x04 /* Support for synchronization commands */ +#define MCAP_CTRL_CONN 0x08 /* MCL is in connecting process */ +#define MCAP_CTRL_FREE 0x10 /* MCL is marked as releasable */ +#define MCAP_CTRL_NOCACHE 0x20 /* MCL is marked as not cacheable */ + +/* + * MCAP Request Packet Format + */ + +typedef struct { + uint8_t op; + uint16_t mdl; + uint8_t mdep; + uint8_t conf; +} __attribute__ ((packed)) mcap_md_create_mdl_req; + +typedef struct { + uint8_t op; + uint16_t mdl; +} __attribute__ ((packed)) mcap_md_req; + +/* MCAP Response Packet Format */ + +typedef struct { + uint8_t op; + uint8_t rc; + uint16_t mdl; + uint8_t data[0]; +} __attribute__ ((packed)) mcap_rsp; + +/* MCAP Clock Synchronization Protocol */ + +typedef struct { + uint8_t op; + uint16_t timest; +} __attribute__ ((packed)) mcap_md_sync_cap_req; + +typedef struct { + uint8_t op; + uint8_t rc; +} __attribute__ ((packed)) mcap_md_sync_rsp; + +typedef struct { + uint8_t op; + uint8_t rc; + uint8_t btclock; + uint16_t sltime; + uint16_t timestnr; + uint16_t timestna; +} __attribute__ ((packed)) mcap_md_sync_cap_rsp; + +typedef struct { + uint8_t op; + uint8_t timestui; + uint32_t btclock; + uint64_t timestst; +} __attribute__ ((packed)) mcap_md_sync_set_req; + +typedef struct { + int8_t op; + uint8_t rc; + uint32_t btclock; + uint64_t timestst; + uint16_t timestsa; +} __attribute__ ((packed)) mcap_md_sync_set_rsp; + +typedef struct { + uint8_t op; + uint32_t btclock; + uint64_t timestst; + uint16_t timestsa; +} __attribute__ ((packed)) mcap_md_sync_info_ind; + +typedef enum { +/* MCAP Error Response Codes */ + MCAP_ERROR_INVALID_OP_CODE = 1, + MCAP_ERROR_INVALID_PARAM_VALUE, + MCAP_ERROR_INVALID_MDEP, + MCAP_ERROR_MDEP_BUSY, + MCAP_ERROR_INVALID_MDL, + MCAP_ERROR_MDL_BUSY, + MCAP_ERROR_INVALID_OPERATION, + MCAP_ERROR_RESOURCE_UNAVAILABLE, + MCAP_ERROR_UNSPECIFIED_ERROR, + MCAP_ERROR_REQUEST_NOT_SUPPORTED, + MCAP_ERROR_CONFIGURATION_REJECTED, +/* MCAP Internal Errors */ + MCAP_ERROR_INVALID_ARGS, + MCAP_ERROR_ALREADY_EXISTS, + MCAP_ERROR_REQ_IGNORED, + MCAP_ERROR_MCL_CLOSED, + MCAP_ERROR_FAILED +} McapError; + +typedef enum { + MCAP_MDL_CB_INVALID, + MCAP_MDL_CB_CONNECTED, /* mcap_mdl_event_cb */ + MCAP_MDL_CB_CLOSED, /* mcap_mdl_event_cb */ + MCAP_MDL_CB_DELETED, /* mcap_mdl_event_cb */ + MCAP_MDL_CB_ABORTED, /* mcap_mdl_event_cb */ + MCAP_MDL_CB_REMOTE_CONN_REQ, /* mcap_remote_mdl_conn_req_cb */ + MCAP_MDL_CB_REMOTE_RECONN_REQ /* mcap_remote_mdl_reconn_req_cb */ +} McapMclCb; + +typedef enum { + MCL_CONNECTED, + MCL_PENDING, + MCL_ACTIVE, + MCL_IDLE +} MCLState; + +typedef enum { + MCL_ACCEPTOR, + MCL_INITIATOR +} MCLRole; + +typedef enum { + MCL_AVAILABLE, + MCL_WAITING_RSP +} MCAPCtrl; + +typedef enum { + MDL_WAITING, + MDL_CONNECTED, + MDL_DELETING, + MDL_CLOSED +} MDLState; + +struct mcap_csp; +struct mcap_mdl_op_cb; +struct mcap_instance; +struct mcap_mcl; +struct mcap_mdl; +struct sync_info_ind_data; + +/************ Callbacks ************/ + +/* MDL callbacks */ + +typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, gpointer data); +typedef void (* mcap_mdl_operation_conf_cb) (struct mcap_mdl *mdl, uint8_t conf, + GError *err, gpointer data); +typedef void (* mcap_mdl_operation_cb) (struct mcap_mdl *mdl, GError *err, + gpointer data); +typedef void (* mcap_mdl_notify_cb) (GError *err, gpointer data); + +/* Next function should return an MCAP appropriate response code */ +typedef uint8_t (* mcap_remote_mdl_conn_req_cb) (struct mcap_mcl *mcl, + uint8_t mdepid, uint16_t mdlid, + uint8_t *conf, gpointer data); +typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl, + gpointer data); + +/* MCL callbacks */ + +typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data); +typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err, + gpointer data); + +/* CSP callbacks */ + +typedef void (* mcap_info_ind_event_cb) (struct mcap_mcl *mcl, + struct sync_info_ind_data *data); + +typedef void (* mcap_sync_cap_cb) (struct mcap_mcl *mcl, + uint8_t mcap_err, + uint8_t btclockres, + uint16_t synclead, + uint16_t tmstampres, + uint16_t tmstampacc, + GError *err, + gpointer data); + +typedef void (* mcap_sync_set_cb) (struct mcap_mcl *mcl, + uint8_t mcap_err, + uint32_t btclock, + uint64_t timestamp, + uint16_t accuracy, + GError *err, + gpointer data); + +struct mcap_mdl_cb { + mcap_mdl_event_cb mdl_connected; /* Remote device has created a MDL */ + mcap_mdl_event_cb mdl_closed; /* Remote device has closed a MDL */ + mcap_mdl_event_cb mdl_deleted; /* Remote device requested deleting a MDL */ + mcap_mdl_event_cb mdl_aborted; /* Remote device aborted the mdl creation */ + mcap_remote_mdl_conn_req_cb mdl_conn_req; /* Remote device requested creating a MDL */ + mcap_remote_mdl_reconn_req_cb mdl_reconn_req; /* Remote device requested reconnecting a MDL */ + gpointer user_data; /* User data */ +}; + +struct mcap_instance { + bdaddr_t src; /* Source address */ + GIOChannel *ccio; /* Control Channel IO */ + GIOChannel *dcio; /* Data Channel IO */ + GSList *mcls; /* MCAP instance list */ + GSList *cached; /* List with all cached MCLs (MAX_CACHED macro) */ + BtIOSecLevel sec; /* Security level */ + mcap_mcl_event_cb mcl_connected_cb; /* New MCL connected */ + mcap_mcl_event_cb mcl_reconnected_cb; /* Old MCL has been reconnected */ + mcap_mcl_event_cb mcl_disconnected_cb; /* MCL disconnected */ + mcap_mcl_event_cb mcl_uncached_cb; /* MCL has been removed from MCAP cache */ + mcap_info_ind_event_cb mcl_sync_infoind_cb; /* (CSP Master) Received info indication */ + gpointer user_data; /* Data to be provided in callbacks */ + int ref; /* Reference counter */ + + gboolean csp_enabled; /* CSP: functionality enabled */ +}; + +struct mcap_mcl { + struct mcap_instance *mi; /* MCAP instance where this MCL belongs */ + bdaddr_t addr; /* Device address */ + GIOChannel *cc; /* MCAP Control Channel IO */ + guint wid; /* MCL Watcher id */ + GSList *mdls; /* List of Data Channels shorted by mdlid */ + MCLState state; /* Current MCL State */ + MCLRole role; /* Initiator or acceptor of this MCL */ + MCAPCtrl req; /* Request control flag */ + struct mcap_mdl_op_cb *priv_data; /* Temporal data to manage responses */ + struct mcap_mdl_cb *cb; /* MDL callbacks */ + guint tid; /* Timer id for waiting for a response */ + uint8_t *lcmd; /* Last command sent */ + int ref; /* References counter */ + uint8_t ctrl; /* MCL control flag */ + uint16_t next_mdl; /* id used to create next MDL */ + struct mcap_csp *csp; /* CSP control structure */ +}; + +struct mcap_mdl { + struct mcap_mcl *mcl; /* MCL where this MDL belongs */ + GIOChannel *dc; /* MCAP Data Channel IO */ + guint wid; /* MDL Watcher id */ + uint16_t mdlid; /* MDL id */ + uint8_t mdep_id; /* MCAP Data End Point */ + MDLState state; /* MDL state */ + int ref; /* References counter */ +}; + +struct sync_info_ind_data { + uint32_t btclock; + uint64_t timestamp; + uint16_t accuracy; +}; + +/************ Operations ************/ + +/* MDL operations */ + +gboolean mcap_create_mdl(struct mcap_mcl *mcl, + uint8_t mdepid, + uint8_t conf, + mcap_mdl_operation_conf_cb connect_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); +gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl, + mcap_mdl_operation_cb reconnect_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); +gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl, + mcap_mdl_notify_cb delete_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); +gboolean mcap_delete_mdl(struct mcap_mdl *mdl, + mcap_mdl_notify_cb delete_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); +gboolean mcap_connect_mdl(struct mcap_mdl *mdl, + uint8_t mode, + uint16_t dcpsm, + mcap_mdl_operation_cb connect_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); +gboolean mcap_mdl_abort(struct mcap_mdl *mdl, + mcap_mdl_notify_cb abort_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); + +int mcap_mdl_get_fd(struct mcap_mdl *mdl); +uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl); +struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl); +void mcap_mdl_unref(struct mcap_mdl *mdl); + +/* MCL operations */ + +gboolean mcap_create_mcl(struct mcap_instance *mi, + const bdaddr_t *addr, + uint16_t ccpsm, + mcap_mcl_connect_cb connect_cb, + gpointer user_data, + GDestroyNotify destroy, + GError **err); +void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache); +gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, + GError **gerr, McapMclCb cb1, ...); +void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr); +struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl); +void mcap_mcl_unref(struct mcap_mcl *mcl); + +/* CSP operations */ + +void mcap_enable_csp(struct mcap_instance *mi); +void mcap_disable_csp(struct mcap_instance *mi); +uint64_t mcap_get_timestamp(struct mcap_mcl *mcl, + struct timespec *given_time); +uint32_t mcap_get_btclock(struct mcap_mcl *mcl); + +void mcap_sync_cap_req(struct mcap_mcl *mcl, + uint16_t reqacc, + mcap_sync_cap_cb cb, + gpointer user_data, + GError **err); + +void mcap_sync_set_req(struct mcap_mcl *mcl, + uint8_t update, + uint32_t btclock, + uint64_t timestamp, + mcap_sync_set_cb cb, + gpointer user_data, + GError **err); + +/* MCAP main operations */ + +struct mcap_instance *mcap_create_instance(const bdaddr_t *src, + BtIOSecLevel sec, uint16_t ccpsm, + uint16_t dcpsm, + mcap_mcl_event_cb mcl_connected, + mcap_mcl_event_cb mcl_reconnected, + mcap_mcl_event_cb mcl_disconnected, + mcap_mcl_event_cb mcl_uncached, + mcap_info_ind_event_cb mcl_sync_info_ind, + gpointer user_data, + GError **gerr); +void mcap_release_instance(struct mcap_instance *mi); + +struct mcap_instance *mcap_instance_ref(struct mcap_instance *mi); +void mcap_instance_unref(struct mcap_instance *mi); + +uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err); +uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err); + +gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode, + GError **err); + +int mcap_send_data(int sock, const void *buf, uint32_t size); + +void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len); +void mcap_sync_init(struct mcap_mcl *mcl); +void mcap_sync_stop(struct mcap_mcl *mcl); diff --git a/profiles/health/mcap.h b/profiles/health/mcap.h deleted file mode 100644 index 1129e691d..000000000 --- a/profiles/health/mcap.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * - * MCAP for BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. - * Copyright (C) 2010 Signove - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __MCAP_H -#define __MCAP_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define MCAP_VERSION 0x0100 /* current version 01.00 */ - -/* bytes to get MCAP Supported Procedures */ -#define MCAP_SUP_PROC 0x06 - -/* maximum transmission unit for channels */ -#define MCAP_CC_MTU 48 -#define MCAP_DC_MTU 65535 - -/* MCAP Standard Op Codes */ -#define MCAP_ERROR_RSP 0x00 -#define MCAP_MD_CREATE_MDL_REQ 0x01 -#define MCAP_MD_CREATE_MDL_RSP 0x02 -#define MCAP_MD_RECONNECT_MDL_REQ 0x03 -#define MCAP_MD_RECONNECT_MDL_RSP 0x04 -#define MCAP_MD_ABORT_MDL_REQ 0x05 -#define MCAP_MD_ABORT_MDL_RSP 0x06 -#define MCAP_MD_DELETE_MDL_REQ 0x07 -#define MCAP_MD_DELETE_MDL_RSP 0x08 - -/* MCAP Clock Sync Op Codes */ -#define MCAP_MD_SYNC_CAP_REQ 0x11 -#define MCAP_MD_SYNC_CAP_RSP 0x12 -#define MCAP_MD_SYNC_SET_REQ 0x13 -#define MCAP_MD_SYNC_SET_RSP 0x14 -#define MCAP_MD_SYNC_INFO_IND 0x15 - -/* MCAP Response codes */ -#define MCAP_SUCCESS 0x00 -#define MCAP_INVALID_OP_CODE 0x01 -#define MCAP_INVALID_PARAM_VALUE 0x02 -#define MCAP_INVALID_MDEP 0x03 -#define MCAP_MDEP_BUSY 0x04 -#define MCAP_INVALID_MDL 0x05 -#define MCAP_MDL_BUSY 0x06 -#define MCAP_INVALID_OPERATION 0x07 -#define MCAP_RESOURCE_UNAVAILABLE 0x08 -#define MCAP_UNSPECIFIED_ERROR 0x09 -#define MCAP_REQUEST_NOT_SUPPORTED 0x0A -#define MCAP_CONFIGURATION_REJECTED 0x0B - -/* MDL IDs */ -#define MCAP_MDLID_RESERVED 0x0000 -#define MCAP_MDLID_INITIAL 0x0001 -#define MCAP_MDLID_FINAL 0xFEFF -#define MCAP_ALL_MDLIDS 0xFFFF - -/* MDEP IDs */ -#define MCAP_MDEPID_INITIAL 0x00 -#define MCAP_MDEPID_FINAL 0x7F - -/* CSP special values */ -#define MCAP_BTCLOCK_IMMEDIATE 0xffffffffUL -#define MCAP_TMSTAMP_DONTSET 0xffffffffffffffffULL -#define MCAP_BTCLOCK_MAX 0x0fffffff -#define MCAP_BTCLOCK_FIELD (MCAP_BTCLOCK_MAX + 1) - -/* - * MCAP Request Packet Format - */ - -typedef struct { - uint8_t op; - uint16_t mdl; - uint8_t mdep; - uint8_t conf; -} __attribute__ ((packed)) mcap_md_create_mdl_req; - -typedef struct { - uint8_t op; - uint16_t mdl; -} __attribute__ ((packed)) mcap_md_req; - -/* - * MCAP Response Packet Format - */ - -typedef struct { - uint8_t op; - uint8_t rc; - uint16_t mdl; - uint8_t data[0]; -} __attribute__ ((packed)) mcap_rsp; - -/* - * MCAP Clock Synchronization Protocol - */ - -typedef struct { - uint8_t op; - uint16_t timest; -} __attribute__ ((packed)) mcap_md_sync_cap_req; - -typedef struct { - uint8_t op; - uint8_t rc; -} __attribute__ ((packed)) mcap_md_sync_rsp; - -typedef struct { - uint8_t op; - uint8_t rc; - uint8_t btclock; - uint16_t sltime; - uint16_t timestnr; - uint16_t timestna; -} __attribute__ ((packed)) mcap_md_sync_cap_rsp; - -typedef struct { - uint8_t op; - uint8_t timestui; - uint32_t btclock; - uint64_t timestst; -} __attribute__ ((packed)) mcap_md_sync_set_req; - -typedef struct { - int8_t op; - uint8_t rc; - uint32_t btclock; - uint64_t timestst; - uint16_t timestsa; -} __attribute__ ((packed)) mcap_md_sync_set_rsp; - -typedef struct { - uint8_t op; - uint32_t btclock; - uint64_t timestst; - uint16_t timestsa; -} __attribute__ ((packed)) mcap_md_sync_info_ind; - -#ifdef __cplusplus -} -#endif - -#endif /* __MCAP_H */ diff --git a/profiles/health/mcap_internal.h b/profiles/health/mcap_internal.h deleted file mode 100644 index 7191b23e3..000000000 --- a/profiles/health/mcap_internal.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * MCAP for BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __MCAP_INTERNAL_H -#define __MCAP_INTERNAL_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - MCL_CONNECTED, - MCL_PENDING, - MCL_ACTIVE, - MCL_IDLE -} MCLState; - -typedef enum { - MCL_ACCEPTOR, - MCL_INITIATOR -} MCLRole; - -typedef enum { - MCL_AVAILABLE, - MCL_WAITING_RSP -} MCAPCtrl; - -typedef enum { - MDL_WAITING, - MDL_CONNECTED, - MDL_DELETING, - MDL_CLOSED -} MDLState; - -struct mcap_mdl_cb { - mcap_mdl_event_cb mdl_connected; /* Remote device has created a MDL */ - mcap_mdl_event_cb mdl_closed; /* Remote device has closed a MDL */ - mcap_mdl_event_cb mdl_deleted; /* Remote device requested deleting a MDL */ - mcap_mdl_event_cb mdl_aborted; /* Remote device aborted the mdl creation */ - mcap_remote_mdl_conn_req_cb mdl_conn_req; /* Remote device requested creating a MDL */ - mcap_remote_mdl_reconn_req_cb mdl_reconn_req; /* Remote device requested reconnecting a MDL */ - gpointer user_data; /* User data */ -}; - -struct mcap_instance { - bdaddr_t src; /* Source address */ - GIOChannel *ccio; /* Control Channel IO */ - GIOChannel *dcio; /* Data Channel IO */ - GSList *mcls; /* MCAP instance list */ - GSList *cached; /* List with all cached MCLs (MAX_CACHED macro) */ - BtIOSecLevel sec; /* Security level */ - mcap_mcl_event_cb mcl_connected_cb; /* New MCL connected */ - mcap_mcl_event_cb mcl_reconnected_cb; /* Old MCL has been reconnected */ - mcap_mcl_event_cb mcl_disconnected_cb; /* MCL disconnected */ - mcap_mcl_event_cb mcl_uncached_cb; /* MCL has been removed from MCAP cache */ - mcap_info_ind_event_cb mcl_sync_infoind_cb; /* (CSP Master) Received info indication */ - gpointer user_data; /* Data to be provided in callbacks */ - int ref; /* Reference counter */ - - gboolean csp_enabled; /* CSP: functionality enabled */ -}; - -struct mcap_csp; -struct mcap_mdl_op_cb; - -struct mcap_mcl { - struct mcap_instance *mi; /* MCAP instance where this MCL belongs */ - bdaddr_t addr; /* Device address */ - GIOChannel *cc; /* MCAP Control Channel IO */ - guint wid; /* MCL Watcher id */ - GSList *mdls; /* List of Data Channels shorted by mdlid */ - MCLState state; /* Current MCL State */ - MCLRole role; /* Initiator or acceptor of this MCL */ - MCAPCtrl req; /* Request control flag */ - struct mcap_mdl_op_cb *priv_data; /* Temporal data to manage responses */ - struct mcap_mdl_cb *cb; /* MDL callbacks */ - guint tid; /* Timer id for waiting for a response */ - uint8_t *lcmd; /* Last command sent */ - int ref; /* References counter */ - uint8_t ctrl; /* MCL control flag */ - uint16_t next_mdl; /* id used to create next MDL */ - struct mcap_csp *csp; /* CSP control structure */ -}; - -#define MCAP_CTRL_CACHED 0x01 /* MCL is cached */ -#define MCAP_CTRL_STD_OP 0x02 /* Support for standard op codes */ -#define MCAP_CTRL_SYNC_OP 0x04 /* Support for synchronization commands */ -#define MCAP_CTRL_CONN 0x08 /* MCL is in connecting process */ -#define MCAP_CTRL_FREE 0x10 /* MCL is marked as releasable */ -#define MCAP_CTRL_NOCACHE 0x20 /* MCL is marked as not cacheable */ - -struct mcap_mdl { - struct mcap_mcl *mcl; /* MCL where this MDL belongs */ - GIOChannel *dc; /* MCAP Data Channel IO */ - guint wid; /* MDL Watcher id */ - uint16_t mdlid; /* MDL id */ - uint8_t mdep_id; /* MCAP Data End Point */ - MDLState state; /* MDL state */ - int ref; /* References counter */ -}; - -struct sync_info_ind_data { - uint32_t btclock; - uint64_t timestamp; - uint16_t accuracy; -}; - -int mcap_send_data(int sock, const void *buf, uint32_t size); - -void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len); -void mcap_sync_init(struct mcap_mcl *mcl); -void mcap_sync_stop(struct mcap_mcl *mcl); - -#ifdef __cplusplus -} -#endif - -#endif /* __MCAP_INTERNAL_H */ diff --git a/profiles/health/mcap_lib.h b/profiles/health/mcap_lib.h deleted file mode 100644 index 603ccc097..000000000 --- a/profiles/health/mcap_lib.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * - * MCAP for BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __MCAP_LIB_H -#define __MCAP_LIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { -/* MCAP Error Response Codes */ - MCAP_ERROR_INVALID_OP_CODE = 1, - MCAP_ERROR_INVALID_PARAM_VALUE, - MCAP_ERROR_INVALID_MDEP, - MCAP_ERROR_MDEP_BUSY, - MCAP_ERROR_INVALID_MDL, - MCAP_ERROR_MDL_BUSY, - MCAP_ERROR_INVALID_OPERATION, - MCAP_ERROR_RESOURCE_UNAVAILABLE, - MCAP_ERROR_UNSPECIFIED_ERROR, - MCAP_ERROR_REQUEST_NOT_SUPPORTED, - MCAP_ERROR_CONFIGURATION_REJECTED, -/* MCAP Internal Errors */ - MCAP_ERROR_INVALID_ARGS, - MCAP_ERROR_ALREADY_EXISTS, - MCAP_ERROR_REQ_IGNORED, - MCAP_ERROR_MCL_CLOSED, - MCAP_ERROR_FAILED -} McapError; - -typedef enum { - MCAP_MDL_CB_INVALID, - MCAP_MDL_CB_CONNECTED, /* mcap_mdl_event_cb */ - MCAP_MDL_CB_CLOSED, /* mcap_mdl_event_cb */ - MCAP_MDL_CB_DELETED, /* mcap_mdl_event_cb */ - MCAP_MDL_CB_ABORTED, /* mcap_mdl_event_cb */ - MCAP_MDL_CB_REMOTE_CONN_REQ, /* mcap_remote_mdl_conn_req_cb */ - MCAP_MDL_CB_REMOTE_RECONN_REQ /* mcap_remote_mdl_reconn_req_cb */ -} McapMclCb; - -struct mcap_instance; -struct mcap_mcl; -struct mcap_mdl; -struct sync_info_ind_data; - -/************ Callbacks ************/ - -/* MDL callbacks */ - -typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, gpointer data); -typedef void (* mcap_mdl_operation_conf_cb) (struct mcap_mdl *mdl, uint8_t conf, - GError *err, gpointer data); -typedef void (* mcap_mdl_operation_cb) (struct mcap_mdl *mdl, GError *err, - gpointer data); -typedef void (* mcap_mdl_notify_cb) (GError *err, gpointer data); - -/* Next function should return an MCAP appropriate response code */ -typedef uint8_t (* mcap_remote_mdl_conn_req_cb) (struct mcap_mcl *mcl, - uint8_t mdepid, uint16_t mdlid, - uint8_t *conf, gpointer data); -typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl, - gpointer data); - -/* MCL callbacks */ - -typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data); -typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err, - gpointer data); - -/* CSP callbacks */ - -typedef void (* mcap_info_ind_event_cb) (struct mcap_mcl *mcl, - struct sync_info_ind_data *data); - -typedef void (* mcap_sync_cap_cb) (struct mcap_mcl *mcl, - uint8_t mcap_err, - uint8_t btclockres, - uint16_t synclead, - uint16_t tmstampres, - uint16_t tmstampacc, - GError *err, - gpointer data); - -typedef void (* mcap_sync_set_cb) (struct mcap_mcl *mcl, - uint8_t mcap_err, - uint32_t btclock, - uint64_t timestamp, - uint16_t accuracy, - GError *err, - gpointer data); - -/************ Operations ************/ - -/* MDL operations */ - -gboolean mcap_create_mdl(struct mcap_mcl *mcl, - uint8_t mdepid, - uint8_t conf, - mcap_mdl_operation_conf_cb connect_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); -gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl, - mcap_mdl_operation_cb reconnect_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); -gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl, - mcap_mdl_notify_cb delete_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); -gboolean mcap_delete_mdl(struct mcap_mdl *mdl, - mcap_mdl_notify_cb delete_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); -gboolean mcap_connect_mdl(struct mcap_mdl *mdl, - uint8_t mode, - uint16_t dcpsm, - mcap_mdl_operation_cb connect_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); -gboolean mcap_mdl_abort(struct mcap_mdl *mdl, - mcap_mdl_notify_cb abort_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); - -int mcap_mdl_get_fd(struct mcap_mdl *mdl); -uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl); - -struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl); -void mcap_mdl_unref(struct mcap_mdl *mdl); - -/* MCL operations */ - -gboolean mcap_create_mcl(struct mcap_instance *mi, - const bdaddr_t *addr, - uint16_t ccpsm, - mcap_mcl_connect_cb connect_cb, - gpointer user_data, - GDestroyNotify destroy, - GError **err); -void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache); -gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, - GError **gerr, McapMclCb cb1, ...); -void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr); - -struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl); -void mcap_mcl_unref(struct mcap_mcl *mcl); - -/* CSP operations */ - -void mcap_enable_csp(struct mcap_instance *mi); -void mcap_disable_csp(struct mcap_instance *mi); - -uint64_t mcap_get_timestamp(struct mcap_mcl *mcl, - struct timespec *given_time); -uint32_t mcap_get_btclock(struct mcap_mcl *mcl); - -void mcap_sync_cap_req(struct mcap_mcl *mcl, - uint16_t reqacc, - mcap_sync_cap_cb cb, - gpointer user_data, - GError **err); - -void mcap_sync_set_req(struct mcap_mcl *mcl, - uint8_t update, - uint32_t btclock, - uint64_t timestamp, - mcap_sync_set_cb cb, - gpointer user_data, - GError **err); - -/* MCAP main operations */ - -struct mcap_instance *mcap_create_instance(const bdaddr_t *src, - BtIOSecLevel sec, uint16_t ccpsm, - uint16_t dcpsm, - mcap_mcl_event_cb mcl_connected, - mcap_mcl_event_cb mcl_reconnected, - mcap_mcl_event_cb mcl_disconnected, - mcap_mcl_event_cb mcl_uncached, - mcap_info_ind_event_cb mcl_sync_info_ind, - gpointer user_data, - GError **gerr); -void mcap_release_instance(struct mcap_instance *mi); - -struct mcap_instance *mcap_instance_ref(struct mcap_instance *mi); -void mcap_instance_unref(struct mcap_instance *mi); - -uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err); -uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err); - -gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode, - GError **err); - -#ifdef __cplusplus -} -#endif - -#endif /* __MCAP_LIB_H */ diff --git a/profiles/health/mcap_sync.c b/profiles/health/mcap_sync.c deleted file mode 100644 index a0cc02a24..000000000 --- a/profiles/health/mcap_sync.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * - * MCAP for BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. - * Copyright (C) 2010 Signove - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdint.h> -#include <netinet/in.h> -#include <time.h> -#include <stdlib.h> -#include <sys/ioctl.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/l2cap.h> - -#include "btio/btio.h" -#include "src/adapter.h" -#include "src/log.h" - -#include "mcap.h" -#include "mcap_lib.h" -#include "mcap_internal.h" - -#define MCAP_BTCLOCK_HALF (MCAP_BTCLOCK_FIELD / 2) -#define CLK CLOCK_MONOTONIC - -#define MCAP_CSP_ERROR g_quark_from_static_string("mcap-csp-error-quark") -#define MAX_RETRIES 10 -#define SAMPLE_COUNT 20 - -struct mcap_csp { - uint64_t base_tmstamp; /* CSP base timestamp */ - struct timespec base_time; /* CSP base time when timestamp set */ - guint local_caps; /* CSP-Master: have got remote caps */ - guint remote_caps; /* CSP-Slave: remote master got caps */ - guint rem_req_acc; /* CSP-Slave: accuracy required by master */ - guint ind_expected; /* CSP-Master: indication expected */ - uint8_t csp_req; /* CSP-Master: Request control flag */ - guint ind_timer; /* CSP-Slave: indication timer */ - guint set_timer; /* CSP-Slave: delayed set timer */ - void *set_data; /* CSP-Slave: delayed set data */ - void *csp_priv_data; /* CSP-Master: In-flight request data */ -}; - -struct mcap_sync_cap_cbdata { - mcap_sync_cap_cb cb; - gpointer user_data; -}; - -struct mcap_sync_set_cbdata { - mcap_sync_set_cb cb; - gpointer user_data; -}; - -struct csp_caps { - int ts_acc; /* timestamp accuracy */ - int ts_res; /* timestamp resolution */ - int latency; /* Read BT clock latency */ - int preempt_thresh; /* Preemption threshold for latency */ - int syncleadtime_ms; /* SyncLeadTime in ms */ -}; - -struct sync_set_data { - uint8_t update; - uint32_t sched_btclock; - uint64_t timestamp; - int ind_freq; - gboolean role; -}; - -static gboolean csp_caps_initialized = FALSE; -struct csp_caps _caps; - -static int send_sync_cmd(struct mcap_mcl *mcl, const void *buf, uint32_t size) -{ - int sock; - - if (mcl->cc == NULL) - return -1; - - sock = g_io_channel_unix_get_fd(mcl->cc); - return mcap_send_data(sock, buf, size); -} - -static int send_unsupported_cap_req(struct mcap_mcl *mcl) -{ - mcap_md_sync_cap_rsp *cmd; - int sent; - - cmd = g_new0(mcap_md_sync_cap_rsp, 1); - cmd->op = MCAP_MD_SYNC_CAP_RSP; - cmd->rc = MCAP_REQUEST_NOT_SUPPORTED; - - sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); - g_free(cmd); - - return sent; -} - -static int send_unsupported_set_req(struct mcap_mcl *mcl) -{ - mcap_md_sync_set_rsp *cmd; - int sent; - - cmd = g_new0(mcap_md_sync_set_rsp, 1); - cmd->op = MCAP_MD_SYNC_SET_RSP; - cmd->rc = MCAP_REQUEST_NOT_SUPPORTED; - - sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); - g_free(cmd); - - return sent; -} - -static void reset_tmstamp(struct mcap_csp *csp, struct timespec *base_time, - uint64_t new_tmstamp) -{ - csp->base_tmstamp = new_tmstamp; - if (base_time) - csp->base_time = *base_time; - else - clock_gettime(CLK, &csp->base_time); -} - -void mcap_sync_init(struct mcap_mcl *mcl) -{ - if (!mcl->mi->csp_enabled) { - mcl->csp = NULL; - return; - } - - mcl->csp = g_new0(struct mcap_csp, 1); - - mcl->csp->rem_req_acc = 10000; /* safe divisor */ - mcl->csp->set_data = NULL; - mcl->csp->csp_priv_data = NULL; - - reset_tmstamp(mcl->csp, NULL, 0); -} - -void mcap_sync_stop(struct mcap_mcl *mcl) -{ - if (!mcl->csp) - return; - - if (mcl->csp->ind_timer) - g_source_remove(mcl->csp->ind_timer); - - if (mcl->csp->set_timer) - g_source_remove(mcl->csp->set_timer); - - if (mcl->csp->set_data) - g_free(mcl->csp->set_data); - - if (mcl->csp->csp_priv_data) - g_free(mcl->csp->csp_priv_data); - - mcl->csp->ind_timer = 0; - mcl->csp->set_timer = 0; - mcl->csp->set_data = NULL; - mcl->csp->csp_priv_data = NULL; - - g_free(mcl->csp); - mcl->csp = NULL; -} - -static uint64_t time_us(struct timespec *tv) -{ - return tv->tv_sec * 1000000ll + tv->tv_nsec / 1000ll; -} - -static int64_t bt2us(int bt) -{ - return bt * 312.5; -} - -static int bt2ms(int bt) -{ - return bt * 312.5 / 1000; -} - -static int btoffset(uint32_t btclk1, uint32_t btclk2) -{ - int offset = btclk2 - btclk1; - - if (offset <= -MCAP_BTCLOCK_HALF) - offset += MCAP_BTCLOCK_FIELD; - else if (offset > MCAP_BTCLOCK_HALF) - offset -= MCAP_BTCLOCK_FIELD; - - return offset; -} - -static int btdiff(uint32_t btclk1, uint32_t btclk2) -{ - return btoffset(btclk1, btclk2); -} - -static gboolean valid_btclock(uint32_t btclk) -{ - return btclk <= MCAP_BTCLOCK_MAX; -} - -/* This call may fail; either deal with retry or use read_btclock_retry */ -static gboolean read_btclock(struct mcap_mcl *mcl, uint32_t *btclock, - uint16_t *btaccuracy) -{ - int which = 1; - struct btd_adapter *adapter; - - adapter = adapter_find(&mcl->mi->src); - if (!adapter) - return FALSE; - - if (btd_adapter_read_clock(adapter, &mcl->addr, which, 1000, - btclock, btaccuracy) < 0) - return FALSE; - - return TRUE; -} - -static gboolean read_btclock_retry(struct mcap_mcl *mcl, uint32_t *btclock, - uint16_t *btaccuracy) -{ - int retries = 5; - - while (--retries >= 0) { - if (read_btclock(mcl, btclock, btaccuracy)) - return TRUE; - DBG("CSP: retrying to read bt clock..."); - } - - return FALSE; -} - -static gboolean get_btrole(struct mcap_mcl *mcl) -{ - int sock, flags; - socklen_t len; - - if (mcl->cc == NULL) - return -1; - - sock = g_io_channel_unix_get_fd(mcl->cc); - len = sizeof(flags); - - if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len)) - DBG("CSP: could not read role"); - - return flags & L2CAP_LM_MASTER; -} - -uint64_t mcap_get_timestamp(struct mcap_mcl *mcl, - struct timespec *given_time) -{ - struct timespec now; - uint64_t tmstamp; - - if (!mcl->csp) - return MCAP_TMSTAMP_DONTSET; - - if (given_time) - now = *given_time; - else - clock_gettime(CLK, &now); - - tmstamp = time_us(&now) - time_us(&mcl->csp->base_time) - + mcl->csp->base_tmstamp; - - return tmstamp; -} - -uint32_t mcap_get_btclock(struct mcap_mcl *mcl) -{ - uint32_t btclock; - uint16_t accuracy; - - if (!mcl->csp) - return MCAP_BTCLOCK_IMMEDIATE; - - if (!read_btclock_retry(mcl, &btclock, &accuracy)) - btclock = 0xffffffff; - - return btclock; -} - -static gboolean initialize_caps(struct mcap_mcl *mcl) -{ - struct timespec t1, t2; - int latencies[SAMPLE_COUNT]; - int latency, avg, dev; - uint32_t btclock; - uint16_t btaccuracy; - int i; - int retries; - - clock_getres(CLK, &t1); - - _caps.ts_res = time_us(&t1); - if (_caps.ts_res < 1) - _caps.ts_res = 1; - - _caps.ts_acc = 20; /* ppm, estimated */ - - /* A little exercise before measuing latency */ - clock_gettime(CLK, &t1); - read_btclock_retry(mcl, &btclock, &btaccuracy); - - /* Read clock a number of times and measure latency */ - avg = 0; - i = 0; - retries = MAX_RETRIES; - while (i < SAMPLE_COUNT && retries > 0) { - clock_gettime(CLK, &t1); - if (!read_btclock(mcl, &btclock, &btaccuracy)) { - retries--; - continue; - } - clock_gettime(CLK, &t2); - - latency = time_us(&t2) - time_us(&t1); - latencies[i] = latency; - avg += latency; - i++; - } - - if (retries <= 0) - return FALSE; - - /* Calculate average and deviation */ - avg /= SAMPLE_COUNT; - dev = 0; - for (i = 0; i < SAMPLE_COUNT; ++i) - dev += abs(latencies[i] - avg); - dev /= SAMPLE_COUNT; - - /* Calculate corrected average, without 'freak' latencies */ - latency = 0; - for (i = 0; i < SAMPLE_COUNT; ++i) { - if (latencies[i] > (avg + dev * 6)) - latency += avg; - else - latency += latencies[i]; - } - latency /= SAMPLE_COUNT; - - _caps.latency = latency; - _caps.preempt_thresh = latency * 4; - _caps.syncleadtime_ms = latency * 50 / 1000; - - csp_caps_initialized = TRUE; - return TRUE; -} - -static struct csp_caps *caps(struct mcap_mcl *mcl) -{ - if (!csp_caps_initialized) - if (!initialize_caps(mcl)) { - /* Temporary failure in reading BT clock */ - return NULL; - } - - return &_caps; -} - -static int send_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t rspcode, - uint8_t btclockres, uint16_t synclead, - uint16_t tmstampres, uint16_t tmstampacc) -{ - mcap_md_sync_cap_rsp *rsp; - int sent; - - rsp = g_new0(mcap_md_sync_cap_rsp, 1); - - rsp->op = MCAP_MD_SYNC_CAP_RSP; - rsp->rc = rspcode; - - rsp->btclock = btclockres; - rsp->sltime = htons(synclead); - rsp->timestnr = htons(tmstampres); - rsp->timestna = htons(tmstampacc); - - sent = send_sync_cmd(mcl, rsp, sizeof(*rsp)); - g_free(rsp); - - return sent; -} - -static void proc_sync_cap_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) -{ - mcap_md_sync_cap_req *req; - uint16_t required_accuracy; - uint16_t our_accuracy; - uint32_t btclock; - uint16_t btres; - - if (len != sizeof(mcap_md_sync_cap_req)) { - send_sync_cap_rsp(mcl, MCAP_INVALID_PARAM_VALUE, - 0, 0, 0, 0); - return; - } - - if (!caps(mcl)) { - send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, - 0, 0, 0, 0); - return; - } - - req = (mcap_md_sync_cap_req *) cmd; - required_accuracy = ntohs(req->timest); - our_accuracy = caps(mcl)->ts_acc; - - if (required_accuracy < our_accuracy || required_accuracy < 1) { - send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, - 0, 0, 0, 0); - return; - } - - if (!read_btclock_retry(mcl, &btclock, &btres)) { - send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, - 0, 0, 0, 0); - return; - } - - mcl->csp->remote_caps = 1; - mcl->csp->rem_req_acc = required_accuracy; - - send_sync_cap_rsp(mcl, MCAP_SUCCESS, btres, - caps(mcl)->syncleadtime_ms, - caps(mcl)->ts_res, our_accuracy); -} - -static int send_sync_set_rsp(struct mcap_mcl *mcl, uint8_t rspcode, - uint32_t btclock, uint64_t timestamp, - uint16_t tmstampres) -{ - mcap_md_sync_set_rsp *rsp; - int sent; - - rsp = g_new0(mcap_md_sync_set_rsp, 1); - - rsp->op = MCAP_MD_SYNC_SET_RSP; - rsp->rc = rspcode; - rsp->btclock = htonl(btclock); - rsp->timestst = hton64(timestamp); - rsp->timestsa = htons(tmstampres); - - sent = send_sync_cmd(mcl, rsp, sizeof(*rsp)); - g_free(rsp); - - return sent; -} - -static gboolean get_all_clocks(struct mcap_mcl *mcl, uint32_t *btclock, - struct timespec *base_time, - uint64_t *timestamp) -{ - int latency; - int retry = 5; - uint16_t btres; - struct timespec t0; - - if (!caps(mcl)) - return FALSE; - - latency = caps(mcl)->preempt_thresh + 1; - - while (latency > caps(mcl)->preempt_thresh && --retry >= 0) { - - clock_gettime(CLK, &t0); - - if (!read_btclock(mcl, btclock, &btres)) - continue; - - clock_gettime(CLK, base_time); - - /* Tries to detect preemption between clock_gettime - * and read_btclock by measuring transaction time - */ - latency = time_us(base_time) - time_us(&t0); - } - - *timestamp = mcap_get_timestamp(mcl, base_time); - - return TRUE; -} - -static gboolean sync_send_indication(gpointer user_data) -{ - struct mcap_mcl *mcl; - mcap_md_sync_info_ind *cmd; - uint32_t btclock; - uint64_t tmstamp; - struct timespec base_time; - int sent; - - if (!user_data) - return FALSE; - - mcl = user_data; - - if (!caps(mcl)) - return FALSE; - - if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) - return FALSE; - - cmd = g_new0(mcap_md_sync_info_ind, 1); - - cmd->op = MCAP_MD_SYNC_INFO_IND; - cmd->btclock = htonl(btclock); - cmd->timestst = hton64(tmstamp); - cmd->timestsa = htons(caps(mcl)->latency); - - sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); - g_free(cmd); - - return !sent; -} - -static gboolean proc_sync_set_req_phase2(gpointer user_data) -{ - struct mcap_mcl *mcl; - struct sync_set_data *data; - uint8_t update; - uint32_t sched_btclock; - uint64_t new_tmstamp; - int ind_freq; - int role; - uint32_t btclock; - uint64_t tmstamp; - struct timespec base_time; - uint16_t tmstampacc; - gboolean reset; - int delay; - - if (!user_data) - return FALSE; - - mcl = user_data; - - if (!mcl->csp->set_data) - return FALSE; - - data = mcl->csp->set_data; - update = data->update; - sched_btclock = data->sched_btclock; - new_tmstamp = data->timestamp; - ind_freq = data->ind_freq; - role = data->role; - - if (!caps(mcl)) { - send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); - return FALSE; - } - - if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) { - send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); - return FALSE; - } - - if (get_btrole(mcl) != role) { - send_sync_set_rsp(mcl, MCAP_INVALID_OPERATION, 0, 0, 0); - return FALSE; - } - - reset = (new_tmstamp != MCAP_TMSTAMP_DONTSET); - - if (reset) { - if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE) { - delay = bt2us(btdiff(sched_btclock, btclock)); - if (delay >= 0 || ((new_tmstamp - delay) > 0)) { - new_tmstamp += delay; - DBG("CSP: reset w/ delay %dus, compensated", - delay); - } else - DBG("CSP: reset w/ delay %dus, uncompensated", - delay); - } - - reset_tmstamp(mcl->csp, &base_time, new_tmstamp); - tmstamp = new_tmstamp; - } - - tmstampacc = caps(mcl)->latency + caps(mcl)->ts_acc; - - if (mcl->csp->ind_timer) { - g_source_remove(mcl->csp->ind_timer); - mcl->csp->ind_timer = 0; - } - - if (update) { - int when = ind_freq + caps(mcl)->syncleadtime_ms; - mcl->csp->ind_timer = g_timeout_add(when, - sync_send_indication, - mcl); - } - - send_sync_set_rsp(mcl, MCAP_SUCCESS, btclock, tmstamp, tmstampacc); - - /* First indication after set is immediate */ - if (update) - sync_send_indication(mcl); - - return FALSE; -} - -static void proc_sync_set_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) -{ - mcap_md_sync_set_req *req; - uint32_t sched_btclock, cur_btclock; - uint16_t btres; - uint8_t update; - uint64_t timestamp; - struct sync_set_data *set_data; - int phase2_delay, ind_freq, when; - - if (len != sizeof(mcap_md_sync_set_req)) { - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); - return; - } - - req = (mcap_md_sync_set_req *) cmd; - sched_btclock = ntohl(req->btclock); - update = req->timestui; - timestamp = ntoh64(req->timestst); - - if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE && - !valid_btclock(sched_btclock)) { - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); - return; - } - - if (update > 1) { - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); - return; - } - - if (!mcl->csp->remote_caps) { - /* Remote side did not ask our capabilities yet */ - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); - return; - } - - if (!caps(mcl)) { - send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); - return; - } - - if (!read_btclock_retry(mcl, &cur_btclock, &btres)) { - send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); - return; - } - - if (sched_btclock == MCAP_BTCLOCK_IMMEDIATE) - phase2_delay = 0; - else { - phase2_delay = btdiff(cur_btclock, sched_btclock); - - if (phase2_delay < 0) { - /* can not reset in the past tense */ - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, - 0, 0, 0); - return; - } - - /* Convert to miliseconds */ - phase2_delay = bt2ms(phase2_delay); - - if (phase2_delay > 61*1000) { - /* More than 60 seconds in the future */ - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, - 0, 0, 0); - return; - } else if (phase2_delay < caps(mcl)->latency / 1000) { - /* Too fast for us to do in time */ - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, - 0, 0, 0); - return; - } - } - - if (update) { - /* Indication frequency: required accuracy divided by ours */ - /* Converted to milisseconds */ - ind_freq = (1000 * mcl->csp->rem_req_acc) / caps(mcl)->ts_acc; - - if (ind_freq < MAX(caps(mcl)->latency * 2 / 1000, 100)) { - /* Too frequent, we can't handle */ - send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, - 0, 0, 0); - return; - } - - DBG("CSP: indication every %dms", ind_freq); - } else - ind_freq = 0; - - if (mcl->csp->ind_timer) { - /* Old indications are no longer sent */ - g_source_remove(mcl->csp->ind_timer); - mcl->csp->ind_timer = 0; - } - - if (!mcl->csp->set_data) - mcl->csp->set_data = g_new0(struct sync_set_data, 1); - - set_data = (struct sync_set_data *) mcl->csp->set_data; - - set_data->update = update; - set_data->sched_btclock = sched_btclock; - set_data->timestamp = timestamp; - set_data->ind_freq = ind_freq; - set_data->role = get_btrole(mcl); - - /* TODO is there some way to schedule a call based directly on - * a BT clock value, instead of this estimation that uses - * the SO clock? */ - - if (phase2_delay > 0) { - when = phase2_delay + caps(mcl)->syncleadtime_ms; - mcl->csp->set_timer = g_timeout_add(when, - proc_sync_set_req_phase2, - mcl); - } else - proc_sync_set_req_phase2(mcl); - - /* First indication is immediate */ - if (update) - sync_send_indication(mcl); -} - -static void proc_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) -{ - mcap_md_sync_cap_rsp *rsp; - uint8_t mcap_err; - uint8_t btclockres; - uint16_t synclead; - uint16_t tmstampres; - uint16_t tmstampacc; - struct mcap_sync_cap_cbdata *cbdata; - mcap_sync_cap_cb cb; - gpointer user_data; - - if (mcl->csp->csp_req != MCAP_MD_SYNC_CAP_REQ) { - DBG("CSP: got unexpected cap respose"); - return; - } - - if (!mcl->csp->csp_priv_data) { - DBG("CSP: no priv data for cap respose"); - return; - } - - cbdata = mcl->csp->csp_priv_data; - cb = cbdata->cb; - user_data = cbdata->user_data; - g_free(cbdata); - - mcl->csp->csp_priv_data = NULL; - mcl->csp->csp_req = 0; - - if (len != sizeof(mcap_md_sync_cap_rsp)) { - DBG("CSP: got corrupted cap respose"); - return; - } - - rsp = (mcap_md_sync_cap_rsp *) cmd; - mcap_err = rsp->rc; - btclockres = rsp->btclock; - synclead = ntohs(rsp->sltime); - tmstampres = ntohs(rsp->timestnr); - tmstampacc = ntohs(rsp->timestna); - - if (!mcap_err) - mcl->csp->local_caps = TRUE; - - cb(mcl, mcap_err, btclockres, synclead, tmstampres, tmstampacc, NULL, - user_data); -} - -static void proc_sync_set_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) -{ - mcap_md_sync_set_rsp *rsp; - uint8_t mcap_err; - uint32_t btclock; - uint64_t timestamp; - uint16_t accuracy; - struct mcap_sync_set_cbdata *cbdata; - mcap_sync_set_cb cb; - gpointer user_data; - - if (mcl->csp->csp_req != MCAP_MD_SYNC_SET_REQ) { - DBG("CSP: got unexpected set respose"); - return; - } - - if (!mcl->csp->csp_priv_data) { - DBG("CSP: no priv data for set respose"); - return; - } - - cbdata = mcl->csp->csp_priv_data; - cb = cbdata->cb; - user_data = cbdata->user_data; - g_free(cbdata); - - mcl->csp->csp_priv_data = NULL; - mcl->csp->csp_req = 0; - - if (len != sizeof(mcap_md_sync_set_rsp)) { - DBG("CSP: got corrupted set respose"); - return; - } - - rsp = (mcap_md_sync_set_rsp *) cmd; - mcap_err = rsp->rc; - btclock = ntohl(rsp->btclock); - timestamp = ntoh64(rsp->timestst); - accuracy = ntohs(rsp->timestsa); - - if (!mcap_err && !valid_btclock(btclock)) - mcap_err = MCAP_ERROR_INVALID_ARGS; - - cb(mcl, mcap_err, btclock, timestamp, accuracy, NULL, user_data); -} - -static void proc_sync_info_ind(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) -{ - mcap_md_sync_info_ind *req; - struct sync_info_ind_data data; - uint32_t btclock; - - if (!mcl->csp->ind_expected) { - DBG("CSP: received unexpected info indication"); - return; - } - - if (len != sizeof(mcap_md_sync_info_ind)) - return; - - req = (mcap_md_sync_info_ind *) cmd; - - btclock = ntohl(req->btclock); - - if (!valid_btclock(btclock)) - return; - - data.btclock = btclock; - data.timestamp = ntoh64(req->timestst); - data.accuracy = ntohs(req->timestsa); - - if (mcl->mi->mcl_sync_infoind_cb) - mcl->mi->mcl_sync_infoind_cb(mcl, &data); -} - -void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) -{ - if (!mcl->mi->csp_enabled || !mcl->csp) { - switch (cmd[0]) { - case MCAP_MD_SYNC_CAP_REQ: - send_unsupported_cap_req(mcl); - break; - case MCAP_MD_SYNC_SET_REQ: - send_unsupported_set_req(mcl); - break; - } - return; - } - - switch (cmd[0]) { - case MCAP_MD_SYNC_CAP_REQ: - proc_sync_cap_req(mcl, cmd, len); - break; - case MCAP_MD_SYNC_CAP_RSP: - proc_sync_cap_rsp(mcl, cmd, len); - break; - case MCAP_MD_SYNC_SET_REQ: - proc_sync_set_req(mcl, cmd, len); - break; - case MCAP_MD_SYNC_SET_RSP: - proc_sync_set_rsp(mcl, cmd, len); - break; - case MCAP_MD_SYNC_INFO_IND: - proc_sync_info_ind(mcl, cmd, len); - break; - } -} - -void mcap_sync_cap_req(struct mcap_mcl *mcl, uint16_t reqacc, - mcap_sync_cap_cb cb, gpointer user_data, - GError **err) -{ - struct mcap_sync_cap_cbdata *cbdata; - mcap_md_sync_cap_req *cmd; - - if (!mcl->mi->csp_enabled || !mcl->csp) { - g_set_error(err, - MCAP_CSP_ERROR, - MCAP_ERROR_RESOURCE_UNAVAILABLE, - "CSP not enabled for the instance"); - return; - } - - if (mcl->csp->csp_req) { - g_set_error(err, - MCAP_CSP_ERROR, - MCAP_ERROR_RESOURCE_UNAVAILABLE, - "Pending CSP request"); - return; - } - - mcl->csp->csp_req = MCAP_MD_SYNC_CAP_REQ; - cmd = g_new0(mcap_md_sync_cap_req, 1); - - cmd->op = MCAP_MD_SYNC_CAP_REQ; - cmd->timest = htons(reqacc); - - cbdata = g_new0(struct mcap_sync_cap_cbdata, 1); - cbdata->cb = cb; - cbdata->user_data = user_data; - mcl->csp->csp_priv_data = cbdata; - - send_sync_cmd(mcl, cmd, sizeof(*cmd)); - - g_free(cmd); -} - -void mcap_sync_set_req(struct mcap_mcl *mcl, uint8_t update, uint32_t btclock, - uint64_t timestamp, mcap_sync_set_cb cb, - gpointer user_data, GError **err) -{ - mcap_md_sync_set_req *cmd; - struct mcap_sync_set_cbdata *cbdata; - - if (!mcl->mi->csp_enabled || !mcl->csp) { - g_set_error(err, - MCAP_CSP_ERROR, - MCAP_ERROR_RESOURCE_UNAVAILABLE, - "CSP not enabled for the instance"); - return; - } - - if (!mcl->csp->local_caps) { - g_set_error(err, - MCAP_CSP_ERROR, - MCAP_ERROR_RESOURCE_UNAVAILABLE, - "Did not get CSP caps from slave yet"); - return; - } - - if (mcl->csp->csp_req) { - g_set_error(err, - MCAP_CSP_ERROR, - MCAP_ERROR_RESOURCE_UNAVAILABLE, - "Pending CSP request"); - return; - } - - mcl->csp->csp_req = MCAP_MD_SYNC_SET_REQ; - cmd = g_new0(mcap_md_sync_set_req, 1); - - cmd->op = MCAP_MD_SYNC_SET_REQ; - cmd->timestui = update; - cmd->btclock = htonl(btclock); - cmd->timestst = hton64(timestamp); - - mcl->csp->ind_expected = update; - - cbdata = g_new0(struct mcap_sync_set_cbdata, 1); - cbdata->cb = cb; - cbdata->user_data = user_data; - mcl->csp->csp_priv_data = cbdata; - - send_sync_cmd(mcl, cmd, sizeof(*cmd)); - - g_free(cmd); -} - -void mcap_enable_csp(struct mcap_instance *mi) -{ - mi->csp_enabled = TRUE; -} - -void mcap_disable_csp(struct mcap_instance *mi) -{ - mi->csp_enabled = FALSE; -} |