MCAP patches
Subsystems (2)
Hello,
Next are the patches that we have prepared for MCAP.
Git can be cloned from git://gitorious.org/bluez-mcap-hdp/mcap-hdp.git
Regards.
PATCH 1/16 Initial support for MCAP
--- Makefile.am | 12 +++++++++- acinclude.m4 | 6 +++++ health/mcap.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ health/mcap.h | 38 +++++++++++++++++++++++++++++++++ health/mcap_lib.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 1 deletions(-) create mode 100644 health/mcap.c create mode 100644 health/mcap.h create mode 100644 health/mcap_lib.h
Makefile.am +11 -1
@@ -102,6 +102,7 @@ gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/object.c gdbus/watch.c builtin_modules = builtin_sources = builtin_nodist = +mcap_sources = if PNATPLUGIN builtin_modules += pnat
@@ -168,6 +169,11 @@ builtin_modules += service builtin_sources += plugins/service.c endif +if MCAP +mcap_sources += health/mcap_lib.h \ + health/mcap.h health/mcap.c +endif + builtin_modules += hciops builtin_sources += plugins/hciops.c
@@ -201,7 +207,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \ src/adapter.h src/adapter.c \ src/device.h src/device.c \ src/dbus-common.c src/dbus-common.h \ - src/dbus-hci.h src/dbus-hci.c + src/dbus-hci.h src/dbus-hci.c \ + $(mcap_sources) src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \ @CAPNG_LIBS@ -ldl src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
@@ -323,6 +330,9 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \ INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \ -I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus +if MCAP +INCLUDES += -I$(builddir)/health +endif pkgconfigdir = $(libdir)/pkgconfig
acinclude.m4 +6 -0
@@ -167,6 +167,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [ serial_enable=yes network_enable=yes service_enable=yes + mcap_enable=no pnat_enable=no tracer_enable=no tools_enable=yes
@@ -216,6 +217,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [ service_enable=${enableval} ]) + AC_ARG_ENABLE(mcap, AC_HELP_STRING([--enable-mcap], [enable mcap support]), [ + mcap_enable=${enableval} + ]) + AC_ARG_ENABLE(pnat, AC_HELP_STRING([--enable-pnat], [enable pnat plugin]), [ pnat_enable=${enableval} ])
@@ -330,6 +335,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [ AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes") AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes") AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes") + AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes") AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes") AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes") AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
health/mcap.c new file +55 -0
55 lines not on this page · raw message
health/mcap.h new file +38 -0
@@ -0,0 +1,38 @@ +/* +* +* MCAP for BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. +* +* Authors: +* Santiago Carot-Nemesio <sancane at gmail.com> +* Jose Antonio Santos-Cadenas <santoscadenas at gmail.com> +* +* 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 + +#ifdef __cplusplus +} +#endif + +#endif /* __MCAP_H */
health/mcap_lib.h new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
1.6.3.3
PATCH 2/16 Add MCAP instance management
--- Makefile.am | 2 +- health/mcap.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 4 + health/mcap_internal.h | 52 ++++++++++++++++ health/mcap_lib.h | 30 +++++++++ 5 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 health/mcap_internal.h
Makefile.am +1 -1
@@ -170,7 +170,7 @@ builtin_sources += plugins/service.c endif if MCAP -mcap_sources += health/mcap_lib.h \ +mcap_sources += health/mcap_lib.h health/mcap_internal.h \ health/mcap.h health/mcap.c endif
health/mcap.c +150 -3
167 lines not on this page · raw message
health/mcap.h +4 -0
@@ -31,6 +31,10 @@extern "C" {#endif +/* maximum transmission unit for channels */ +#define MCAP_CC_MTU 48 +#define MCAP_DC_MTU L2CAP_DEFAULT_MTU + #ifdef __cplusplus }#endif
health/mcap_internal.h new file +52 -0
52 lines not on this page · raw message
health/mcap_lib.h +30 -0
@@ -35,11 +35,38 @@ extern "C" {#include "btio.h" #include <bluetooth/l2cap.h> +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 ; +struct mcap_instance ;struct mcap_mcl ; +/************ Callbacks ************/ + +/* mcl callbacks */ +typedef void (*mcap_mcl_event_cb ) (struct mcap_mcl *mcl,gpointer data); +/************ Operations ************/ +/* MCAP main operations */ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
@@ -54,6 +81,9 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,void mcap_release_instance (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); + #ifdef __cplusplus }#endif
Signature · 1 line
1.6.3.3
PATCH 3/16 Receive MCAP mcl connections from remote devices
--- health/mcap.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 21 +++++ health/mcap_internal.h | 52 ++++++++++++ health/mcap_lib.h | 15 ++++ 4 files changed, 295 insertions(+), 2 deletions(-)
health/mcap.c +207 -2
@@ -38,24 +38,229 @@#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark") +static void default_mdl_connected_cb (struct mcap_mdl *mdl,gpointer data) +{ +DBG ("MCAP Unmanaged mdl connection" ); +} + +static void default_mdl_closed_cb (struct mcap_mdl *mdl,gpointer data) +{ +DBG ("MCAP Unmanaged mdl closed" ); +} + +static void default_mdl_deleted_cb (struct mcap_mdl *mdl,gpointer data) +{ +DBG ("MCAP Unmanaged mdl deleted" ); +} + +static void default_mdl_aborted_cb (struct mcap_mdl *mdl,gpointer data) +{ +DBG ("MCAP Unmanaged mdl aborted" ); +} + +static uint8_t default_mdl_conn_req_cb (struct mcap_mcl *mcl, +uint8_t mdepid,uint16_t mdlid, +uint8_t *conf,gpointer data) +{ +DBG ("MCAP mdl remote connection aborted" ); +/* Due to this callback isn't managed this request won't be supported */ +return MCAP_REQUEST_NOT_SUPPORTED ; +} + +static uint8_t default_mdl_reconn_req_cb (struct mcap_mdl *mdl, +gpointer data) +{ +DBG ("MCAP mdl remote reconnection aborted" ); +/* Due to this callback isn't managed this request won't be supported */ +return MCAP_REQUEST_NOT_SUPPORTED ; +} + +static void set_default_cb (struct mcap_mcl *mcl) +{ +if (!mcl->cb) + mcl->cb = g_new0(struct mcap_mdl_cb, 1); + + mcl->cb->mdl_connected = default_mdl_connected_cb; + mcl->cb->mdl_closed = default_mdl_closed_cb; + mcl->cb->mdl_deleted = default_mdl_deleted_cb; + mcl->cb->mdl_aborted = default_mdl_aborted_cb; + mcl->cb->mdl_conn_req = default_mdl_conn_req_cb; + mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; +} + +static struct mcap_mcl *find_mcl (GSList *list,const bdaddr_t *addr) +{ +GSList *l; +struct mcap_mcl *mcl; + +for (l = list; l; l = l->next) { + mcl = l->data; + +if (!bacmp (&mcl->addr, addr)) +return mcl; + } + +return NULL ; +} +static void mcap_mcl_shutdown (struct mcap_mcl *mcl) {/* TODO: implement mcap_mcl_shutdown */ } +static void mcap_mcl_release (struct mcap_mcl *mcl) +{ +/* TODO: implement mcap_mcl_release */ +} + +static void mcap_mcl_check_del (struct mcap_mcl *mcl) +{ +if (mcl->ctrl &MCAP_CTRL_CACHED ) +mcap_mcl_shutdown (mcl); +else +mcap_mcl_unref (mcl); +} + +static void mcap_uncache_mcl (struct mcap_mcl *mcl) +{ +if (!(mcl->ctrl &MCAP_CTRL_CACHED )) +return ; + +DBG ("Got MCL from cache" ); + + mcl->ms->cached =g_slist_remove (mcl->ms->cached, mcl); + mcl->ms->mcls =g_slist_prepend (mcl->ms->mcls, mcl); + mcl->ctrl &= ~MCAP_CTRL_CACHED ; + mcl->ctrl &= ~MCAP_CTRL_FREE ; +} + +struct mcap_mcl *mcap_mcl_ref (struct mcap_mcl *mcl) +{ + mcl->ref++; + +DBG ("mcap_mcl_ref(%p): ref=%d" , mcl, mcl->ref); + +return mcl; +} +void mcap_mcl_unref (struct mcap_mcl *mcl) { -/* TODO: implement mcap_mcl_unref */ + mcl->ref--; + +DBG ("mcap_mcl_unref(%p): ref=%d" , mcl, mcl->ref); + +if ((mcl->ctrl &MCAP_CTRL_CACHED ) && (mcl->ref <2 )) { +/* Free space in cache memory due any other profile has a local +* copy of current MCL stored in cache */ +DBG ("Remove from cache (%p): ref=%d" , mcl, mcl->ref); + mcl->ms->cached =g_slist_remove (mcl->ms->cached, mcl); +mcap_mcl_release (mcl); +return ; + } + +if (mcl->ref >0 ) +return ; + +mcap_mcl_release (mcl); } +static gboolean mcl_control_cb (GIOChannel *chan,GIOCondition cond, +gpointer data) +{ +/* TODO: Create mcl_control_cb */ +return FALSE; +}static void confirm_dc_event_cb (GIOChannel *chan,gpointer user_data) {/* TODO: implement confirm_dc_event_cb */ } +static void connect_mcl_event_cb (GIOChannel *chan,GError *err, +gpointer user_data) +{ +struct mcap_mcl *mcl = user_data; +gboolean reconn; + +if (err) { +mcap_mcl_check_del (mcl); +return ; + } + + mcl->state =MCL_CONNECTED ; + mcl->role =MCL_ACCEPTOR ; + mcl->req =MCL_AVAILABLE ; + mcl->cc =g_io_channel_ref (chan); + mcl->ctrl |=MCAP_CTRL_STD_OP ; + + reconn = (mcl->ctrl &MCAP_CTRL_CACHED ); +if (reconn) +mcap_uncache_mcl (mcl); +else + mcl->ms->mcls =g_slist_prepend (mcl->ms->mcls, mcl); + + mcl->wid =g_io_add_watch (mcl->cc, +G_IO_IN |G_IO_ERR |G_IO_HUP |G_IO_NVAL , + (GIOFunc ) mcl_control_cb, mcl); + +/* Callback to report new MCL */ +if (reconn) + mcl->ms->mcl_reconnected_cb (mcl, mcl->ms->user_data); +else + mcl->ms->mcl_connected_cb (mcl, mcl->ms->user_data); + +if (mcl->ref ==1 ) { + mcl->ms->mcls =g_slist_remove (mcl->ms->mcls, mcl); +mcap_mcl_unref (mcl); + } +} +static void confirm_mcl_event_cb (GIOChannel *chan,gpointer user_data) { -/* TODO: implement confirm_mcl_event_cb */ +struct mcap_instance *ms = user_data; +struct mcap_mcl *mcl; +bdaddr_t dst; +char address[18 ], srcstr[18 ]; +GError *err =NULL ; + +bt_io_get (chan,BT_IO_L2CAP , &err, +BT_IO_OPT_DEST_BDADDR , &dst, +BT_IO_OPT_DEST , address, +BT_IO_OPT_INVALID ); +if (err) { +error ("%s" , err->message); +g_error_free (err); + goto drop; + } + +ba2str (&ms->src, srcstr); + mcl =find_mcl (ms->mcls, &dst); +if (mcl) { +error ("Control channel already created with %s on adapter %s" , + address, srcstr); + goto drop; + } + + mcl =find_mcl (ms->cached, &dst); +if (!mcl) { + mcl = g_new0(struct mcap_mcl, 1); + mcl->ms = ms; +bacpy (&mcl->addr, &dst); +set_default_cb (mcl); + mcl->next_mdl = (rand () %MCAP_MDLID_FINAL ) +1 ; + mcl =mcap_mcl_ref (mcl); + } + +if (!bt_io_accept (chan, connect_mcl_event_cb, mcl,NULL , &err)) { +error ("mcap accept error: %s" , err->message); +if (!(mcl->ctrl &MCAP_CTRL_CACHED )) +mcap_mcl_unref (mcl); +g_error_free (err); + goto drop; + } + +return ; +drop: +g_io_channel_shutdown (chan, TRUE,NULL ); } struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
health/mcap.h +21 -0
@@ -35,6 +35,27 @@ extern "C" {#define MCAP_CC_MTU 48#define MCAP_DC_MTU L2CAP_DEFAULT_MTU +/* 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 + + #ifdef __cplusplus }#endif
health/mcap_internal.h +52 -0
64 lines not on this page · raw message
health/mcap_lib.h +15 -0
@@ -58,15 +58,30 @@ typedef enum {struct mcap_instance ;struct mcap_mcl ; +struct mcap_mdl ;/************ Callbacks ************/ +/* mdl callbacks */ + +typedef void (*mcap_mdl_event_cb ) (struct mcap_mdl *mdl,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);/************ Operations ************/ +struct mcap_mcl *mcap_mcl_ref (struct mcap_mcl *mcl); +void mcap_mcl_unref (struct mcap_mcl *mcl); +/* MCAP main operations */ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
Signature · 1 line
1.6.3.3
PATCH 4/16 Added function for MCAP control channel (MCL) management
--- health/mcap.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 30 ++++++ 2 files changed, 298 insertions(+), 2 deletions(-)
health/mcap.c +268 -2
@@ -37,6 +37,16 @@#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark") +#define RELEASE_TIMER (__mcl) do { \ + g_source_remove(__mcl->tid); \ + __mcl->tid = 0; \ +} while(0) + +struct connect_mcl { +struct mcap_mcl *mcl;/* MCL for this operation */ +mcap_mcl_connect_cb connect_cb;/* Connect callback */ +gpointer user_data;/* Callback user data */ +};static void default_mdl_connected_cb (struct mcap_mdl *mdl,gpointer data) {
@@ -103,14 +113,59 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)return NULL ; } +static void mcap_free_mdls (struct mcap_mcl *mcl,gboolean save) +{ +/* TODO: implement mcap_free_mdls */ +} + +static void close_mcl (struct mcap_mcl *mcl,gboolean save) +{ +gboolean store = ((!(mcl->ctrl &MCAP_CTRL_FREE )) && save); + +if (mcl->tid) { +RELEASE_TIMER (mcl); + } + +if (mcl->cc) { +g_io_channel_shutdown (mcl->cc, TRUE,NULL ); +g_io_channel_unref (mcl->cc); + mcl->cc =NULL ; + } + +g_source_remove (mcl->wid); +if (mcl->lcmd) { +g_free (mcl->lcmd); + mcl->lcmd =NULL ; + } + +if (mcl->priv_data) { +g_free (mcl->priv_data); + mcl->priv_data =NULL ; + } + +mcap_free_mdls (mcl, store); + +if (mcl->cb && !store) { +g_free (mcl->cb); + mcl->cb =NULL ; + } + + mcl->state =MCL_IDLE ; + +if (store) +return ; + +g_free (mcl); +} +static void mcap_mcl_shutdown (struct mcap_mcl *mcl) { -/* TODO: implement mcap_mcl_shutdown */ +close_mcl (mcl, TRUE); }static void mcap_mcl_release (struct mcap_mcl *mcl) { -/* TODO: implement mcap_mcl_release */ +close_mcl (mcl, FALSE); }static void mcap_mcl_check_del (struct mcap_mcl *mcl)
@@ -134,6 +189,23 @@ static void mcap_uncache_mcl(struct mcap_mcl *mcl) mcl->ctrl &= ~MCAP_CTRL_FREE ; } +void mcap_close_mcl (struct mcap_mcl *mcl,gboolean cache) +{ +if (!mcl) +return ; + +if (mcl->cc) { +g_io_channel_shutdown (mcl->cc, TRUE,NULL ); +g_io_channel_unref (mcl->cc); + mcl->cc =NULL ; + } + + mcl->state =MCL_IDLE ; + +if (!cache) + mcl->ctrl |=MCAP_CTRL_NOCACHE ; +} +struct mcap_mcl *mcap_mcl_ref (struct mcap_mcl *mcl) { mcl->ref++;
@@ -164,12 +236,206 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)mcap_mcl_release (mcl); } +static gboolean parse_set_opts (struct mcap_mdl_cb *mdl_cb,GError **err, +McapMclCb cb1,va_list args) +{ +McapMclCb cb = cb1; +struct mcap_mdl_cb *c; + + c = g_new0(struct mcap_mdl_cb, 1); + +while (cb !=MCAP_MDL_CB_INVALID ) { +switch (cb) { +case MCAP_MDL_CB_CONNECTED : + c->mdl_connected =va_arg (args, + mcap_mdl_event_cb); +break ; +case MCAP_MDL_CB_CLOSED : + c->mdl_closed =va_arg (args, + mcap_mdl_event_cb); +break ; +case MCAP_MDL_CB_DELETED : + c->mdl_deleted =va_arg (args, + mcap_mdl_event_cb); +break ; +case MCAP_MDL_CB_ABORTED : + c->mdl_aborted =va_arg (args, + mcap_mdl_event_cb); +break ; +case MCAP_MDL_CB_REMOTE_CONN_REQ : + c->mdl_conn_req =va_arg (args, + mcap_remote_mdl_conn_req_cb); +break ; +case MCAP_MDL_CB_REMOTE_RECONN_REQ : + c->mdl_reconn_req =va_arg (args, + mcap_remote_mdl_reconn_req_cb); +break ; +default : +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_INVALID_ARGS , +"Unknown option %d" , cb); +return FALSE; + } + cb =va_arg (args, int); + } + +/* Set new callbacks */ +if (c->mdl_connected) + mdl_cb->mdl_connected = c->mdl_connected; +if (c->mdl_closed) + mdl_cb->mdl_closed = c->mdl_closed; +if (c->mdl_deleted) + mdl_cb->mdl_deleted = c->mdl_deleted; +if (c->mdl_aborted) + mdl_cb->mdl_aborted = c->mdl_aborted; +if (c->mdl_conn_req) + mdl_cb->mdl_conn_req = c->mdl_conn_req; +if (c->mdl_reconn_req) + mdl_cb->mdl_reconn_req = c->mdl_reconn_req; + +g_free (c); +return TRUE; +} + +void mcap_mcl_set_cb (struct mcap_mcl *mcl,gpointer user_data,GError **gerr, +McapMclCb cb1, ...) +{ +va_list args; +gboolean ret; + +va_start (args, cb1); + ret =parse_set_opts (mcl->cb, gerr, cb1, args); +va_end (args); + +if (!ret) +return ; + + mcl->cb->user_data = user_data; +return ; +} + +void mcap_mcl_get_addr (struct mcap_mcl *mcl,bdaddr_t *addr) +{ +bacpy (addr, &mcl->addr); +} +static gboolean mcl_control_cb (GIOChannel *chan,GIOCondition cond,gpointer data) {/* TODO: Create mcl_control_cb */ return FALSE; } + +static void mcap_connect_mcl_cb (GIOChannel *chan,GError *conn_err, +gpointer user_data) +{ +char dstaddr[18 ]; +struct connect_mcl *con = user_data; +struct mcap_mcl *aux, *mcl = con->mcl; +mcap_mcl_connect_cb connect_cb = con->connect_cb; +gpointer data = con->user_data; +GError *gerr =NULL ; + +g_free (con); + + mcl->ctrl &= ~MCAP_CTRL_CONN ; + +if (conn_err) { +if (mcl->ctrl &MCAP_CTRL_FREE ) + mcl->ms->mcl_uncached_cb (mcl, mcl->ms->user_data); +mcap_mcl_check_del (mcl); +connect_cb (NULL , conn_err, data); +return ; + } + +ba2str (&mcl->addr, dstaddr); + + aux =find_mcl (mcl->ms->mcls, &mcl->addr); +if (aux) { +/* Double MCL connection case */ +if (aux != mcl) { +/* This MCL was not in cache */ +mcap_mcl_unref (mcl); + } +error ("MCL error: Device %s is already connected" , dstaddr); +g_set_error (&gerr,MCAP_ERROR ,MCAP_ERROR_ALREADY_EXISTS , +"MCL %s is already connected" , dstaddr); +connect_cb (NULL , gerr, data); +g_error_free (gerr); +return ; + } + + mcl->state =MCL_CONNECTED ; + mcl->role =MCL_INITIATOR ; + mcl->req =MCL_AVAILABLE ; + mcl->ctrl |=MCAP_CTRL_STD_OP ; + +if (mcl->ctrl &MCAP_CTRL_CACHED ) +mcap_uncache_mcl (mcl); +else + mcl->ms->mcls =g_slist_prepend (mcl->ms->mcls, mcl); + + mcl->wid =g_io_add_watch (mcl->cc, +G_IO_IN |G_IO_ERR |G_IO_HUP |G_IO_NVAL , + (GIOFunc ) mcl_control_cb, mcl); +connect_cb (mcl, gerr, data); + +if (mcl->ref ==1 ) { + mcl->ms->mcls =g_slist_remove (mcl->ms->mcls, mcl); +mcap_mcl_unref (mcl); + } +} + +void mcap_create_mcl (struct mcap_instance *ms, +const bdaddr_t *addr, +uint16_t ccpsm, +mcap_mcl_connect_cb connect_cb, +gpointer user_data, +GError **err) +{ +struct mcap_mcl *mcl; +struct connect_mcl *con; + + mcl =find_mcl (ms->mcls, addr); +if (mcl) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_ALREADY_EXISTS , +"MCL is already connected." ); +return ; + } + + mcl =find_mcl (ms->cached, addr); +if (!mcl) { + mcl = g_new0(struct mcap_mcl, 1); + mcl->ms = ms; + mcl->state =MCL_IDLE ; +bacpy (&mcl->addr, addr); +set_default_cb (mcl); + mcl->next_mdl = (rand () %MCAP_MDLID_FINAL ) +1 ; + mcl =mcap_mcl_ref (mcl); + }else + mcl->ctrl |=MCAP_CTRL_CONN ; + + con = g_new0(struct connect_mcl, 1); + con->mcl = mcl; + con->connect_cb = connect_cb; + con->user_data = user_data; + + mcl->cc =bt_io_connect (BT_IO_L2CAP , mcap_connect_mcl_cb, con, +NULL , err, +BT_IO_OPT_SOURCE_BDADDR , &ms->src, +BT_IO_OPT_DEST_BDADDR , addr, +BT_IO_OPT_PSM , ccpsm, +BT_IO_OPT_MTU ,MCAP_CC_MTU , +BT_IO_OPT_SEC_LEVEL , ms->sec, +BT_IO_OPT_INVALID ); +if (*err) { +g_free (con); + mcl->ctrl &= ~MCAP_CTRL_CONN ; +if (mcl->ctrl &MCAP_CTRL_FREE ) + mcl->ms->mcl_uncached_cb (mcl, mcl->ms->user_data); +mcap_mcl_check_del (mcl); + } +} +static void confirm_dc_event_cb (GIOChannel *chan,gpointer user_data) {/* TODO: implement confirm_dc_event_cb */
health/mcap_lib.h +30 -0
@@ -56,6 +56,16 @@ typedef enum { 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 ;
@@ -65,6 +75,11 @@ struct mcap_mdl;/* 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,
@@ -76,9 +91,24 @@ typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl,/* 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);/************ Operations ************/ +/* Mcl operations*/ + +void mcap_create_mcl (struct mcap_instance *ms, +const bdaddr_t *addr, +uint16_t ccpsm, +mcap_mcl_connect_cb connect_cb, +gpointer user_data, +GError **err); +void mcap_close_mcl (struct mcap_mcl *mcl,gboolean cache); +void 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);
Signature · 1 line
1.6.3.3
PATCH 5/16 Prepare FSM functions for processing comands
--- health/mcap.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 29 +++++++ health/mcap_internal.h | 4 + 3 files changed, 224 insertions(+), 1 deletions(-)
health/mcap.c +191 -1
@@ -35,6 +35,8 @@#include "mcap_lib.h" #include "mcap_internal.h" +#define MAX_CACHED 10/* 10 devices */ +#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")#define RELEASE_TIMER (__mcl) do { \
@@ -48,6 +50,17 @@ struct connect_mcl {gpointer user_data;/* Callback user data */ }; +/* MCAP finite state machine functions */ +static void proc_req_connected (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t l); +static void proc_req_pending (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t l); +static void proc_req_active (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t l); + +static void (*proc_req[])(struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) = { + proc_req_connected, + proc_req_pending, + proc_req_active +}; +static void default_mdl_connected_cb (struct mcap_mdl *mdl,gpointer data) {DBG ("MCAP Unmanaged mdl connection" );
@@ -98,6 +111,50 @@ static void set_default_cb(struct mcap_mcl *mcl) mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; } +static void mcap_notify_error (struct mcap_mcl *mcl,GError *err) +{ +/* TODO: implement mcap_notify_error */ +} + +int mcap_send_data (int sock,const uint8_t *buf,uint32_t size) +{ +uint32_t sent =0 ; + +while (sent < size) { +int n =send (sock, buf + sent, size - sent,0 ); +if (n <0 ) +return -1 ; + sent += n; + } +return 0 ; +} + +static int mcap_send_cmd (struct mcap_mcl *mcl,uint8_t oc,uint8_t rc, +uint16_t mdl,uint8_t *data,size_t len) +{ +mcap_rsp *cmd; +uint8_t *rsp; +int sock, sent; + +if (mcl->cc ==NULL ) +return -1 ; + + sock =g_io_channel_unix_get_fd (mcl->cc); + + rsp =g_malloc (sizeof (mcap_rsp) + len); + cmd = (mcap_rsp *)rsp; + cmd->op = oc; + cmd->rc = rc; + cmd->mdl =htons (mdl); + +if (data && len >0 ) +memcpy (rsp +sizeof (mcap_rsp), data, len); + + sent =mcap_send_data (sock, rsp,sizeof (mcap_rsp) + len); +g_free (rsp); +return sent; +} +static struct mcap_mcl *find_mcl (GSList *list,const bdaddr_t *addr) {GSList *l;
@@ -176,6 +233,46 @@ static void mcap_mcl_check_del(struct mcap_mcl *mcl)mcap_mcl_unref (mcl); } +static void mcap_cache_mcl (struct mcap_mcl *mcl) +{ +GSList *l; +struct mcap_mcl *last; +int len; + +if (mcl->ctrl &MCAP_CTRL_CACHED ) +return ; + + mcl->ms->mcls =g_slist_remove (mcl->ms->mcls, mcl); + +if ((mcl->ctrl &MCAP_CTRL_NOCACHE ) || (mcl->ref <2 )) { +mcap_mcl_unref (mcl); +return ; + } + +DBG ("Caching MCL" ); + + len =g_slist_length (mcl->ms->cached); +if (len ==MAX_CACHED ) { +/* Remove the latest cached mcl */ + l =g_slist_last (mcl->ms->cached); + last = l->data; + mcl->ms->cached =g_slist_remove (mcl->ms->cached, last); + last->ctrl &= ~MCAP_CTRL_CACHED ; +if (last->ctrl &MCAP_CTRL_CONN ) { +/* If connection process is not success this MCL will be +* freed next time that close_mcl is invoked */ + last->ctrl |=MCAP_CTRL_FREE ; + }else { + last->ms->mcl_uncached_cb (last, last->ms->user_data); +mcap_mcl_unref (last); + } + } + + mcl->ms->cached =g_slist_prepend (mcl->ms->cached, mcl); + mcl->ctrl |=MCAP_CTRL_CACHED ; +mcap_mcl_shutdown (mcl); +} +static void mcap_uncache_mcl (struct mcap_mcl *mcl) {if (!(mcl->ctrl &MCAP_CTRL_CACHED ))
@@ -318,10 +415,103 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)bacpy (addr, &mcl->addr); } +/* Function used to process commands depending of MCL state */ +static void proc_req_connected (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) +{ +/* TODO: Implement proc_req_connected */ +} + +static void proc_req_pending (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) +{ +/* TODO: Implement proc_req_pending */ +} + +static void proc_req_active (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) +{ +/* TODO: Implement proc_req_active */ +} + +static void proc_response (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) +{ +/* TODO: Implement proc_response */ +} + +static void proc_cmd (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) +{ +GError *gerr =NULL ; + +if (cmd[0 ] >MCAP_MD_SYNC_INFO_IND || + (cmd[0 ] >MCAP_MD_DELETE_MDL_RSP && + cmd[0 ] <MCAP_MD_SYNC_CAP_REQ )) { +error ("Unknown cmd received (op code = %d)" , cmd[0 ]); +mcap_send_cmd (mcl,MCAP_ERROR_RSP ,MCAP_INVALID_OP_CODE , +MCAP_MDLID_RESERVED ,NULL ,0 ); +return ; + } + +if (cmd[0 ] >=MCAP_MD_SYNC_CAP_REQ && + cmd[0 ] <=MCAP_MD_SYNC_INFO_IND ) { +/* TODO: proc_sync_cmd(mcl, cmd, len);*/ +return ; + } + +if (!(mcl->ctrl &MCAP_CTRL_STD_OP )) { +/* In case the remote device doesn't work correctly */ +error ("Remote device does not support opcodes, cmd ignored" ); +return ; + } + +if (mcl->req ==MCL_WAITING_RSP ) { +if (cmd[0 ] &0x01 ) { +/* Request arrived when a response is expected */ +if (mcl->role ==MCL_INITIATOR ) +/* ignore */ +return ; +/* Initiator will ignore our last request */ + proc_req[mcl->state](mcl, cmd, len); +RELEASE_TIMER (mcl); + mcl->req =MCL_AVAILABLE ; +g_set_error (&gerr,MCAP_ERROR ,MCAP_ERROR_REQ_IGNORED , +"Initiator sent a request with more priority" ); +mcap_notify_error (mcl, gerr); +return ; + } +proc_response (mcl, cmd, len); + }else if (cmd[0 ] &0x01 ) + proc_req[mcl->state](mcl, cmd, len); +} +static gboolean mcl_control_cb (GIOChannel *chan,GIOCondition cond,gpointer data) { -/* TODO: Create mcl_control_cb */ +GError *gerr =NULL ; + +struct mcap_mcl *mcl = data; +int sk, len; +uint8_t buf[MCAP_CC_MTU ]; + +if (cond & (G_IO_ERR |G_IO_HUP |G_IO_NVAL )) + goto fail; + + sk =g_io_channel_unix_get_fd (chan); + len =recv (sk, buf,sizeof (buf),0 ); +if (len <0 ) + goto fail; + +proc_cmd (mcl, buf, (uint32_t )len); +return TRUE; +fail: +if (mcl->state !=MCL_IDLE ) { +if (mcl->req ==MCL_WAITING_RSP ) { +/* notify error in pending callback */ +g_set_error (&gerr,MCAP_ERROR ,MCAP_ERROR_MCL_CLOSED , +"MCL closed" ); +mcap_notify_error (mcl, gerr); +g_error_free (gerr); + } + mcl->ms->mcl_disconnected_cb (mcl, mcl->ms->user_data); + } +mcap_cache_mcl (mcl);return FALSE; }
health/mcap.h +29 -0
@@ -35,6 +35,25 @@ extern "C" {#define MCAP_CC_MTU 48#define MCAP_DC_MTU L2CAP_DEFAULT_MTU + +/* 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
@@ -55,6 +74,16 @@ extern "C" {#define MCAP_MDLID_FINAL 0xFEFF#define MCAP_ALL_MDLIDS 0xFFFF +/* +* MCAP Response Packet Format +*/ + +typedef struct { +uint8_t op; +uint8_t rc; +uint16_t mdl; +} __attribute__ ((packed))mcap_rsp ; + #ifdef __cplusplus }
health/mcap_internal.h +4 -0
@@ -97,6 +97,10 @@ struct mcap_mcl {#define MCAP_CTRL_FREE 0x10/* MCL is marked as releasable */ #define MCAP_CTRL_NOCACHE 0x20/* MCL is marked as not cacheable */ +int mcap_send_data (int sock,const uint8_t *buf,uint32_t size); + +void proc_sync_cmd (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len); + #ifdef __cplusplus }#endif
Signature · 1 line
1.6.3.3
PATCH 6/16 Send MCAP request mcap_md_create_mdl_req
--- health/mcap.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ health/mcap.h | 11 +++ health/mcap_internal.h | 16 ++++ health/mcap_lib.h | 9 +++ 4 files changed, 214 insertions(+), 0 deletions(-)
health/mcap.c +178 -0
@@ -35,6 +35,7 @@#include "mcap_lib.h" #include "mcap_internal.h" +#define RESPONSE_TIMER 2/* seconds */ #define MAX_CACHED 10/* 10 devices */ #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
@@ -50,6 +51,18 @@ struct connect_mcl {gpointer user_data;/* Callback user data */ }; +typedef union { +mcap_mdl_operation_cb op; +mcap_mdl_operation_conf_cb op_conf; +mcap_mdl_notify_cb notify; +}mcap_cb_type ; + +struct mcap_mdl_op_cb { +struct mcap_mdl *mdl;/* MDL for this operation */ +mcap_cb_type cb;/* Operation callback */ +gpointer user_data;/* Callback user data */ +}; +/* MCAP finite state machine functions */ static void proc_req_connected (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t l);static void proc_req_pending (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t l);
@@ -61,6 +74,8 @@ static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = { proc_req_active }; +static void mcap_cache_mcl (struct mcap_mcl *mcl); +static void default_mdl_connected_cb (struct mcap_mdl *mdl,gpointer data) {DBG ("MCAP Unmanaged mdl connection" );
@@ -111,6 +126,43 @@ static void set_default_cb(struct mcap_mcl *mcl) mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; } +static void mcap_send_std_opcode (struct mcap_mcl *mcl,void *cmd, +uint32_t size,GError **err) +{ +if (mcl->state ==MCL_IDLE ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"MCL is not connected" ); +return ; + } + +if (mcl->req !=MCL_AVAILABLE ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_RESOURCE_UNAVAILABLE , +"Pending request" ); +return ; + } + +if (!(mcl->ctrl &MCAP_CTRL_STD_OP )) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_REQUEST_NOT_SUPPORTED , +"Remote does not support standard opcodes" ); +return ; + } + +if (mcl->state ==MCL_PENDING ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_INVALID_OPERATION , +"Not Std Op. Codes can be sent in PENDING State" ); +return ; + } + +if (mcap_send_data (g_io_channel_unix_get_fd (mcl->cc), cmd, size) <0 ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Command can't be sent, write error" ); +return ; + } + + mcl->lcmd = cmd; + mcl->req =MCL_WAITING_RSP ; +} +static void mcap_notify_error (struct mcap_mcl *mcl,GError *err) {/* TODO: implement mcap_notify_error */
@@ -155,6 +207,132 @@ static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,return sent; } +static struct mcap_mdl *get_mdl (struct mcap_mcl *mcl,uint16_t mdlid) +{ +GSList *l; +struct mcap_mdl *mdl; + +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; +if (mdlid == mdl->mdlid) +return mdl; + } + +return NULL ; +} + +static uint16_t generate_mdlid (struct mcap_mcl *mcl) +{ +uint16_t mdlid = mcl->next_mdl; +struct mcap_mdl *mdl; + +do { + mdl =get_mdl (mcl, mdlid); +if (!mdl) { + mcl->next_mdl = (mdlid %MCAP_MDLID_FINAL ) +1 ; +return mdlid; + }else + mdlid = (mdlid %MCAP_MDLID_FINAL ) +1 ; + }while (mdlid != mcl->next_mdl); + +/* No more mdlids availables */ +return 0 ; +} + +static mcap_md_create_mdl_req *create_mdl_req (uint16_t mdl_id,uint8_t mdep, +uint8_t conf) +{ +mcap_md_create_mdl_req *req_mdl; + + req_mdl =g_malloc0 (sizeof (mcap_md_create_mdl_req)); + + req_mdl->op =MCAP_MD_CREATE_MDL_REQ ; + req_mdl->mdl =htons (mdl_id); + req_mdl->mdep = mdep; + req_mdl->conf = conf; + +return req_mdl; +} + +static gint compare_mdl (gconstpointer a,gconstpointer b) +{ +const struct mcap_mdl *mdla = a; +const struct mcap_mdl *mdlb = b; + +if (mdla->mdlid == mdlb->mdlid) +return 0 ; +else if (mdla->mdlid < mdlb->mdlid) +return -1 ; +else +return 1 ; +} + +static gboolean wait_response_timer (gpointer data) +{ +struct mcap_mcl *mcl = data; + +GError *gerr =NULL ; + +RELEASE_TIMER (mcl); + +g_set_error (&gerr,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Timeout waiting response" ); + +mcap_notify_error (mcl, gerr); + +g_error_free (gerr); + mcl->ms->mcl_disconnected_cb (mcl, mcl->ms->user_data); +mcap_cache_mcl (mcl); +return FALSE; +} + +void mcap_create_mdl (struct mcap_mcl *mcl, +uint8_t mdepid, +uint8_t conf, +mcap_mdl_operation_conf_cb connect_cb, +gpointer user_data, +GError **err) +{ +struct mcap_mdl *mdl; +struct mcap_mdl_op_cb *con; +mcap_md_create_mdl_req *cmd; +uint16_t id; + + id =generate_mdlid (mcl); +if (!id) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Not more mdlids available" ); +return ; + } + + mdl = g_new0(struct mcap_mdl, 1); + mdl->mcl = mcl; + mdl->mdlid = id; + mdl->mdep_id = mdepid; + mdl->state =MDL_WAITING ; + + con = g_new0(struct mcap_mdl_op_cb, 1); + con->mdl = mdl; + con->cb.op_conf = connect_cb; + con->user_data = user_data; + + cmd =create_mdl_req (id, mdepid, conf); +mcap_send_std_opcode (mcl, cmd,sizeof (mcap_md_create_mdl_req), err); +if (*err) { +g_free (mdl); +g_free (con); +g_free (cmd); +return ; + } + + mcl->state =MCL_ACTIVE ; + mcl->priv_data = con; + + mcl->mdls =g_slist_insert_sorted (mcl->mdls, mdl, compare_mdl); + mcl->tid =g_timeout_add_seconds (RESPONSE_TIMER , wait_response_timer, + mcl); +} +static struct mcap_mcl *find_mcl (GSList *list,const bdaddr_t *addr) {GSList *l;
health/mcap.h +11 -0
@@ -75,6 +75,17 @@ extern "C" {#define MCAP_ALL_MDLIDS 0xFFFF/* +* 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 ; + +/* * MCAP Response Packet Format */
health/mcap_internal.h +16 -0
@@ -48,6 +48,13 @@ typedef enum {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 */
@@ -97,6 +104,15 @@ struct mcap_mcl {#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 mcap_send_data (int sock,const uint8_t *buf,uint32_t size);void proc_sync_cmd (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len);
health/mcap_lib.h +9 -0
@@ -96,6 +96,15 @@ typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err,/************ Operations ************/ +/* Mdl operations*/ + +void mcap_create_mdl (struct mcap_mcl *mcl, +uint8_t mdepid, +uint8_t conf, +mcap_mdl_operation_conf_cb connect_cb, +gpointer user_data, +GError **err); +/* Mcl operations*/ void mcap_create_mcl(struct mcap_instance *ms,
Signature · 1 line
1.6.3.3
PATCH 7/16 Process MCAP request mcap_md_create_mdl_req
--- health/mcap.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 5 + 2 files changed, 255 insertions(+), 5 deletions(-)
health/mcap.c +250 -5
@@ -163,9 +163,103 @@ static void mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd, mcl->req =MCL_WAITING_RSP ; } +static void update_mcl_state (struct mcap_mcl *mcl) +{ +GSList *l; +struct mcap_mdl *mdl; + +if (mcl->state ==MCL_PENDING ) +return ; + +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; + +if (mdl->state ==MDL_CONNECTED ) { + mcl->state =MCL_ACTIVE ; +return ; + } + } + + mcl->state =MCL_CONNECTED ; +} + +static void shutdown_mdl (struct mcap_mdl *mdl) +{ + mdl->state =MDL_CLOSED ; + +g_source_remove (mdl->wid); + +if (mdl->dc) { +g_io_channel_shutdown (mdl->dc, TRUE,NULL ); +g_io_channel_unref (mdl->dc); + mdl->dc =NULL ; + } +} + +static gint cmp_mdl_state (gconstpointer a,gconstpointer b) +{ +const struct mcap_mdl *mdl = a; +const MDLState *st = b; + +if (mdl->state == *st) +return 0 ; +else if (mdl->state < *st) +return -1 ; +else +return 1 ; +} +static void mcap_notify_error (struct mcap_mcl *mcl,GError *err) { -/* TODO: implement mcap_notify_error */ +struct mcap_mdl_op_cb *con = mcl->priv_data; +struct mcap_mdl *mdl; +MDLState st; +GSList *l; + +if (!con || !mcl->lcmd) +return ; + +switch (mcl->lcmd[0 ]){ +case MCAP_MD_CREATE_MDL_REQ : + st =MDL_WAITING ; + l =g_slist_find_custom (mcl->mdls, &st, cmp_mdl_state); + mdl = l->data; + mcl->mdls =g_slist_remove (mcl->mdls, mdl); +g_free (mdl); +update_mcl_state (mcl); + con->cb.op_conf (NULL ,0 , err, con->user_data); +break ; +case MCAP_MD_ABORT_MDL_REQ : + st =MDL_WAITING ; + l =g_slist_find_custom (mcl->mdls, &st, cmp_mdl_state); +shutdown_mdl (l->data); +update_mcl_state (mcl); + con->cb.notify (err, con->user_data); +break ; +case MCAP_MD_DELETE_MDL_REQ : +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; +if (mdl->state ==MDL_DELETING ) + mdl->state = (mdl->dc) ?MDL_CONNECTED : +MDL_CLOSED ; + } +update_mcl_state (mcl); + con->cb.notify (err, con->user_data); +break ; +case MCAP_MD_RECONNECT_MDL_REQ : + st =MDL_WAITING ; + l =g_slist_find_custom (mcl->mdls, &st, cmp_mdl_state); +shutdown_mdl (l->data); +update_mcl_state (mcl); + con->cb.op (NULL , err, con->user_data); +break ; + } + +g_free (mcl->priv_data); + mcl->priv_data =NULL ; + +g_free (mcl->lcmd); + mcl->lcmd =NULL ; }int mcap_send_data (int sock,const uint8_t *buf,uint32_t size)
@@ -350,7 +444,23 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)static void mcap_free_mdls (struct mcap_mcl *mcl,gboolean save) { -/* TODO: implement mcap_free_mdls */ +GSList *l; +struct mcap_mdl *mdl; + +if (!mcl->mdls) +return ; + +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; +shutdown_mdl (mdl); +if (!save) +g_free (mdl); + } + +if (!save) { +g_slist_free (mcl->mdls); + mcl->mdls =NULL ; + } }static void close_mcl (struct mcap_mcl *mcl,gboolean save)
@@ -593,20 +703,155 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)bacpy (addr, &mcl->addr); } +static void process_md_create_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd, +uint32_t len) +{ +mcap_md_create_mdl_req *req; +struct mcap_mdl *mdl; +uint16_t mdl_id; +uint8_t mdep_id; +uint8_t cfga, conf; +uint8_t rsp; + +if (len !=sizeof (mcap_md_create_mdl_req)) { +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP , +MCAP_INVALID_PARAM_VALUE , +MCAP_MDLID_RESERVED , +NULL ,0 ); +return ; + } + + req = (mcap_md_create_mdl_req *)cmd; + + mdl_id =ntohs (req->mdl); +if (mdl_id <MCAP_MDLID_INITIAL || mdl_id >MCAP_MDLID_FINAL ) { +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP ,MCAP_INVALID_MDL , + mdl_id,NULL ,0 ); +return ; + } + + mdep_id = req->mdep; +if (mdep_id >MCAP_MDEPID_FINAL ) { +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP ,MCAP_INVALID_MDEP , + mdl_id,NULL ,0 ); +return ; + } + + 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 */ +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP ,MCAP_MDL_BUSY , + mdl_id,NULL ,0 ); +return ; + } + + cfga = conf = req->conf; +/* Callback to upper layer */ + rsp = mcl->cb->mdl_conn_req (mcl, mdep_id, mdl_id, &conf, + mcl->cb->user_data); +if (mcl->state ==MCL_IDLE ) { +/* MCL has been closed int the callback */ +return ; + } + +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 */ +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP , +MCAP_UNSPECIFIED_ERROR , mdl_id,NULL ,0 ); +return ; + } +if (rsp !=MCAP_SUCCESS ) { +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP , rsp, mdl_id, +NULL ,0 ); +return ; + } + +if (!mdl) { + mdl =g_malloc0 (sizeof (struct mcap_mdl )); + mdl->mcl = mcl; + mdl->mdlid = mdl_id; + mcl->mdls =g_slist_insert_sorted (mcl->mdls, 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 */ +shutdown_mdl (mdl); + } + + mdl->mdep_id = mdep_id; + mdl->state =MDL_WAITING ; + + mcl->state =MCL_PENDING ; +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP ,MCAP_SUCCESS , mdl_id, + &conf,1 ); +} + +static void process_md_reconnect_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd, +uint32_t len) +{ +/* TODO: Implement process_md_reconnect_mdl_req */ +} + +static void process_md_abort_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd, +uint32_t len) +{ +/* TODO: Implement process_md_abort_mdl_req */ +} + +static void process_md_delete_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd, +uint32_t len) +{ +/* TODO: Implement process_md_delete_mdl_req */ +} + +static void invalid_req_state (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) +{ +/* TODO: Implements invalid_req_state */ +} +/* Function used to process commands depending of MCL state */ static void proc_req_connected (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement proc_req_connected */ +switch (cmd[0 ]) { +case MCAP_MD_CREATE_MDL_REQ : +process_md_create_mdl_req (mcl, cmd, len); +break ; +case MCAP_MD_RECONNECT_MDL_REQ : +process_md_reconnect_mdl_req (mcl, cmd, len); +break ; +case MCAP_MD_DELETE_MDL_REQ : +process_md_delete_mdl_req (mcl, cmd, len); +break ; +default : +invalid_req_state (mcl, cmd, len); + } }static void proc_req_pending (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement proc_req_pending */ +if (cmd[0 ] ==MCAP_MD_ABORT_MDL_REQ ) +process_md_abort_mdl_req (mcl, cmd, len); +else +invalid_req_state (mcl, cmd, len); }static void proc_req_active (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement proc_req_active */ +switch (cmd[0 ]) { +case MCAP_MD_CREATE_MDL_REQ : +process_md_create_mdl_req (mcl, cmd, len); +break ; +case MCAP_MD_RECONNECT_MDL_REQ : +process_md_reconnect_mdl_req (mcl, cmd, len); +break ; +case MCAP_MD_DELETE_MDL_REQ : +process_md_delete_mdl_req (mcl, cmd, len); +break ; +default : +invalid_req_state (mcl, cmd, len); + } }static void proc_response (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len)
health/mcap.h +5 -0
@@ -74,6 +74,11 @@ extern "C" {#define MCAP_MDLID_FINAL 0xFEFF#define MCAP_ALL_MDLIDS 0xFFFF +/* MDEP IDs */ +#define MCAP_MDEPID_INITIAL 0x00 +#define MCAP_MDEPID_FINAL 0x7F + +/* * MCAP Request Packet Format */
Signature · 1 line
1.7.0.4
PATCH 8/16 Process MCAP response mcap_md_create_mdl_rsp
--- health/mcap.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 6 ++ 2 files changed, 200 insertions(+), 1 deletions(-)
health/mcap.c +194 -1
@@ -126,6 +126,38 @@ static void set_default_cb(struct mcap_mcl *mcl) mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; } +static char *error2str (uint8_t rc) +{ +switch (rc) { +case MCAP_SUCCESS : +return "Success" ; +case MCAP_INVALID_OP_CODE : +return "Invalid Op Code" ; +case MCAP_INVALID_PARAM_VALUE : +return "Invalid Parameter Value" ; +case MCAP_INVALID_MDEP : +return "Invalid MDEP" ; +case MCAP_MDEP_BUSY : +return "MDEP Busy" ; +case MCAP_INVALID_MDL : +return "Invalid MDL" ; +case MCAP_MDL_BUSY : +return "MDL Busy" ; +case MCAP_INVALID_OPERATION : +return "Invalid Operation" ; +case MCAP_RESOURCE_UNAVAILABLE : +return "Resource Unavailable" ; +case MCAP_UNSPECIFIED_ERROR : +return "Unspecified Error" ; +case MCAP_REQUEST_NOT_SUPPORTED : +return "Request Not Supported" ; +case MCAP_CONFIGURATION_REJECTED : +return "Configuration Rejected" ; +default : +return "Unknown Response Code" ; + } +} +static void mcap_send_std_opcode (struct mcap_mcl *mcl,void *cmd,uint32_t size,GError **err) {
@@ -854,9 +886,170 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) } } +/* Function used to process replies */ +static gboolean check_err_rsp (struct mcap_mcl *mcl,uint8_t *cmd, +uint32_t rlen,uint32_t len,GError **gerr) +{ +mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; +gint err =MCAP_ERROR_FAILED ; +gboolean close = FALSE; +uint16_t rmdl, smdl; +mcap_rsp *rsp; +char *msg; + +if (cmd[0 ] ==MCAP_ERROR_RSP ) { + msg ="MCAP_ERROR_RSP received" ; + close = TRUE; + goto fail; + } + +/* Check if the response matches with the last request */ +if (rlen <sizeof (mcap_rsp) || (mcl->lcmd[0 ] +1 ) != cmd[0 ]) { + msg ="Protocol error" ; + close = TRUE; + goto fail; + } + +if (rlen < len) { + msg ="Protocol error" ; + close = TRUE; + goto fail; + } + + rsp = (mcap_rsp *)cmd; + smdl =ntohs (cmdlast->mdl); + rmdl =ntohs (rsp->mdl); +if (rmdl != smdl) { + msg ="MDLID received doesn't match with MDLID sent" ; + close = TRUE; + goto fail; + } + +if (rsp->rc ==MCAP_REQUEST_NOT_SUPPORTED ) { + msg ="Remote does not support opcodes" ; + mcl->ctrl &= ~MCAP_CTRL_STD_OP ; + goto fail; + } + +if (rsp->rc ==MCAP_UNSPECIFIED_ERROR ) { + msg ="Unspecified error" ; + close = TRUE; + goto fail; + } + +if (rsp->rc !=MCAP_SUCCESS ) { + msg =error2str (rsp->rc); + err = rsp->rc; + goto fail; + } + +return FALSE; + +fail: +g_set_error (gerr,MCAP_ERROR , err,"%s" , msg); +return close; +} + +static gboolean process_md_create_mdl_rsp (struct mcap_mcl *mcl, +uint8_t *cmd,uint32_t len) +{ +mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *)mcl->lcmd; +struct mcap_mdl_op_cb *conn = mcl->priv_data; +mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf; +gpointer user_data = conn->user_data; +struct mcap_mdl *mdl = conn->mdl; +uint8_t conf = cmdlast->conf; +gboolean close = FALSE; +GError *gerr =NULL ; +uint8_t *param; + +g_free (mcl->priv_data); + mcl->priv_data =NULL ; + + close =check_err_rsp (mcl, cmd, len,sizeof (mcap_rsp) +1 , &gerr); +g_free (mcl->lcmd); + mcl->lcmd =NULL ; + mcl->req =MCL_AVAILABLE ; + +if (gerr) + goto fail; + +if (len <sizeof (mcap_rsp)) { +g_set_error (&gerr,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Protocol error" ); + close = TRUE; + goto fail; + } + + param = cmd +sizeof (mcap_rsp); +/* Check if preferences changed */ +if (conf !=0x00 && *param != conf) { +g_set_error (&gerr,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Configuration changed" ); + close = TRUE; + goto fail; + } + +connect_cb (mdl, *param, gerr, user_data); +return close; +fail: +connect_cb (NULL ,0 , gerr, user_data); + mcl->mdls =g_slist_remove (mcl->mdls, mdl); +g_free (mdl); +g_error_free (gerr); +update_mcl_state (mcl); +return close; +} + +static gboolean process_md_reconnect_mdl_rsp (struct mcap_mcl *mcl, +uint8_t *cmd,uint32_t len) +{ +/* TODO: Implement process_md_reconnect_mdl_rsp */ +return TRUE; +} + +static gboolean process_md_abort_mdl_rsp (struct mcap_mcl *mcl, +uint8_t *cmd,uint32_t len) +{ +/* TODO: Implement process_md_abort_mdl_rsp */ +return TRUE; +} + +static gboolean process_md_delete_mdl_rsp (struct mcap_mcl *mcl,uint8_t *cmd, +uint32_t len) +{ +/* TODO: Implement process_md_delete_mdl_rsp */ +return TRUE; +} +static void proc_response (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement proc_response */ +gboolean close; +RELEASE_TIMER (mcl); + +switch (mcl->lcmd[0 ] +1 ) { +case MCAP_MD_CREATE_MDL_RSP : + close =process_md_create_mdl_rsp (mcl, cmd, len); +break ; +case MCAP_MD_RECONNECT_MDL_RSP : + close =process_md_reconnect_mdl_rsp (mcl, cmd, len); +break ; +case MCAP_MD_ABORT_MDL_RSP : + close =process_md_abort_mdl_rsp (mcl, cmd, len); +break ; +case MCAP_MD_DELETE_MDL_RSP : + close =process_md_delete_mdl_rsp (mcl, cmd, len); +break ; +default : +DBG ("Unknown cmd response received (op code = %d)" ,cmd[0 ]); + close = TRUE; +break ; + } + +if (close) { + mcl->ms->mcl_disconnected_cb (mcl, mcl->ms->user_data); +mcap_cache_mcl (mcl); + } }static void proc_cmd (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len)
health/mcap.h +6 -0
@@ -90,6 +90,12 @@ typedef struct {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 */
Signature · 1 line
1.7.0.4
PATCH 9/16 Implement connection of MCAP data links (MDL's)
--- health/mcap.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 6 ++ 2 files changed, 137 insertions(+), 1 deletions(-)
health/mcap.c +131 -1
@@ -1097,6 +1097,87 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) proc_req[mcl->state](mcl, cmd, len); } +static gboolean mdl_event_cb (GIOChannel *chan,GIOCondition cond,gpointer data) +{ + +struct mcap_mdl *mdl = data; +gboolean notify; + +DBG ("Close MDL %d" , mdl->mdlid); + + notify = (mdl->state ==MDL_CONNECTED ); +shutdown_mdl (mdl); + +update_mcl_state (mdl->mcl); + +if (notify) { +/*Callback to upper layer */ + mdl->mcl->cb->mdl_closed (mdl, mdl->mcl->cb->user_data); + } + +return FALSE; +} + +static void mcap_connect_mdl_cb (GIOChannel *chan,GError *conn_err, +gpointer data) +{ +struct mcap_mdl_op_cb *con = data; +struct mcap_mdl *mdl = con->mdl; +mcap_mdl_operation_cb cb = con->cb.op; +gpointer user_data = con->user_data; + +g_free (con); +DBG ("mdl connect callback" ); + +if (conn_err) { +DBG ("ERROR: mdl connect callback" ); + mdl->state =MDL_CLOSED ; +g_io_channel_unref (mdl->dc); + mdl->dc =NULL ; +cb (mdl, conn_err, user_data); +return ; + } + + mdl->state =MDL_CONNECTED ; + mdl->wid =g_io_add_watch (mdl->dc,G_IO_ERR |G_IO_HUP |G_IO_NVAL , + (GIOFunc ) mdl_event_cb, mdl); + +cb (mdl, conn_err, user_data); +} + +void mcap_connect_mdl (struct mcap_mdl *mdl,BtIOType BtType,uint16_t dcpsm, +mcap_mdl_operation_cb connect_cb,gpointer user_data,GError **err) +{ +struct mcap_mdl_op_cb *con; + +if (mdl->state !=MDL_WAITING ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_INVALID_MDL , +"%s" ,error2str (MCAP_INVALID_MDL )); +return ; + } + + con = g_new0(struct mcap_mdl_op_cb, 1); + con->mdl = mdl; + con->cb.op = connect_cb; + con->user_data = user_data; + +/* TODO: Check if BtIOType is ERTM or Streaming before continue */ + + mdl->dc =bt_io_connect (BtType, mcap_connect_mdl_cb, con, +NULL , err, +BT_IO_OPT_SOURCE_BDADDR , &mdl->mcl->ms->src, +BT_IO_OPT_DEST_BDADDR , &mdl->mcl->addr, +BT_IO_OPT_PSM , dcpsm, +BT_IO_OPT_MTU ,MCAP_DC_MTU , +BT_IO_OPT_SEC_LEVEL , mdl->mcl->ms->sec, +BT_IO_OPT_INVALID ); +if (*err) { +DBG ("MDL Connection error" ); + mdl->state =MDL_CLOSED ; +g_free (con); + } +} +static gboolean mcl_control_cb (GIOChannel *chan,GIOCondition cond,gpointer data) {
@@ -1191,6 +1272,21 @@ static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err, } } +static void connect_dc_event_cb (GIOChannel *chan,GError *err, +gpointer user_data) +{ +struct mcap_mdl *mdl = user_data; +struct mcap_mcl *mcl = mdl->mcl; + + mdl->state =MDL_CONNECTED ; + mdl->dc =g_io_channel_ref (chan); + mdl->wid =g_io_add_watch (mdl->dc,G_IO_ERR |G_IO_HUP |G_IO_NVAL , + (GIOFunc ) mdl_event_cb, mdl); + + mcl->state =MCL_ACTIVE ; + mcl->cb->mdl_connected (mdl, mcl->cb->user_data); +} + void mcap_create_mcl(struct mcap_instance *ms, const bdaddr_t *addr, uint16_t ccpsm,
@@ -1244,7 +1340,41 @@ void mcap_create_mcl(struct mcap_instance *ms,static void confirm_dc_event_cb (GIOChannel *chan,gpointer user_data) { -/* TODO: implement confirm_dc_event_cb */ +struct mcap_instance *ms = user_data; +struct mcap_mcl *mcl; +struct mcap_mdl *mdl; +GError *err =NULL ; +bdaddr_t dst; +GSList *l; + +bt_io_get (chan,BT_IO_L2CAP , &err, +BT_IO_OPT_DEST_BDADDR , &dst, +BT_IO_OPT_INVALID ); +if (err) { +error ("%s" , err->message); +g_error_free (err); + goto drop; + } + + mcl =find_mcl (ms->mcls, &dst); +if (!mcl || mcl->state !=MCL_PENDING ) + goto drop; + +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; +if (mdl->state ==MDL_WAITING ) { +if (!bt_io_accept (chan, connect_dc_event_cb, mdl,NULL , + &err)) { +error ("MDL accept error %s" , err->message); + mdl->state =MDL_CLOSED ; +g_error_free (err); + goto drop; + } +return ; + } + } +drop: +g_io_channel_shutdown (chan, TRUE,NULL ); } static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
health/mcap_lib.h +6 -0
@@ -104,6 +104,12 @@ void mcap_create_mdl(struct mcap_mcl *mcl,mcap_mdl_operation_conf_cb connect_cb, gpointer user_data, GError **err); +void mcap_connect_mdl (struct mcap_mdl *mdl, +BtIOType BtType, +uint16_t dcpsm, +mcap_mdl_operation_cb connect_cb, +gpointer user_data, +GError **err);/* Mcl operations*/
Signature · 1 line
1.7.0.4
PATCH 10/16 Process MCAP process_md_abort_mdl request and response commands
--- health/mcap.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 4 ++ 2 files changed, 117 insertions(+), 3 deletions(-)
health/mcap.c +113 -3
@@ -365,6 +365,18 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)return 0 ; } +static mcap_md_req *create_req (uint8_t op,uint16_t mdl_id) +{ +mcap_md_req *req_cmd; + + req_cmd =g_malloc0 (sizeof (mcap_md_req)); + + req_cmd->op = op; + req_cmd->mdl =htons (mdl_id); + +return req_cmd; +} +static mcap_md_create_mdl_req *create_mdl_req (uint16_t mdl_id,uint8_t mdep,uint8_t conf) {
@@ -459,6 +471,38 @@ void mcap_create_mdl(struct mcap_mcl *mcl, mcl); } +void mcap_mdl_abort (struct mcap_mdl *mdl,mcap_mdl_notify_cb abort_cb, +gpointer user_data,GError **err) +{ +struct mcap_mdl_op_cb *con; +struct mcap_mcl *mcl = mdl->mcl; +mcap_md_req *cmd; + +if (mdl->state !=MDL_WAITING ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Mdl in invalid state" ); +return ; + } + + con = g_new0(struct mcap_mdl_op_cb, 1); + cmd =create_req (MCAP_MD_ABORT_MDL_REQ , mdl->mdlid); +mcap_send_std_opcode (mcl, cmd,sizeof (mcap_md_req), err); +if (*err) { +g_free (con); +g_free (cmd); +return ; + } + + con->mdl = mdl; + con->cb.notify = abort_cb; + con->user_data = user_data; + + mcl->priv_data = con; + + mcl->tid =g_timeout_add_seconds (RESPONSE_TIMER , wait_response_timer, + mcl); +} +static struct mcap_mcl *find_mcl (GSList *list,const bdaddr_t *addr) {GSList *l;
@@ -829,7 +873,45 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,static void process_md_abort_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement process_md_abort_mdl_req */ +mcap_md_req *req; +GSList *l; +struct mcap_mdl *mdl, *abrt; +uint16_t mdl_id; + +if (len !=sizeof (mcap_md_req)) { +mcap_send_cmd (mcl,MCAP_MD_ABORT_MDL_RSP , +MCAP_INVALID_PARAM_VALUE ,MCAP_MDLID_RESERVED ,NULL ,0 ); +return ; + } + + req = (mcap_md_req *)cmd; + mdl_id =ntohs (req->mdl); + mcl->state =MCL_CONNECTED ; +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; +if (mdl_id == mdl->mdlid && mdl->state ==MDL_WAITING ) { + abrt = mdl; +if (mcl->state !=MCL_CONNECTED ) +break ; +continue ; + } +if (mdl->state ==MDL_CONNECTED && mcl->state !=MCL_ACTIVE ) + mcl->state =MCL_ACTIVE ; + +if (abrt && mcl->state ==MCL_ACTIVE ) +break ; + } + +if (!abrt) { +mcap_send_cmd (mcl,MCAP_MD_ABORT_MDL_RSP ,MCAP_INVALID_MDL , + mdl_id,NULL ,0 ); +return ; + } + + mcl->cb->mdl_aborted (abrt, mcl->cb->user_data); + abrt->state =MDL_CLOSED ; +mcap_send_cmd (mcl,MCAP_MD_ABORT_MDL_RSP ,MCAP_SUCCESS , mdl_id, +NULL ,0 ); } static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
@@ -1011,8 +1093,36 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,static gboolean process_md_abort_mdl_rsp (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement process_md_abort_mdl_rsp */ -return TRUE; +struct mcap_mdl_op_cb *abrt = mcl->priv_data; +mcap_mdl_notify_cb abrt_cb = abrt->cb.notify; +gpointer user_data = abrt->user_data; +struct mcap_mdl *mdl = abrt->mdl; +mcap_rsp *rsp = (mcap_rsp *)cmd; +GError *gerr =NULL ; +gboolean close = FALSE; + +g_free (mcl->priv_data); + mcl->priv_data =NULL ; + + close =check_err_rsp (mcl, cmd, len,sizeof (mcap_rsp), &gerr); + +g_free (mcl->lcmd); + mcl->lcmd =NULL ; + mcl->req =MCL_AVAILABLE ; + +abrt_cb (gerr, user_data); +shutdown_mdl (mdl); + +if (len >=sizeof (mcap_rsp) && rsp->rc ==MCAP_INVALID_MDL ) { + mcl->mdls =g_slist_remove (mcl->mdls, mdl); +g_free (mdl); + } + +if (!gerr) +g_error_free (gerr); + +update_mcl_state (mcl); +return close; } static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
health/mcap_lib.h +4 -0
@@ -110,6 +110,10 @@ void mcap_connect_mdl(struct mcap_mdl *mdl,mcap_mdl_operation_cb connect_cb, gpointer user_data, GError **err); +void mcap_mdl_abort (struct mcap_mdl *mdl, +mcap_mdl_notify_cb abort_cb, +gpointer user_data, +GError **err);/* Mcl operations*/
Signature · 1 line
1.7.0.4
PATCH 11/16 Process MCAP process_md_reconnect_mdl request and response commands
--- health/mcap.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 4 ++ 2 files changed, 122 insertions(+), 3 deletions(-)
health/mcap.c +118 -3
@@ -471,6 +471,43 @@ void mcap_create_mdl(struct mcap_mcl *mcl, mcl); } +void mcap_reconnect_mdl (struct mcap_mdl *mdl, +mcap_mdl_operation_cb reconnect_cb, +gpointer user_data, +GError **err) +{ +struct mcap_mdl_op_cb *con; +struct mcap_mcl *mcl = mdl->mcl; +mcap_md_req *cmd; + +if (mdl->state !=MDL_CLOSED ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"MDL is not closed" ); +return ; + } + con = g_new0(struct mcap_mdl_op_cb, 1); + + cmd =create_req (MCAP_MD_RECONNECT_MDL_REQ , mdl->mdlid); +mcap_send_std_opcode (mcl, cmd,sizeof (mcap_md_req), err); +if (*err) { +g_free (con); +g_free (cmd); +return ; + } + + mdl->state =MDL_WAITING ; + + con->mdl = mdl; + con->cb.op = reconnect_cb; + con->user_data = user_data; + + mcl->state =MCL_ACTIVE ; + mcl->priv_data = con; + + mcl->tid =g_timeout_add_seconds (RESPONSE_TIMER , wait_response_timer, + mcl); +} +void mcap_mdl_abort (struct mcap_mdl *mdl,mcap_mdl_notify_cb abort_cb,gpointer user_data,GError **err) {
@@ -867,7 +904,53 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,static void process_md_reconnect_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement process_md_reconnect_mdl_req */ +mcap_md_req *req; +struct mcap_mdl *mdl; +uint16_t mdl_id; +uint8_t rsp; + +if (len !=sizeof (mcap_md_req)) { +mcap_send_cmd (mcl,MCAP_MD_RECONNECT_MDL_RSP , +MCAP_INVALID_PARAM_VALUE , +MCAP_MDLID_RESERVED , +NULL ,0 ); +return ; + } + + req = (mcap_md_req *)cmd; + mdl_id =ntohs (req->mdl); + + mdl =get_mdl (mcl, mdl_id); +if (!mdl) { +mcap_send_cmd (mcl,MCAP_MD_RECONNECT_MDL_RSP ,MCAP_INVALID_MDL , + 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 */ +mcap_send_cmd (mcl,MCAP_MD_RECONNECT_MDL_RSP ,MCAP_MDL_BUSY , + mdl_id,NULL ,0 ); +return ; + } + +/* Callback to upper layer */ + rsp = mcl->cb->mdl_reconn_req (mdl, mcl->cb->user_data); +if (mcl->state ==MCL_IDLE ) +return ; + +if (rsp !=MCAP_SUCCESS ) { +mcap_send_cmd (mcl,MCAP_MD_RECONNECT_MDL_RSP , rsp, mdl_id, +NULL ,0 ); +return ; + } + +if (mdl->state ==MDL_CONNECTED ) +shutdown_mdl (mdl); + + mdl->state =MDL_WAITING ; + mcl->state =MCL_PENDING ; +mcap_send_cmd (mcl,MCAP_MD_RECONNECT_MDL_RSP ,MCAP_SUCCESS , mdl_id, +NULL ,0 ); } static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
@@ -1086,8 +1169,40 @@ fail:static gboolean process_md_reconnect_mdl_rsp (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement process_md_reconnect_mdl_rsp */ -return TRUE; +struct mcap_mdl_op_cb *reconn = mcl->priv_data; +mcap_mdl_operation_cb reconn_cb = reconn->cb.op; +gpointer user_data = reconn->user_data; +struct mcap_mdl *mdl = reconn->mdl; +mcap_rsp *rsp = (mcap_rsp *)cmd; +GError *gerr =NULL ; +gboolean close = FALSE; + +g_free (mcl->priv_data); + mcl->priv_data =NULL ; + + close =check_err_rsp (mcl, cmd, len,sizeof (mcap_rsp), &gerr); + +g_free (mcl->lcmd); + mcl->lcmd =NULL ; + mcl->req =MCL_AVAILABLE ; + +reconn_cb (mdl, gerr, user_data); +if (!gerr) +return close; + +g_error_free (gerr); +shutdown_mdl (mdl); +update_mcl_state (mcl); + +if (rsp->rc !=MCAP_INVALID_MDL ) +return close; + +/* Remove cached mdlid */ + mcl->mdls =g_slist_remove (mcl->mdls, mdl); + mcl->cb->mdl_deleted (mdl, mcl->cb->user_data); +g_free (mdl); + +return close; } static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
health/mcap_lib.h +4 -0
@@ -104,6 +104,10 @@ void mcap_create_mdl(struct mcap_mcl *mcl,mcap_mdl_operation_conf_cb connect_cb, gpointer user_data, GError **err); +void mcap_reconnect_mdl (struct mcap_mdl *mdl, +mcap_mdl_operation_cb reconnect_cb, +gpointer user_data, +GError **err); void mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
Signature · 1 line
1.7.0.4
PATCH 12/16 Process MCAP process_md_delete_mdl request and response commands
--- health/mcap.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 8 ++ 2 files changed, 208 insertions(+), 3 deletions(-)
health/mcap.c +200 -3
@@ -508,6 +508,86 @@ void mcap_reconnect_mdl(struct mcap_mdl *mdl, mcl); } +static void send_delete_req (GError **err,struct mcap_mcl *mcl, +struct mcap_mdl_op_cb *con,uint16_t mdlid) +{ +mcap_md_req *cmd; + + cmd =create_req (MCAP_MD_DELETE_MDL_REQ , mdlid); +mcap_send_std_opcode (mcl, cmd,sizeof (mcap_md_req), err); +if (*err) { +g_free (cmd); +return ; + } + + mcl->priv_data = con; + + mcl->tid =g_timeout_add_seconds (RESPONSE_TIMER , wait_response_timer, + mcl); +} + +void mcap_delete_all_mdls (struct mcap_mcl *mcl,mcap_mdl_notify_cb delete_cb, +gpointer user_data,GError **err) +{ +GSList *l; +struct mcap_mdl *mdl; +struct mcap_mdl_op_cb *con; + +DBG ("MCL in state: %d" , mcl->state); +if (!mcl->mdls) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"There are not MDLs created" ); +return ; + } + +for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; +if (mdl->state !=MDL_WAITING ) + mdl->state =MDL_DELETING ; + } + + con = g_new0(struct mcap_mdl_op_cb, 1); + con->mdl =NULL ; + con->cb.notify = delete_cb; + con->user_data = user_data; + +send_delete_req (err, mcl, con,MCAP_ALL_MDLIDS ); +if (*err) +g_free (con); +} + +void mcap_delete_mdl (struct mcap_mdl *mdl,mcap_mdl_notify_cb delete_cb, +gpointer user_data,GError **err) +{ +struct mcap_mcl *mcl= mdl->mcl; +struct mcap_mdl_op_cb *con; +GSList *l; + + l =g_slist_find (mcl->mdls, mdl); + +if (!l) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_INVALID_MDL , +"%s" ,error2str (MCAP_INVALID_MDEP )); +return ; + } + +if (mdl->state ==MDL_WAITING ) { +g_set_error (err,MCAP_ERROR ,MCAP_ERROR_FAILED , +"Mdl is not created" ); +return ; + } + mdl->state =MDL_DELETING ; + + con = g_new0(struct mcap_mdl_op_cb, 1); + con->mdl = mdl; + con->cb.notify = delete_cb; + con->user_data = user_data; + +send_delete_req (err, mcl, con, mdl->mdlid); +if (*err) +g_free (con); +} +void mcap_mdl_abort (struct mcap_mdl *mdl,mcap_mdl_notify_cb abort_cb,gpointer user_data,GError **err) {
@@ -816,6 +896,18 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)bacpy (addr, &mcl->addr); } +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); + +g_free (mdl); +} +static void process_md_create_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) {
@@ -1000,7 +1092,58 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,static void process_md_delete_mdl_req (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement process_md_delete_mdl_req */ +mcap_md_req *req; +struct mcap_mdl *mdl, *aux; +uint16_t mdlid; +gboolean notify; +GSList *l; + +if (len !=sizeof (mcap_md_req)) { +mcap_send_cmd (mcl,MCAP_MD_ABORT_MDL_RSP , +MCAP_INVALID_PARAM_VALUE ,MCAP_MDLID_RESERVED ,NULL ,0 ); +return ; + } + + req = (mcap_md_req *)cmd; + mdlid =ntohs (req->mdl); +if (mdlid ==MCAP_ALL_MDLIDS ) { + notify = FALSE; +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; + } + +if (mdlid <MCAP_MDLID_INITIAL || mdlid >MCAP_MDLID_FINAL ) { +mcap_send_cmd (mcl,MCAP_MD_CREATE_MDL_RSP ,MCAP_INVALID_MDL , + mdlid,NULL ,0 ); +return ; + } + +for (l = mcl->mdls, mdl =NULL ; l; l = l->next) { + aux = l->data; +if (aux->mdlid == mdlid) { + mdl = aux; +break ; + } + } + +if (!mdl || mdl->state ==MDL_WAITING ) { +mcap_send_cmd (mcl,MCAP_MD_DELETE_MDL_RSP ,MCAP_INVALID_MDL , + mdlid,NULL ,0 ); +return ; + } + mcl->mdls =g_slist_remove (mcl->mdls, mdl); +update_mcl_state (mcl); + notify = TRUE; +mcap_del_mdl (mdl, ¬ify); + +resp: +mcap_send_cmd (mcl,MCAP_MD_DELETE_MDL_RSP ,MCAP_SUCCESS , mdlid, +NULL ,0 ); }static void invalid_req_state (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len)
@@ -1240,11 +1383,65 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,return close; } +static void restore_mdl (gpointer elem,gpointer data) +{ +struct mcap_mdl *mdl = elem; + +if (mdl->state ==MDL_DELETING ) { +if (mdl->dc) + mdl->state =MDL_CONNECTED ; +else + mdl->state =MDL_CLOSED ; + }else if (mdl->state ==MDL_CLOSED ) + mdl->mcl->cb->mdl_closed (mdl, mdl->mcl->cb->user_data); +} +static gboolean process_md_delete_mdl_rsp (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implement process_md_delete_mdl_rsp */ -return TRUE; +struct mcap_mdl_op_cb *del = mcl->priv_data; +struct mcap_mdl *mdl = del->mdl; +mcap_mdl_notify_cb deleted_cb = del->cb.notify; +gpointer user_data = del->user_data; +mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; +uint16_t mdlid =ntohs (cmdlast->mdl); +GError *gerr =NULL ; +gboolean close = FALSE; +gboolean notify = FALSE; + +g_free (mcl->priv_data); + mcl->priv_data =NULL ; + + close =check_err_rsp (mcl, cmd, len,sizeof (mcap_rsp), &gerr); + +g_free (mcl->lcmd); + mcl->lcmd =NULL ; + mcl->req =MCL_AVAILABLE ; + +if (gerr) { +if (mdl) +restore_mdl (mdl,NULL ); +else +g_slist_foreach (mcl->mdls, restore_mdl,NULL ); +deleted_cb (gerr, user_data); +g_error_free (gerr); +return close; + } + +if (mdlid ==MCAP_ALL_MDLIDS ) { +g_slist_foreach (mcl->mdls, mcap_del_mdl, ¬ify); +g_slist_free (mcl->mdls); + mcl->mdls =NULL ; + mcl->state =MCL_CONNECTED ; + goto end; + } + + mcl->mdls =g_slist_remove (mcl->mdls, mdl); +update_mcl_state (mcl); +mcap_del_mdl (mdl, ¬ify); +end: +deleted_cb (gerr, user_data); +return close; }static void proc_response (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len)
health/mcap_lib.h +8 -0
@@ -108,6 +108,14 @@ void mcap_reconnect_mdl(struct mcap_mdl *mdl,mcap_mdl_operation_cb reconnect_cb, gpointer user_data, GError **err); +void mcap_delete_all_mdls (struct mcap_mcl *mcl, +mcap_mdl_notify_cb delete_cb, +gpointer user_data, +GError **err); +void mcap_delete_mdl (struct mcap_mdl *mdl, +mcap_mdl_notify_cb delete_cb, +gpointer user_data, +GError **err); void mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
Signature · 1 line
1.7.0.4
PATCH 13/16 Add functions for getting mdl properties
--- health/mcap.c | 16 ++++++++++++++++ health/mcap_lib.h | 3 +++ 2 files changed, 19 insertions(+), 0 deletions(-)
health/mcap.c +16 -0
@@ -635,6 +635,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)return NULL ; } +int mcap_mdl_get_fd (struct mcap_mdl *mdl) +{ +if (!mdl || mdl->state !=MDL_CONNECTED ) +return -ENOTCONN ; + +return g_io_channel_unix_get_fd (mdl->dc); +} + +uint16_t mcap_mdl_get_mdlid (struct mcap_mdl *mdl) +{ +if (!mdl) +return MCAP_MDLID_RESERVED ; + +return mdl->mdlid; +} +static void mcap_free_mdls (struct mcap_mcl *mcl,gboolean save) {GSList *l;
health/mcap_lib.h +3 -0
@@ -127,6 +127,9 @@ void mcap_mdl_abort(struct mcap_mdl *mdl,gpointer user_data, GError **err); +int mcap_mdl_get_fd (struct mcap_mdl *mdl); +uint16_t mcap_mdl_get_mdlid (struct mcap_mdl *mdl); +/* Mcl operations*/ void mcap_create_mcl(struct mcap_instance *ms,
Signature · 1 line
1.6.3.3
PATCH 14/16 Response with invalid operation when an invalid request is received
--- health/mcap.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
health/mcap.c +9 -1
@@ -1164,7 +1164,15 @@ resp:static void invalid_req_state (struct mcap_mcl *mcl,uint8_t *cmd,uint32_t len) { -/* TODO: Implements invalid_req_state */ +uint16_t mdlr; + +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 */ + 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 ); }/* Function used to process commands depending of MCL state */
Signature · 1 line
1.6.3.3
PATCH 15/16 Add version and supported procedures values
--- health/mcap.h | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
health/mcap.h +5 -0
@@ -31,6 +31,11 @@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 L2CAP_DEFAULT_MTU
Signature · 1 line
1.6.3.3
PATCH 16/16 Add initial support for synchronization protocol
--- Makefile.am | 3 +- health/mcap.c | 2 +- health/mcap.h | 38 +++++++++++++++++++++++++++++++ health/mcap_sync.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 health/mcap_sync.c
Makefile.am +2 -1
@@ -171,7 +171,8 @@ endif if MCAP mcap_sources += health/mcap_lib.h health/mcap_internal.h \ - health/mcap.h health/mcap.c + health/mcap.h health/mcap.c \ + health/mcap_sync.c endif builtin_modules += hciops
health/mcap.c +1 -1
@@ -1513,7 +1513,7 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)if (cmd[0 ] >=MCAP_MD_SYNC_CAP_REQ && cmd[0 ] <=MCAP_MD_SYNC_INFO_IND ) { -/* TODO: proc_sync_cmd(mcl, cmd, len);*/ +proc_sync_cmd (mcl, cmd, len);return ; }
health/mcap.h +38 -0
@@ -111,6 +111,44 @@ typedef struct {uint16_t mdl; } __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; +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 { +uint8_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 }
health/mcap_sync.c new file +62 -0
62 lines not on this page · raw message
Signature · 1 line
1.6.3.3
Hi all,
Quoted 5 lines · Wednesday 28 July 2010 10:00:09 Santiago Carot-Nemesio wrote:
Hello,
Next are the patches that we have prepared for MCAP.
Git can be cloned fromgit://gitorious.org/bluez-mcap-hdp/mcap-hdp.gitRegards.
Any comments about this patches?
Regards.