BlueZ: How to set up a GATT server from the command line - linux

I would like to know if there is a way to set up a gatt server from the Linux command line. I know that the BlueZ gatttool command allows you to act as a gatt client and interrogate a remote gatt server, however, I do not think that this tool can be used to set up a server.
What I want to achieve is a gatt server, created from the command line, and can be interrogated by any central device (e.g. iOS or Android device) to connect to the GATT server, discover the services and characteristics, and manipulate the data in the characteristics.
Example:
Gatt Server with 1 service which contains 3 characteristics.
Service uuid = 0xFFFF
Char 1 uuid = 0xAAAA, value = 01, properties = readable
Char 2 uuid = 0xBBBB, value = 00, properties = readable & writable
Char 3 uuid = 0xCCCC, value = 02, properties = notifiable
I am using kernel version 3.11.0 and BlueZ 5.19

So this is now handled with the new bluetoothctl tool. A gatt table can be set up using this tool as follows:-
#bluetoothctl
[bluetoothctl] menu gatt
[bluetoothctl] register-service 0xFFFF # (Choose yes when asked if primary service)
[bluetoothctl] register-characteristic 0xAAAA read # (Select a value of 1 when prompted)
[bluetoothctl] register-characteristic 0xBBBB read,write # (Select a value of 0 when prompted)
[bluetoothctl] register-characteristic 0xCCCC read # (Select a value of 2 when prompted)
[bluetoothctl] register-application # (This commits the services/characteristics and registers the profile)
[bluetoothctl] back
[bluetoothctl] advertise on
I've tried this with a few service/characteristic combinations and was able to get it to work. The GAP (0x1800) and GATT (0x1801) services are available by default and will be part of the GATT table when you advertise. You can also use the following command to see the available services:-
[bluetoothctl] show
Controller 00:AA:BB:CC:DD:EE (public)
Name: MyMachine
Alias: MyMachine
Class: 0x000c0000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Headset AG (00001112-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
**UUID: Unknown (0000ffff-0000-1000-8000-00805f9b34fb)**
UUID: Headset (00001108-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0532
Discovering: no

I have also faced the same issue, but could find any proper solution, what you can best do using a bluez stack on an Ubuntu machine is use some hci commands to advertise LE packets. These packets will be constantly advertised as the this is if it is an LE server, If you go for scan using an GATT Client you will get the name of your bluez device on the scan list.
Use the following commands below:
Set the LE advertisement packets by the following command:
sudo hcitool -i hcix cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00 00 00 00 C8 00
ยท Now advertise the LE packets by the following command:
sudo hciconfig hcix leadv

I believe it is not possible to setup GattServer from CLI.
Mainly because it is a upper layer functionality so there is no tool available to do it (as most of the tools provide lower layer functionalities).
But you can use mimic the way bluez creates service using dbus.
We needed a GattService with two characteristics (R,W,N)
What we ended up doing was following -
1. use the libgdbus (from bluez source) It has all the dbus wrapper to register services to bluez.
Created a translator (socket IPC) to separate the licensing issue (GPL)
Send command to the service registrar to create a service
e,g - op_code = create_service, uuid = 'service_uuid'
op_code = create_charac, uuid='charac_uuid' flags='rwn'
Hope this helps.

Related

Can't set fast-connectable on my Bluetooth controller with BlueZ5

I can't set fast-connectable on my Bluetooth controller:
# btmgmt fast-conn on
Set Fast Connectable for hci0 failed with status 0x0c (Not Supported)
though fast-connectable is supported according to btmgmt!
# btmgmt info
Index list with 1 item
hci0: Primary controller
addr 4C:74:03:64:82:1F version 7 manufacturer 15 class 0x000000
supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr hs le advertising secure-conn debug-keys privacy configuration static-addr
current settings: powered connectable bondable le secure-conn
name mybox
short name
hci0: Configuration options
supported options: public-address
missing options:
Same problem if the controller is powered off
# btmgmt power off
before trying to apply fast-connectable...
Would you have any idea why?
I'm running a Linux 4.1.20 kernel, with BlueZ 5.49.
I searched the Internet, the BlueZ documentation, but couldn't find much information about the setting fast-connectable. Help would be appreciated.

Raspberry Pi as a audio Transmitter to a Bluetooth Speaker

i wanted to ask you guys, if it is possible to use the Raspberry Pi as a transmitter from a audio source, lets say a TV for example.
I want to send the sound from the TV to the Raspberry Pi via audio Jack and then send the sound via Bluetooth to a wireless speaker. So the Rasberry should act like a bridge between TV and the speaker.
It should look like this in the end:
TV --Sound via audio jack--> Raspberry Pi ~~Sound via Bluetooth~~>
speaker
So, if there is a way, how can i do this ? Thanks in advance
RPi doen't have audio input. You need one of these adapter like this (http://raspberry-projects.com/pi/pi-hardware/audio-input) and connect input to TV and RPi output to wireless / bluetooth speakers. I haven't tried it yet. Let me your feedback.
Since a web search might bring others here as it did me, here's how I did this connecting my record player through a Raspberry Pi 3 to a Bose Portable Home/Smart Speaker.
Get an audio input into the Pi
I used a cheap USB soundcard bought on Adafruit
Identify your new PulseAudio input/source and note name
This can be done by calling pactl list sources (mine was identifiable from its name and description)
$ pactl list sources
...
Source #2
State: RUNNING
Name: alsa_input.usb-GeneralPlus_USB_Audio_Device-00.mono-fallback
Description: USB Audio Device Mono
...
Connect your Pi to your bluetooth speaker
Run sudo bluetoothctl (running this without sudo resulted in settings being forgotten upon reboot) and enter the commands below
(Optional) Give your Pi an alias when connecting over bluetooth: [bluetooth]# system-alias 'Your New BT Alias'
Enter scanning mode [bluetooth]# scan on
Put your speaker in pairing mode and wait for it to be listed in the rolling output. E.g.
[NEW] Device AA:AA:AA:AA:AA:AA AA-AA-AA-AA-AA-AA
[NEW] Device BB:BB:BB:BB:BB:BB BB-BB-BB-BB-BB-BB
[NEW] Device CC:CC:CC:CC:CC:CC My speaker's name
Pair with it referencing its address:
[bluetooth]# pair CC:CC:CC:CC:CC:CC
Attempting to pair with CC:CC:CC:CC:CC:CC
[CHG] Device CC:CC:CC:CC:CC:CC Connected: yes
Request confirmation
[agent] Confirm passkey 123456 (yes/no): yes
Connect to the speaker now
[bluetooth]# connect CC:CC:CC:CC:CC:CC
Attempting to connect to CC:CC:CC:CC:CC:CC
[CHG] Device CC:CC:CC:CC:CC:CC Connected: yes
Connection successful
Trust the speaker so it is automatically connected to when available
[My speaker's name]# trust CC:CC:CC:CC:CC:CC
[CHG] Device CC:CC:CC:CC:CC:CC Trusted: yes
Changing CC:CC:CC:CC:CC:CC trust succeeded
Note your bluetooth speaker's associated PulseAudio output/sink name
This can be done by calling pactl list sinks (again, should be identifiable by name and description)
$ pactl list sinks
...
Sink #2
State: RUNNING
Name: bluez_sink.CC_CC_CC_CC_CC_CC.a2dp_sink
Description: My speaker's name
...
Set up PulseAudio defaults
Identify a good volume level for your input so distortion is minimal. E.g.
pactl set-source-volume alsa_input.usb-GeneralPlus_USB_Audio_Device-00.mono-fallback 16000
Add your version of the following lines to /etc/pulse/default.pa to set up an audio loopback and ensure the correct devices (based on the names you noted above) are used by default:
### Make some devices default
set-default-sink bluez_sink.60_AB_D2_57_42_A9.a2dp_sink
set-default-source alsa_input.usb-GeneralPlus_USB_Audio_Device-00.mono-fallback
# Set up loopback
load-module module-loopback latency_msec=1
# Set input volume
set-source-volume alsa_input.usb-GeneralPlus_USB_Audio_Device-00.mono-fallback 16000

Is there a way to find out which Bluetooth device is plugged into which USB port?

I'm using two Bluetooth adaptors with BlueZ, both are the same device but with different types of antenna, is there any method to find out which usb port the identifier on BlueZ (hci0/hci1) is referring to?
I can discover the MAC address of the device through hcitool dev, so if there was a way to discover which USB port the adaptor with that MAC address was connected to, that would also solve my problem.
As both the adaptors are the same model, lsusb does not provide any identifying information I can use.
Using Ubuntu 16.04. I am looking for a solution in any form, whether it is a shell command or java/C/python/etc.
This answer should point you in the right direction, though doesn't give you a complete solution.
You should be able to use the contents of the "sys" filesystem, under /sys/class/bluetooth:
$ ls -lA /sys/class/bluetooth/
total 0
lrwxrwxrwx 1 root root 0 Dec 8 09:35 hci0 -> ../../devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/bluetooth/hci0
lrwxrwxrwx 1 root root 0 Dec 8 09:35 hci1 -> ../../devices/platform/soc/3f201000.serial/tty/ttyAMA0/hci1
That's from my Raspberry Pi, with a builtin adapter on the /dev/ttyAMA0 UART interface, and an added Bluetooth adapter on USB. The information in the symlink target technically tells you which physical port the adapter is plugged into.
If you're not familiar with the convention for USB device numbering (which forms a tree of nodes, since a port can have a USB hub with multiple additional ports, etc), look under /sys/bus/usb/devices, and match that up with the "lsusb" output and you should figure it out. In my case, "lsusb" shows that adapter as "Bus 001 Device 004: ID 0a5c:21e8 Broadcom Corp. BCM20702A0 Bluetooth 4.0", which if I recall corresponds to the "1-3" stuff in the /sys/class/bluetooth path (where unfortunately it appears the bus value uses index origin 1, while the device number uses index origin 0 so the 4 turns into a 3 there).
If you experiment with moving your USB adapter around to different physical ports, you should be able to work out the pattern.
I don't know if this is what you need, but you should find detailed information about the devices attached through the following command:-
hciconfig -a
This will give you enough details to identify the specific devices. You can add this in a shell script and use some string manipulation and conditionals to figure out your devices.
In my case, I have one BT dongle connected, and running hciconfig -a give the following output:-
hci0: Type: BR/EDR Bus: USB
BD Address: 00:16:A4:06:AC:E6 ACL MTU: 310:10 SCO MTU: 64:8
UP RUNNING
RX bytes:670 acl:0 sco:0 events:46 errors:0
TX bytes:2495 acl:0 sco:0 commands:46 errors:0
Features: 0xff 0xff 0xcf 0xfe 0xdb 0xff 0x5b 0x87
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: SLAVE ACCEPT
Name: 'youssif'
Class: 0x0c0000
Service Classes: Rendering, Capturing
Device Class: Miscellaneous,
HCI Version: 4.0 (0x6) Revision: 0x22bb
LMP Version: 4.0 (0x6) Subversion: 0x22bb
Manufacturer: Cambridge Silicon Radio (10)
If this is not sufficient, you can use also use a combination of lsusb and hciconfig commands to figure out which device is connected to what port.

change Bluetooth from master to slave using bluez library

Description:
I have a small in-house device with bluetooth capabilities.
At the moment , other devices connect to that box.
Requirement:
Now we have to make it slave so that it get connected with other devices. I am wondering how to do it ? I don't need source code or anything just your views.
Additional Information:
The application uses Bluez libraires to send command to firmware/hardware and we extensively use HCItool.
Operating system :
Fedora.
I am also wondering , do I need to change chipset? From google it doesnt look like we need to change it.
Any help will be beneficial to us.
Thanks
From the command line, the way to achieve what you want is to use the #hcitool. However, you must first be connected. Try this sequence:
hcitool cc AA:BB:CC:DD:EE:FF #Connect to the device
hcitool con #To make sure you are in a connection
hcitool sr AA:BB:CC:DD:EE:FF <role> #switch master/slave role
If the output of "hcitool con" indicates that you are not in a connection, try the following sequence:
hciconfig hci0 sspmode 1
hciconfig hci0 piscan
sdptool add SP
rfcomm connect /dev/rfcomm0 AA:BB:CC:DD:EE:FF 1 &
hcitool con
hcitool sr AA:BB:CC:DD:EE:FF <role>
The above code is specifically for the serial profile, but it has worked for me on several occasions when 'hcitool cc' failed.
If you want to see the source code for this, open the tools/hcitool.c source file in the bluez directory and navigate to the function:
static void cmd_sr(int dev_id, int argc, char **argv)
This is the function that fires up the sequence for switching between master and slave role. Following this function you can see what exactly happens through the bluez stack.
I hope this helps.

Legacy pairing, SSP - enable from command line [Linux]

As part of my automation project, I have two USB dongles and I need to automate the bluetooth test-cases. Both the devices seem to support SSP. This I infer from the hciconfig output. For ex: typing $hciconfig hci0 sspmode
I get,
hci0: Type: BR/EDR Bus: USB
BD Address: xx:xx:xx:xx:xx:xx ACL MTU: 1021:8 SCO MTU: 64:1
Simple Pairing mode: Enabled
and I get a similar output for hci1. My questions are as follows:
a) How do I make them do SSP from command line [with and without encryption]?
b) How do I make them pair using legacy pairing method from command line [with and without encryption]?
For both #a and #b, how do I validate that indeed SSP and legacy pairing have happened using hcidump [if someone can point me to what to expect from the hci logs, I Would be very thankful.

Resources