Once we setting bluetooth low energy(BLE) advertising, we would want to setting this beacon being connectable. The clients (like phone, computer) could read/upload data to/from that.
That applying is very wide: for example, the all-day heartbeat measurer in current, the sensors and recorder are connected physicallly as one device. The patient will feel it is not comfortable when he carry it (Just like carry urine bag but smaller) . If the manufacturer of heartbeat measurer introduce BLE technology, the recorder could be indenpendent device.
The connection between recorder and sensors is wireless. It is not necessary to carry recorder like shoulder bag all day, it could be put in desk.
Why not apply classical bluetooth for that goal ? For classical bluetooth spends too much energy, mercury battery could not afford such costing.
Ok, for our major issue: setting gatt service in linux.
In my environment, I use fedora 21 + bluez 5.
If dbus version of your linux distribution is lower than 1.6, you should use bluez 4.
DO NOT force upgrading your dbus version to 1.6, unless you know what you do.
The gatt service warm-up be the follow steps:
0. Download and untar the bluez package from bluez
(Use tar Jxvf XXX.tar.xz to uncompress file)
1. Build bluez on your computer.
For me, the configure parameters of bluez are:
./configure CFLAGS="$CFLAGS -Wno-sign-compare" --disable-udev --prefix=$PWD/built --enable-experimental --enable-maintainer-mode
The --enable-experimental and --enable-maintainer-mode set gatt-service example being included into compilation. and --disable-udev is for avoiding configuration error(and the udev module is useless for me). CFLAGS="$CFLAGS -Wno-sign-compare" set compiler to ignore sign/unsigned warning (the Makefile of Bluez set compiler to treat warning as error!).
2. Run the bluetoothd program, which is under src folder of bluez
The bluetoothd is a daemon program to manage all bluetooth device and (maybe all) service.
Once we have built this bluez, we could run the sbluetoothd as test.
But before the running, we should stop the one bluetoothd which has been run:
sudo killall -9 bluetoothd
we could read the help of bluetoothd.
[gaiger@localhost src]$ ./bluetoothd -h
Usage:
bluetoothd [OPTION...]
Help Options:
-h, --help Show help options
Application Options:
-d, --debug=DEBUG Specify debug options to enable
-p, --plugin=NAME,.., Specify plugins to load
-P, --noplugin=NAME,... Specify plugins not to load
-C, --compat Provide deprecated command line interfaces
-E, --experimental Enable experimental interfaces
-n, --nodetach Run with logging in foreground
-v, --version Show version information and exit
I note here : the -d argument would make the output be tedeious, and the -n argument would make the programming running on the front-end.
What is plugin? those are gatt service (example) which have been included in bluez.
Check the files under profiles and plugin, we could watch what service bluez have done:
[gaiger@localhost src]$ ls ../profiles/
alert cyclingspeed health input sap time
audio deviceinfo heartrate network scanparam
cups gap iap proximity thermometer
[gaiger@localhost src]$ ls ../plugins/*.c
../plugins/autopair.c ../plugins/hostname.c ../plugins/sixaxis.c
../plugins/external-dummy.c ../plugins/neard.c ../plugins/wiimote.c
../plugins/gatt-example.c ../plugins/policy.c
Now we try to enable the timer service in bluetoothd:
[gaiger@localhost src]$ sudo ./bluetoothd --plugin=time -n
bluetoothd[8511]: Bluetooth daemon 5.27
bluetoothd[8511]: Starting SDP server
bluetoothd[8511]: Ignoring (cli) hostname
bluetoothd[8511]: Ignoring (cli) wiimote
bluetoothd[8511]: Ignoring (cli) autopair
bluetoothd[8511]: Ignoring (cli) policy
bluetoothd[8511]: Ignoring (cli) gatt_example
bluetoothd[8511]: Ignoring (cli) neard
bluetoothd[8511]: Ignoring (cli) sap
bluetoothd[8511]: Ignoring (cli) a2dp
bluetoothd[8511]: Ignoring (cli) avrcp
bluetoothd[8511]: Ignoring (cli) network
bluetoothd[8511]: Ignoring (cli) input
bluetoothd[8511]: Ignoring (cli) hog
bluetoothd[8511]: Ignoring (cli) health
bluetoothd[8511]: Ignoring (cli) gap
bluetoothd[8511]: Ignoring (cli) scanparam
bluetoothd[8511]: Ignoring (cli) deviceinfo
bluetoothd[8511]: Ignoring (cli) alert
bluetoothd[8511]: Ignoring (cli) proximity
bluetoothd[8511]: Ignoring (cli) thermometer
bluetoothd[8511]: Ignoring (cli) heartrate
bluetoothd[8511]: Ignoring (cli) cyclingspeed
bluetoothd[8511]: Ignoring (cli) external_dummy
bluetoothd[8511]: Bluetooth management interface 1.7 initialized
Then run the script I have provided in the last article, we could use BLE scanner (android's app) to detect this service.
Now we know that is a good example for us to set a gatt service.
Take look at the time service code, in profiles/time/server.c (buttom):
struct btd_profile time_profile = { .name = "gatt-time-server", .adapter_probe = time_server_init, .adapter_remove = time_server_exit, }; static int time_init(void) { return btd_profile_register(&time_profile); } static void time_exit(void) { btd_profile_unregister(&time_profile); } BLUETOOTH_PLUGIN_DEFINE(time, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, time_init, time_exit)
The declaration of macro BLUETOOTH_PLUGIN_DEFINE be
#define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit)
(in src/plugin.h). it is , to define what function is for initialization(entrance), what is for exit. As this example, the entrance and exit are just for setting/un-setting structure btd_profile, the structure are for customizing gatt service distinctly.
The structure btd_profile has 3 member, are name, service_init and service_exit, respectively.
Now look at the function time_server_init , time_server_exit and relative functions in the same file:
#define CURRENT_TIME_SVC_UUID 0x1805 #define REF_TIME_UPDATE_SVC_UUID 0x1806 #define LOCAL_TIME_INFO_CHR_UUID 0x2A0F #define TIME_UPDATE_CTRL_CHR_UUID 0x2A16 #define TIME_UPDATE_STAT_CHR_UUID 0x2A17 #define CT_TIME_CHR_UUID 0x2A2B static uint8_t current_time_read(struct attribute *a, struct btd_device *device, gpointer user_data) { struct btd_adapter *adapter = user_data; uint8_t value[10]; if (encode_current_time(value) < 0) return ATT_ECODE_IO; attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL); return 0; } static uint8_t local_time_info_read(struct attribute *a, struct btd_device *device, gpointer user_data) { struct btd_adapter *adapter = user_data; uint8_t value[2]; DBG("a=%p", a); tzset(); /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile * format (offset from UTC in number of 15 minutes increments). */ value[0] = (uint8_t) (-1 * timezone / (60 * 15)); /* FIXME: POSIX "daylight" variable only indicates whether there * is DST for the local time or not. The offset is unknown. */ value[1] = daylight ? 0xff : 0x00; attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL); return 0; } static gboolean register_current_time_service(struct btd_adapter *adapter) { bt_uuid_t uuid; bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID); /* Current Time service */ return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, /* CT Time characteristic */ GATT_OPT_CHR_UUID16, CT_TIME_CHR_UUID, GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ | GATT_CHR_PROP_NOTIFY, GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, current_time_read, adapter, /* Local Time Information characteristic */ GATT_OPT_CHR_UUID16, LOCAL_TIME_INFO_CHR_UUID, GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, local_time_info_read, adapter, GATT_OPT_INVALID); } static int time_server_init(struct btd_profile *p, struct btd_adapter *adapter) { const char *path = adapter_get_path(adapter); DBG("path %s", path); if (!register_current_time_service(adapter)) { error("Current Time Service could not be registered"); return -EIO; } if (!register_ref_time_update_service(adapter)) { error("Reference Time Update Service could not be registered"); return -EIO; } return 0; } static void time_server_exit(struct btd_profile *p, struct btd_adapter *adapter) { const char *path = adapter_get_path(adapter); DBG("path %s", path); }
That is very obvious:
The function time_server_init register 2 service : register_current_time_service and register_ref_time_update_service. In the function register_current_time_service, the code call the function bt_uuid16_create with uuid REF_TIME_UPDATE_SVC_UUID to create a service, and add 2 characteristic CT_TIME_CHR_UUID and LOCAL_TIME_INFO_CHR_UUID by calling function gatt_service_add which be added function local_time_info_read and current_time_read. In these pointed function, the data be sent by calling function attrib_db_update.
bt_uuid16_create : create service.
gatt_service_add: set characteristic and set function pointer corresponding the characteristic.
attrib_db_update: sent data to client.
The functions are declared in src/plugin.h and attrib/gatt-service.h:
Note, gatt_service_add:
gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid, bt_uuid_t *svc_uuid, gatt_option opt1, ...); It is an uncertain parameter function, we could register several characteristic in formal of : gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, /*first characteristic */ GATT_OPT_CHR_UUID16, FRIST_CHR_UUID, GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ | GATT_CHR_PROP_NOTIFY, GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, first_pointer_read, adapter, /* 2nd characteristic */ GATT_OPT_CHR_UUID16, SECOND_CHR_UUID, GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, second_pointer_read, adapter, /* 3rd characteristic */ GATT_OPT_CHR_UUID16, THIRD_CHR_UUID, GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, third_pointer_read, adapter, : GATT_OPT_INVALID);
You could refer to the other gatt service example, I recommend plugins/gatt-example.c.
If you want to customize your gatt service, It is complicated to create a whole new one but without changing original example: it is hard to modify Makefile files! Just backup and modify the plugins/wiimote.c file, It maybe be the most useless one for being refered.
NOTE : If you want to know more detailedly about how to implement or modify a gatt-server ( peripheral) as yours, please read the article written by me, which is the sequel of this one.
root@phidgetsbc:~/bluez-5.30/src# ./bluetoothd --plugin=time -n
回覆刪除bluetoothd[14343]: Bluetooth daemon 5.30
bluetoothd[14343]: Starting SDP server
bluetoothd[14343]: Ignoring (cli) hostname
bluetoothd[14343]: Ignoring (cli) wiimote
bluetoothd[14343]: Ignoring (cli) autopair
bluetoothd[14343]: Ignoring (cli) policy
bluetoothd[14343]: Ignoring (cli) gatt_example
bluetoothd[14343]: Ignoring (cli) neard
bluetoothd[14343]: Ignoring (cli) sap
bluetoothd[14343]: Ignoring (cli) a2dp
bluetoothd[14343]: Ignoring (cli) avrcp
bluetoothd[14343]: Ignoring (cli) network
bluetoothd[14343]: Ignoring (cli) input
bluetoothd[14343]: Ignoring (cli) hog
bluetoothd[14343]: Ignoring (cli) health
bluetoothd[14343]: Ignoring (cli) gap
bluetoothd[14343]: Ignoring (cli) scanparam
bluetoothd[14343]: Ignoring (cli) deviceinfo
bluetoothd[14343]: Ignoring (cli) alert
bluetoothd[14343]: Ignoring (cli) proximity
bluetoothd[14343]: Ignoring (cli) thermometer
bluetoothd[14343]: Ignoring (cli) heartrate
bluetoothd[14343]: Ignoring (cli) cyclingspeed
bluetoothd[14343]: Ignoring (cli) external_dummy
bluetoothd[14343]: Bluetooth management interface 1.4 initialized
bluetoothd[14343]: Failed to obtain handles for "Service Changed" characteristic
bluetoothd[14343]: Failed to register org.bluez.LEAdvertisingManager1
bluetoothd[14343]: Failed to register LEAdvertisingManager1 interface for adapter
bluetoothd[14343]: Not enough free handles to register service
bluetoothd[14343]: Current Time Service could not be registered
bluetoothd[14343]: gatt-time-server: Input/output error (5)
bluetoothd[14343]: hci0 Load Connection Parameters failed: Unknown Command (0x01)
I was hoping you could help me with the above errors..
回覆刪除Great article! thanks!
0. Did you modify your bluez code for this result ?
刪除1. if not, have you used the others gatt services? (wiimote, deviceinfo..and so forth..)
2. if you modified, please post code you changed.
Hello! Have you had a chance to look into this?
刪除Hello! Thanks for your response!
回覆刪除0 - I did not modify the bluez code. I'm using version 5.30, btw
1 - I tried: time, heartrate, input and health.. they all had the same exact input.
I am trying this on phidget SBC 3, that helps...
Kernel Version
Linux version 3.14.27 (james@james-VirtualBox) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-12ubuntu1) ) #2 Fri Jun 12 13:35:01 EDT 2015
Distribution
Debian GNU/Linux 7
Thanks! I look forward to your response!
Sorry I have not tried to modify bluez in non-x86 based computer. Have you tried it zeroth in your x86 pc ?
刪除I guess that is driver's issue : the bluetooth driver in phidget SBC 3 does not be updated with time . Maybe you could try to disable the tradition bluetooth mode to see if it works or not.
I found a point : do not use Bluez version later than 5.28, those would occur endpoint errors.
刪除Hi,
回覆刪除My setup: Intel Edison ,yocto linux + bluez5.27.
Error: On Ediosn Side....
root@edison:~/bluez-5.27# sh script.sh &
[1] 9692
+ export BLUETOOTH_DEVICE=hci0
+ BLUETOOTH_DEVICE=hci0
+ export OGF=0x08
+ OGF=0x08
+ export OCF=0x0008
+ OCF=0x0008
+ export 'IBEACONPROFIX=1E 02 01 1A 1A FF 4C 00 02 15'
+ IBEACONPROFIX='1E 02 01 1A 1A FF 4C 00 02 15'
+ export 'UUID=4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66'
+ UUID='4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66'
+ export 'MAJOR=00 01'
+ MAJOR='00 01'
+ export 'MINOR=00 00'
+ MINOR='00 00'
+ POWER='C5 00'
+ hciconfig hci0 up
root@edison:~/bluez-5.27# + hciconfig hci0 noleadv
LE set advertise enable on hci0 returned status 12
+ hciconfig hci0 noscan
+ hciconfig hci0 pscan
+ hciconfig hci0 leadv
+ hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66 00 01 00 00 C5 00
< HCI Command: ogf 0x08, ocf 0x0008, plen 32
1E 02 01 1A 1A FF 4C 00 02 15 4A 4E CE 60 7E B0 11 E4 B4 A9
08 00 20 0C 9A 66 00 01 00 00 C5 00
> HCI Event: 0x0e plen 4
01 08 20 00
+ hcitool -i hci0 cmd 0x08 0x0006 A0 00 A0 00 00 00 00 00 00 00 00 00 00 07 00
< HCI Command: ogf 0x08, ocf 0x0006, plen 15
A0 00 A0 00 00 00 00 00 00 00 00 00 00 07 00
> HCI Event: 0x0e plen 4
01 06 20 0C
+ hcitool -i hci0 cmd 0x08 0x000a 01
< HCI Command: ogf 0x08, ocf 0x000a, plen 1
01
> HCI Event: 0x0e plen 4
01 0A 20 0C
+ echo complete
complete
^C
[1]+ Done sh script.sh
root@edison:~/bluez-5.27# src/bluetoothd --plugin=time -n
bluetoothd[9701]: Bluetooth daemon 5.27
bluetoothd[9701]: Starting SDP server
bluetoothd[9701]: Ignoring (cli) hostname
bluetoothd[9701]: Ignoring (cli) wiimote
bluetoothd[9701]: Ignoring (cli) autopair
bluetoothd[9701]: Ignoring (cli) policy
bluetoothd[9701]: Ignoring (cli) gatt_example
bluetoothd[9701]: Ignoring (cli) neard
bluetoothd[9701]: Ignoring (cli) sap
bluetoothd[9701]: Ignoring (cli) a2dp
bluetoothd[9701]: Ignoring (cli) avrcp
bluetoothd[9701]: Ignoring (cli) network
bluetoothd[9701]: Ignoring (cli) input
bluetoothd[9701]: Ignoring (cli) hog
bluetoothd[9701]: Ignoring (cli) health
bluetoothd[9701]: Ignoring (cli) gap
bluetoothd[9701]: Ignoring (cli) scanparam
bluetoothd[9701]: Ignoring (cli) deviceinfo
bluetoothd[9701]: Ignoring (cli) alert
bluetoothd[9701]: Ignoring (cli) proximity
bluetoothd[9701]: Ignoring (cli) thermometer
bluetoothd[9701]: Ignoring (cli) heartrate
bluetoothd[9701]: Ignoring (cli) cyclingspeed
bluetoothd[9701]: Ignoring (cli) external_dummy
bluetoothd[9701]: Bluetooth management interface 1.3 initialized
bluetoothd[9701]: hci0 Load Connection Parameters failed: Unknown Command (0x01)
bluetoothd[9701]: No agent available for request type 2
bluetoothd[9701]: device_confirm_passkey: Operation not permitted
bluetoothd[9701]: No agent available for request type 2
bluetoothd[9701]: device_confirm_passkey: Operation not permitted
bluetoothd[9701]: No agent available for request type 2
bluetoothd[9701]: device_confirm_passkey: Operation not permitted
On Android App:
Status: connecting...
I get pairing request but when I press pair option then "device_confirm_passkey: Operation not permitted" error comes on Edison.
Please help to solve this issue.
Thanks
Watch out this line :
刪除hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66 00 01 00 00 C5 00
You has set the bluetooth as "dual mode", please refer to this post http://stackoverflow.com/questions/30966837/how-to-set-bluez-mode or my the other post http://gaiger-programming.blogspot.tw/2015/07/bluetooth-low-energy-customizing-gatt.html to set it as BLE only.
Also are you using two different terminals to run bluetoothd deamon and script?
回覆刪除That is not possible with Edison as it is connected via serial port and only 1 serial terminal can be opened.
How so I solve this?
Thanks
remove the parameter -n, the bluetoothd would run in daemon defaultly.
回覆刪除hello
回覆刪除I hope you find the solution
I made every thing you made
but still I have a problem : when I scan by BLE scanner I find the Bluez device but when I connect to it I don`t find any service ??
thanks in advance.
and this error appears:
回覆刪除(bluetoothd:32357): GLib-CRITICAL **: Source ID 45 was not found when attempting to remove it
Hi When I ran sudo ./bluetoothd --plugin=time -n, I got the following log:
回覆刪除bluetoothd[4818]: Bluetooth daemon 4.99
bluetoothd[4818]: Starting SDP server
bluetoothd[4818]: Ignoring (cli) pnat
bluetoothd[4818]: Ignoring (cli) audio
bluetoothd[4818]: Ignoring (cli) sap
bluetoothd[4818]: Ignoring (cli) input
bluetoothd[4818]: Ignoring (cli) serial
bluetoothd[4818]: Ignoring (cli) network
bluetoothd[4818]: Ignoring (cli) proximity
bluetoothd[4818]: Ignoring (cli) service
bluetoothd[4818]: Ignoring (cli) gatt_example
bluetoothd[4818]: Ignoring (cli) alert
bluetoothd[4818]: Ignoring (cli) health
bluetoothd[4818]: Ignoring (cli) thermometer
bluetoothd[4818]: Ignoring (cli) hciops
bluetoothd[4818]: Ignoring (cli) mgmtops
bluetoothd[4818]: Ignoring (cli) formfactor
bluetoothd[4818]: Ignoring (cli) storage
bluetoothd[4818]: Ignoring (cli) adaptername
bluetoothd[4818]: Ignoring (cli) wiimote
bluetoothd[4818]: Ignoring (cli) dbusoob
bluetoothd[4818]: Failed to init time plugin
bluetoothd[4818]: adapter_ops_setup failed
How to resolve the last two errors?
My explanation has based on bluetooth version 5.X, but yours is version 4.99.
回覆刪除Hi,
回覆刪除My setup : Raspberry pi 2 + Bluez 5.27 and a bluetooth dongle.
The problem is when I type 'which bluetoothd' it didn't return anything.
So I installed bluetooth again by typing the command `sudo apt-get install --no-install-recommends bluetooth`
It installed bluetooth demon 4.99 only. But I have bluez 5.27. Pretty much confused.
see the result now:
回覆刪除pi@raspberrypi ~/bluez/bluez-5.32/src $ sudo ./bluetoothd --plugin=time -n
bluetoothd[11651]: Bluetooth daemon 5.32
bluetoothd[11651]: Starting SDP server
bluetoothd[11651]: Ignoring (cli) hostname
bluetoothd[11651]: Ignoring (cli) wiimote
bluetoothd[11651]: Ignoring (cli) autopair
bluetoothd[11651]: Ignoring (cli) policy
bluetoothd[11651]: Ignoring (cli) gatt_example
bluetoothd[11651]: Ignoring (cli) neard
bluetoothd[11651]: Ignoring (cli) sap
bluetoothd[11651]: Ignoring (cli) a2dp
bluetoothd[11651]: Ignoring (cli) avrcp
bluetoothd[11651]: Ignoring (cli) network
bluetoothd[11651]: Ignoring (cli) input
bluetoothd[11651]: Ignoring (cli) hog
bluetoothd[11651]: Ignoring (cli) health
bluetoothd[11651]: Ignoring (cli) gap
bluetoothd[11651]: Ignoring (cli) scanparam
bluetoothd[11651]: Ignoring (cli) deviceinfo
bluetoothd[11651]: Ignoring (cli) alert
bluetoothd[11651]: Ignoring (cli) proximity
bluetoothd[11651]: Ignoring (cli) thermometer
bluetoothd[11651]: Ignoring (cli) heartrate
bluetoothd[11651]: Ignoring (cli) cyclingspeed
bluetoothd[11651]: Ignoring (cli) external_dummy
bluetoothd[11651]: Bluetooth management interface 1.9 initialized
bluetoothd[11651]: Failed to obtain handles for "Service Changed" characteristic
bluetoothd[11651]: Not enough free handles to register service
bluetoothd[11651]: Current Time Service could not be registered
bluetoothd[11651]: gatt-time-server: Input/output error (5)
I had to press ctrl+c to terminate this.