/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2021 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ /** ** brl.c -- EuroBraille core driver file. ** Made by Yannick PLASSIARD and Olivier BERT */ #include "prologue.h" typedef enum { PARM_PROTOCOL } DriverParameter; #define BRLPARMS "protocol" #include #include #include "message.h" #include "log.h" #define BRL_HAVE_PACKET_IO #include "brl_driver.h" #include "parse.h" #include "async_wait.h" #include "eu_protocol.h" BEGIN_KEY_TABLE_LIST &KEY_TABLE_DEFINITION(clio), &KEY_TABLE_DEFINITION(iris), &KEY_TABLE_DEFINITION(esys_small), &KEY_TABLE_DEFINITION(esys_medium), &KEY_TABLE_DEFINITION(esys_large), &KEY_TABLE_DEFINITION(esytime), END_KEY_TABLE_LIST const InputOutputOperations *io = NULL; static const ProtocolOperations *protocol = NULL; static inline void updateWriteDelay (BrailleDisplay *brl, size_t count) { brl->writeDelay += gioGetMillisecondsToTransfer(brl->gioEndpoint, count); } static int awaitInput_generic (BrailleDisplay *brl, int timeout) { return awaitBrailleInput(brl, timeout); } static int readByte_generic (BrailleDisplay *brl, unsigned char *byte, int wait) { return gioReadByte(brl->gioEndpoint, byte, wait); } static ssize_t writeData_generic (BrailleDisplay *brl, const void *data, size_t length) { updateWriteDelay(brl, length); return gioWriteData(brl->gioEndpoint, data, length); } static ssize_t writeData_USB (BrailleDisplay *brl, const void *data, size_t length) { size_t offset = 0; while (offset < length) { unsigned char report[64]; size_t count = length - offset; if (count > sizeof(report)) { count = sizeof(report); } else { memset(&report[count], 0X55, (sizeof(report) - count)); } memcpy(report, data+offset, count); updateWriteDelay(brl, sizeof(report)); if (gioSetHidReport(brl->gioEndpoint, 0, report, sizeof(report)) < 0) return -1; offset += count; } return length; } static const InputOutputOperations serialOperations = { .awaitInput = awaitInput_generic, .readByte = readByte_generic, .writeData = writeData_generic }; static const InputOutputOperations usbOperations = { .protocol = &esysirisProtocolOperations, .awaitInput = awaitInput_generic, .readByte = readByte_generic, .writeData = writeData_USB }; static const InputOutputOperations bluetoothOperations = { .protocol = &esysirisProtocolOperations, .awaitInput = awaitInput_generic, .readByte = readByte_generic, .writeData = writeData_generic }; static int connectResource (BrailleDisplay *brl, const char *identifier) { static const SerialParameters serialParameters = { SERIAL_DEFAULT_PARAMETERS, .baud = 9600, .parity = SERIAL_PARITY_EVEN }; BEGIN_USB_CHANNEL_DEFINITIONS { /* Esys (version < 3.0, no SD card) */ .vendor=0XC251, .product=0X1122, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X1123, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* Esys (version < 3.0, with SD card) */ .vendor=0XC251, .product=0X1124, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X1125, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* Esys (version >= 3.0, no SD card) */ .vendor=0XC251, .product=0X1126, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X1127, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* Esys (version >= 3.0, with SD card) */ .vendor=0XC251, .product=0X1128, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X1129, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X112A, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X112B, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X112C, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X112D, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X112E, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X112F, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* Esytime */ .vendor=0XC251, .product=0X1130, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .verifyInterface = 1, .disableEndpointReset = 1 }, { /* Esytime (firmware 1.03, 2014-03-31) */ .vendor=0XC251, .product=0X1130, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=7, .outputEndpoint=0, .verifyInterface = 1, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X1131, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, { /* reserved */ .vendor=0XC251, .product=0X1132, .configuration=1, .interface=0, .alternative=0, .inputEndpoint=1, .outputEndpoint=0, .disableEndpointReset = 1 }, END_USB_CHANNEL_DEFINITIONS GioDescriptor descriptor; gioInitializeDescriptor(&descriptor); descriptor.serial.parameters = &serialParameters; descriptor.serial.options.applicationData = &serialOperations; descriptor.usb.channelDefinitions = usbChannelDefinitions; descriptor.usb.options.applicationData = &usbOperations; descriptor.bluetooth.channelNumber = 1; descriptor.bluetooth.options.applicationData = &bluetoothOperations; if (connectBrailleResource(brl, identifier, &descriptor, NULL)) { io = gioGetApplicationData(brl->gioEndpoint); return 1; } return 0; } static int brl_construct (BrailleDisplay *brl, char **parameters, const char *device) { io = NULL; protocol = NULL; makeOutputTable(dotsTable_ISO11548_1); if (parameters[PARM_PROTOCOL]) { static const char *const choices[] = { "auto", "azerbraille", "clio", "eurobraille", "notebraille", "pupibraille", "scriba", "esys", "esytime", "iris", "esysiris", NULL }; static const ProtocolOperations *const protocols[] = { NULL, // auto &clioProtocolOperations, // azerbraille &clioProtocolOperations, // clio &clioProtocolOperations, // eurobraille &clioProtocolOperations, // notebraille &clioProtocolOperations, // pupibraille &clioProtocolOperations, // scriba &esysirisProtocolOperations, // esys &esysirisProtocolOperations, // esytime &esysirisProtocolOperations, // iris &esysirisProtocolOperations // esysiris }; unsigned int choice; if (!validateChoice(&choice, parameters[PARM_PROTOCOL], choices)) { logMessage(LOG_ERR, "unknown EuroBraille protocol: %s", parameters[PARM_PROTOCOL]); choice = 0; } protocol = protocols[choice]; } if (connectResource(brl, device)) { if (protocol) { if (!io->protocol || (io->protocol == protocol)) { if (protocol->initializeDevice(brl)) return 1; } else { logMessage(LOG_ERR, "protocol not supported by device: %s", protocol->protocolName); } } else if (io->protocol) { protocol = io->protocol; if (protocol->initializeDevice(brl)) return 1; } else { static const ProtocolOperations *const protocols[] = { &esysirisProtocolOperations, &clioProtocolOperations, NULL }; const ProtocolOperations *const *p = protocols; while (*p) { const ProtocolOperations *protocol = *p++; logMessage(LOG_NOTICE, "trying protocol: %s", protocol->protocolName); if (protocol->initializeDevice(brl)) return 1; asyncWait(700); } } disconnectBrailleResource(brl, NULL); } return 0; } static void brl_destruct (BrailleDisplay *brl) { if (protocol) { protocol = NULL; } disconnectBrailleResource(brl, NULL); } #ifdef BRL_HAVE_PACKET_IO static ssize_t brl_readPacket (BrailleDisplay *brl, void *buffer, size_t size) { if (!protocol || !io) return (-1); return protocol->readPacket(brl, buffer, size); } static ssize_t brl_writePacket (BrailleDisplay *brl, const void *packet, size_t length) { if (!protocol || !io) return (-1); return protocol->writePacket(brl, packet, length); } static int brl_reset (BrailleDisplay *brl) { if (!protocol || !io) return (-1); return protocol->resetDevice(brl); } #endif /* BRL_HAVE_PACKET_IO */ static int brl_writeWindow (BrailleDisplay *brl, const wchar_t *text) { if (!protocol) return 1; if (text) if (!protocol->writeVisual(brl, text)) return 0; return protocol->writeWindow(brl); } static int brl_readCommand (BrailleDisplay *brl, KeyTableCommandContext context) { if (protocol) return protocol->readCommand(brl, context); return EOF; }