2015-07-21 23:16:33

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 00/15] Introducing Soletta peripheral node-type

Hi,

Sorry for the delay, Soletta is now using kbuild as a build system,
the format of the configuration files changed and a few other changes,
so it was needed some time for the dust to settle.

Changes from the RFC:
- Added a README;
- Added a sample Makefile for building an binary implementing the
behaviour expressed in the .fbp file;


Cheers,

Vinicius Costa Gomes (15):
build: Add configure-time checks for soletta
shared: Add a mainloop implementation using soletta
peripheral/gatt: Fix usage of mainloop_ functions
peripheral/gatt: Add a way to external services to register services
peripheral/gap: Fix missing includes
peripheral/gap: Init the gatt_server
peripheral: Disable support for static random addresses
peripheral/gap: Set the discoverable flag in the advertising
peripheral/gatt: Use LOW security level
soletta/heartrate: Add a node-type for the Heartrate profile
.gitignore: Ignore soletta generated files
build: Add heartrate soletta node type to the build system
soletta: Add a sample flow using the heartrate node
peripheral: Add a README for the Soletta support
peripheral: Add a Makefile for building a binary using soletta

.gitignore | 5 +
Makefile.am | 8 +-
Makefile.tools | 20 ++
configure.ac | 38 ++++
peripheral/gap.c | 12 +-
peripheral/gatt.c | 124 +++++++++---
peripheral/gatt.h | 6 +
peripheral/soletta/Makefile | 22 +++
peripheral/soletta/README | 140 +++++++++++++
peripheral/soletta/heartrate-genspec.json | 31 +++
peripheral/soletta/heartrate.c | 270 +++++++++++++++++++++++++
peripheral/soletta/heartrate.fbp | 1 +
peripheral/soletta/sol-flow.json | 8 +
src/shared/io-soletta.c | 317 ++++++++++++++++++++++++++++++
src/shared/timeout-soletta.c | 111 +++++++++++
15 files changed, 1078 insertions(+), 35 deletions(-)
create mode 100644 peripheral/soletta/Makefile
create mode 100644 peripheral/soletta/README
create mode 100644 peripheral/soletta/heartrate-genspec.json
create mode 100644 peripheral/soletta/heartrate.c
create mode 100644 peripheral/soletta/heartrate.fbp
create mode 100644 peripheral/soletta/sol-flow.json
create mode 100644 src/shared/io-soletta.c
create mode 100644 src/shared/timeout-soletta.c

--
2.4.6


2015-07-21 23:16:48

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 15/15] peripheral: Add a Makefile for building a binary using soletta

Add a sample Makefile using some of the soletta tools for building a
binary linking with the soletta binary implementing the Heartrate Sensor
profile.
---
peripheral/soletta/Makefile | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 peripheral/soletta/Makefile

diff --git a/peripheral/soletta/Makefile b/peripheral/soletta/Makefile
new file mode 100644
index 0000000..86dbd7d
--- /dev/null
+++ b/peripheral/soletta/Makefile
@@ -0,0 +1,22 @@
+PKG_CONFIG ?= pkg-config
+
+PREFIX=$(shell $(PKG_CONFIG) --variable=prefix soletta)
+DATADIR=$(shell $(PKG_CONFIG) --variable=pkgdatadir soletta)
+SOLETTA_CFLAGS=$(shell $(PKG_CONFIG) --cflags soletta)
+SOLETTA_LDFLAGS=$(shell $(PKG_CONFIG) --libs soletta)
+SOLETTA_INCLUDEDIR=$(shell $(PKG_CONFIG) --variable=includedir soletta)
+
+GENERATOR=$(PREFIX)/bin/sol-fbp-generator
+
+all: soletta-init main.c
+
+main.c: sol-flow.json heartrate.json heartrate.fbp
+ $(GENERATOR) -c sol-flow.json -j heartrate.json -j $(DATADIR)/flow/descriptions/timer.json heartrate.fbp $@
+
+soletta-init: main.c
+ $(CC) $(CFLAGS) -Os -o $@ $< .libs/heartrate.a $(SOLETTA_CFLAGS) -include $(SOLETTA_INCLUDEDIR)/soletta/timer-gen.h -include heartrate-gen.h $(SOLETTA_LDFLAGS)
+
+clean:
+ @rm main.c soletta-init
+
+.PHONY: clean
--
2.4.6


2015-07-21 23:16:47

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 14/15] peripheral: Add a README for the Soletta support

This gives an overview about what is Soletta, what is gained by having
this support in the BlueZ tree and how to build and use it.
---
peripheral/soletta/README | 140 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 140 insertions(+)
create mode 100644 peripheral/soletta/README

diff --git a/peripheral/soletta/README b/peripheral/soletta/README
new file mode 100644
index 0000000..a11df63
--- /dev/null
+++ b/peripheral/soletta/README
@@ -0,0 +1,140 @@
+Bluetooth node types for Soletta
+********************************
+
+Soletta
+=======
+
+From the Soletta project github[1] repository:
+
+"Soletta Project is a framework for making IoT devices. With Soletta
+Project's libraries developers can easily write software for devices
+that control actuators/sensors and communicate using standard
+technologies. It enables adding smartness even on the smallest edge
+devices."
+
+Soletta support in BlueZ will provide node types for common Bluetooth
+profiles, so applications written for Soletta may target devices
+running BlueZ.
+
+
+Build requirements
+------------------
+
+- GLib
+
+- python-jsonschema (Used for validating JSON files, for code
+ generation and providing meta-data about node types)
+
+- chrpath
+
+
+Building Soletta
+----------------
+
+Soletta uses kconfig as build system, the default config is enough for
+the purposes of building an external module. From the soletta project
+root directory:
+
+$ make alldefconfig
+
+(It will complain if the required dependencies aren't found)
+
+If you run:
+
+$ make menuconfig
+
+Then the configuration can be tweaked for different objectives, for
+example, changing 'Core library -> Target platform' to linux-micro and
+'Core library -> Mainloop' to posix, would make the resulting soletta
+library more adequate for building self contained applications.
+
+After Soletta is configured, the usual incantations for building and
+installing:
+
+$ make
+
+$ make install
+
+
+Bluetooth LE peripheral support for Soletta
+===========================================
+
+LE peripheral use cases mainly target low power devices, potentially
+coin cell operated, so running Linux on these devices is not usually
+adequate for production devices. But when developing applications,
+having all the development/debug tools available for Linux on hand is
+valuable.
+
+What is possible is to develop the application using Soletta node
+nodes on Linux (or linux-micro), and when the application is feature
+complete, target the final device.
+
+
+Building
+--------
+
+Soletta support is activated by the '--enable-soletta' option
+(protected by the --enable-experimental flag) to the configure step
+when building BlueZ. For buildind an static version of the library,
+pass '--enable-static'. For example, from BlueZ root directory:
+
+$ ./bootstrap
+
+$ ./configure --prefix=/usr --enable-experimental --enable-soletta --enable-static
+
+('--enable-static' enables building static version of the libraries as
+well, this makes it easier building a standalone binary, see the last
+section.)
+
+$ make
+
+$ make install
+
+The install step is necessary so the node types (and its associated
+meta-data) are installed where the soletta tools can find them.
+
+
+Running
+-------
+
+After building and installing BlueZ, go to the 'peripheral/soletta'
+directory and do:
+
+$ sol-fbp-runner heartrate.fbp
+
+You may need super user privileges to properly register the Heartrate service.
+
+The content of the 'heartrate.fbp' file should be similar to this:
+
+"""
+Timer(timer:interval=1000) OUT -> IN Heartrate(heartrate)
+"""
+
+It should read like this, create a node of type 'timer' with the
+'interval' option set to '1000' and name it 'Timer', then connect
+'Timer' 'OUT' port to the 'IN' port of the node named 'Heartrate' of
+type 'heartrate'.
+
+
+Standalone binary
+-----------------
+
+Also in the 'peripheral/soletta' there is a sample 'Makefile'
+demonstrating how you would build an executable using the soletta
+tools.
+
+Building an completely static binary is easier accomplished when using
+the musl[2] libc, and it is left as an exercise.
+
+
+Supported Profiles
+==================
+
+Profile name node type name
+------------------------------------------------------
+Heartrate Sensor heartrate
+
+
+[1] https://github.com/solettaproject/soletta
+
+[2] http://www.musl-libc.org/
\ No newline at end of file
--
2.4.6


2015-07-21 23:16:46

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 13/15] soletta: Add a sample flow using the heartrate node

The flow and associated conffile, defines a very simple flow using the
heartrate node.

With soletta already installed you just run it, something like this:

$ sol-fbp-runner heartrate.fbp

It will look for the sol-flow.conf (which would define options for the
nodes) in the current directory.
---
peripheral/soletta/heartrate.fbp | 1 +
peripheral/soletta/sol-flow.json | 8 ++++++++
2 files changed, 9 insertions(+)
create mode 100644 peripheral/soletta/heartrate.fbp
create mode 100644 peripheral/soletta/sol-flow.json

diff --git a/peripheral/soletta/heartrate.fbp b/peripheral/soletta/heartrate.fbp
new file mode 100644
index 0000000..63185c4
--- /dev/null
+++ b/peripheral/soletta/heartrate.fbp
@@ -0,0 +1 @@
+Timer(timer:interval=1000) OUT -> IN Heartrate(heartrate)
diff --git a/peripheral/soletta/sol-flow.json b/peripheral/soletta/sol-flow.json
new file mode 100644
index 0000000..c1f8fca
--- /dev/null
+++ b/peripheral/soletta/sol-flow.json
@@ -0,0 +1,8 @@
+{
+ "nodetypes": [
+ {
+ "name": "Heartrate",
+ "type": "heartrate"
+ }
+ ]
+}
--
2.4.6


2015-07-21 23:16:45

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 12/15] build: Add heartrate soletta node type to the build system

---
Makefile.tools | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/Makefile.tools b/Makefile.tools
index 1899fcb..4e5d645 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -73,6 +73,26 @@ peripheral_btsensor_SOURCES = peripheral/main.c \
peripheral_btsensor_LDADD = src/libshared-mainloop.la \
lib/libbluetooth-internal.la

+if SOLETTA
+soletta_descdir = @SOLETTA_DESCDIR@/flow/descriptions/
+soletta_desc_DATA = peripheral/soletta/heartrate.json
+solettamodulesdir = @SOLETTA_MODULESDIR@/flow
+solettamodules_LTLIBRARIES = peripheral/soletta/heartrate.la
+peripheral_soletta_heartrate_la_SOURCES = peripheral/soletta/heartrate.c peripheral/gap.h peripheral/gap.c \
+ peripheral/gatt.h peripheral/gatt.c
+peripheral_soletta_heartrate_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version
+peripheral_soletta_heartrate_la_LIBADD = src/libshared-soletta.la \
+ lib/libbluetooth-internal.la \
+ @SOLETTA_LIBS@
+peripheral_soletta_heartrate_la_CFLAGS = $(AM_CFLAGS) @SOLETTA_CFLAGS@ -DSOL_FLOW_NODE_TYPE_MODULE_EXTERNAL
+
+peripheral/soletta/%-gen.c peripheral/soletta/%-gen.h: peripheral/soletta/heartrate-genspec.json
+ $(AM_V_GEN)$(PYTHON) @SOLETTA_PREFIX@/bin/sol-flow-node-type-gen.py $< peripheral/soletta/$*-gen.h peripheral/soletta/$*-gen.c peripheral/soletta/heartrate.json
+
+BUILT_SOURCES += peripheral/soletta/heartrate-gen.c peripheral/soletta/heartrate-gen.h
+
+endif
+
tools_3dsp_SOURCES = tools/3dsp.c monitor/bt.h
tools_3dsp_LDADD = src/libshared-mainloop.la

--
2.4.6


2015-07-21 23:16:43

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 10/15] soletta/heartrate: Add a node-type for the Heartrate profile

This simple node type exports a node with only a input port that
receives pulses that will be exported via the Heartrate service as beats
per minute.
---
peripheral/soletta/heartrate-genspec.json | 31 ++++
peripheral/soletta/heartrate.c | 270 ++++++++++++++++++++++++++++++
2 files changed, 301 insertions(+)
create mode 100644 peripheral/soletta/heartrate-genspec.json
create mode 100644 peripheral/soletta/heartrate.c

diff --git a/peripheral/soletta/heartrate-genspec.json b/peripheral/soletta/heartrate-genspec.json
new file mode 100644
index 0000000..2b9c90a
--- /dev/null
+++ b/peripheral/soletta/heartrate-genspec.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "http://solettaproject.github.io/soletta/schemas/node-type-genspec.schema",
+ "name": "Bluetooth",
+ "meta": {
+ "author": "Intel Corporation",
+ "version": "1"
+ },
+ "types": [
+ {
+ "category": "output/hw",
+ "description": "Bluetooth Smart Heart Rate Profile server",
+ "in_ports": [
+ {
+ "data_type": "any",
+ "description": "each packet is a beat",
+ "methods": {
+ "process": "heartrate_in_process"
+ },
+ "name": "IN"
+ }
+ ],
+ "methods": {
+ "close": "heartrate_close",
+ "open": "heartrate_open"
+ },
+ "name": "heartrate",
+ "private_data_type": "heartrate_data",
+ "url": "http://soletta.org/doc/latest/node_types/heartrate.html"
+ }
+ ]
+}
diff --git a/peripheral/soletta/heartrate.c b/peripheral/soletta/heartrate.c
new file mode 100644
index 0000000..4f6fbfa
--- /dev/null
+++ b/peripheral/soletta/heartrate.c
@@ -0,0 +1,270 @@
+#include "heartrate-gen.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <bluetooth.h>
+#include <l2cap.h>
+
+#include <uuid.h>
+
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/timeout.h"
+#include "src/shared/util.h"
+
+#include "peripheral/gap.h"
+#include "peripheral/gatt.h"
+
+#include <sol-flow.h>
+#include <sol-log.h>
+
+/* In seconds */
+#define WINDOW_SIZE 5
+
+struct heartrate_data {
+ struct gatt_db_attribute *service;
+ struct queue *to_notify;
+ int notifier;
+ int beats_per_window;
+ unsigned int disconnect_watch;
+ uint16_t handle;
+};
+
+static struct queue *sensors;
+
+static struct gatt_db *gatt_db;
+
+static int heartrate_in_process(struct sol_flow_node *node, void *data,
+ uint16_t port, uint16_t conn_id,
+ const struct sol_flow_packet *packet)
+{
+ struct heartrate_data *hr = data;
+
+ if (queue_isempty(hr->to_notify))
+ return 0;
+
+ hr->beats_per_window++;
+
+ return 0;
+}
+
+static bool bluetooth_init(void)
+{
+ gap_start();
+
+ sensors = queue_new();
+ if (!sensors)
+ return false;
+
+ return true;
+}
+
+static bool match_att(const void *data, const void *match_data) {
+ return data == match_data;
+}
+
+static void ccc_read(struct gatt_db_attribute *attrib, unsigned int id,
+ uint16_t offset, uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct heartrate_data *hr = user_data;
+ uint8_t value[2] = { 0 };
+
+ if (queue_find(hr->to_notify, match_att, att))
+ value[0] = 0x01;
+
+ gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
+}
+
+static void remove_att(void *data, void *user_data)
+{
+ struct heartrate_data *hr = data;
+ struct bt_att *att = user_data;
+
+ if (!queue_find(hr->to_notify, match_att, att))
+ return;
+
+ queue_remove(hr->to_notify, att);
+
+ bt_att_unref(att);
+
+ if (queue_isempty(hr->to_notify)) {
+ timeout_remove(hr->notifier);
+ hr->notifier = -1;
+ }
+}
+
+static void remove_notify_cb(int err, void *user_data)
+{
+ struct bt_att *att = user_data;
+
+ queue_foreach(sensors, remove_att, att);
+}
+
+static bool send_notification(void *user_data)
+{
+ struct heartrate_data *hr = user_data;
+ const struct queue_entry *e;
+ uint8_t pdu[4];
+
+ e = queue_get_entries(hr->to_notify);
+ if (!e)
+ return true;
+
+ put_le16(hr->handle, &pdu[0]);
+
+ pdu[2] = 0x06;
+ pdu[3] = hr->beats_per_window * (60 / WINDOW_SIZE);
+
+ hr->beats_per_window = 0;
+
+ while (e) {
+ struct bt_att *att = e->data;
+ bt_att_send(att, BT_ATT_OP_HANDLE_VAL_NOT, pdu, sizeof(pdu), NULL, NULL, NULL);
+ e = e->next;
+ }
+
+ return true;
+}
+
+static void enable_notification(struct heartrate_data *hr, struct bt_att *att)
+{
+ if (queue_find(hr->to_notify, match_att, att)) {
+ return;
+ }
+
+ if (!queue_push_tail(hr->to_notify, bt_att_ref(att))) {
+ bt_att_unref(att);
+ return;
+ }
+
+ hr->disconnect_watch = bt_att_register_disconnect(att, remove_notify_cb, att, NULL);
+
+ if (hr->notifier != -1)
+ return;
+
+ hr->notifier = timeout_add(WINDOW_SIZE * 1000, send_notification, hr, NULL);
+}
+
+static void disable_notification(struct heartrate_data *hr, struct bt_att *att)
+{
+ if (!queue_remove(hr->to_notify, att))
+ return;
+
+ bt_att_unref(att);
+
+ if (queue_isempty(hr->to_notify)) {
+ timeout_remove(hr->notifier);
+ hr->notifier = -1;
+ }
+}
+
+static void ccc_write(struct gatt_db_attribute *attrib, unsigned int id,
+ uint16_t offset, const uint8_t *value, size_t len,
+ uint8_t opcode, struct bt_att *att, void *user_data)
+{
+ struct heartrate_data *hr = user_data;
+ uint8_t ecode = 0;
+
+ if (!value || len != 2) {
+ ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+ goto done;
+ }
+
+ if (offset) {
+ ecode = BT_ATT_ERROR_INVALID_OFFSET;
+ goto done;
+ }
+
+ if (value[0] == 0x01)
+ enable_notification(hr, att);
+ else if (value[0] == 0x00)
+ disable_notification(hr, att);
+
+done:
+ gatt_db_attribute_write_result(attrib, id, ecode);
+}
+
+static void heartrate_register(struct gatt_db *db, void *user_data)
+{
+ struct heartrate_data *hr = user_data;
+ struct gatt_db_attribute *service, *chr;
+ bt_uuid_t uuid;
+
+ gatt_db = gatt_db_ref(db);
+
+ bt_uuid16_create(&uuid, 0x180d);
+
+ service = gatt_db_add_service(gatt_db, &uuid, true, 6);
+
+ /* Heart Rate Measurement characteristic */
+ bt_uuid16_create(&uuid, 0x2a37);
+ chr = gatt_db_service_add_characteristic(service, &uuid,
+ BT_ATT_PERM_NONE,
+ BT_GATT_CHRC_PROP_NOTIFY,
+ NULL, NULL, NULL);
+ hr->handle = gatt_db_attribute_get_handle(chr);
+
+ /* Heart Rate CCC descriptor */
+ bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ gatt_db_service_add_descriptor(chr, &uuid,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ ccc_read, ccc_write, hr);
+
+ hr->service = service;
+
+ gatt_db_service_set_active(service, true);
+}
+
+static int heartrate_open(struct sol_flow_node *node, void *data,
+ const struct sol_flow_node_options *options)
+{
+ static bool initialized = false;
+ struct heartrate_data *hr = data;
+
+ if (!initialized) {
+ initialized = bluetooth_init();
+
+ if (!initialized) {
+ SOL_WRN("Could not initialize Bluetooth module");
+ return -EINVAL;
+ }
+ }
+
+ /* FIXME: remove when supporting multiple locations */
+ if (!queue_isempty(sensors))
+ return 0;
+
+ hr->to_notify = queue_new();
+ hr->notifier = -1;
+
+ gatt_server_add_service(heartrate_register, hr);
+
+ queue_push_tail(sensors, hr);
+
+ return 0;
+}
+
+static void heartrate_close(struct sol_flow_node *node, void *data)
+{
+ struct heartrate_data *hr = data;
+
+ if (hr->service)
+ gatt_db_remove_service(gatt_db, hr->service);
+
+ hr->service = NULL;
+
+ queue_destroy(hr->to_notify, (queue_destroy_func_t) bt_att_unref);
+
+ if (hr->notifier >= 0)
+ timeout_remove(hr->notifier);
+
+ hr->notifier = -1;
+
+ queue_remove(sensors, hr);
+
+ gatt_db_unref(gatt_db);
+}
+
+#include "heartrate-gen.c"
--
2.4.6


2015-07-21 23:16:44

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 11/15] .gitignore: Ignore soletta generated files

---
.gitignore | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/.gitignore b/.gitignore
index 7c1b7e0..ac705f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -154,6 +154,11 @@ android/test-ipc
android/test-*.log
android/test-*.trs

+peripheral/soletta/heartrate-gen.c
+peripheral/soletta/heartrate-gen.h
+peripheral/soletta/heartrate.json
+peripheral/soletta/main.c
+
cscope.in.out
cscope.out
cscope.po.out
--
2.4.6


2015-07-21 23:16:42

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 09/15] peripheral/gatt: Use LOW security level

Mostly to help testing. And for heartrate, the profile being implemented
in later patches, this is a valid security level for useful use cases.
---
peripheral/gatt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/peripheral/gatt.c b/peripheral/gatt.c
index 0cb4f6d..0b5d5fe 100644
--- a/peripheral/gatt.c
+++ b/peripheral/gatt.c
@@ -134,7 +134,7 @@ static struct gatt_conn *gatt_conn_new(int fd)
bt_att_set_close_on_unref(conn->att, true);
bt_att_register_disconnect(conn->att, gatt_conn_disconnect, conn, NULL);

- bt_att_set_security(conn->att, BT_SECURITY_MEDIUM);
+ bt_att_set_security(conn->att, BT_SECURITY_LOW);

conn->gatt = bt_gatt_server_new(gatt_db, conn->att, mtu);
if (!conn->gatt) {
--
2.4.6


2015-07-21 23:16:41

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 08/15] peripheral/gap: Set the discoverable flag in the advertising

---
peripheral/gap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/peripheral/gap.c b/peripheral/gap.c
index 9c45057..e95394c 100644
--- a/peripheral/gap.c
+++ b/peripheral/gap.c
@@ -98,7 +98,7 @@ static void add_advertising(uint16_t index)
memset(buf, 0, sizeof(*cp) + sizeof(ad));
cp = buf;
cp->instance = 0x01;
- cp->flags = cpu_to_le32((1 << 0) | (1 << 1) | (1 << 4));
+ cp->flags = cpu_to_le32((1 << 0) | (1 << 1) | (1 << 3) | (1 << 4));
cp->duration = cpu_to_le16(0);
cp->timeout = cpu_to_le16(0);
cp->adv_data_len = sizeof(ad);
--
2.4.6


2015-07-21 23:16:40

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 07/15] peripheral: Disable support for static random addresses

This is mostly to make testing easier. I don't have any device which
support this properly.
---
peripheral/gap.c | 2 +-
peripheral/gatt.c | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/peripheral/gap.c b/peripheral/gap.c
index fe65700..9c45057 100644
--- a/peripheral/gap.c
+++ b/peripheral/gap.c
@@ -48,7 +48,7 @@ static bool adv_features = false;
static bool adv_instances = false;
static bool require_connectable = true;

-static uint8_t static_addr[6] = { 0x90, 0x78, 0x56, 0x34, 0x12, 0xc0 };
+static uint8_t static_addr[6] = { 0 };
static uint8_t dev_name[260] = { 0x00, };
static uint8_t dev_name_len = 0;

diff --git a/peripheral/gatt.c b/peripheral/gatt.c
index a859adc..0cb4f6d 100644
--- a/peripheral/gatt.c
+++ b/peripheral/gatt.c
@@ -285,8 +285,7 @@ void gatt_server_start(void)
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
addr.l2_cid = htobs(ATT_CID);
- memcpy(&addr.l2_bdaddr, static_addr, 6);
- addr.l2_bdaddr_type = BDADDR_LE_RANDOM;
+ addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;

if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "Failed to bind ATT server socket: %m\n");
--
2.4.6


2015-07-21 23:16:39

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 06/15] peripheral/gap: Init the gatt_server

This will init the list that will have all the callbacks that will
register the services not part of the core.
---
peripheral/gap.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/peripheral/gap.c b/peripheral/gap.c
index a78dc45..fe65700 100644
--- a/peripheral/gap.c
+++ b/peripheral/gap.c
@@ -535,6 +535,8 @@ void gap_start(void)
return;
}

+ gatt_server_init();
+
if (!mgmt_send(mgmt, MGMT_OP_READ_COMMANDS,
MGMT_INDEX_NONE, 0, NULL,
read_commands_complete, NULL, NULL)) {
--
2.4.6


2015-07-21 23:16:38

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 05/15] peripheral/gap: Fix missing includes

---
peripheral/gap.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/peripheral/gap.c b/peripheral/gap.c
index f659f7f..a78dc45 100644
--- a/peripheral/gap.c
+++ b/peripheral/gap.c
@@ -27,9 +27,15 @@

#include <stdio.h>
#include <string.h>
+#include <stdbool.h>

#include "lib/bluetooth.h"
#include "lib/mgmt.h"
+#include "lib/uuid.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+
#include "src/shared/util.h"
#include "src/shared/mgmt.h"
#include "peripheral/gatt.h"
--
2.4.6


2015-07-21 23:16:37

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 04/15] peripheral/gatt: Add a way to external services to register services

This will allow profiles implemented using the peripheral/ helpers to
register asynchronously their services. This cannot be done directly
because when gatt_service_start() the GATT database doesn't exist yet.
---
peripheral/gatt.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
peripheral/gatt.h | 6 ++++++
2 files changed, 53 insertions(+)

diff --git a/peripheral/gatt.c b/peripheral/gatt.c
index a66292f..a859adc 100644
--- a/peripheral/gatt.c
+++ b/peripheral/gatt.c
@@ -54,6 +54,11 @@ struct gatt_conn {
struct bt_gatt_client *client;
};

+struct service_registerer_data {
+ gatt_service_register_t callback;
+ void *user_data;
+};
+
static struct io *att_io = NULL;
static struct queue *conn_list = NULL;
static struct gatt_db *gatt_db = NULL;
@@ -63,6 +68,8 @@ static uint8_t static_addr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static uint8_t dev_name[20];
static uint8_t dev_name_len = 0;

+static struct queue *registered_services = NULL;
+
void gatt_set_static_address(uint8_t addr[6])
{
memcpy(static_addr, addr, sizeof(static_addr));
@@ -243,6 +250,21 @@ static void populate_devinfo_service(struct gatt_db *db)
gatt_db_service_set_active(service, true);
}

+void gatt_server_init(void)
+{
+ registered_services = queue_new();
+}
+
+static void register_each_service(void *data, void *user_data)
+{
+ struct gatt_db *db = user_data;
+ struct service_registerer_data *registerer = data;
+
+ fprintf(stderr, "registering service %p\n", registerer);
+
+ registerer->callback(db, registerer->user_data);
+}
+
void gatt_server_start(void)
{
struct sockaddr_l2 addr;
@@ -287,6 +309,8 @@ void gatt_server_start(void)
populate_gap_service(gatt_db);
populate_devinfo_service(gatt_db);

+ queue_foreach(registered_services, register_each_service, gatt_db);
+
gatt_cache = gatt_db_new();

conn_list = queue_new();
@@ -323,10 +347,33 @@ void gatt_server_stop(void)

queue_destroy(conn_list, gatt_conn_destroy);

+ queue_destroy(registered_services, free);
+ registered_services = NULL;
+
gatt_db_unref(gatt_cache);
gatt_cache = NULL;

gatt_db_unref(gatt_db);
gatt_db = NULL;
+}
+
+int gatt_server_add_service(gatt_service_register_t callback, void *user_data)
+{
+ struct service_registerer_data *registerer;
+
+ fprintf(stderr, "gatt_server_add_service %p data %p\n", callback, user_data);
+
+ registerer = new0(struct service_registerer_data, 1);
+ if (!registerer)
+ return -ENOMEM;
+
+ registerer->callback = callback;
+ registerer->user_data = user_data;
+
+ if (!queue_push_tail(registered_services, registerer)) {
+ free(registerer);
+ return -ENOMEM;
+ }

+ return 0;
}
diff --git a/peripheral/gatt.h b/peripheral/gatt.h
index 5b68f35..5e16875 100644
--- a/peripheral/gatt.h
+++ b/peripheral/gatt.h
@@ -26,5 +26,11 @@
void gatt_set_static_address(uint8_t addr[6]);
void gatt_set_device_name(uint8_t name[20], uint8_t len);

+void gatt_server_init(void);
+
void gatt_server_start(void);
void gatt_server_stop(void);
+
+typedef void (*gatt_service_register_t)(struct gatt_db *db, void *user_data);
+
+int gatt_server_add_service(gatt_service_register_t callback, void *user_data);
--
2.4.6


2015-07-21 23:16:35

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 02/15] shared: Add a mainloop implementation using soletta

This will allow apps willing to integrate directly with the solleta
mainloop, with no need to implement custom ways (threads and pipes) to
communicate via Bluetooth and send/receive soletta flow packets.
---
Makefile.am | 8 +-
src/shared/io-soletta.c | 317 +++++++++++++++++++++++++++++++++++++++++++
src/shared/timeout-soletta.c | 111 +++++++++++++++
3 files changed, 435 insertions(+), 1 deletion(-)
create mode 100644 src/shared/io-soletta.c
create mode 100644 src/shared/timeout-soletta.c

diff --git a/Makefile.am b/Makefile.am
index 41ace22..7779c1b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -95,7 +95,7 @@ gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \
gdbus/mainloop.c gdbus/watch.c \
gdbus/object.c gdbus/client.c gdbus/polkit.c

-noinst_LTLIBRARIES += src/libshared-glib.la src/libshared-mainloop.la
+noinst_LTLIBRARIES += src/libshared-glib.la src/libshared-mainloop.la src/libshared-soletta.la

shared_sources = src/shared/io.h src/shared/timeout.h \
src/shared/queue.h src/shared/queue.c \
@@ -128,6 +128,12 @@ src_libshared_mainloop_la_SOURCES = $(shared_sources) \
src/shared/io-mainloop.c \
src/shared/timeout-mainloop.c \
src/shared/mainloop.h src/shared/mainloop.c
+if SOLETTA
+src_libshared_soletta_la_SOURCES = $(shared_sources) \
+ src/shared/io-soletta.c \
+ src/shared/timeout-soletta.c
+src_libshared_soletta_la_CFLAGS = $(AM_CFLAGS) @SOLETTA_CFLAGS@
+endif

attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
attrib/gatt.h attrib/gatt.c \
diff --git a/src/shared/io-soletta.c b/src/shared/io-soletta.c
new file mode 100644
index 0000000..3ad66f0
--- /dev/null
+++ b/src/shared/io-soletta.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; 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 <stdio.h> /* FIXME: REMOVE ME */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <sol-mainloop.h>
+
+#include "io.h"
+#include "mainloop.h"
+#include "util.h"
+
+struct io {
+ int fd;
+ int refcount;
+ unsigned int events;
+
+ bool close_on_destroy;
+
+ struct sol_fd *watch;
+
+ io_callback_func_t read_cb;
+ void *read_data;
+
+ io_callback_func_t write_cb;
+ void *write_data;
+
+ io_callback_func_t disconnect_cb;
+ void *disconnect_data;
+
+ io_destroy_func_t read_destroy;
+ io_destroy_func_t write_destroy;
+ io_destroy_func_t disconnect_destroy;
+};
+
+static bool io_event_cb(void *data, int fd, unsigned int events);
+
+static struct io *io_ref(struct io *io)
+{
+ if (!io)
+ return NULL;
+
+ __sync_fetch_and_add(&io->refcount, 1);
+
+ return io;
+}
+
+static void io_unref(struct io *io)
+{
+ if (!io)
+ return;
+
+ if (__sync_sub_and_fetch(&io->refcount, 1))
+ return;
+
+ free(io);
+}
+
+static void reset_io_watch(struct io *io, unsigned int events)
+{
+ if (!io)
+ return;
+
+ if (io->watch) {
+ sol_fd_del(io->watch);
+ io->watch = NULL;
+ }
+
+ if (events)
+ io->watch = sol_fd_add(io->fd, events, io_event_cb, io);
+
+ io->events = events;
+}
+
+static bool io_event_cb(void *data, int fd, unsigned int events)
+{
+ struct io *io = io_ref(data);
+ unsigned int old_events = io->events;
+ bool r = true;
+
+ if ((events & (SOL_FD_FLAGS_HUP | SOL_FD_FLAGS_ERR))) {
+ io->read_cb = NULL;
+ io->write_cb = NULL;
+
+ if (!io->disconnect_cb) {
+ io_destroy(io);
+ return false;
+ }
+
+ if (!io->disconnect_cb(io, io->disconnect_data)) {
+ if (io->disconnect_destroy)
+ io->disconnect_destroy(io->disconnect_data);
+
+ io->disconnect_cb = NULL;
+ io->disconnect_destroy = NULL;
+ io->disconnect_data = NULL;
+
+ io->events &= ~SOL_FD_FLAGS_HUP;
+ }
+
+ io_unref(io);
+ return false;
+ }
+
+ if ((events & SOL_FD_FLAGS_IN) && io->read_cb) {
+ if (!io->read_cb(io, io->read_data)) {
+ if (io->read_destroy)
+ io->read_destroy(io->read_data);
+
+ io->read_cb = NULL;
+ io->read_destroy = NULL;
+ io->read_data = NULL;
+
+ io->events &= ~SOL_FD_FLAGS_IN;
+ }
+ }
+
+ if ((events & SOL_FD_FLAGS_OUT) && io->write_cb) {
+ if (!io->write_cb(io, io->write_data)) {
+ if (io->write_destroy)
+ io->write_destroy(io->write_data);
+
+ io->write_cb = NULL;
+ io->write_destroy = NULL;
+ io->write_data = NULL;
+
+ io->events &= ~SOL_FD_FLAGS_OUT;
+ }
+ }
+
+ if (old_events != io->events)
+ reset_io_watch(io, io->events);
+
+ if (!io->events) {
+ io->watch = NULL;
+ r = false;
+ }
+
+ io_unref(io);
+
+ return r;
+}
+
+struct io *io_new(int fd)
+{
+ struct io *io;
+
+ if (fd < 0)
+ return NULL;
+
+ io = new0(struct io, 1);
+ if (!io)
+ return NULL;
+
+ io->fd = fd;
+
+ return io_ref(io);
+}
+
+void io_destroy(struct io *io)
+{
+ if (!io)
+ return;
+
+ io->read_cb = NULL;
+ io->write_cb = NULL;
+ io->disconnect_cb = NULL;
+
+ sol_fd_del(io->watch);
+ io->watch = NULL;
+
+ io_unref(io);
+}
+
+int io_get_fd(struct io *io)
+{
+ if (!io)
+ return -ENOTCONN;
+
+ return io->fd;
+}
+
+bool io_set_close_on_destroy(struct io *io, bool do_close)
+{
+ if (!io)
+ return false;
+
+ io->close_on_destroy = do_close;
+
+ return true;
+}
+
+ssize_t io_send(struct io *io, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+
+ if (!io || io->fd < 0)
+ return -ENOTCONN;
+
+ do {
+ ret = writev(io->fd, iov, iovcnt);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0)
+ return -errno;
+
+ return ret;
+}
+
+bool io_shutdown(struct io *io)
+{
+ if (!io || io->fd < 0)
+ return false;
+
+ return shutdown(io->fd, SHUT_RDWR) == 0;
+}
+
+bool io_set_read_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy)
+{
+ unsigned int events;
+
+ if (!io || io->fd < 0)
+ return false;
+
+ if (io->read_destroy)
+ io->read_destroy(io->read_data);
+
+ if (callback)
+ events = io->events | SOL_FD_FLAGS_IN;
+ else
+ events = io->events & ~SOL_FD_FLAGS_IN;
+
+ reset_io_watch(io, events);
+
+ io->read_cb = callback;
+ io->read_destroy = destroy;
+ io->read_data = user_data;
+
+ return true;
+}
+
+bool io_set_write_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy)
+{
+ unsigned int events;
+
+ if (!io || io->fd < 0)
+ return false;
+
+ if (io->write_destroy)
+ io->write_destroy(io->write_data);
+
+ if (callback)
+ events = io->events | SOL_FD_FLAGS_OUT;
+ else
+ events = io->events & ~SOL_FD_FLAGS_OUT;
+
+ reset_io_watch(io, events);
+
+ io->write_cb = callback;
+ io->write_destroy = destroy;
+ io->write_data = user_data;
+
+ return true;
+}
+
+bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy)
+{
+ unsigned int events;
+
+ if (!io || io->fd < 0)
+ return false;
+
+ if (io->disconnect_destroy)
+ io->disconnect_destroy(io->disconnect_data);
+
+ if (callback)
+ events = io->events | SOL_FD_FLAGS_HUP;
+ else
+ events = io->events & ~SOL_FD_FLAGS_HUP;
+
+ reset_io_watch(io, events);
+
+ io->disconnect_cb = callback;
+ io->disconnect_destroy = destroy;
+ io->disconnect_data = user_data;
+
+ return true;
+}
diff --git a/src/shared/timeout-soletta.c b/src/shared/timeout-soletta.c
new file mode 100644
index 0000000..f7e2a23
--- /dev/null
+++ b/src/shared/timeout-soletta.c
@@ -0,0 +1,111 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; 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 <stdio.h> /* FIXME: remove me */
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <sol-mainloop.h>
+
+#include "timeout.h"
+#include "util.h"
+
+struct timeout_data {
+ struct sol_timeout *timeout;
+ timeout_func_t func;
+ timeout_destroy_func_t destroy;
+ void *user_data;
+};
+
+#define MAX_TIMEOUTS 32
+
+static struct timeout_data timeouts[MAX_TIMEOUTS];
+
+static bool timeout_callback(void *user_data)
+{
+ struct timeout_data *data = user_data;
+
+ if (data->func(data->user_data))
+ return true;
+
+ if (data->destroy)
+ data->destroy(data->user_data);
+
+ data->timeout = NULL;
+
+ return false;
+}
+
+unsigned int timeout_add(unsigned int timeout, timeout_func_t func,
+ void *user_data, timeout_destroy_func_t destroy)
+{
+ struct timeout_data *data;
+ int i;
+
+ if (!func)
+ return 0;
+
+ for (i = 0; i < MAX_TIMEOUTS; i++)
+ if (!timeouts[i].timeout)
+ break;
+
+ if (i == MAX_TIMEOUTS)
+ return 0;
+
+ data = &timeouts[i];
+
+ data->timeout = sol_timeout_add(timeout, timeout_callback, data);
+ if (!data->timeout)
+ return 0;
+
+ data->func = func;
+ data->destroy = destroy;
+ data->user_data = user_data;
+
+ return i + 1;
+}
+
+void timeout_remove(unsigned int id)
+{
+ struct timeout_data *data;
+
+ if (!id)
+ return;
+
+ if ((id - 1) >= MAX_TIMEOUTS)
+ return;
+
+ data = &timeouts[id - 1];
+
+ if (data->destroy)
+ data->destroy(data->user_data);
+
+ sol_timeout_del(data->timeout);
+ data->timeout = NULL;
+}
--
2.4.6


2015-07-21 23:16:36

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 03/15] peripheral/gatt: Fix usage of mainloop_ functions

If we want that this example is mainloop agnostic, it should use the
mainloop agnostic functions.
---
peripheral/gatt.c | 72 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 43 insertions(+), 29 deletions(-)

diff --git a/peripheral/gatt.c b/peripheral/gatt.c
index 4c5531d..a66292f 100644
--- a/peripheral/gatt.c
+++ b/peripheral/gatt.c
@@ -25,6 +25,7 @@
#include <config.h>
#endif

+#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@@ -34,7 +35,7 @@
#include "lib/bluetooth.h"
#include "lib/l2cap.h"
#include "lib/uuid.h"
-#include "src/shared/mainloop.h"
+#include "src/shared/io.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
#include "src/shared/att.h"
@@ -53,7 +54,7 @@ struct gatt_conn {
struct bt_gatt_client *client;
};

-static int att_fd = -1;
+static struct io *att_io = NULL;
static struct queue *conn_list = NULL;
static struct gatt_db *gatt_db = NULL;
static struct gatt_db *gatt_cache = NULL;
@@ -153,41 +154,43 @@ static struct gatt_conn *gatt_conn_new(int fd)
return conn;
}

-static void att_conn_callback(int fd, uint32_t events, void *user_data)
+static bool att_conn_callback(struct io *io, void *user_data)
{
struct gatt_conn *conn;
struct sockaddr_l2 addr;
socklen_t addrlen;
- int new_fd;
+ int fd, new_fd;

- if (events & (EPOLLERR | EPOLLHUP)) {
- mainloop_remove_fd(fd);
- return;
- }
+ fd = io_get_fd(io);
+
+ fprintf(stderr, "att_conn_callback io %p\n", io);

memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);

- new_fd = accept(att_fd, (struct sockaddr *) &addr, &addrlen);
+ new_fd = accept(fd, (struct sockaddr *) &addr, &addrlen);
if (new_fd < 0) {
fprintf(stderr, "Failed to accept new ATT connection: %m\n");
- return;
+ return true;
}

conn = gatt_conn_new(new_fd);
if (!conn) {
fprintf(stderr, "Failed to create GATT connection\n");
close(new_fd);
- return;
+ return true;
}

if (!queue_push_tail(conn_list, conn)) {
fprintf(stderr, "Failed to add GATT connection\n");
gatt_conn_destroy(conn);
close(new_fd);
+ return true;
}

printf("New device connected\n");
+
+ return true;
}

static void gap_device_name_read(struct gatt_db_attribute *attrib,
@@ -243,13 +246,16 @@ static void populate_devinfo_service(struct gatt_db *db)
void gatt_server_start(void)
{
struct sockaddr_l2 addr;
+ int fd;
+
+ fprintf(stderr, "gatt_server_start\n");

- if (att_fd >= 0)
+ if (att_io)
return;

- att_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_CLOEXEC,
+ fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK,
BTPROTO_L2CAP);
- if (att_fd < 0) {
+ if (fd < 0) {
fprintf(stderr, "Failed to create ATT server socket: %m\n");
return;
}
@@ -260,24 +266,21 @@ void gatt_server_start(void)
memcpy(&addr.l2_bdaddr, static_addr, 6);
addr.l2_bdaddr_type = BDADDR_LE_RANDOM;

- if (bind(att_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "Failed to bind ATT server socket: %m\n");
- close(att_fd);
- att_fd = -1;
+ close(fd);
return;
}

- if (listen(att_fd, 1) < 0) {
+ if (listen(fd, 1) < 0) {
fprintf(stderr, "Failed to listen on ATT server socket: %m\n");
- close(att_fd);
- att_fd = -1;
+ close(fd);
return;
}

gatt_db = gatt_db_new();
if (!gatt_db) {
- close(att_fd);
- att_fd = -1;
+ close(fd);
return;
}

@@ -290,20 +293,33 @@ void gatt_server_start(void)
if (!conn_list) {
gatt_db_unref(gatt_db);
gatt_db = NULL;
- close(att_fd);
- att_fd = -1;
+ close(fd);
+ return;
+ }
+
+ att_io = io_new(fd);
+
+ fprintf(stderr, "att_io %p\n", att_io);
+
+ if (!att_io) {
+ gatt_db_unref(gatt_db);
+ gatt_db = NULL;
+ close(fd);
+ queue_destroy(conn_list, NULL);
return;
}

- mainloop_add_fd(att_fd, EPOLLIN, att_conn_callback, NULL, NULL);
+ if (!io_set_read_handler(att_io, att_conn_callback, NULL, NULL))
+ fprintf(stderr, "Failed to add read handler\n");
}

void gatt_server_stop(void)
{
- if (att_fd < 0)
+ if (!att_io)
return;

- mainloop_remove_fd(att_fd);
+ io_destroy(att_io);
+ att_io = NULL;

queue_destroy(conn_list, gatt_conn_destroy);

@@ -313,6 +329,4 @@ void gatt_server_stop(void)
gatt_db_unref(gatt_db);
gatt_db = NULL;

- close(att_fd);
- att_fd = -1;
}
--
2.4.6


2015-07-21 23:16:34

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ v1 01/15] build: Add configure-time checks for soletta

The idea will be to re-use the work done in peripheral/ so we can easily
export node types for common Bluetooth profiles (the focus right now is
GATT profiles).

[1] https://github.com/solettaproject/soletta
---
configure.ac | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)

diff --git a/configure.ac b/configure.ac
index 4f81517..9592ffa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -283,4 +283,42 @@ fi
AC_DEFINE_UNQUOTED(ANDROID_STORAGEDIR, "${storagedir}/android",
[Directory for the Android daemon storage files])

+AC_ARG_ENABLE(soletta, AC_HELP_STRING([--enable-soletta],
+ [enable building BlueZ soletta nodes]),
+ [enable_soletta=${enableval}])
+AM_CONDITIONAL(SOLETTA, test "${enable_soletta}" = "yes")
+
+if (test "${enable_soletta}" = "yes"); then
+ PKG_CHECK_MODULES(SOLETTA, soletta, dummy=yes,
+ AC_MSG_ERROR(soletta is required))
+ AC_SUBST(SOLETTA_CFLAGS)
+ AC_SUBST(SOLETTA_LIBS)
+ solettaprefix="`$PKG_CONFIG --variable=prefix soletta`"
+ AC_SUBST(SOLETTA_PREFIX, [${solettaprefix}])
+fi
+
+AC_ARG_WITH([solettamodulesdir], AC_HELP_STRING([--with-solettamodulesdir=DIR],
+ [path to soletta modules directory]), [path_solettamodulesdir=${withval}])
+if (test "${enable_soletta}" != "no" && test -z "${path_solettamodulesdir}"); then
+ AC_MSG_CHECKING([soletta modules directory])
+ path_solettamodulesdir="`$PKG_CONFIG --variable=modulesdir soletta`"
+ if (test -z "${path_solettamodulesdir=}"); then
+ AC_MSG_ERROR([soletta modules directory is required])
+ fi
+ AC_MSG_RESULT([${path_solettamodulesdir}])
+fi
+AC_SUBST(SOLETTA_MODULESDIR, [${path_solettamodulesdir}])
+
+AC_ARG_WITH([solettadescdir], AC_HELP_STRING([--with-solettadescdir=DIR],
+ [path to soletta node type descriptions directory]), [path_solettadescdir=${withval}])
+if (test "${enable_soletta}" != "no" && test -z "${path_solettadescdir}"); then
+ AC_MSG_CHECKING([soletta modules directory])
+ path_solettadescdir="`$PKG_CONFIG --variable=pkgdatadir soletta`"
+ if (test -z "${path_solettadescdir=}"); then
+ AC_MSG_ERROR([soletta descriptions directory is required])
+ fi
+ AC_MSG_RESULT([${path_solettadescdir}])
+fi
+AC_SUBST(SOLETTA_DESCDIR, [${path_solettadescdir}])
+
AC_OUTPUT(Makefile src/bluetoothd.8 lib/bluez.pc)
--
2.4.6