In this post I will explain how to setup a Bluetooth device (for example a GPS receiver) so that it can be used for serial communication through Linux’ rfcomm system.
I created some Bash scripts to make the process somewhat easier.
Prerequisites
- Linux distribution with Bluetooth support (BlueZ stack, available on most distro’s)
- Bluetooth MAC address of the device to be configured. This can be found by pairing your device with
for example a mobile phone and check in the settings for a string in the form of XX:XX:XX:XX:XX:XX
Pairing
Pairing of a device is done with the bluetoothctl program (which is part of the BlueZ stack) It’s a interactive program but with some tricks it can be executed from a script along the lines of:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
pair_device() {
MAC=$1 # BT MAC address
PIN=$2 # PIN needed for pairing
printf "\n"
echo "Setup device $MAC with PIN $PIN"
printf "\n"
# This block will be piped to bluetoothctl line by line
{
printf "power on\n\n" # Enable BT controller
printf "scan on\n\n" # Enable scan mode, adds discovered devices to an internal list
sleep 20 # Wait a bit until we're sure that our device is discovered
printf "scan off\n\n" # Disable scan mode
printf "agent on\n\n" # Enable agent (needed for pairing)
printf "pair $MAC\n\n" # Start pairing process
sleep 5 # Wait for the 'Enter pin' prompt
printf "$PIN\n\n" # Send PIN
sleep 5
printf "trust $MAC\n\n" # Trust this device so that the PIN is not
sleep 5 # needed the next time the device is accessed
printf "quit\n\n"
} | bluetoothctl
# The 'info' command gives information about a device, among others if a device is paired and/of trusted
STATUS=$(bluetoothctl info $MAC | grep yes)
# Check output
if [[ $STATUS == *"Paired"* ]] && [[ $STATUS == *"Trusted"* ]] ; then
echo "Successfully paired $MAC "
return 0
fi
echo "ERROR: $MAC not succesfully paired"
printf "\n"
return 1
}
Notes:
- Script needs to be run as root.
- The scan delay (
sleep 20
) is something to play around with. - This script needs only to be executed once, the pairing survives reboots.
Serial port setup
Rfcomm
To use the Bluetooth device as a serial device the rfcomm command is used. This program creates a virtual device in /dev/rfcommX which then can be used as a regular serial device.
First determine the channel number by executing sdptool browse $MAC
and find the channel number under the RFCOMM
section.
Example output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
pi@raspberrypi:~ $ sdptool browse 00:1C:88:01:DD:A4
Browsing 00:1C:88:01:DD:A4 ...
Service Name: SPP slave
Service RecHandle: 0x10000
Service Class ID List:
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Then execute the rfcomm command as follows:
1
2
3
sudo rfcomm bind /dev/rfcommX $MAC $CHANNEL # X is a number between 0 and 9
(e.g.)
sudo rfcomm bind /dev/rfcomm0 00:1C:88:01:DD:A4 1
To check if everything went well, execute and check output:
1
2
pi@raspberrypi:~ $ rfcomm -a
rfcomm0: 00:1C:88:01:DD:A4 channel 1 clean
Binding at startup
Since the binding of the port to the device as described in the previous section doesn’t survive a reboot a systemd service can be created that does the binding at system startup. This can be done as follows:
Create a file rfcomm.service
with something along the lines of:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=RFCOMM service
After=bluetooth.service
Requires=bluetooth.service
[Service]
Type=oneshot
ExecStart=/usr/bin/rfcomm bind /dev/rfcommX $MAC $CHANNEL
RemainAfterExit=true
ExecStop=/usr/bin/rfcomm release /dev/rfcommX # Clean up things when service is stopped
StandardOutput=journal
[Install]
WantedBy=multi-user.target
Copy this file to /etc/systemd/system
.
Enable the service at boot time by executing:
1
sudo systemctrl enable rfcomm
To start the service immediately:
1
sudo systemctrl start rfcomm
Check if everything went well by checking:
1
sudo systemctrl status rfcomm
and
1
rfcomm -a