2

I have a Raspberry PI 3 model B, with built-in Bluetooth hardware, and I'm running the latest Debian distro on it (Linux raspberry 5.15.61-v7+).

I successfully paired and connected from Raspberry (using a SSH terminal) to a Windows 10 machine (Surface 3 tablet).

I did the scanning, pairing and trusting using the bluetoothctl utility, then I used the rfcomm utility to create a COM port (/dev/rfcomm0) on Debian side: sudo rfcomm connect hci0 38:FC:98:47:05:67 - W10 automatically connected and it's looking like this:

enter image description here

On the W10 machine I now now have this following setup: enter image description here

So far so good, I hope!

Now I want to test the BT communication between this two devices, and I want to pass some messages using terminals.

On Raspberry side I first set the BAUD rate associated to /dev/rfcomm0 port to 19200 using this command: stty -F /dev/rfcomm0 19200, then I start a terminal session on this port using the screen tool: screen /dev/rfcomm0 19200.

Now on W10 side I'm using RealTerm tool and I'm trying to connect to one of the new two COM ports that were created after pairing and connecting to Raspberry: (COM5 - Outgoing, and COM9 - Incoming) - not sure which one should be used so I'll just try both of them.

  • When trying to connect to COM5 RealTerm throws me the following error, so can't do any testing using this Outgoing COM port - I've also tested using TeraTerm - same issue, won't open the port: enter image description here

  • When trying to connect to COM9 RealTerm successfully connects but doesn't send any data over BT (or the Raspberry doesn't receive - not sure), and this weird thing: TXD "pin" remains always ON until I disconnect: enter image description here

On the Raspberry side all this time the screen terminal session is still active and blank - if I'm pressing some keys nothing shows on RealTerm (COM9) side.

I've restarted W10 and Raspberry a couple of times, also redo all the BT scanning and pairing - same issue every time.

How should I fix this? What else should I check?

3
  • I am not sure about RealTerm. It looks like the software designed for capture data from serial communication. Try PuTTY or something like that. All your steps look correct. Commented Feb 3, 2023 at 16:26
  • @MikePetrichenko Tried PuTTY and TeraTerm as well, same issue - both can't open the Outgoing port. One thing I noticed is that W10 sees the BT connection as "Audio", I've found and followed a fix for this: raspberrypi.stackexchange.com/questions/140552/… Now "raspberry" connection is listed in "Others" list, but the same issue persists - Outgoing COM port can't be opened, and the Incoming COM port doesn't receive nor transmit any data...
    – mariusmmg2
    Commented Feb 3, 2023 at 20:17
  • I'm not very familiar with Bluetooth tools on *nix platforms. Can you please provide details how you created rfcomm port on raspbery side so I can reproduce it here and took a look deeper on the issue? Commented Feb 4, 2023 at 7:12

1 Answer 1

2

The first thing to mention is that rfcomm was deprecated back in 2017 by the BlueZ project so if you are following a tutorial, it is likely that it is out of date.

The second thing to mention is that trying to develop both ends of the connection at the same time makes life tricky. Try to develop one end at a time so it is clear where the issue is.

There isn't really a direct replacement tool for rfcomm. bluetoothctl will show what services (specified by UUID) the RPi is making available. For example:

[bluetooth]# show
Controller B8:27:EB:22:57:E0 (public)
        Name: SensePi
        Alias: SensePi
        Class: 0x002c0000
        Powered: yes
        Discoverable: no
        DiscoverableTimeout: 0x000000b4
        Pairable: yes
        UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
        UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
        UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
        UUID: Audio Sink                (0000110b-0000-1000-8000-00805f9b34fb)
        UUID: Headset                   (00001108-0000-1000-8000-00805f9b34fb)
        UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Device Information        (0000180a-0000-1000-8000-00805f9b34fb)
        UUID: Headset AG                (00001112-0000-1000-8000-00805f9b34fb)
        Modalias: usb:v1D6Bp0246d0537
        Discovering: no
        Roles: central
        Roles: peripheral
Advertising Features:
        ActiveInstances: 0x00 (0)
        SupportedInstances: 0x05 (5)
        SupportedIncludes: tx-power
        SupportedIncludes: appearance
        SupportedIncludes: local-name

By default there is typically not "1101" Serial Port Profile.

        UUID: Serial Port               (00001101-0000-1000-8000-00805f9b34fb)

which there needs to be for the type of serial connection you want to make. Below is some Python code that will create a server that echo's back any data (after reversing it) that is useful for testing.

#!/usr/bin/python3

import os
import dbus
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib


class Profile(dbus.service.Object):
    fd = -1

    @dbus.service.method('org.bluez.Profile1',
                         in_signature='',
                         out_signature='')
    def Release(self):
        print('Release')

    @dbus.service.method('org.bluez.Profile1',
                         in_signature='oha{sv}',
                         out_signature='')
    def NewConnection(self, path, fd, properties):
        self.fd = fd.take()
        print('NewConnection(%s, %d)' % (path, self.fd))
        for key in properties.keys():
            if key == 'Version' or key == 'Features':
                print('  %s = 0x%04x' % (key, properties[key]))
            else:
                print('  %s = %s' % (key, properties[key]))
        io_id = GLib.io_add_watch(self.fd,
                                  GLib.PRIORITY_DEFAULT,
                                  GLib.IO_IN | GLib.IO_PRI,
                                  self.io_cb)

    def io_cb(self, fd, conditions):
        data = os.read(fd, 1024)
        print('Callback Data: {0}'.format(data.decode('ascii')))
        os.write(fd, bytes(list(reversed(data.rstrip()))) + b'\n')
        return True

    @dbus.service.method('org.bluez.Profile1',
                         in_signature='o',
                         out_signature='')
    def RequestDisconnection(self, path):
        print('RequestDisconnection(%s)' % (path))

        if self.fd > 0:
            os.close(self.fd)
            self.fd = -1


def main():
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SystemBus()

    manager = dbus.Interface(bus.get_object('org.bluez',
                                            '/org/bluez'),
                             'org.bluez.ProfileManager1')

    mainloop = GLib.MainLoop()

    adapter = dbus.Interface(bus.get_object('org.bluez',
                                            '/org/bluez/hci0'),
                            dbus.PROPERTIES_IFACE)
    discoverable = adapter.Get('org.bluez.Adapter1', 'Discoverable')
    if not discoverable:
        print('Making discoverable...')
        adapter.Set('org.bluez.Adapter1', 'Discoverable', True)

    profile_path = '/foo/baz/profile'
    server_uuid = '00001101-0000-1000-8000-00805f9b34fb'
    opts = {
        'Version': dbus.UInt16(0x0102),
        'AutoConnect': dbus.Boolean(True),
        'Role': 'server',
        'Name': 'SerialPort',
        'Service': '00001101-0000-1000-8000-00805f9b34fb',
        'RequireAuthentication': dbus.Boolean(False),
        'RequireAuthorization': dbus.Boolean(False),
        'Channel': dbus.UInt16(1),
    }

    print('Starting Serial Port Profile...')

    profile = Profile(bus, profile_path)

    manager.RegisterProfile(profile_path, server_uuid, opts)

    try:
        mainloop.run()
    except KeyboardInterrupt:
        mainloop.quit()


if __name__ == '__main__':
    main()

Save this code as spp_server.py for example. To run it python3 spp_server.py

$ python3 spp_server.py 
Making discoverable...
Starting Serial Port Profile...

If you are running with a Python Virtual Environment (venv) then you will need to install a couple of extra packages into the venv. If you are running with the system wide python on a RPi then I would expect them to be installed already

They are:

$ pip install dbus-python
$ pip install vext.gi

This can now be tested with an app such as the following on an Android phone:

https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal&gl=DE&pli=1

Make sure you have a the python script running and you also have a window with bluetoothctl running so you can respond to pairing requests.

Once you have that running you can move on to the Windows client. Initially I used the following Python code (In python 3.9 or newer) to establish the connection:

import socket

server_address = "B8:27:EB:22:57:E0"
server_port = 1

with socket.socket(socket.AF_BLUETOOTH,
                   socket.SOCK_STREAM,
                   socket.BTPROTO_RFCOMM) as c:

    c.connect((server_address, server_port))
    c.send(b'desserts')
    print(c.recv(1024).decode())

Again, have a bluetoothctl open on the RPi to respond to pairing requests.

Once I had done this once I had a device with the correct kind of port available

enter image description here

And could connect with putty:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.