summaryrefslogtreecommitdiff
path: root/profiles/health
diff options
context:
space:
mode:
authorRavi kumar Veeramally <ravikumar.veeramally@linux.intel.com>2014-10-01 16:45:34 +0300
committerJohan Hedberg <johan.hedberg@intel.com>2014-10-02 14:24:28 +0300
commitc2a70e6b9d0c2257a3ae579d62faa1d60e4962bd (patch)
treeb56126ee8caa66813af2b847a174d2e86f141608 /profiles/health
parent88adaba587bc53c795a2bebab95058f804412ab4 (diff)
downloadbluez-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.c3
-rw-r--r--profiles/health/hdp_util.c3
-rw-r--r--profiles/health/mcap-lib.c (renamed from profiles/health/mcap.c)1047
-rw-r--r--profiles/health/mcap-lib.h437
-rw-r--r--profiles/health/mcap.h164
-rw-r--r--profiles/health/mcap_internal.h137
-rw-r--r--profiles/health/mcap_lib.h224
-rw-r--r--profiles/health/mcap_sync.c1009
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, &notify);
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;
-}