1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
|
<!doctype linuxdoc system>
<article>
<title>BrlAPI Reference manual
<author>
<name>Sbastien Hinderer <tt><htmlurl url="mailto:sebastien.hinderer@libertysurf.fr" name="<sebastien.hinderer@libertysurf.fr>"></tt><newline></name>
<and>
<name>Samuel Thibault <tt><htmlurl url="mailto:samuel.thibault@fnac.net" name="<samuel.thibault@fnac.net>"></tt><newline></name>
</author>
<date>V1.0, June 2003
<abstract>
This document describes how to use <tt>BrlAPI</tt>.
</abstract>
<toc>
<!-- rappel des attributs:
<bf/gras/ <em/mis en valeur/ <sf/sans serif/ <sl/slanted/ <tt/machine crire
<it/italique
-->
<!---->
<sect>Introduction
<!---->
<!-- Seb -->
<!-- an introduction explaining very briefly what BrlAPI does, the
vocabulary it uses, and how to read this documentation -->
<p><em/BrlAPI/ is a service provided by the <em/brltty/ daemon.
Its purpose is to allow programmers to write applications that take advantage
of a braille terminal in order to deliver a blind user suitable information
for his/her specific needs.
While an application communicates with the braille terminal, everything
<em/brltty/ sends to the braille terminal in the application's console is
ignored, whereas each piece of data coming from the braille terminal is sent to
the application, rather than to <em/brltty/.
<sect1>Concepts
<p> All throughout this manual, a few terms will be used which are either
specific to braille terminals, or introduced because of <em/BrlAPI/. They are defined
below. Taking a few minutes to go through this glossary will save a lot
of time and questions later.
<descrip>
<tag/Authentication key/
A file containing arbitrary data, that has to be sent to the server by the
client, to prove it is allowed to establish a connection and then control
the braille terminal.
<tag/Braille display/
The small screen on the braille terminal that is able to display braille text.
<tag/Braille keyboard/
The keyboard of the braille terminal.
<tag/Braille terminal/
A computer designed to display text in braille. In this case, the text is
supposed to come from another computer running Linux or any other Unix system.
<tag/Brltty/
The background process that gives a blind person access to the Linux console
thanks to a braille terminal or speech synthetizer.
<tag/Client/
An application designed to handle a braille terminal thanks to <em/BrlAPI/.
<tag/Command/
A code returned by the driver, indicating an action do to, for instance
"go to previous line", "go to next line", etc.
<tag/Driver/
A library that has functions to communicate with a braille terminal.
Basically, a driver has functions to open communication with the
braille terminal, close the communication, write on the braille
display, and read keypresses from the braille keyboard, plus some special
functions that will be described in detail in this manual.
<tag/Key/
A code that is returned by the driver when a key is pressed. This is
different from a command, because the command concept is driver-independent
(all drivers use the same command codes - those defined by <em/brltty/), whereas
codes used for returning keypresses may vary between drivers.
<tag/BrlAPI's Library/
This library helps clients to connect and use <em/BrlAPI/'s
server thanks to a series of <tt/brlapi_/-prefixed functions.
<tag/Packet/
A sequence of bytes making up the atomic unit in communications, either between
braille drivers and braille terminals or between the server and clients.
<tag/Raw mode/
Mode in which the client application exchanges packets with the driver.
Normal operations like sending text for display or reading keypresses are
not available in this mode. It lets applications take advantage of advanced
functionalities of the driver's communication protocol.
<tag/Server/
The part of <em/brltty/ that controls incoming connections and communication
between clients and braille drivers.
</descrip>
<sect1>How to read this manual
<p>This manual is split in five parts.
<descrip>
<tag/General description/
Describes more precisely what <em/BrlAPI/
is and how it works in collaboration with <em/brltty/'s core, the braille driver
and clients. In this part, a "connection-use-disconnection" scenario
will be described step by step, explaining for each step what <em/BrlAPI/ does in
reaction to client instructions. These explanations will take place at a
user level.
<tag/Installation and configuration/
This part explains in detail how to install and configure the API. For
instructions on how to install and configure <em/brltty/, please report to
the <em/brltty/ documentation.
<tag/Library description/
This part describes how client applications
can communicate with the server using the <em/BrlAPI/ library that
comes with <em/brltty/. Each function will be briefly described,
classified by categories. More exhaustive descriptions of every
function are available in the corresponding online manual pages.
<tag/Writing braille drivers/
This part describes how the braille drivers included in <em/brltty/ should be
written in order to take advantage of <em/BrlAPI/'s services.
<tag/Protocol reference/
This part describes in detail the communication
protocol that is used to communicate between server and clients.
</descrip>
What should be read probably depends on what should be done by applications with
<em/BrlAPI/.
Reading chapters 2 and 3 is recommanded, since they provide useful
information and (hopefully) lead to a good understanding of <em/BrlAPI/,
for an efficient use.
Chapter 4 concerns writing applications that take advantage of
braille terminals so as to bring specific (and more useful) information to
blind people.
Chapter 5 is for braille driver implementation: either adding a braille driver
to <em/brltty/ or modifying an existing one so that it can benefit from
<em/BrlAPI/'s features, this chapter will be of interest, since it describes
exactly what is needed to write a driver for <em/brltty/: the core
of drivers interface for instance.
Finally, Chapter 6 is for <em/not using/ the library, but using the <em/BrlAPI/
server directly, when the library might not be sufficient: it describes the
underlying protocol that will have to be used to do so.
<!---->
<sect>General description of <em/BrlAPI/
<!---->
<!-- a general documentation, which explains the issue and the design we
chose to handle it -->
<p>Here is explained what <em/BrlAPI/ is, and what it precisely does.
These explanations should be simple enough to be accessible to every user.
For a more technical review of <em/BrlAPI/'s functionalities, please see chapter
4.
<sect1>Historical notes.
<p>Originally, <em/brltty/ was designed to give access to the Linux
console to visually impaired people, through a braille terminal
or a speech synthetizer. At that time, applications running in the
console were not taking care of the presence of a braille
terminal (most applications didn't even know what a braille
terminal was).
This situation where applications are not aware of the presence of a
special device is elegant of course, since it lets use an
unlimited number of applications which don't need to be specially
designed for visually impaired people.
However, it appeared that applications specially designed to take
advantage of a braille terminal could be wanted, to
provide the suitable information to blind users, for instance.
The idea of <em/BrlAPI/ is to propose an efficient communication
mechanism, to control the braille display, read keys from the
braille keyboard, or to exhange data with the braille terminal at
a lower level (e.g. to write file transfer protocols between
braille terminals and Linux systems).
<sect1>Why <em/BrlAPI/ is part of <em/brltty/.
<p>Instead of rewriting a whole communication program from
scratch, we chose to add communication
mechanisms to <em/brltty/. This choice has two main justifications.
On the one hand, integration to <em/brltty/ allows us to use the
increasing number of drivers written for <em/brltty/, thus handling
a large number of braille terminals without having to rewrite any
piece of existing code.
On the other hand, if an application chooses to send its own
information to the braille display, and to process braille keys,
<em/brltty/ has to be warned, so that it won't try to communicate
with the braille terminal while the application already does.
To make this synchronzation between <em/brltty/
and client applications possible, it seemed easier to add the
communication mechanisms to <em/brltty/'s core, instead of writing an
external program providing them.
<sect1>How it works.
<p>We are now going to describe the steps an application should
go through to get control of the braille terminal, and what
happens on <em/brltty/'s side at each step. This step-by-step
description will let us introduce more precisely some
concepts that are useful for every <em/BrlAPI/ user.
<sect2>Connection.
<p>The first thing any client application has to do is to
connect (in the Unix sense of the word) to <em/BrlAPI/ which is
an mere application server. If this is not
clear, the only thing to be remembered is that this
step allows the client application to let the server know about its
presence. At this stage, nothing special is done on <em/brltty/'s
side.
<sect2>Authentication.
<p>Since Unix is designed to allow many users to work on the
same machine, it's quite possible that there are more than one
user accounts on the system. Most probably, one doesn't want
any user with an account on the machine to be able to communicate
with the braille terminal (just imagine what would happen if,
while somebody was working with the braille terminal, another user
connected to the system began to communicate with it,
preventing the first one from doing his job...). That's why <em/BrlAPI/ has to
provide a way to determine whether a user who established a
connection is really allowed to communicate with the braille
terminal. To achieve this, <em/BrlAPI/ requires that each
application that wants to control a braille terminal sends an
authentication key before doing anything else. The control of
the braille terminal will only be possible for the client once
it has sent the proper authentication key. What is called
authentication key is in fact a Unix file containing data (it
must be non-empty) on your system. All the things you have to do is to give
read permissions on this file to users that are allowed to
communicate with the braille terminal, and only to them. This
way, only authorized users will have access to the
authentication key and then be able to send it to <em/BrlAPI/.
To see how to do that, please see chapter 3.
At the end of this step, the user is authorized to take
control of the braille terminal. On <em/brltty/'s side, some data
structures are allocated to store information on the client,
but this has no user-level side-effect.
<sect2>Real use of the braille terminal.
<p>Once the client is properly connected and authenticated,
there are two possible types of communication with the braille
terminal. The chosen type of communication depends on what the
client plans to do. If its purpose is to display information on
the braille display or to process braille keys, it will have to
take control of the Linux tty on which it is running. If its
purpose is to exchange data with the braille terminal (e.g. for
file transfer), it will enter what is called "raw mode".
<sect3>Braille display and braille key presses processing.
<p>If the client wants to display something on the braille
display or to process braille keys itself, rather than letting
<em/brltty/ process them, it has to take control of the Linux
terminal it is running on.
Each Linux terminal (tty) can be controlled by at most one
application at a time,
that's why <em/BrlAPI/ will honnor a valid tty control request if
and only if no other application already controls this tty.
Once a client has obtained the control of his tty, <em/BrlAPI/
will completely discard <em/brltty/'s display on this tty (and only
this one), leaving the braille display free for the client.
At the same time, if a key is pressed on the braille
keyboard, <em/BrlAPI/ checks whether the client application is
interested in this key or not. If it is, the key is passed to
it, either as a key code or as a <em/brltty/ command. If it is not, the
key code is converted into a <em/brltty/ command and returned to
<em/brltty/.
Once the client is not interested in displaying text
or reading braille keys any more, it has to leave the tty, so
that either <em/brltty/ can continue its job, or another client can
take control of it.
<sect3>Raw mode.
<p>Only one client can be in raw mode at the same time. In
this mode, data coming from the braille terminal are checked
by the driver (to ensure they are valid), but instead of being processed,
they are delivered "as-is" to the client that is in raw mode.
In the other direction, packets sent to <em/BrlAPI/ by the
client that is in raw mode are passed to the driver which is
expected to deliver them to the braille terminal without any
modification.
<sect3>Remarks.
<p>
<itemize>
<item>The operations described in the two previous
subsections are not completely mutually exclusive. An
application that controls its current tty can enter raw
mode, provided that no other application already is in this
mode. However, the contrary is not possible: an application
which has entered raw mode cannot take control of its tty
before having left raw mode. Indeed, it would make no sense
to take control of a tty during raw mode since in this mode,
braille display and reading of braille keys are impossible.
<item>Not every braille driver supports raw mode. It has
to be specially (re)written to support it, since it has
to provide special functions to process incoming and outgoing
packets. The same restriction is true (but less strong)
concerning the ability to deliver/convert keycodes into
commands: not every driver has this ability, it has to be
modified to get it.
<item>Operations described in 3.1 and 3.2 can be repeated.
You can, for instance, use raw mode to transfer data onto
your braille terminal, display text in braille, return to raw
mode..., all that without having to reconnect to <em/BrlAPI/ before
each operation.
</itemize>
<sect2>Disconnection.
<p>Once the client has finished using the braille terminal, it
has to disconnect from the API, so that the memory structures
allocated for the connection can be freed and eventually used by
another client. This step is transparent for the user, in the
sense that it involves no change on the braille display.
<!---->
<sect>Installation and configuration <em/BrlAPI/
<!---->
<!-- Seb -->
<!-- an installation and configuration documentation -->
<p>
Will be written later with Dave Mielke, the maintainer of <em/brltty/, since
the precise installation steps are not known yet.
<!---->
<sect>Library description
<!---->
<!-- the library documentation, for those who want to write
applications which use it, it should be split in: -->
<p>
Let's now see how one can write dedicated applications. Basic notions will be
seen, along with a very simple client. Greater details are given as online
manual pages.
<!-- a basic documentation, which briefly shows
how one is supposed to use our library, with trivial examples -->
<p>
The historical test program for <em/BrlAPI/ was something like:
<itemize>
<item>connect to <em/BrlAPI/
<item>get driver id
<item>get driver name
<item>get display size
<item>try entering raw mode, immediately leave raw mode.
<item>get tty control
<item>write something on the display
<item>wait for a key press
<item>leave tty control
<item>disconnect from <em/BrlAPI/
</itemize>
It is here rewritten, its working briefly explained.
<sect1>Connecting to <em/BrlAPI/
<p>Connection to <em/BrlAPI/ is needed first, thanks to the
<tt>brlapi_initializeConnection</tt> call. For this, a
<tt>brlapi_settings_t</tt> variable must be filled which will hold the
settings the library needs to connect to the server. Just giving <tt/NULL/
will work for local use. The other parameter lets you get back the parameters
which were actually used to initialize connection. <tt/NULL/ will also be nice
for now.
<tscreen><code>
if (brlapi_initializeConnection(NULL,NULL)<0)
{
brlapi_perror("brlapi_initializeConnection");
exit(1);
}
</code></tscreen>
The connection might fail, so testing is needed.
<sect1>Getting driver id and name
<p>Knowing the type of the braille device might be useful (<tt/p/ is defined as
<tt/char */):
<tscreen><code>
p = brlapi_getDriverId();
if (!p)
brlapi_perror("brlapi_getDriverId");
else
printf("Driver id: %s\n",p);
p = brlapi_getDriverName();
if (!p)
brlapi_perror("brlapi_getDriverName");
else
printf("Driver name: %s\n",p);
</code></tscreen>
This is particularly useful before entering raw mode to achieve file
transfers for instance, just to check that the device is really the one
expected.
<sect1>Getting display size
<p>Before writing on the braille display, the size should be always first
checked to be sure everything will hold on it:
<tscreen><code>
if (brlapi_getDisplaySize(&x, &y)<0)
brlapi_perror("brlapi_getDisplaySize");
else
printf("Braille display has %d line%s of %d column%s\n",y,y>1?"s":"",x,x>1?"s":"");
</code></tscreen>
<sect1>Entering raw mode, immediately leaving raw mode.
<p>Entering raw mode is very simple:
<tscreen><code>
fprintf(stderr,"Trying to enter in raw mode... ");
if (brlapi_getRaw()<0)
brlapi_perror("brlapi_getRaw");
else {
fprintf(stderr,"Ok, leaving raw mode immediately\n");
brlapi_leaveRaw();
}
</code></tscreen>
Not every driver supports raw mode (actually only one does for the moment ;-),
so testing is needed.
While in raw mode, <tt>brlapi_sendRaw</tt> and <tt>brlapi_recvRaw</tt>
can be used to send and get data directly to and from the device.
It should be used with care, improper use might completely thrash the device !
<sect1>Getting tty control
<p>Let's now display something on the device. control of the tty must be get
first:
<tscreen><code>
fprintf(stderr,"Taking control of the tty... ");
if (brlapi_getTty(0,BRLCOMMANDS,NULL)>=0)
{
printf("Ok\n");
</code></tscreen>
The first parameter tells the server the number of the tty to take
control of. Setting 0 lets the library determine it for us.
<p>The server is asked to send <em/brltty/ commands, which are device-independant.
The last parameter might be used when binding keys. This is discussed in
online manual pages.
<p>Getting control might fail if, for instance, another application already took
control of this tty, so testing is needed.
<p>From now on, the braille display is detached from the screen.
<sect1>Writing something on the display
<p>The application can now write things on the braille display without
altering the screen display:
<tscreen><code>
fprintf(stderr,"Writing to braille display... ");
if (brlapi_writeBrl(0,"Press a braille key to continue...")>=0)
{
fprintf(stderr,"Ok\n");
</code></tscreen>
The cursor is also asked <em/not/ to be shown: its position is set to 0.
<p>"Writing to braille display... Ok" is now displayed on the screen, and
"Press a braille key to continue..." on the braille display.
<sect1>Waiting for a key press
<p>To have a break for the user to be able to read these messages,
a key press (a command here, which is driver-independent) may be waited for:
<tscreen><code>
fprintf(stderr,"Waiting until a braille key is pressed to continue... ");
if (brlapi_readCommand(1,&key)>0)
fprintf(stderr,"got it! (code=%d)\n",key);
</code></tscreen>
The command code is returned, as described in <tt><brltty/brldefs.h></tt>.
It is not transmitted to <em/brltty/: it is up to the application to define
the behavior, here cleanly exitting, as described below.
The first parameter tells the lib to block until a key press is indeed read.
<sect1>Leaving tty control
<p>Let's now leave the tty:
<tscreen><code>
fprintf(stderr,"Leaving tty... ");
if (brlapi_leaveTty()>=0)
fprintf(stderr,"Ok\n");
</code></tscreen>
But control of another tty can still be get for instance, by calling
<tt>brlapi_getTty()</tt> again...
<sect1>Disconnecting from <em/BrlAPI/
<p>Let's disconnect from <em/BrlAPI/:
<tscreen><code>
brlapi_closeConnection();
</code></tscreen>
The application can as well still need to connect to another server on another
computer for instance, by calling <tt>brlapi_initializeConnection()</tt>
again...
<sect1>Putting everything together...
<p>
<tscreen><code>
#include <stdio.h>
#include <stdlib.h>
#include <brltty/brlapi.h>
int main()
{
brl_keycode_t key;
char *p,*c;
int x, y;
/* Connect to BrlAPI */
if (brlapi_initializeConnection(NULL,NULL)<0)
{
brlapi_perror("brlapi_initializeConnection");
exit(1);
}
/* Get driver id & name */
p = brlapi_getDriverId();
if (!p)
brlapi_perror("brlapi_getDriverId");
else
printf("Driver id: %s\n",p);
p = brlapi_getDriverName();
if (!p)
brlapi_perror("brlapi_getDriverName");
else
printf("Driver name: %s\n",p);
/* Get display size */
if (brlapi_getDisplaySize(&x, &y)<0)
brlapi_perror("brlapi_getDisplaySize");
else
printf("Braille display has %d line%s of %d column%s\n",y,y>1?"s":"",x,x>1?"s":"");
/* Try entering raw mode, immediately go out from raw mode */
printf("Trying to enter in raw mode... ");
if (brlapi_getRaw()<0)
brlapi_perror("brlapi_getRaw");
else {
printf("Ok, leaving raw mode immediately\n");
brlapi_leaveRaw();
}
/* Get tty control */
printf("Taking control of the tty... ");
if (brlapi_getTty(0,BRLCOMMANDS,NULL)>=0)
{
printf("Ok\n");
/* Write something on the display */
fprintf(stderr,"Writing to braille display... ");
if (brlapi_writeBrl(0,"Press a braille key to continue...")>=0)
{
fprintf(stderr,"Ok\n");
/* Wait for a key press */
fprintf(stderr,"Waiting until a braille key is pressed to continue... ");
if (brlapi_readCommand(1,&key)>0)
fprintf(stderr,"got it! (code=%d)\n",key);
else brlapi_perror("brlapi_readCommand");
} else brlapi_perror("brlapi_writeBrl");
/* Leave tty control */
fprintf(stderr,"Leaving tty... ");
if (brlapi_leaveTty()>=0)
fprintf(stderr,"Ok\n");
else brlapi_perror("brlapi_leaveTty");
} else brlapi_perror("brlapi_getTty");
/* Disconnect from BrlAPI */
brlapi_closeConnection();
return 0;
}
</code></tscreen>
This should compile well thanks to
<tt>gcc apiclient.c -o apiclient -lbrlapi</tt>
<!---->
<sect>Writing (<em/BrlAPI/-compliant) drivers for <em/brltty/
<!---->
<!-- Seb -->
<p>In this chapter, we will describe in details how to write a
driver for <em/brltty/. We begin with a general description of the
structure the driver should have, before explaining more precisely
what each function is supposed to do.
<sect1>Overview of the driver's structure
<p>A braille driver is in fact a library that is either
dynamically loaded by <em/brltty/ at startup, or statically linked to
it during the compilation, depending on the options given to the
<tt>./configure</tt> script.
This library has to provide every function needed by the core,
plus some additional functions, that are not mandatory, but which
improve communication with <em/BrlAPI/ and the service level provided
to client applications.
Basically, a driver library needs to provide a function to open
the communication with the braille terminal, one to close this
communication, one to read key codes from the braille keyboard, and
one to write text on the braille display. As we will see in a
moment, other functions are required.
Moreover, a driver can provide additional functionalities, by
defining some macros asserting that it has these functionalities,
and by defining associated functions.
<sect1>Basic driver structure
<p><em>Every</em> <em/brltty/ driver <em>must</em> consist in at least
a file called braille.c, located in an appropriate subdirectory of
the Drivers subdirectory. This braille.c file must have the
following layout
<verb>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
/* Include standard C headers */
#include "Programs/brl.h"
#include "Programs/misc.h"
#include "Programs/scr.h"
#include "Programs/message.h"
/* Include other files */
static void brl_identify() { }
static int brl_open(BrailleDisplay *brl, char **parameters, const char *tty) { ... }
static void brl_close(BrailleDisplay *brl) { ... }
static void brl_writeWindow(BrailleDisplay *brl) { ... }
static void brl_writeStatus(BrailleDisplay *brl) { ... }
static int brl_readCommand(BrailleDisplay *brl, DriverCommandContext context) { ... }
</verb>
Before giving a detailed description of what each function is
supposed to do, we define the <tt>BrailleDisplay</tt> structure,
since each function has an argument of type <tt>BrailleDisplay
*</tt>. The <tt>BrailleDisplay</tt> structure is defined like this:
<verb>
typedef struct {
int x, y; /* The dimensions of the display */
int helpPage; /* The page number within the help file */
unsigned char *buffer; /* The contents of the display */
unsigned isCoreBuffer:1; /* The core allocated the buffer */
unsigned resizeRequired:1; /* The display size has changed */
unsigned int writeDelay;
void (*bufferResized)(int rows, int columns);
} BrailleDisplay;
</verb>
We now describe each function's semantics and calling
convention.
The <tt/brl_identify()/ function takes no argument and returns
nothing. It is called as soon as the driver is loaded, and its
purpose is to print some information about the driver in the system
log. To achieve this, the only thing this function has to do is to
call LOG_PRINT with appropriate arguments (log level and string to
put in the syslog).
The <tt/brl_open()/ function takes 3 arguments and returns an int. Its
purpose is to initialize the communication with the braille
terminal. Generally, this function has to open the file referred to by
the <tt/tty/ argument, and to configure the associated communication
port. The <tt/parameters/ argument contains parameters passed to the
driver with the -B command-line option. It's up to the driver's
author to decide wether or not he/she wants to use this argument,
and what for. The function can perform some additional tasks such
as trying to identify precisely which braille terminal model is
connected to the computer, by sending it a request and analyzing its
answer. The value that is finally returned depends on the success of
the initialization process. If it fails, th function has to return
-1. The function returns 0 on success.
The <tt/brl_close()/ function takes just one argument, and returns
nothing. The name of this function should be self-explanatory; it's
goal is to close (finish) the communication between the computer and
the braille terminal. In general, the only thing this function has
to do is to close the file descriptor associated to the braille
terminal's communication port.
The <tt/brl_writeWindow()/ function takes just one argument of type
BrailleDisplay, and returns nothing. This function displays the
specified text on the braille window. This routine is the right
place to check if the text that has to be displayed is not already
on the braille display, to send it only if necessary. More
generally, if the braille terminal supports partial refresh of the
display, the calculus of what exactly has to be sent to the braille
display to have a proper display, according to what was previously
displayed should be done in this function.
The <tt/brl_writeStatus()/ function is very similar to <tt/brl_writeWindow()/.
The only difference is that whereas <tt/brl_writeWindow()/ writes on the
main braille display, <tt/brl_writeStatus()/ writes on an auxiliary braille
display, which occasionaly appears on some braille terminals. The
remarks that have been done concerning optimizations for refreshing
the display still apply here.
The <tt/brl_readCommand()/ function takes two arguments, and returns an
integer. Its purpose is to read commands from the braille keyboard
and to pass them to <em/brltty/'s core, which in turn will process them.
The first argument, of type <tt/BrailleDisplay/, is for future use, and
can safely be ignored for the moment. The second argument indicates
in which context (state) <em/brltty/ is. For instance, it specifies if
<em/brltty/ is in a menu, displays a help screen, etc. This information
can indeed be of some interest when translating a key into a
command, especially if the keys can have different meanings,
depending on the context. So, this function has to read keypresses
from the braille keyboard, and to convert them into commands,
according to the given context, these commands then being returned
to <em/brltty/. For a complete list of available command codes, please
have a look at <tt/brl.h/ in the Programs subdirectory. Two codes have special
meanings:
<descrip>
<tag/eof/ specifies that no command is available now, and that
no key is waiting to be converted into command in a near future.
<tag/CMD_NOOP/ specifies that no command is available, but
that one will be, soon. As a consequence, brl_readCommand will be
called again immediately. Returning CMD_NOOP is appropriate for
instance when a key is composed of two consecutive data packets.
When the first of them is received, one can expect that the second
will arrive quickly, so that trying to read it as soon as possible
is a good idea.
</descrip>
<sect1>Enhancements for <em/BrlAPI/
<p>To improve the level of service provided to client
applications communicating with braille drivers through <em/BrlAPI/, the
drivers should declare some additional functions that will then be
called by the API when needed.
For each additional feature that has to be implemented in a
driver, a specific macro must be defined, in addition to the
functions implementing that feature. For the moment, two features
are supported by <em/BrlAPI/:
<itemize>
<item>reading braille terminal specific key codes,
<item>exchanging raw data packets between the braille
terminal and a client application running on the PC.
</itemize>
For each feature presented below, only a short description of each
concerned macro and function will be given. For a more complete description
of concepts used here, please refer to previous chapters.
<sect2>Reading braille key codes
<p>
When a client takes control of a tty and asks for getting raw key codes, it
has, like in command mode, the possibility to mask some keys. The masked
keys will then be passed to <em/brltty/. This assumes the existence of a
conversion mechanism from key codes to <em/brltty/ commands.
This conversion mechanism can only be implemented by the braille driver,
since
it is the only piece of code that knows about braille terminal specific key
codes. So, to make it possible for client applications to read raw key
codes, the driver has to define the following macro:
<verb>
#define BRL_HAVE_KEY_CODES
</verb>
and the following functions:
<verb>
static int brl_readKey(BrailleDisplay *)
int brl_keyToCommand(BrailleDisplay *brl, DriverCommandContext caller, int code)
</verb>
The semantics of <tt>brl_readKey()</tt> is very similar to
<tt>brl_readCommand()</tt>'s, with one essential difference: a key code
is not context-dependant, so no context argument needs to be given to this
function. Moreover, the code this function returns is driver-specific, and
has to be properly defined by the driver's author so that client applications
can rely on it.
The <tt>brl_keyToCommand()</tt> function's purpose is to convert a key code
as delivered by <tt>brl_readKey()</tt> into a <em/brltty/ command. As explained
above, this function is called by brlapi when a key is pressed on the
braille keyboard that is ignored by the client application. The
corresponding command is then returned to <em/brltty/.
<sect3>Remarks
<p>When these two functions are present, the only thing
<tt>brl_readCommand()</tt> has to do is to call <tt>brl_readKey()</tt> and then
call <tt>brl_keyToCommand()</tt> with the value returned by the first function
as argument.
<sect2>Exchanging raw data packets
<p>Under some circumstances, an application running on the PC
can be interested in a raw level communication with the braille
terminal. For instance, to implement a file transfer protocol,
commands to display braille or to read keys are not enough. In
such a case, one must have a way to send raw data to the
terminal, and to receive them from it.
A driver that wants to provide such a mechanism has to define
three functions: one to send packets, another one to receive them,
and the last one to reset the communication when problems occur.
The macro that declares that a driver is able to transmit packets
is:
<verb>
#define BRL_HAVE_PACKET_IO
</verb>
The prototypes of the functions the driver should define are:
<verb>
static int brl_writePacket(BrailleDisplay *brl, const unsigned char *packet, int size);
static int brl_readPacket(BrailleDisplay *brl, unsigned char *p, int size);
static void brl_rescue(BrailleDisplay *brl)
</verb>
<tt>brl_writePacket()</tt> sends a packet of <tt/size/ bytes, stored
at <tt/packet/, to the braille terminal. If the communication protocol
allows to determined if a packet has been send properly (e.g. the
terminal sends back an acknowledgement for each packet he
receives), then this function should wait the acknowledgement,
and, if it is not received, retransmission of the packet should take
place.
<tt>brl_readPacket()</tt> reads a packet of at most <tt/size/ bytes, and
stores it at the specified address. The read must not block. I.e.,
if no packet is available, the function should return immediately,
returning 0.
<tt>brl_rescue()</tt> is called by <em/BrlAPI/ when a client
application terminates without properly leaving the raw mode. This
function should restore the terminal's state, so that it is
able to display text in braille again.
<sect3>Remarks.
<p>
<itemize>
<item> If the driver provides such functions, every other
functions should use them, instead of trying to communicate
directly with the braille terminal. For instance, <tt/readCommand()/
should call <tt/readPacket()/, and then extract a key from the packet,
rather than reading directly from the communication port's file
descriptor. The same applies for <tt/brl_writeWindow()/, which should
use <tt/brl_writePacket()/, rather than writing on the communication
port's file descriptor.
<item> For the moment, the argument of type BrailleDisplay
can safely be ignored by the functions described here.
</itemize>
<!---->
<sect>Protocol reference
<!---->
<!-- a boring documentation, explaining the underlying protocol of the api
in detail -->
<p>
Under some circumstances, it may be preferable to communicate directly with
<em/BrlAPI/'s server.avoid rather than using <em/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.
<p>
In all the following, <em/integer/ will mean an unsigned 32 bits integer in
network byte order (ie most significant bytes first).
<sect1>Reliable packet transmission channel
<p>
The protocol between <em/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 <em/BrlAPI/ needs
a reliable packet transmission channel.
<p>
To achieve this, <em/BrlAPI/ uses a TCP-based connection, on which packets
are transmitted this way:
<itemize>
<item>the size in bytes of the packet is transmitted first as an integer,
<item>then the type of the packet, as an integer,
<item>and finally the packet data.
</itemize>
<p>
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 <tt/BRLPACKET_*/ constants defined in <tt/brlapi.h/. Each type of
packet will be further discussed below.
<p>
<em/BrlAPI/'s library ships two functions to achieve packets sending and receiving
using this protocol: <tt/brlapi_writePacket/ and <tt/brlapi_readPacket/. It
is a good idea to use instead of rewriting them, since this protocol
might change one day in favor of a real reliable packet transmission protocol
such as the experimental RDP.
<sect1>Responses from the server
<p>
As described below, many packets are `acknowledged'. It means that upon
reception, the server sends either:
<itemize>
<item>a <tt/BRLPACKET_ACK/ packet, with no data, which means the operation
corresponding to the received packet was successful,
<item>or a <tt/BRLPACKET_ERROR/ packet, the data being an integer
which should be one of <tt/BRLERR_*/ constants. This
means the operation corresponding to the received packet failed.
</itemize>
<p>
Some other packets need some information as a response.
Upon reception, the server will send either:
<itemize>
<item>a packet of the same type, its data being the response,
<item>or a <tt/BRLPACKET_ERROR/ packet.
</itemize>
<sect1>Operating modes
<p>
The connection between the client and the server can be in either of the
four following modes:
<itemize>
<item>authentication mode: this is the initial mode, when the client hasn't
authenticated itself to the server yet. Only one <tt/BRLPACKET_AUTHKEY/ packet
will be accepted, which makes the connection enter normal mode;
<item>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:
<itemize>
<item><tt/BRLPACKET_GETDRIVERID/, <tt/BRLPACKET_GETDRIVERNAME/
or <tt/BRLPACKET_GETDISPLAYSIZE/ to get pieces of information from the server,
<item><tt/BRLPACKET_GETTTY/ to enter tty handling mode,
<item><tt/BRLPACKET_GETRAW/ to enter raw mode,
<item><tt/BRLPACKET_BYE/ to tell the server it wants to close the connection.
</itemize>;
<item>tty handling mode: the client holds the control of a tty: <em/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:
<itemize>
<item><tt/BRLPACKET_GETTTY/ to switch to another tty, but how key presses
should be sent mustn't change,
<item><tt/BRLPACKET_LEAVETTY/ to leave tty handling mode and go back to
normal mode,
<item><tt/BRLPACKET_MASKKEY/ or <tt/BRLPACKET_UNMASKKEY/ to mask and unmask
keys,
<item><tt/BRLPACKET_WRITE/ or <tt/BRLPACKET_STATUSWRITE/ to display text on
this tty,
<item><tt/BRLPACKET_GETRAW/ to enter raw mode,
<item><tt/BRLPACKET_GETDRIVERID/, <tt/BRLPACKET_GETDRIVERNAME/
or <tt/BRLPACKET_GETDISPLAYSIZE/ to get pieces of information from the server,
<item><tt/BRLPACKET_BYE/ to tell the server it wants to close the connection.
</itemize>
And the server might send either <tt/BRLPACKET_KEY/ or <tt/BRLPACKET_COMMAND/
packets to signal key presses;
<item>raw mode: the client wants to exchange packets directly with the braille
terminal. Only these types of packet will be accepted:
<itemize>
<item><tt/BRLPACKET_LEAVERAW/ to get back to previous mode, either normal or
tty handling mode.
<item><tt/BRLPACKET_PACKET/ to send a packet to the braille terminal.
<item><tt/BRLPACKET_BYE/ to tell the server it wants to close the connection.
</itemize>
And the server might send <tt/BRLPACKET_PACKET/ packets to give received packets
from the terminal to the client.
</itemize>
<sect1>Details for each type of packet
<p>
Here is described the semantics of each type of packet. Most of them are
directly linked to some of <em/BrlAPI/'s library's functions. Reading their
online manual page as well will hence be of good help for understanding.
<sect2><tt/BRLPACKET_AUTHKEY/ (see <em/brlapi_loadAuthKey()/)
<p>
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 the
authentication key itself.
If the authentication key matches the servers', it is acknowledged, and
other types of packets might be used, other <tt/BRLPACKET_AUTHKEY/ shouldn't
be sent by the client.
If the authentication key doesn't match, the server sends a
<tt/BRLERR_CONNREFUSED/ and closes the connection.
<sect2><tt/BRLPACKET_BYE/ (see <em/brlapi_closeConnection()/)
<p>
This should be sent by the client when it doesn't need server's services any
more, just before disconnecting from it. The server will acknowledge this
packet and close the connection. It will also clean up things like the tty which
was got by the application, as well as raw mode, by sending a special reset
event to the braille device, if the <tt/brltty/ driver implements it. But this
shouldn't prevent clients from cleanly leaving ttys and raw mode before issuing
<tt/BRLPACKET_BYE/ !
<sect2><tt/BRLPACKET_GETDRIVERID/ (see <em/brlapi_getDriverId()/)
<p>
This should be sent by the client when it needs the 2-char identifier of
the current <tt/brltty/ driver. The returned string is \0 terminated.
<sect2><tt/BRLPACKET_GETDRIVERNAME/ (see <em/brlapi_getDriverName()/)
<p>
This should be sent by the client when it needs the full name of
the current <tt/brltty/ driver. The returned string is \0 terminated.
<sect2><tt/BRLPACKET_GETDISPLAYSIZE/ (see <em/brlapi_getDisplaySize()/)
<p>
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.
<sect2><tt/BRLPACKET_GETTTY/ (see <em/brlapi_getTty()/)
<p>
This should be sent by the client to get control of a tty. Sent data are
two integers: the number of the tty to get control of (it mustn't be 0), and
how key presses should be sent: either <tt/BRLKEYCODES/ or <tt/BRLCOMMANDS/.
This packet is then acknowledged by the server.
<sect2><tt/BRLPACKET_KEY/ and <tt/BRLPACKET_COMMAND/ (see <em/brlapi_readKey()/
and <em/brlapi_readCommand()/)
<p>
As soon as the client got a tty, it must be prepared to handle either
<tt/BRLPACKET_KEY/ or <tt/BRLPACKET_COMMAND/ incoming packets (depending on the
parameter given in the <tt/BRLPACKET_GETTTY/ packet), at any time (as soon as
the key was pressed on the braille terminal, hopefuly).
The data holds the key press code
as an integer, either a raw key code in <tt/BRLPACKET_KEY/ packets, or a
<tt/brltty/ command code in <tt/BRLPACKET_COMMAND/ packets.
<sect2><tt/BRLPACKET_LEAVETTY/ (see <em/brlapi_leaveTty()/)
<p>
This should be sent to free the tty and masked keys lists.
This is acknowledged by the server.
<sect2><tt/BRLPACKET_MASKKEYS/ and <tt/BRLPACKET_UNMASKKEYS/ (see
<em/brlapi_ignoreKeys()/ and <em/brlapi_unignoreKeys()/)
<p>
If the client doesn't want every key press to be signaled to it, but some of
them to be given to <tt/brltty/ for normal processing, it can send
<tt/BRLPACKET_MASKKEYS/ packets to tell ranges of key codes which shouldn't be
sent to it, but given to <tt/brltty/, and <tt/BRLPACKET_UNMASKKEYS/ packets
to tell ranges of key codes which should be sent to it, and not given to
<tt/brltty/. The server keeps a dynamic list of ranges, so that arbitrary
sequences of such packets can be sent. Data are 2 integers: the lower and the
upper boundaries; lower and upper must be equal to tell one key, for instance.
<sect2><tt/BRLPACKET_WRITE/ (see <em/brlapi_writeBrl()/)
<p>
To display text on the braille terminal and set the position of the cursor,
the client can send a <tt/BRLPACKET_WRITE/ packet. This packet holds the cursor
position as an integer, and then the text to display, one byte per
caracter.
The text must exactly fit the braille display, ie hold <em/height/*<em/width/
bytes, where <em/height/ and <em/width/ must be get by sending a
<tt/BRLPACKET_GETDISPLAYSIZE/ packet. Moreover, characters are expected to
be encoded in latin-1. This packet is acknowledged by the server.
<sect2><tt/BRLPACKET_WRITEDOTS/ (see <em/brlapi_writeBrlDots()/)
<p>
Is used the same way as <tt/BRLPACKET_WRITE/, the only difference being that
characters are encoded in braille dots.
<sect2><tt/BRLPACKET_STATWRITE/
<p>
Some braille terminals have a special status display, whose text is independant
from normal display's. To display text on it, the client can send a
<tt/BRLPACKET_STATWRITE/ packet, just like <tt/BRLPACKET_WRITE/ packets.
<sect2><tt/BRLPACKET_STATWRITEDOTS/
<p>
Is used the same way as <tt/BRLPACKET_STATWRITE/, the only difference being that
characters are encoded in braille dots.
<sect2><tt/BRLPACKET_GETRAW/ (see <em/brlapi_getRaw()/)
<p>
To enter raw mode, the client must send a <tt/BRLPACKET_GETRAW/ packet,
which is acknowledged. Once in raw mode, no other packet than
<tt/BRLPACKET_LEAVERAW/ or <tt/BRLPACKET_PACKET/ will be accepted. The data must
hold the special value <tt/BRLRAW_MAGIC/: <tt/0xdeadbeef/, to avoid erroneous
raw mode activating.
<sect2><tt/BRLPACKET_LEAVERAW/ (see <em/brlapi_leaveRaw()/)
<p>
To leave raw mode, the client must send a <tt/BRLPACKET_LEAVERAW/ packet, which
is acknowledged.
<sect2><tt/BRLPACKET_PACKET/ (see <em/brlapi_sendRaw()/ and
<em/brlapi_recvRaw()/)
<p>
While in raw mode, only <tt/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 <tt/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 depend on the braille driver, so that the client should
check for its id or name thanks to a <tt/BRLPACKET_GETDRIVERID/ packet or
a <tt/BRLPACKET_GETDRIVERNAME/ packet, prior to sending any
<tt/BRLPACKET_GETRAW/ packet.
</article>
|