Environment: Bluez 5.14, Linux 3.1, USB Plugable BLE radio, TI BLE keyfob (CC2541 dev kit)
Linux Device <---hci----> USB BLE Radio
We enabled key press events on TI keyfob using gatttool and started to listen for events
gatttool -b [hardware ID] --char-write-req -a [handle] -n [value] --listen
(gatttool -b 90:59:AF:09:E1:5D --char-write-req -a 0x0048 -n 0100 --listen)
Pressing buttons on the keyfob and see these events
Notification handle = 0x0047 value: 02
Notification handle = 0x0047 value: 00
Notification handle = 0x0047 value: 02
Hence we can receive the key press events from the Keyfob through the Bluez stack
Objective:
We need to catch the GATT Disconnect Event i.e. When we remove the battery from the keyfob sooner or later the GATT connection is broken. We would like to receive a disconnect event from Bluez stack. Bluez has this capability since Android supports GATT disconnect event which is built over Bluez.
Question:
How do we receive the GATT Disconnect event using Bluez command line hcitool/gatttool or Bluez API.
Watch for G_IO_HUP and shutdown gracefully.
chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
opt_psm, opt_mtu, connect_cb, &gerr);
if (chan == NULL) {
log_printf(LOG_LEVEL_ERROR,"%s: chan is NULL\n",__func__);
log_printf(LOG_LEVEL_ERROR,"%s\n", gerr->message);
g_error_free(gerr);
g_main_loop_quit(event_loop);
} else {
log_printf(LOG_LEVEL_INFO,"Connected to %s\n",opt_dst);
g_io_add_watch(chan, G_IO_HUP, channel_watcher, NULL);
}
Related
I am using a Fire TV Remote Control Version 1, the old one which has no volume and power buttons.
What I want to achieve is, receive audio samples from the build in mic of this remote.
I am using a Raspberry Pi 4 with debian
Linux raspi4box 5.4.79-v7l+ #1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l GNU/Linux
I have paired the Remote with bluetoothctl successfully and can read the key events.
When the Mic button is pressed, i want to establish a connect to the device and read
audio. I can receive the Mic button events correctly so far.
bluetoothctl -- info FC:65:DE:E8:E8:FD
Name: Amazon Fire TV Remote
Alias: Amazon Fire TV Remote
Class: 0x00001f00
Paired: yes
Trusted: yes
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)
UUID: Human Interface Device... (00001124-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1949p0410d0304
sdptool browse FC:65:DE:E8:E8:FD
Browsing FC:65:DE:E8:E8:FD ...
Service Name: SPPSERVER
Service RecHandle: 0x20000002
Service Class ID List:
UUID 128: 00001101-0000-1000-8000-00805f9b34fb
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 6
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
As You can see, the Remote exposes a Serial Port Profile.
I can connect to the service with:
sudo rfcomm connect /dev/rfcomm1 FC:65:DE:E8:E8:FD 1
...
Connected /dev/rfcomm1 to FC:65:DE:E8:E8:FD on channel 1
Press CTRL-C for hangup
I can use a teminal programm on /dev/rfcomm1 which comes up with a request from the remote:
AT+BRSF=253
At this point you should be able to answer the request and finally initiate the
recording on channel 6.
At this point i am stuck, because i get not further response
from the device.
Regards
Dezi
I am attempting to implement hands-free telephony on my board, I successfully connected my android phone to the board via bluetooth module in phone and media audio sharing mode.
The chip i use is Qualcomm Atheros QCA6174. I have pulseaudio 11.1, bluetoothctl: 5.49, and ofono 1.22 setup on my board.
I was able to play media files via bluetooth by this. But when a call connected the bluetooth speaker works properly, i.e. I can hear what is said on the other end of call via my headphone, but what I say is not heard at the other end( I guess there is some error in getting the data from mic or in transmitting data from bluetooth device). I get the following log message keeps appearing many times as soon as a call is initiated
"***Bluetooth: hci0 SCO packet for unknown connection handle 0***
***Bluetooth: hci0 sending frame failed (-27)***
***Bluetooth: hci0 sending frame failed (-27)***"
The microphone on the phone is also not functioning(after bluetooth connection is established).
Also in *hciconfig -a* it is found as follows
hci0: Type: Primary Bus: USB
BD Address: 00:0E:8E:76:00:55 ACL MTU: 1024:8 SCO MTU: 50:8
UP RUNNING PSCAN
RX bytes:810924 acl:982 sco:18885 events:670 errors:0
**TX bytes:528349 acl:530 sco:10271 commands:108 errors:111**
Features: 0xff 0xfe 0x8f 0xfe 0xd8 0x3f 0x5b 0x87
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF
Link mode: SLAVE ACCEPT
Name: mydevice
Class: 0x2c041c
Service Classes: Rendering, Capturing, Audio
Device Class: Audio/Video, Portable Audio
HCI Version: 4.2 (0x8) Revision: 0x0
LMP Version: 4.2 (0x8) Subversion: 0x25a
Manufacturer: Qualcomm
The steps I followed to setup connection are as follows
$ hciconfig hci0 up
$ pactl list sources short
$ pactl list sinks short
$ bluetoothctl
agent on
scan on
scan off
pair <address>
connect<address>
My hcitool connections gives the following
$ hcitool con
Connections:
< ACL 78:C3:E9:21:1B:0B handle 2 state 1 lm MASTER AUTH ENCRYPT
No SCO connection is shown here.
How can I solve this and implement proper hands-free telephony?
I am using Bluez 5.50; 5.48 was the version acquire-write became officially (non-experimentally) supported. Am I using the acquire-write / write feature properly?
On my Raspberry Pi Zero W:
pi#raspberrypi:~ $ bluetoothctl
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Discovery started
[bluetooth]# connect B8:27:E8:72:33:7A
Attempting to connect to B8:27:E8:72:33:7A
Connection successful
[DSD TECH]# menu gatt
[DSD TECH]# select-attribute 0000ffe1-0000-1000-8000-00805f9b34fb
[DSD TECH:/service0010/char0011]# acquire-write
[CHG] Attribute /org/bluez/hci0/dev_B8_27_E8_72_33_7A/service0010/char0011 WriteAcquired: yes
AcquireWrite success: fd 7 MTU 23
[DSD TECH:/service0010/char0011]# write("h")
[DSD TECH:/service0010/char0011]# write('h')
[DSD TECH:/service0010/char0011]# write(h)
[DSD TECH:/service0010/char0011]# write(0x68)
On my Arduino Nano connected to HM-10:
void setup()
{
Serial.begin(9600);
}
void loop() {
delay(10);
if (Serial.available())
{
char c = Serial.read();
Serial.println("Read value");
}
}
I use the iOS app named "Serial" which connects to my HM-10. I send the letter h over and read "Read value" on the arduino serial monitor. I do this directly before and after using the raspberry pi, on the same arduino serial monitor. The raspberry pi notifications never come thru. Yes, I am certain it is the same HM-10. It is the only HM-10 I have powered on in BLE range, and I cannot connect to the UUID while my phone is connected. (Actually, I submit connect B8:27:E8:72:33:7A to the raspberry pi, and keeps trying, and then disconnect from phone, and rpi automatically connects).
Thanks in advance!
When using gatt services with bluetoothctl, leave off the parentheses and just use:
write 0x68
acquire-write returns a file descriptor that can be used for writing to the GATT characteristic, usage of write will be locked. so either use acquire-write (which requires a write-without-response flag) or use write.
void WriteValue(array{byte} value, dict options)
Issues a request to write the value of the
characteristic.
Possible options: "offset": Start offset
"device": Device path (Server only)
"link": Link type (Server only)
"prepare-authorize": boolean Is prepare
authorization
request
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
org.bluez.Error.InvalidValueLength
org.bluez.Error.NotAuthorized
org.bluez.Error.NotSupported
fd, uint16 AcquireWrite(dict options) [optional]
Acquire file descriptor and MTU for writing. Usage of
WriteValue will be locked causing it to return
NotPermitted error.
For server the MTU returned shall be equal or smaller
than the negotiated MTU.
For client it only works with characteristic that has
WriteAcquired property which relies on
write-without-response Flag.
To release the lock the client shall close the file
descriptor, a HUP is generated in case the device
is disconnected.
Note: the MTU can only be negotiated once and is
symmetric therefore this method may be delayed in
order to have the exchange MTU completed, because of
that the file descriptor is closed during
reconnections as the MTU has to be renegotiated.
Possible options: "device": Object Device (Server only)
"MTU": Exchanged MTU (Server only)
"link": Link type (Server only)
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.NotSupported
How to set scan parameters and disable the filter duplicates, so that I can receive all advertisement from the controller ?
StartDiscovery API only notifies, whenever new device is identified but I want to set filter duplicate to disabled, so that I can receive each and every advertisement from the controller?.
But I didn't find any DBus API to set the scan parameters nor set scan enable API.
My Goal is simple I need get notify each advertisement received on controller to my client app, How can I do that with Bluez?
Note : I might missing some basic points because new to bluetooth and bluez.
In the below output you can see that the Device "Parthiban" is already present under /org/bluez/hci0/dev_44_D8_84_02_A3_17. I have started the scan which in turn triggers "StartDiscovery()" method and the same device is updated with RSSI value.
root#mx6q:~# bluetoothctl
[NEW] Controller 5C:F3:70:6E:26:02 Adapter [default]
**[NEW] Device 44:D8:84:02:A3:17 Parthiban**
[NEW] Device 2C:F0:A2:26:D7:F5 iPhone tteam
[NEW] Device 78:F8:82:10:E7:0C Nexus 5X
[bluetooth]# scan on
Discovery started
[CHG] Controller 5C:F3:70:6E:26:02 Discovering: yes
**[CHG] Device 44:D8:84:02:A3:17 RSSI: -52**
So you can use "g_dbus_connection_signal_subscribe" on the interface "org.freedesktop.DBus.Properties" for "PropertiesChanged" signal.
while(g_variant_iter_loop(&iter, "{sv}", &property, &value)) {
if(strcasecmp(property, "RSSI") == 0) {
/*
* - Extract the device address from object path
* /org/bluez/hci0/dev_44_D8_84_02_A3_17
* - Play with the device
*/
}
I have previously paired with a Bluetooth device that supports RFCOMM.
When my app is opened I continuously try to connect to the device by opening the RFCOMM. This way my app automatically connects when the device comes in range.
deviceInfoCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
LogData(String.Format("Number of mldp devices is {0}", deviceInfoCollection.Count));
foreach (DeviceInformation deviceInfo in deviceInfoCollection)
{
LogData(String.Format("ID:{0}, NAME:{1}", deviceInfo.Id, deviceInfo.Name));
}
Then run this on a timer:
try
{
// The first time this method is invoked by a store app, it should be called
// from a UI thread in order to display the consent prompt
// https://msdn.microsoft.com/en-us/windows.devices.bluetooth.rfcomm.rfcommdeviceservice.fromidasync
RfcommDeviceService rfcommService = await RfcommDeviceService.FromIdAsync(deviceInfo.Id);
LogData(String.Format("ID:{0}, NAME:{1}", deviceInfo.Id, deviceInfo.Name));
}
catch (Exception)
{
LogData(String.Format("Can not request rfcomm service from device ID:{0}, NAME:{1}", deviceInfo.Id, deviceInfo.Name));
}
Is there any way to query when the device is in range , rather than trying to connect? I would prefer to only attempt connection when the device is in range.
For RFCOMM (BT2.0, BT2.1) you can run a device enumeration periodically, see also Get bluetooth devices in range
However your actual implementation with a connection attempt may work a little better.
For Bluetooth 4.0, you can listen to the advertisements of the BT module, see also https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothAdvertisement
If you're talking to an embedded device (e.g. some robot, or homebrew appliances using RFCOMM) I am afraid there is no better solution than what you're doing.
If you're taking to a phone (which supports both BT4.0 and BT2.1) you can use the BT4 advertisements to signal the proximity of the device, then connect via RFCOMM.