Posts Setting up a bluetooth device for use with serial communication in Linux
Post
Cancel

Setting up a bluetooth device for use with serial communication in Linux

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

Comments

This post is licensed under CC BY 4.0 by the author.