Under some circumstances, it may be preferable to communicate directly with
BrlAPI's server rather than using BrlAPI's
library. Here are the needed details to be able
to do this. This chapter is also of interest if a precise understanding of
how the communication stuff works is desired, to be sure to understand how
to write multithreaded clients, for instance.
In all the following, integer will mean an unsigned 32 bits integer in
network byte order (ie most significant bytes first).
The protocol between BrlAPI's server and clients is based on exchanges
of packets. So as to avoid locks due to packet loss, these exchanges are
supposed reliable, and ordering must be preserved, thus BrlAPI needs
a reliable packet transmission channel.
To achieve this, BrlAPI uses a TCP-based connection, on which packets
are transmitted this way:
the size in bytes of the packet is transmitted first as an integer,
then the type of the packet, as an integer,
and finally the packet data.
The size does not include the { size, type } header, so that packets which
don't need any data have a size of 0 byte. The type of the packet can be
either of BRLPACKET_* constants defined in api_protocol.h. Each type of
packet will be further discussed below.
BrlAPI's library ships two functions to achieve packets sending and receiving
using this protocol: brlapi_writePacket and brlapi_readPacket. It
is a good idea to use these functions rather than rewriting them, since this protocol
might change one day in favor of a real reliable packet transmission protocol
such as the experimental RDP.
As described below, many packets are `acknowledged'. It means that upon
reception, the server sends either:
a BRLPACKET_ACK packet, with no data, which means the operation
corresponding to the received packet was successful,
or a BRLPACKET_ERROR packet, the data being an integer
which should be one of BRLERR_* constants. This
means the operation corresponding to the received packet failed.
Some other packets need some information as a response.
Upon reception, the server will send either:
a packet of the same type, its data being the response,
or a BRLPACKET_ERROR packet.
If at some point an ill-formed or non-sense packet is received by the server,
and BRLPACKET_EXCEPTION is returned, holding the guilty packet for
further analysis.
The connection between the client and the server can be in either of the
four following modes:
authentication mode: this is the initial mode, when the client hasn't
authenticated itself to the server yet. Only one BRLPACKET_AUTHKEY packet
will be accepted, which makes the connection enter normal mode.
normal mode: the client is authenticated, but didn't ask for a tty
or raw mode. The client can send either of these types of packet:
BRLPACKET_GETDRIVERID, BRLPACKET_GETDRIVERNAME
or BRLPACKET_GETDISPLAYSIZE to get pieces of information from the server,
BRLPACKET_GETTTY to enter tty handling mode,
BRLPACKET_GETRAW to enter raw mode,
tty handling mode: the client holds the control of a tty: brltty has
no power on it any more, masked keys excepted. It's up to the client to manage
display and keypresses. For this, it can send either of these types of packet:
BRLPACKET_GETTTY to switch to another tty, but how key presses
should be sent mustn't change,
BRLPACKET_LEAVETTY to leave tty handling mode and go back to
normal mode,
BRLPACKET_IGNOREKEYRANGE, BRLPACKET_UNIGNOREKEYRANGE,
BRLPACKET_IGNOREKEYSET, BRLPACKET_UNIGNOREKEYSET to mask and unmask
keys,
BRLPACKET_WRITE to display text on this tty,
BRLPACKET_GETRAW to enter raw mode,
BRLPACKET_GETDRIVERID, BRLPACKET_GETDRIVERNAME
or BRLPACKET_GETDISPLAYSIZE to get pieces of information from the server,
And the server might send BRLPACKET_KEY packets to signal key presses.
raw mode: the client wants to exchange packets directly with the braille
terminal. Only these types of packet will be accepted.
BRLPACKET_LEAVERAW to get back to previous mode, either normal or
tty handling mode.
BRLPACKET_PACKET to send a packet to the braille terminal.
And the server might send BRLPACKET_PACKET packets to give received packets
from the terminal to the client.
Termination of the connection is initiated by the client in normal mode by
simply closing its side of the socket. The server will then close the
connection.
Here is described the semantics of each type of packet. Most of them are
directly linked to some of BrlAPI's library's functions. Reading their
online manual page as well will hence be of good help for understanding.
BRLPACKET_AUTHKEY (see brlapi_loadAuthKey())
This must be the first packet ever transmitted from the client to the
server. It lets the client authenticate itself to the server. Data is
first an integer indicating a protocol version, then comes the authentication
key itself.
If the protocol version is not the same as the server's, a
BRLERR_PROTOCOL_VERSION error packet is returned and the connection is
closed.
If the authentication key matches the servers', it is acknowledged, and
other types of packets might be used, other BRLPACKET_AUTHKEY shouldn't
be sent by the client.
If the authentication key doesn't match, the server sends a
BRLERR_CONNREFUSED and closes the connection.
BRLPACKET_GETDRIVERID (see brlapi_getDriverId())
This should be sent by the client when it needs the 2-char identifier of
the current brltty driver. The returned string is \0 terminated.
BRLPACKET_GETDRIVERNAME (see brlapi_getDriverName())
This should be sent by the client when it needs the full name of
the current brltty driver. The returned string is \0 terminated.
BRLPACKET_GETDISPLAYSIZE (see brlapi_getDisplaySize())
This should be sent by the client when it needs to know the braille display
size. The returned data are two integers: width and then height.
BRLPACKET_GETTTY (see brlapi_getTty())
This should be sent by the client to get control of a tty. Sent data are
first a series of integers: the first one gives the number of following
integers, which are the numbers of ttys that leads to the tty that
the application wants to take control of (it can be empty if the tty is
one of the machine's VT). The last integer of this series tells the number of
the tty to get control of. Finaly, how key presses should be reported is sent:
either a driver name or "", preceded by the number of caracters in the driver
name (0 in the case of ""), as an unsigned byte. This packet is then
acknowledged by the server.
BRLPACKET_KEY (see brlapi_readKey())
As soon as the client gets a tty, it must be prepared to handle
BRLPACKET_KEY incoming packets
at any time (as soon as the key
was pressed on the braille terminal, hopefuly).
The data holds the key or command code
as an integer, depending on what has been request in the
BRLPACKET_GETTTY packet.
BRLPACKET_SETFOCUS (see brlapi_setFocus())
For the server to know which tty is active, one particular client is responsible
for sending BRLPACKET_SETFOCUS packets. They hold a single integer telling
the new current tty. For instance, when running an X server on VT 7, the
xbrlapi client would have sent a BRLPACKET_GETTTY(7) and will send
window IDs whenever X focus changes, allowing display and keypresses switching
between xterms.
BRLPACKET_LEAVETTY (see brlapi_leaveTty())
This should be sent to free the tty and masked keys lists.
This is acknowledged by the server.
BRLPACKET_IGNOREKEYRANGE, BRLPACKET_UNIGNOREKEYRANGE,BRLPACKET_IGNOREKEYSET and BRLPACKET_UNIGNOREKEYSET (seebrlapi_ignoreKeyRange(), brlapi_unignoreKeyRange,brlapi_ignoreKeySet(), and brlapi_unignoreKeySet())
If the client doesn't want every key press to be signaled to it, but some of
them to be given to brltty for normal processing, it can send
BRLPACKET_IGNOREKEYRANGE (resp. BRLPACKET_IGNOREKEYSET) packets to
tell ranges (resp. sets) of key codes which shouldn't be
sent to it, but given to brltty, and BRLPACKET_UNIGNOREKEYRANGE
(resp. BRLPACKET_UNIGNOREKEYSET) packets to tell ranges (resp. sets)
of key codes which should be sent to it, and not given to
brltty. The server keeps a dynamic list of ranges, so that arbitrary
sequences of such packets can be sent.
For ranges, Data are 2 integers: the lower and the
upper boundaries; lower and upper must be equal to tell one key, for instance.
For Sets, Data simply consists of integers, one per key in the set.
BRLPACKET_WRITE (see brlapi_write())
To display text on the braille terminal and set the position of the cursor,
the client can send a BRLPACKET_WRITE packet. The packet begins
with an integer holding flags (see BRLAPI_WF_*). These flags indicate
which data will then be available, in the following order (corresponding to
flag weight):
A display number can be given as a integer, in case the braille
display has several. If not given, usual display is used.
A region can be given as two integers indicating the beginning and the
number of characters of the part of the braille display which is to be updated,
the first cell of the display being numbered 1. If not given, the whole display
is considered to be updated (and hence the following three fields should exactly
fit the braille display ie hold height*width
bytes, where height and width must be got by sending a
BRLPACKET_GETDISPLAYSIZE packet.
The text to display can then be given, preceded by its size in bytes
expressed as an integer.
Then an AND field can be given, one byte per character: the 8-dot
representation of the above text will be AND-ed with this field, hence allowing
to erase some unwanted parts of characters. Dots are coded as described in
ISO/TR 11548-1: dot 1 is set iff bit 0 is set, dot 2 is set iff bit 1 is set,
... dot i+1 is set if bit i is set. This also corresponds to the
low-order byte of the coding of unicode's braille row U+2800.
As well, an OR field may be given, one byte per character: the 8-dot
result of the AND operation above (or the 8-dot representation of the text if
no AND operation was performed) is OR-ed with this field, hence allowing
to set some dots, to underline characters for instance.
A cursor position can be specified. 1 representing
the first character of the display, 0 turning the cursor off. If not given,
the cursor (if any) is left unmodified.
Last but not least, the charset of the text can be specified. If it is
not, an 8-bit charset is assumed, and it is assumed to be the same as the
server's. Multibyte charsets may be used, AND and OR fields' bytes will
correspond to each text's wide character, be it a composing or a
double-width character.
A BRLPACKET_WRITE packet without any flag (and hence no data) means a
"void" WRITE: the server clears the output buffer for this connection.
BRLPACKET_GETRAW (see brlapi_getRaw())
To enter raw mode, the client must send a BRLPACKET_GETRAW packet,
which is acknowledged. Once in raw mode, no other packet than
BRLPACKET_LEAVERAW or BRLPACKET_PACKET will be accepted. The data must
hold the special value BRLRAW_MAGIC: 0xdeadbeef, to avoid erroneous
raw mode activating.
BRLPACKET_LEAVERAW (see brlapi_leaveRaw())
To leave raw mode, the client must send a BRLPACKET_LEAVERAW packet, which
is acknowledged.
BRLPACKET_PACKET (see brlapi_sendRaw() andbrlapi_recvRaw())
While in raw mode, only BRLPACKET_PACKET packets can be exchanged between
the client and the server: to send a packet to the braille terminal, the
client merely sends a BRLPACKET_PACKET packet, its data being the packet to
send to the terminal. Whenever its receives a packet from the terminal, the
server does exactly the same, so that packet exchanges between the terminal and
the server are exactly reproduced between the server and the client.
Packets' content depends on the braille driver, so that the client should
check for its id or name thanks to a BRLPACKET_GETDRIVERID packet or
a BRLPACKET_GETDRIVERNAME packet, prior to sending any
BRLPACKET_GETRAW packet.