Tuesday, August 26, 2014

Upscaling baud rates

There is almost no philosophy here. :-)

Suppose I want to send some data to a device that runs at baud rate a from a serial device that runs at a different baud rate b.  If a > b, I am out of luck.  Probably likewise I'm out of luck if they're close.  But if a is much smaller than b, then I can emulate the lower baud rate a from the higher baud rate device, by rescaling the bit data, taking into account mark and stop bits.  Unfortunately, required mark and stop bits will introduce some problems into the bit stream--but if you're lucky, your receiving device will just treat these problems as a glitch and ignore them.

For instance, suppose I want to send the hex byte
53 (ASCII 'S')
from a device running at 57600 baud (8 N 1) to a device running at 9600 baud (also 8 N 1).  It turns out that if I transmit
E0 7F 00 1F 7E F8  
this may be a decent approximation.

For when I send the longer byte string, what actually goes over the wire is:
0000001111011111110100000000010111110001001111110100001111110
(where red zeros are start bits and blue ones are stop bits, and data is sent least-significant-bit first).
The bit pattern for hex 53 (including the start and stop bits) should be:
0110010101
which with a perfect 6X (=57600/9600) rescaling would be:
000000111111111111000000000000111111000000111111000000111111

Putting the two side-by-side we get the following bit differences:
0000001111011111110100000000010111110001001111110100001111110
000000111111111111000000000000111111000000111111000000111111
(the final zero in the first stream doesn't matter).  

If you're lucky, the device you're talking to will take the highlighted bits to be glitches and ignore them and the data will get through just fine.

The code for scaling the bitstream is here (it's GPL3 on the face, but feel free to use DataLink.java under the BSD 3-clause license if you prefer). 

Would one ever need to do this?  Maybe.  I want to make the Mindflex toy EEG headset behave just like the MindWave Mobile EEG headset.  To do that, I hook up a Bluetooth-to-TTL-serial link to the Mindflex toy headset, and I need to send the hex data 02 to the toy headset to switch it to the mode that the MindWave Mobile headset runs at.  Unfortunately, that 02 needs to be sent at 9600 baud, and then the headset will switch to 57600 baud.  This alright if you can control the baud rate of the serial link on the fly, as has been the case when I've been using a Brainlink with custom firmware (and an Android app to switch to the mode that works like the MindWave).  But I want to switch to a simple HC-06 link, and those can't adjust baud rate dynamically, so I will have to use the above trick.  (I've already tested the trick using the Brainlink and that works.)  

I said there was almost no philosophy here.  The little bit of philosophy is the curious self-observation that in my programming work, a not insignificant proportion of what I do is fooling devices.  In the above case, I am fooling a device that expects a 9600 baud connection into "thinking" it's getting one.  This is an entirely morally innocent kind of "deception".  I suppose the Kantian point is that when we try to deceive people, we are treating them in a way that is appropriate for machines.

1 comment:

Alexander R Pruss said...

Sometimes one can remove an error by shifting over the bitstream before scaling it, and making use of the fact that the link goes high when there is no transmission. For instance, I was able to transmit 0x02 at 9600 baud with four errors instead of the five that the naive method gave by shifting it over by two bytes, and using the idle-high at the end to transmit some of the mark bit.

I wonder if one might be able to do slightly better by smoothing out the output signal with an RC low-pass filter.