Sending binary data over Bluetooth/RFCOMM/SPP converts 0x0A to 0x0D 0x0A

bluetooth, linux, newline, serial-port

Solution

It looks like you are being bitten by the line discipline of the TTY (remember that `rfcomm` does not create a fifo, but a tty).

You may try changing the TTY to raw mode, that is, without any magic. The easiest way is with `stty --file <tty> raw`. I don't know if `rfcomm` will admit several commands in its command line but you can do easily with a script:

command_raw

#!/bin/bash
stty --file "$1" raw
"$COMMAND" "$1"

And then run:

sdptool add --channel 1 SP
rfcomm watch hci0 1 ./command_raw {}

If you have the source of the command to be run, you can also change it easily in C:

 #include <termios.h>
 #include <unistd.h>

 //WARNING: error checking left as an exercise to the reader!
 void make_raw(int fd)
 {
     struct termios ios;

     //Not a TTY: nothing to do
     if (!isatty(fd))
         return; 

     tcgetattr(fd, &ios);
     cfmakeraw(&ios);
     tcsetattr(fd, TCSANOW, &ios);
 }

Problem

I have a Bluetooth RFCOMM service running on Linux via the commands: ``` sdptool add --channel 1 SP rfcomm watch hci0 1 "$COMMAND" {} # ^ here ``` The `$COMMAND` will write binary data to the file passed as a parameter. I have tested that it behaves correctly by doing: ``` FIFO=$(tempfile) mkfifo "$FIFO" "$COMMAND" "$FIFO" & cat "$FIFO" | hexdump -C # <- output is correct ``` However, when connecting to the service from a different device via SPP/RFCOMM discovery (UUID `00001101-0000-1000-8000-00805F9B34FB`), I see that every instance of `0x0A` (`LF`) is replaced by `0x0D` `0x0A` (`CR` `LF`) in the stream. The issue isn't on the receiving end, because I have tried connecting to a hardware serial device that also sends binary data, and there the conversion doesn't happen. It must be the command in the first snippet (above the `# ^ here` line) that performs the replacement. Why does the `rfcomm` tool do this replacement and how can I disable it?

Original source