3

I have got a RPi 3 loaded with Raspbian GNU/Linux 8.0 (jessie) and I use pyserial to send data over Bluetooth to an Android application. Pairing the Pi with the Android device works fine.

For my Android device to connect to the Pi, I need to run

sudo rfcomm watch hci0

or

sudo rfcomm listen hci0

otherwise the Android device is unable to connect (because there is no serial port abstraction available for the communication) and /dev/rfcomm0 is never created.

Once rfcomm watch is runnning, the Android device is able to establish the connection and /dev/rfcomm0 appears. I can start my python script to send data from the Pi to the Android device:

import serial
from serial.serialutil import SerialException

def initiate_ble_serial_port():
        try:
                port_ble_tablet = serial.Serial("/dev/rfcomm0")
                print("Serial port for the Android device initialized: " + str(port_ble_tablet))
                return port_ble_tablet
        except SerialException as e:
                print(e)
                return None

port_ble_tablet = initiate_ble_serial_port()

while True:
        # doing some unrelated stuff
        ble_msg = str(rcv_cnt/10) + ":::"
        if port_ble_tablet:
                port_ble_tablet.write(ble_msg.encode())

This works like a charm provided that the order between the different actions is as follow:

rfcomm watch > Android connected > python script

However, if you change that order or if my Android disconnects for some reason (rebooting, restarting the application, out of range, etc.) and tries to reconnect to the Pi after some time, the communication is lost. That is, the write instruction in the above script raises a SerialException

write failed: [Errno 5] Input/output error

and /dev/rfcomm0 no longer exists, although the Android device says it is connected to the Pi. The same problem occurs both with rfcomm watch and rfcomm listen.

Trying to reset the Serial object in python (namely, calling port_ble_tablet = initiate_ble_serial_port() again) does not help.

How do I ensure a smooth, robust (re)connection behaviour between my Android device and the RPi 3?

1 Answer 1

2

In short

The problem comes from the python script which does not close the serial port after the Android device has disconnected. One can implement a mechanism (doesn't matter how exactly you want to achieve it) that reacts to a Disconnected message received by rfcomm watch. Namely, when the disconnection occurs, you want to

  1. Either close the port in python by calling Serial.close or kill the python process
  2. Wait for the device to reconnect
  3. Reopen the port or restart the python process

In detail

After calling rfcomm listen <dev> or rfcomm watch <dev>, the Pi is effectively waiting for a connection to be established on /dev/rfcomm0.

When the Android device initiates the connection, the endpoint /dev/rfcomm0 is created and will live forever unless the connection is broken by either of the parties.

In this situation, the python script referred in the question opens up the newly created serial interface (/dev/rfcomm0) via the Serial object abstraction.

Now when the Android device breaks the link, /dev/rfcomm0 is indeed removed but the python Serial object still lives in memory and keeps the port open even though the Android device is down. So when the Android device tries to reconnect after some time, rfcomm watch rightfully complains:

Can't create RFCOMM TTY: Address already in use

simply because the port hasn't been properly closed by the python script when the Android device first left.

To circumvent the problem, one can implement a mechanism (does not matter how exactly you want to achieve it) that reacts to a Disconnected message received by rfcomm watch. Namely, when the disconnection occurs, you want to

  1. Either close the port in python or kill the python process
  2. Wait for the device to reconnect
  3. Reopen the port or restart the python process

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.