These are a bunch of assorted notes I've been taking as I've been learning & working.
First, enable "Enable Bluetooth HCI snoop log" in the developer options.
Turn bluetooth off and on again. Now you can use the app to control the HT and the bluetooth commands will be recorded.
Then, run the following command to create a bug report:
adb bugreport bugreport_name
Use wireshark to read the log found in:
FS/data/misc/bluetooth/logs/btsnoop_hci.log
For more info, this is a good resource.
I found that the app uses the rfcomm (AKA SPP) protocol to communicate with the HT. It uses channel 1 transfering tx and rx sound clips. Then channel 3 is used for most of the data (setting / getting channel info, APRS data, etc.)
It does NOT use the more modern GATT protocol, which is for BLE.
bluetoothctl
is a command line utility that can be used to interact with
bluetooth devices. Here we use it to connect to the HT
sudo bluetoothctl
You'll get a console where you can interact with the bluetooth devices:
scan on # Start scanning for devices
scan off # Stop scanning for devices
pair XX:XX:XX:XX:XX:XX # Pair with the device
trust XX:XX:XX:XX:XX:XX # Trust the device
connect XX:XX:XX:XX:XX:XX # Connect to the device
disconnect XX:XX:XX:XX:XX:XX # Disconnect from the device
When you connect to the device, it seems to connect as a headset. It's not necessary to connect to the device to send commands, however -- you can just
There are a lot of examples of connecting to rfcomm channels with pybluez, but it doesn't seem to be actively developed anymore.
Instead, we can use the built-in socket library in python to connect to the device. See [simple_connect.py] for an example without error handling:
python3 simple_connect.py XX:XX:XX:XX:XX:XX
If you run the above code after freshly turning on the radio, it will work. But if you quit and then try to run it again, connecting to the data channel will result in a "Connection Refused" error.
If you turn the device on and off again, it will work again. But the app appears to not have this problem. After some digging I found that the app will just move to the next channel! So if you try to connect on channel 3 and it fails, try channel 4, then 5, etc. Perhaps this will be fixed in future firmwares?
Update 2024-10-04: I think SPP clients automatically handle this. When I connect to the device with the bluetooth serial API, it doesn't give any problems. However, I don't get all the audio traffic on the channel 1... I think I need an RFCOMM profile to do that, which bluetooth serial doesn't have.
GATT services and characteristics can be probed with gatttool
:
gatttool -b XX:XX:XX:XX:XX:XX -I
connect # Connect to the device
char-desc # List all characteristics
characteristics # List all characteristics
char-read-uuid <UUID> # Read a characteristic
disconnect # Disconnect from the device
rfcomm
can also be used to bind the device to a virtual serial port:
sudo rfcomm bind /dev/rfcomm0 XX:XX:XX:XX:XX:XX 1
This will bind the device to /dev/rfcomm0
on channel 1.
You can then view the data being sent to the device with:
sudo cat /dev/rfcomm0
You can also send data to the device with:
echo -n -e '\x7e\x02\x00\x00\x00\x00\x00\x00\x00\x00\x7e' | sudo tee /dev/rfcomm0
When you're done, you can unbind the device with:
sudo rfcomm release /dev/rfcomm0
You can look at the status via
sudo rfcomm
You can connect to a bound rfcomm via a terminal emulator like picocom as well:
picocom /dev/rfcomm0 -b 9600
Also pyserial:
import serial
ser = serial.Serial('/dev/rfcomm0', 9600)
ser.write(b'\x7e\x02\x00\x00\x00\x00\x00\x00\x00\x00\x7e')
while True:
print(ser.read())
Note that the baud rate doesn't really mean anything in this context; The bluetooth stack handles everything under the surface...