Resuming from last article , I modify the bluez code to be a simple peripheral (GATT server).
Step 0.
download the last bluez .
and
Step 1.
use the parameters to configurate it.
gaiger@i5-3210m:~/sandbox/bluez-5.32/src$./configure --enable-experimental --enable-maintainer-mode --prefix=$PWD/built CFLAGS="$CFLAGS -Wno-sign-compare -Wno-unused-function"
If you encounter some error like that :
configure: error: libical is required
or
checking for UDEV... no
configure: error: libudev >= 172 is required
just install those libraries. I note here, in fedora, the libudev has been included in systemd package, you should use that command line:
gaiger@i5-3210m:~/sandbox/bluez-5.32/src$sudo yum install systemd-devel
To install libudev-dev.
After configuration has been done, the building should be passed without error.
Step2.
Stop current bluetoothd program:
In fedora :
gaiger@i5-3210m:~/sandbox/bluez-5.32/src$sudo killall -p bluetoothd
In Ubuntu :
gaiger@i5-3210m:~/sandbox/bluez-5.32/src$sudo service bluetooth status
bluetooth start/running, process 2619
gaiger@i5-3210m:~/sandbox/bluez-5.32/src$ sudo service bluetooth stop
bluetooth stop/waiting
Then, goto the src folder under your bluez package, and execute that:
[gaiger@localhost src]$ sudo ./bluetoothd -p xx -n
If the output log be :
bluetoothd[12465]: Bluetooth daemon 5.30
bluetoothd[12465]: Starting SDP server
bluetoothd[12465]: Bluetooth management interface 1.7 initialized
bluetoothd[12465]: Failed to obtain handles for "Service Changed" characteristic
bluetoothd[12465]: Failed to register org.bluez.LEAdvertisingManager1
bluetoothd[12465]: Failed to register LEAdvertisingManager1 interface for adapter
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: gatt-example-adapter-driver: Input/output error (5)
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: Error adding Link Loss service
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: Current Time Service could not be registered
bluetoothd[12465]: gatt-time-server: Input/output error (5)
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: Not enough free handles to register service
bluetoothd[12465]: Sap driver initialization failed.
bluetoothd[12465]: sap-server: Operation not permitted (1)
bluetoothd[12465]: Endpoint registered: sender=:1.122 path=/MediaEndpoint/A2DPSource
bluetoothd[12465]: Endpoint registered: sender=:1.122 path=/MediaEndpoint/A2DPSink
That is, the gatt-server start fall. The only solution I know currently, is to use the Bluez version which is not later than 5.28. please back to Step 0, use version 5.28 and do all again.
if your result be :
[gaiger@localhost src]$ sudo ./bluetoothd -p xx -n
bluetoothd[31541]: Bluetooth daemon 5.28
bluetoothd[31541]: Starting SDP server
bluetoothd[31541]: Ignoring (cli) hostname
bluetoothd[31541]: Ignoring (cli) wiimote
bluetoothd[31541]: Ignoring (cli) autopair
bluetoothd[31541]: Ignoring (cli) policy
bluetoothd[31541]: Ignoring (cli) gatt_example
bluetoothd[31541]: Ignoring (cli) neard
bluetoothd[31541]: Ignoring (cli) sap
bluetoothd[31541]: Ignoring (cli) a2dp
bluetoothd[31541]: Ignoring (cli) avrcp
bluetoothd[31541]: Ignoring (cli) network
bluetoothd[31541]: Ignoring (cli) input
bluetoothd[31541]: Ignoring (cli) hog
bluetoothd[31541]: Ignoring (cli) health
bluetoothd[31541]: Ignoring (cli) gap
bluetoothd[31541]: Ignoring (cli) scanparam
bluetoothd[31541]: Ignoring (cli) deviceinfo
bluetoothd[31541]: Ignoring (cli) alert
bluetoothd[31541]: Ignoring (cli) time
bluetoothd[31541]: Ignoring (cli) proximity
bluetoothd[31541]: Ignoring (cli) thermometer
bluetoothd[31541]: Ignoring (cli) heartrate
bluetoothd[31541]: Ignoring (cli) cyclingspeed
bluetoothd[31541]: Ignoring (cli) external_dummy
bluetoothd[31541]: Bluetooth management interface 1.7 initialized
Congratulation, you could go below.
Step 3.
Excute the command :
[gaiger@localhost src]$ sudo ./bluetoothd -p gatt_example -n
And run this script, bleAdvertise:
#!/bin/bash
# ref: http://www.theregister.co.uk/Print/2013/11/29/feature_diy_apple_ibeacons/
set -x
# inquiry local bluetooth device
#hcitool dev
export BLUETOOTH_DEVICE=hci0
#sudo hcitool -i hcix cmd <OGF> <OCF> <No. Significant Data Octets> <iBeacon Prefix> <UUID> <Major> <Minor> <Tx Power> <Placeholder Octets>
#OGF = Operation Group Field = Bluetooth Command Group = 0x08
#OCF = Operation Command Field = HCI_LE_Set_Advertising_Data = 0x0008
#No. Significant Data Octets (Max of 31) = 1E (Decimal 30)
#iBeacon Prefix (Always Fixed) = 02 01 1A 1A FF 4C 00 02 15
export OGF="0x08"
export OCF="0x0008"
#export IBEACONPROFIX="1E 02 01 1A 1A FF 4C 00 02 15"
export IBEACONPROFIX="1E 02 01 16 1A FF 4C 00 02 15"
#uuidgen could gerenate uuid
export UUID="4a 4e ce 60 7e b0 11 e4 b4 a9 08 00 20 0c 9a 66"
#export UUID="B9 40 7F 30 F5 F8 46 6E AF F9 25 55 6B 57 FE 6D"
#export UUID="76 E8 B4 E0 7E B5 11 E4 B4 A9 08 00 20 0C 9A 66"
export MAJOR="00 01"
export MINOR="00 00"
export POWER="C5 00"
initialize device
sudo hciconfig $BLUETOOTH_DEVICE up
# disable advertising
sudo hciconfig $BLUETOOTH_DEVICE noleadv
# stop the dongle looking for other Bluetooth devices
sudo hciconfig $BLUETOOTH_DEVICE noscan
sudo hciconfig $BLUETOOTH_DEVICE pscan
#hciconfig $BLUETOOTH_DEVICE iscan
#sudo hciconfig $BLUETOOTH_DEVICE name "i5-3210M "$BLUETOOTH_DEVICE
sudo hciconfig $BLUETOOTH_DEVICE leadv
# advertise
sudo hcitool -i $BLUETOOTH_DEVICE cmd 0x08 0x0008 $IBEACONPROFIX $UUID $MAJOR $MINOR $POWER
#sudo hcitool -i $BLUETOOTH_DEVICE cmd 0x08 0x0006 A0 00 A0 00 00 00 00 00 00 00 00 00 00 07 00
#sudo hcitool -i $BLUETOOTH_DEVICE cmd 0x08 0x000a 01
#sudo hciconfig $BLUETOOTH_DEVICE leadv
#sudo hciconfig $BLUETOOTH_DEVICE pscan
echo "complete"
You should be able to use your moblie appication (BLE scanner for android, LightBlue for iOS)
to scan and connect to this Bluez peripheral.
That Shows the bluez gatt-server works.
Step 4.
Backup the plugin/wiimote.c , and replace that as below code completely:
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 David Herrmann <[email protected]>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <stdbool.h>
#include <bluetooth/bluetooth.h>
#include <glib.h>
#include "lib/uuid.h"
#include "src/plugin.h"
#include "src/adapter.h"
#include "src/shared/util.h"
#include "src/log.h"
#include "attrib/gattrib.h"
#include "attrib/gatt-service.h"
#include "attrib/att.h"
#include "attrib/gatt.h"
#include "attrib/att-database.h"
#include "src/attrib-server.h"
#define MAX_STR_LEN (256)
#define SIMPLE_SVC_UUID 0xfff0
#define SIMPLE_READ1_CHAR_UUID 0xfff1
#define SIMPLE_READ2_CHAR_UUID 0xfff2
#define SIMPLE_WRITE_CHAR_UUID 0xfff3
#define SIMPLE_NOTIFY_CHAR_UUID 0xfff4
static char read1Data[MAX_STR_LEN];
static char read2Data[MAX_STR_LEN];
static int notifyData;
static uint8_t SimpleCharacteristic1Read(struct attribute *a,
struct btd_device *device, gpointer user_data)
{
struct btd_adapter *adapter;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
adapter = user_data;
attrib_db_update(adapter, a->handle, NULL,
(uint8_t*)&read1Data[0], strlen(&read1Data[0]), NULL);
return 0;
}/*Characteristic1Read*/
static uint8_t SimpleCharacteristic2Read(struct attribute *a,
struct btd_device *device, gpointer user_data)
{
struct btd_adapter *adapter;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
adapter = user_data;
attrib_db_update(adapter, a->handle, NULL,
(uint8_t*)&read2Data[0], strlen(&read2Data[0]), NULL);
return 0;
}/*Characteristic2Read*/
static uint8_t SimpleCharacteristicWrite(struct attribute *a,
struct btd_device *device, gpointer user_data)
{
unsigned char data[MAX_STR_LEN];
int i;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
memset(&data[0], 0, MAX_STR_LEN);
memcpy(&data[0], a->data, a->len);
printf("written data : %s \n", &data[0]);
for(i = 0; i< a->len;i++)
printf("%#1x ", (unsigned char)(data[i]));
printf("\n");
return 0;
}/*CharacteristicWrite*/
static uint8_t SimpleCharacteristicNotify(struct attribute *a,
struct btd_device *device, gpointer user_data)
{
struct btd_adapter *adapter;
adapter = user_data;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
do
{
attrib_db_update(adapter, a->handle, NULL,
(uint8_t*)¬ifyData, sizeof(notifyData), NULL);
//usleep(1*1000*1000);
notifyData++;
}while(0);
return 0;
}/*CharacteristicNotify*/
static void RegisterSimpleService(struct btd_adapter *adapter)
{
bt_uuid_t uuid;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
bt_uuid16_create(&uuid, SIMPLE_SVC_UUID);
gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
/* characteristic register*/
/*read 1*/
GATT_OPT_CHR_UUID16, SIMPLE_READ1_CHAR_UUID,
GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ ,
GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
SimpleCharacteristic1Read, adapter,
/*read 2*/
GATT_OPT_CHR_UUID16, SIMPLE_READ1_CHAR_UUID,
GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ ,
GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
SimpleCharacteristic2Read, adapter,
/*write*/
GATT_OPT_CHR_UUID16, SIMPLE_WRITE_CHAR_UUID,
GATT_OPT_CHR_PROPS, GATT_CHR_PROP_WRITE_WITHOUT_RESP,
GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
SimpleCharacteristicWrite, adapter,
/*NOTIFY*/
GATT_OPT_CHR_UUID16, SIMPLE_NOTIFY_CHAR_UUID,
GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ|GATT_CHR_PROP_NOTIFY,
GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
SimpleCharacteristicNotify, adapter,
/*end*/
GATT_OPT_INVALID);
return ;
}/*RegisterSimpleService*/
#define DEVICEINFO_SVC_UUID 0x180a
char versionStr[MAX_STR_LEN] = "0.0.0";
char manufacturerStr[MAX_STR_LEN] = "Gaiger";
static uint8_t SoftwareRevisionStringRead(struct attribute *a,
struct btd_device *device, gpointer user_data)
{
struct btd_adapter *adapter;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
adapter = user_data;
attrib_db_update(adapter, a->handle, NULL,
(uint8_t*)&versionStr[0], strlen(&versionStr[0]), NULL);
return 0;
}/*SoftwareRevisionStringRead*/
static uint8_t ManufacturerStringRead(struct attribute *a,
struct btd_device *device, gpointer user_data)
{
struct btd_adapter *adapter;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
adapter = user_data;
attrib_db_update(adapter, a->handle, NULL,
(uint8_t*)&manufacturerStr[0], strlen(&manufacturerStr[0]), NULL);
return 0;
}/*ManufacturerStringRead*/
static void RegisterDeviceInfo(struct btd_adapter *adapter)
{
bt_uuid_t uuid;
printf("__FILE__ = %s, __FUNCTION__ = %s, __LINE__ =%d\n",
__FILE__, __FUNCTION__, __LINE__);
bt_uuid16_create(&uuid, DEVICEINFO_SVC_UUID);
gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
/* characteristic register*/
/*GATT_CHARAC_SOFTWARE_REVISION_STRING*/
GATT_OPT_CHR_UUID16, GATT_CHARAC_SOFTWARE_REVISION_STRING,
GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ ,
GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
SoftwareRevisionStringRead, adapter,
/*GATT_CHARAC_MANUFACTURER_NAME_STRING*/
GATT_OPT_CHR_UUID16, GATT_CHARAC_MANUFACTURER_NAME_STRING,
GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ ,
GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
ManufacturerStringRead, adapter,
/*end*/
GATT_OPT_INVALID);
return ;
}/*RegisterSimpleService*/
static void update_name(struct btd_adapter *adapter, gpointer user_data)
{
adapter_set_name(adapter, (char*)user_data);
}/*update_name*/
static int wii_probe(struct btd_adapter *adapter)
{
update_name(adapter, "SimplePeripherial");
RegisterDeviceInfo(adapter);
RegisterSimpleService(adapter);
return 0;
}/*wii_probe*/
static void wii_remove(struct btd_adapter *adapter)
{
}/*wii_remove*/
/*function pointers*/
static struct btd_adapter_driver wii_driver = {
.name = "wiimote",
.probe = wii_probe,
.remove = wii_remove,
};
static int wii_init(void)
{
printf("__FUNCTION__ = %s\n", __FUNCTION__);
memset(&read1Data[0], 0, MAX_STR_LEN);
memset(&read2Data[0], 0, MAX_STR_LEN);
notifyData = 0;
snprintf(&read1Data[0], MAX_STR_LEN, "it is read 1");
snprintf(&read2Data[0], MAX_STR_LEN, "it is read 2");
return btd_register_adapter_driver(&wii_driver);
}
static void wii_exit(void)
{
printf("__FUNCTION__ = %s\n", __FUNCTION__);
btd_unregister_adapter_driver(&wii_driver);
}
BLUETOOTH_PLUGIN_DEFINE(wiimote, VERSION,
BLUETOOTH_PLUGIN_PRIORITY_LOW, wii_init, wii_exit)
And re-compiler the bluez library (you could just delete plugins/bluetoothd-wiimote.o and
type make again to boost the compilation time).
Step 5.
Similar with Step 3
Execute the command line under src folder:
[gaiger@localhost src]$ sudo ./bluetoothd -p wiimote -n
And Run the BleAdvertise script again : you may need to run it twice, to ensure that has
been executed indeedly.
Now you could use your BLE Scanner or LightBlue to confirm your Pheripheral has been run:
Known Insuffiecient :
If a central device (moblie) access the Notify characteristic, the bluez peripheral would be led to crash.
After the disconneciton event occurs, the Bluez perihpheral would not start again, it is,
You need to run the BleAdvertise script again.