This started out as my attempt to reconstruct, from existing open code bases and through testing of a unit in hand, the TeleSensory ScreenPower PowerBraille serial wire protocol. While I had feared that, as with so many historic devices, documentation had been lost, Freedom Scientific was willing to provide me with their engineering document about the protocol! That’s amazing. Unfortunately, this document appears to be incomplete, or perhaps just describing an earlier version of the protocol than that spoken by the unit I have. Thus, some additional probing has been required.
In the interest of having an available public reference, this page represents, to the best of my knowledge and ability, enough to write a functional driver for a PowerBraille 80. This protocol is nominally shared by several other devices, but with per-device nuance that I cannot verify and so do not attempt to reproduce here. Please understand that there may be mistakes in the following and it is still mostly the result of educated guesses. There are no warranties associated with this text, not even implied ones.
The Manual¶
The user manual for this device is still quietly accessible at https://support.freedomscientific.com/Content/Documents/Manuals/Legacy/PowerBraille/PB_User_Manual.pdf but it is of limited utility for understanding the device at a software level.
Notably, the manual does not even document the acceptable voltage ranges for DC power input, and The Internet as a whole also seems to have forgotten. There appears to be some suggestion that 9V or 12V is the intended answer. I originally ran mine on 5V to be safe, but have recently supplied 12V instead with no ill effects. Some limited REing of the PSU circuitry on the board (in the fullness of time, I mean to capture the whole schematic) suggests a fairly wide range of acceptable inputs.
Despite that the PB80 does not claim to offer battery support, the circuitry is absolutely there (and so is the battery holder!), and there will be periodic reports of low battery in the serial stream. So much for documentation, eh?
Existing Open-Source Drivers¶
There are (were) several open-source accessibility solutions that speak (spoke) something claiming to be TeleSensory’s protocol, but how much of it is RE’d vs. as described in documentation I don’t know. Anyway, because they are useful references, I’ve included them here:
https://git.savannah.gnu.org/cgit/screen.git/log/src/braille_tsi.c – GNU
screen
had support, but it was removed in 2015.https://github.com/brltty/brltty/tree/master/Drivers/Braille/TSI –
brltty
can drive these devices through a native driverhttps://github.com/brltty/brltty/tree/master/Drivers/Braille/Baum/braille.c –
brltty
also includes a second implementation of TSI’s protocol apparently as spoken by some Baum devices.https://github.com/brltty/brltty/tree/master/Drivers/Braille/Seika/braille.c –
brltty
also includes a third implementation of TSI’s protocol apparently as spoken by some Seika devices.
Messages From The Device¶
Structured device messages are variable length, with the most-significant three bits of the first byte determining the type and nature of any following bytes:
000 |
Miscellaneous reporting; see Low Battery Notice, Device Identification Message, and Cursor Routing Buttons. |
100 |
Never observed |
The remaining 6 values are all used for buttons.
Test Result Messages¶
After initiating a device self test (0x0B), the device should eventually report
success with 0x00 0x06
or failure with 0x00 0x07
.
Device Identification Message¶
Emitted in response to an identify command (0x0A
; see below).
0x00
0x05
– message header.1 byte cell count; for PB80, that’s
0x51
(the device has 81 cells, despite its name).1 byte dot count; either 6 or 8, one assumes; I’ve only seen 8.
A 4 byte version field.
A 4 byte checksum (of what?).
Low Battery Notice¶
The two byte sequence
0x00
0x01
. As the PB80 is not intended to be run from batteries, it’s somewhat mystifying that this gets sent at all, but it does, by default. See 0x12 Set Low Battery Transmission Mode.
Unused Message Headers¶
There appears to be a curious gap in message headers, as 0x00 0x02
, 0x00
0x03
, and 0x00 0x04
are skipped and undocumented. Perhaps they were
reserved for a future use that never came.
Similarly, 0x00 0x09
through 0x00 0xFF
and 0x80
through 0x9F
are seemingly unused.
Messages To The Device¶
Messages to the device always begin with two 0xFF
bytes. A single byte command
determines the type and length of the rest of the payload. So far, we believe:
Command |
Payload Len |
Interpretation |
---|---|---|
|
0 |
Ignored? |
|
40 |
|
|
80 |
|
|
160 |
|
|
Variable |
|
|
1 |
|
|
8 |
|
|
1 |
Set display off timer; 1 second per count |
|
1 |
|
|
0 |
|
|
0 |
|
|
0 |
Trigger cell test; see Test Result Messages |
|
0 |
Trigger full diagnostics loop; power cycle req’d! |
|
2 |
Set typematic rate parameters |
|
1 |
Set debounce time; 10ms/count |
|
1 |
|
|
1 |
|
|
1 |
|
|
1 |
|
|
1 |
Unknown; uncorrelated with 0x09 |
|
3 |
|
|
1 |
Unknown; reset? crash? |
|
1 |
Unknown; uncorrelated with 0x09 |
|
0 |
Ignored? |
… |
0 |
Ignored? |
|
0 |
Ignored? |
… |
? |
Unprobed |
|
0 |
Ignored? |
… |
? |
Unprobed |
|
0 |
Ignored? |
… |
? |
Unprobed |
|
0 |
Ignored? |
|
0 |
Ignored? |
Writes to Display¶
It is unclear why all of 0x01, 0x02, 0x03, 0x04 exist, especially with at least
the last of these being variable length. Apparently 0x04
was added later
and subsumed the earlier commands.
0x01 is like 0x04 with the payload length byte set to 0x28 and the start position set to 0x00 and neither transmitted.
0x02 is like 0x04 with the payload length byte set to 0x50 and the start position set to 0x00 and neither transmitted.
0x03 is like 0x04 with the payload length byte set to 0xA0 and the start position set to 0x00 and neither transmitted.
0x04 Write¶
This variable-length Write command takes the following payload structure:
Mode byte; the logical OR of the following values:
0x01
Cursor display (1 = shown, 0 = hidden)
0x02
Enable first vibration parameters in cells
0x04
Enable second vibration parameters in cells
0x08
Enable third vibration parameters in cells
0x10
Enable fourth vibration parameters in cells
Bits 0xE0 appear ignored.
Cursor position column (0 = leftmost, 1 its right neighbor, etc.); values beyond the number of cells on the display cause the cursor to appear hidden.
Cursor type byte. It appears that only the least significant nibble matters:
0
All dots up
1
2
All dots but 1 up, dot 1 vibrating using first vibration parameters
3
Dots 6 and 7 up
n
All dots up
payload length byte (
n
) in bytes of attr/data byte pairs fieldstart position (0 = leftmost, 1 = its right neighbor, etc.)
attr/data byte pairs. Attribute byte first.
Braille dots are encoded using bit…
0 3
1 4
2 5
6 7
The attribute byte is one of the following; other values have not yet been
probed. Only 0x00
, 0x02
, and 0x04
are specified in the manual;
0x06
and 0x08
were found by experimentation and appear intended, while
0x0A
, 0x0C
, and 0x0E
appear to just happen to work the way they do.
0x00
Character steady on
0x02
Character using first vibration parameters, if enabled in mode
0x04
Character using second vibration parameters, if enabled in mode
0x06
Character using third vibration parameters, if enabled in mode
0x08
Character using fourth vibration parameters, if enabled in mode
0x0A
0x0C
0x0E
Attribute bits 0xF1
appear to be ignored.
It is unclear what happens if one specifies an odd number of bytes for a field composed of pairs… probably unwise.
0x05 UART Parameters¶
0x05
takes a 1-byte payload that appears to configure the UART.
0 |
RTS/CTS off, both UARTs |
1 |
RTS/CTS on, both UARTs |
2 |
Set current UART 4800 baud |
3 |
Set current UART 9600 baud |
4 |
Set current UART 19200 baud |
On power-up, the device defaults to 9600 baud on UART 1, 4800 baud on UART 2, and with RTS/CTS disabled on both UARTs. It seems that 8n1 is always expected.
It does not appear to be possible to change the baud rate of the UART other than the one targeted, in something of an odd contrast to Echo Mode.
0x06 Vibration Parameters¶
There are four vibration sets on the PB65/81. Each defines a square wave using
two parameters: the on duration and off duration, so the 0x06
command
naturally takes eight bytes of payload: 1-On 1-Off 2-On ... 4-Off
. Each
counter has units of centiseconds, and is rounded to the nearest multiple of 5.
Zero (and so byte values 0, 1, and 2) is to be interpreted as 0x104
(that
is, 2.6 seconds) rather than as no time.
The default setting is 0x0A 0x05 0x23 0x0A 0x41 0x0A 0x5F 0x0A
. That is:
Mode |
Period (msec) |
Duty cycle |
---|---|---|
1 |
150 |
2/3 |
2 |
450 |
7/8 |
3 |
750 |
13/15 |
4 |
1050 |
19/21 |
0x08 Display Size¶
This somewhat erroneously named command can be used to split the display, displaying both UART’s screens. The argument is the size of UART 1’s portion of the screen, and is on the left.
0x09 Debug Report¶
Upon receipt of the 0x09
command byte, my unit reports something like
TELESENSORY BRAILLE 65/81 STATUS REPORT
BRAILLE 65/81 FIRMWARE, VERSION 1.0A, JUNE 22, 1995, BATTERY USAGE 07:00:07
NUMBER OF DISPLAY = 51H
DISPLAY SIZE = 51H
NUMBER OF DOTS = 8
DISPLAY OFF TIMER, 1SEC/CT = F0H
CURSOR STATUS UART 1 C_POS C_MODE UP_BIT ON_BIT VIB_BITS = 00H 00H FFH C0H 00H
CURSOR STATUS UART 2 C_POS C_MODE UP_BIT ON_BIT VIB_BITS = 00H 00H FFH C0H 00H
VIBRATION TIMERS, 10MS/CT ONX OFFX 1-4 = 0AH 05H 23H 0AH 41H 0AH 5FH 0AH
UART 1,2 HAND SHAKE RTS/CTS = OFF
UART 1 BAUD RATE = 9600
UART 2 BAUD RATE = 4800
ECHO MODE = 00H
ACTIVE DISPLAY MODE = 01H
KEYPAD SETUP, 10MS/CT DEBOUNSE START CONTINUE MODE = 02H 32H 0AH 03H
LOW BATTERY TRANSMISION MODE = 03H
CHECK SUM = 077EH
CHECK SUM = 077EH
There appear to be no framing bytes or anything around this, so programmatic use
is unlikely to be all that easy. The second CHECK SUM
line has appreciable
delay after the =
and before the result, so likely the unit is processing
during that time.
0x0F Set Echo Mode¶
0x0 |
Disable echo mode |
0x1 |
Bridge UART 1 to UART 2; UART 2 in command mode |
0x2 |
Bridge UART 2 to UART 1; UART 1 in command mode |
0x3 |
Bridge UARTs together; neither in command mode |
When a UART is bridged, a BREAK condition will take it out of bridge mode and lower the corresponding bit (0x01 for UART 1, 0x02 for UART 2) of the bridge mode setting. Bridges are not interpreted by the PowerBraille device; that is, they are electrical, and so the sender must vary their baud rate to match the target of the device.
For sending a command from the terminal connected to UART 1 to a device connected to UART 2, for example, the terminal should…
Set echo mode to 0x01.
Adjust its baud rate to match that of the device.
Send bytes.
Place a BREAK condition on the bus.
Restore its baud rate to that of the PowerBraille.
If a response is expected, the likely procedure is a little more complex:
Set echo mode to 0x03.
Adjust its baud rate to match that of the device.
Transact with the device; the PowerBraille is entirely passive.
Place a BREAK condition on the bus; echo mode will be 0x02.
Restore its baud rate to that of the PowerBraille.
Restore the echo mode to 0x00.
0x10 Set Keypad Mode¶
Select which UARTs receive side and cursor keypress events. Bitwise OR of 0x01 for UART 1, 0x02 for UART 2. Default is 0x03. Other values silence reporting.
0x11 Set Active Display Mode¶
Mode 0x01 displays writes as received from UART 1, while 0x02 from UART 2.
Setting to any other value appears to have no effect; that is, the display behaves as though the mode were in its previous state.
0x12 Set Low Battery Transmission Mode¶
Select which UARTs receive low battery notifications. Bitwise OR of 0x01 for UART 1, 0x02 for UART 2. Default is 0x03.
0x14 Cursor Status¶
This command influences the behavior of cursor “type” 1. It takes three bytes:
The “up” dots: these dots are up if the underlying display has them up.
The “on” bits: these dots are forced up.
The “vibrating” bits: these dots are vibrating if they are up by either of the prior two mechanisms.
So, for example, with a cell displaying 0xA0, an up dots setting of 0xC0, an on dots setting of 0x18, and a vibrating setting of 0x0C, the cell has 0x90 always on and 0x08 vibrating.
The default setting is 0xFF up, 0xC0 on, and 0x00 vibrating. That is, the display unconditionally sets the bottom two dots and passes the six upper dots through (in fact it also passes the bottom two dots through, but they are then overridden).
Open Questions¶
What are commands 0x13, 0x15, and 0x16?
Are there commands we’ve missed? messages?
Is there a firmware dump anywhere?