brailleDisplayDrivers.albatross package
Braille display driver for Tivomatic Caiku albatross 46 and 80 displays.
Submodules
brailleDisplayDrivers.albatross._threading module
Threads for Tivomatic Caiku Albatross braille display driver. Classes: - L{ReadThread}; manages reconnection retries and works as a trigger for read operations excluding initial connection establishment - L{RepeatedTimer}; timer to check periodically if data needs to be sent to display to keep connection. If display gets nothing within approximately 2 seconds, it falls back to “wait for connection” state.
- class brailleDisplayDrivers.albatross._threading.ReadThread(readFunction: Callable[[], None], disableFunction: Callable[[], None], event: Event, dev: Serial, *args, **kwargs)
Bases:
Thread
Controls most of read operations and tries to reconnect when needed.
Constructor. @param readFunction: Handles read operations and reconnection. @param disableFunction: Called on connection failure. @param event: Exit thread when set. @param dev: Port object.
- run()
Method representing the thread’s activity.
You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.
- _portPresent() bool
USB serial port disappears if cable is plugged out or device powered off. @return: C{True} if port is present, C{False} if not
- class brailleDisplayDrivers.albatross._threading.RepeatedTimer(interval: float, feedFunction: Callable[[], None])
Bases:
object
Repeating timer. Timer is used to check if data needs to be sent to display to keep connected.
Constructor. @param interval: Checking frequency @param feedFunction: feeds display with data if needed
- _run()
- start()
- stop()
brailleDisplayDrivers.albatross.constants module
Constants for Tivomatic Caiku Albatross 46 and 80 display driver.
Summary of important constants:
L{INIT_STARTBYTE} and L{MAX_SETTINGS_BYTE}; when there is no connection,
the display continuously sends L{INIT_START_BYTE} followed by the settings byte. The number of these packets is arbitrary. L{INIT_START_BYTE} is ÿ. Settings byte can be from to ÿ. It is limited to be at most L{MAX_SETTINGS_BYTE} to reliably detect init packets.
L{ESTABLISHED}; driver sends this to confirm connection, and
display stops sending init packets
all data to show on display has to be enclosed with L{START_BYTE} and
L{END_BYTE}
L{BOTH_BYTES} is used to keep connection; display falls back to
“wait for connection state” if it does not get appropriate data packet within approximately 2 seconds. L{KC_INTERVAL} defines suitable time which in turn is used by timer.
part of display buttons L{Keys} are control keys used to compose key
combinations. See also L{CONTROL_KEY_CODES}.
L{LEFT_RIGHT_KEY_CODES} is used when handling custom key layouts.
L{RESET_COUNT} defines how many times port buffer reset is done before
trying to establish connection. There are many I/O buffers between device and driver so several resets are done to ensure all buffers are cleared. Buffers may contain unexpected packets possibly due to write operations of other drivers with same PID&VID during automatic detection. There are also arbitrary number of redundant normal init packets which can be safely ignored.
- brailleDisplayDrivers.albatross.constants.BAUD_RATE: Tuple[int] = (19200, 9600)
Possible baud rates. Because 19200 is the display default, it is tried at first.
- brailleDisplayDrivers.albatross.constants.SLEEP_TIMEOUT = 0.2
How long to sleep when port cannot be opened or I/O buffers reset fails.
- brailleDisplayDrivers.albatross.constants.MAX_INIT_RETRIES = 20
How many times port initialization or opening is tried. This large value is required for braille to start. This should not effect other devices with the same PID and VID, because this device is detected as last one.
- brailleDisplayDrivers.albatross.constants.RESET_COUNT = 10
How many times to try to reset I/O buffers. Possibly due to write operations of other drivers with same PID&VID, device appears to send init packets it should not. Although reset is not ideal, unexpected packets are discarded. In addition, there are arbitrary number of redundant normal init packets which can be safely ignored.
- brailleDisplayDrivers.albatross.constants.RESET_SLEEP = 0.05
How long to sleep between I/O buffer resets.
- class brailleDisplayDrivers.albatross.constants.Keys(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Bases:
IntEnum
Defines key names and values. For routing keys see L{RoutingKeyRange}.
- attribute1 = 1
- attribute2 = 42
- f1 = 83
- f2 = 84
- f3 = 85
- f4 = 86
- f5 = 87
- f6 = 88
- f7 = 89
- f8 = 90
- home1 = 91
- end1 = 92
- eCursor1 = 93
- cursor1 = 94
- up1 = 95
- down1 = 96
- left = 97
- up2 = 98
- lWheelRight = 103
- lWheelLeft = 104
- lWheelUp = 105
- lWheelDown = 106
- attribute3 = 151
- attribute4 = 192
- f9 = 193
- f10 = 194
- f11 = 195
- f12 = 196
- f13 = 197
- f14 = 198
- f15 = 199
- f16 = 200
- home2 = 201
- end2 = 202
- eCursor2 = 203
- cursor2 = 204
- up3 = 205
- down2 = 206
- right = 207
- down3 = 208
- rWheelRight = 213
- rWheelLeft = 214
- rWheelUp = 215
- rWheelDown = 216
- brailleDisplayDrivers.albatross.constants.MAX_COMBINATION_KEYS = 4
Maximum number of keys in key combination.
- brailleDisplayDrivers.albatross.constants.CONTROL_KEY_CODES: FrozenSet[Keys] = frozenset({Keys.attribute1, Keys.attribute2, Keys.f1, Keys.f2, Keys.f7, Keys.f8, Keys.home1, Keys.end1, Keys.eCursor1, Keys.cursor1, Keys.attribute3, Keys.attribute4, Keys.f9, Keys.f10, Keys.f15, Keys.f16, Keys.home2, Keys.end2, Keys.eCursor2, Keys.cursor2})
Ctrl keys which may start key combination.
- brailleDisplayDrivers.albatross.constants.LEFT_RIGHT_KEY_CODES: Dict[Keys, Keys] = {Keys.attribute1: Keys.attribute3, Keys.attribute2: Keys.attribute4, Keys.f1: Keys.f9, Keys.f2: Keys.f10, Keys.f3: Keys.f11, Keys.f4: Keys.f12, Keys.f5: Keys.f13, Keys.f6: Keys.f14, Keys.f7: Keys.f15, Keys.f8: Keys.f16, Keys.home1: Keys.home2, Keys.end1: Keys.end2, Keys.eCursor1: Keys.eCursor2, Keys.cursor1: Keys.cursor2, Keys.up1: Keys.up3, Keys.down1: Keys.down2, Keys.lWheelRight: Keys.rWheelRight, Keys.lWheelLeft: Keys.rWheelLeft, Keys.lWheelUp: Keys.rWheelUp, Keys.lWheelDown: Keys.rWheelDown}
Connects corresponding left and right side keys. Dictionary keys are left side keys values, and dictionary values are corresponding right side keys values. Used with custom key layouts.
- brailleDisplayDrivers.albatross.constants.KEY_LAYOUT_MASK = 5
Used to extract bits 1 - 3 from settings byte to determine key layout. See L{KeyLayout}.
- class brailleDisplayDrivers.albatross.constants.KeyLayout(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Bases:
IntEnum
Defines possible key layouts. From settings byte bits 1 - 3 (MSB 0 scheme) are extracted and bit 2 is set to 0 (it represents side of status cells which NVDA does not use). The result is then compared with variables below to determine what key layout should be used.
Switching layout does not affect on Left, right, down3, up2, routing and secondRouting keys. Up2 and down3 are also ignored because they are in the middle of the front panel of 80 model so they do not logically belong to left or right side.
See also L{KEY_LAYOUT_MASK}.
- normal = 0
- bothSidesAsRight = 1
- switched = 4
- bothSidesAsLeft = 5
- class brailleDisplayDrivers.albatross.constants.RoutingKeyRange(name: str, start: int, end: int, indexOffset: int)
Bases:
object
Defines structure of items in L{ROUTING_KEY_RANGES}. Albatross has both routing and secondRouting key rows so L{name} is “routing” or “secondRouting”. Due to hardware design there are 4 address ranges: 2 for each rows which means 4 L{start} L{end} pairs. There are also 4 L{indexOffset} which are used to get real button index on the row. See also L{ROUTING_KEY_RANGES}.
- name: str
- start: int
- end: int
- indexOffset: int
- brailleDisplayDrivers.albatross.constants.ROUTING_KEY_RANGES: FrozenSet[RoutingKeyRange] = frozenset({RoutingKeyRange(name='routing', start=111, end=150, indexOffset=71), RoutingKeyRange(name='routing', start=2, end=41, indexOffset=2), RoutingKeyRange(name='secondRouting', start=152, end=191, indexOffset=112), RoutingKeyRange(name='secondRouting', start=43, end=82, indexOffset=43)})
Defines routing key ranges. See L{RoutingKeyRange}.
- brailleDisplayDrivers.albatross.constants.ESTABLISHED = b'\xfe\xfd'
Send this to Albatross to confirm that connection is established.
- brailleDisplayDrivers.albatross.constants.INIT_START_BYTE = b'\xff'
Starts every init packet. If no connection, Albatross sends continuously byte ÿ followed by byte containing various settings like number of cells.
- brailleDisplayDrivers.albatross.constants.MAX_SETTINGS_BYTE = b'\xfe'
Maximum value allowed for settings byte. Settings byte can be anything from to ÿ. However, ÿ would make connection establishment quite complex:
cannot be sure if the first byte received is L{INIT_START_BYTE} or
settings byte - if settings byte is not L{INIT_START_BYTE} it is easier - similarly it is easy to detect if whole init packet is received, it is possible that the second byte is received during next read operation - typically there are tens of init packets but the number of packets varies
Settings byte limitation causes maximum number of status cells to be 14 (with ÿ 15) in 80 model. Limitation is applied only if other settings would make settings byte to be ÿ. These are very big values (5 could be normal maximum value), and NVDA does not utilize status cells.
Although settings like number of status cells are adjusted in display menu, display itself does not use them. They are just notes for screenreaders. For example, display has no separate status cells. It is screenreader or driver job to use them when applicable.
Only display settings which affects on its own functionality are baud rate and key repeat which can be slow or fast.
There are other devices with same PID&VID. When automatic braille display detection is used, other displays with same PID&VID are tried before Albatross. Those drivers try to send queries to the port to detect their own displays. These queries may cause Albatross to send unexpected init packets which in turn could disturb this driver - it could get inappropriate settings byte. This is tried to prevent by resetting I/O buffers so that strange packets would be discarded.
If however, there are still strange init packets, Albatross should be manually selected from the display list.
- brailleDisplayDrivers.albatross.constants.MAX_STATUS_CELLS_ALLOWED = 14
To inform user how many status cells can be used. See L{MAX_SETTINGS_BYTE}.
- brailleDisplayDrivers.albatross.constants.START_BYTE = b'\xfb'
Send information to Albatross enclosed by L{START_BYTE} and L{END_BYTE}.
- brailleDisplayDrivers.albatross.constants.END_BYTE = b'\xfc'
Send information to Albatross enclosed by L{START_BYTE} and L{END_BYTE}.
- brailleDisplayDrivers.albatross.constants.BOTH_BYTES = b'\xfb\xfc'
To keep connected these both above bytes must be sent periodically.
- brailleDisplayDrivers.albatross.constants.KC_INTERVAL = 1.5
How often BOTH_BYTES should be sent and reconnection tried.
Display requires at least L{START_BYTE} and L{END_BYTE} combination within approximately 2 seconds from previous appropriate data packet. Otherwise it falls back to “wait for connection” state. This behavior is built-in feature of the firmware of device.
- brailleDisplayDrivers.albatross.constants.BUS_DEVICE_DESC = 'Albatross Braille Display'
Bus reported device description
- brailleDisplayDrivers.albatross.constants.VID_AND_PID = 'VID_0403&PID_6001'
Vid and pid
brailleDisplayDrivers.albatross.driver module
Main code for Tivomatic Caiku Albatross braille display driver. Communication with display is done here. See class L{BrailleDisplayDriver} for description of most important functions.
- class brailleDisplayDrivers.albatross.driver.BrailleDisplayDriver(*args, **kwargs)
Bases:
BrailleDisplayDriver
Communication with display.
Most important functions:
L{_readHandling}; all data from display is read there
L{_somethingToWrite}; manages all write operations
L{display}; prepares data which should be displayed on braille so
that display can show it properly
Constructor @param port: Information on how to connect to the device.
Use L{_getTryPorts} to normalise to L{DeviceMatch} instances. - A string (from config “config.conf[“braille”][name][“port”]”). When manually configured.
This value is set via the settings dialog, the source of the options provided to the user is the BrailleDisplayDriver.getPossiblePorts method.
A L{DeviceMatch} instance. When automatically detected.
- name = 'albatross'
The name of the driver; must be the original module file name. @type: str
- description = 'Caiku Albatross 46/80'
A description of the driver. @type: str
- isThreadSafe: bool = True
Whether this driver is thread-safe. If it is, NVDA may initialize, terminate or call this driver on any thread. This allows NVDA to read from and write to the display in the background, which means the rest of NVDA is not blocked while this occurs, thus resulting in better performance. This is also required to use the L{hwIo} module.
- supportsAutomaticDetection: bool = True
Whether this driver is supported for automatic detection of braille displays.
- classmethod registerAutomaticDetection(driverRegistrar: DriverRegistrar)
This method may register the braille display driver in the braille display automatic detection framework. The framework provides a L{bdDetect.DriverRegistrar} object as its only parameter. The methods on the driver registrar can be used to register devices or device scanners. This method should only register itself with the bdDetect framework, and should refrain from doing anything else. Drivers with L{supportsAutomaticDetection} set to C{True} must implement this method. @param driverRegistrar: An object containing several methods to register device identifiers for this driver.
- classmethod getManualPorts()
Get possible manual hardware ports for this driver. This is for ports which cannot be detected automatically such as serial ports. @return: An iterator containing the name and description for each port.
- terminate()
Destructor. Clear display, and close and release all resources before exit.
- _searchPorts(originalPort: str)
Search ports where display can be connected. @param originalPort: original port name as string @raises: RuntimeError if no display found
- _initConnection() bool
_initConnection, _initPort, _openPort, _readInitByte and _readSettingsByte are helper functions to establish connection. If no connection, Albatross sends continuously INIT_START_BYTE followed by byte containing various settings like number of cells.
@raises: RuntimeError if port initialization fails @return: C{True} on success, C{False} on connection failure
- _initPort(i: int = 19) bool
Initializes port. @param i: Just for logging retries. @raises: IOError if port initialization fails @return: C{True} on success, C{False} on I/O buffers reset failure
- _openPort(i: int = 19) bool
Opens port. @param i: Just for logging retries. @return: C{True} on success, C{False} on failure
- _readInitByte() bool
Reads init byte. @return: C{True} on success, C{False} on failure
- _readSettingsByte() bool
Reads settings byte. @return: C{True} on success, C{False} on failure
- _resetBuffers() bool
Resets I/O buffers. Reset is done L{RESET_COUNT} times to get better results. @return: C{True} on success, C{False} on failure
- _disableConnection()
Disables current connection after failure. Reconnection retries are started.
- _readHandling()
Manages all read operations. Most of time called from albatross_read thread when there is something to read in the port. See L{_threading} module ReadThread class. When initial connection is established called from L{_searchPorts} function.
- _somethingToRead() bytes | None
All but connecting/reconnecting related read operations. @return: on success returns data, on failure C{None}
- _skipRedundantInitPackets(data: bytes) bool
Filters redundant init packets. @param data: Bytes read from display. @return: C{True} on success, C{False} on failure
- _somethingToWrite()
All write operations.
- _handleReadQueue()
Handles data read in L{_readHandling}.
- _handleInitPackets(data: bytes)
Handles init packets. Display also starts to send init packets when exited internal menu or when delay sending data to display causes its fallback to ‘wait for connection’ state.
@param data: one byte which can be L{INIT_START_BYTE} or settings byte
- _handleSettingsByte(data: bytes)
Extract current settings from settings byte. All other settings except number of cells are only notes to screenreader, and it is screenreader or driver job to use them when applicable. For example, there are no separate status cells in the device but if screenreader supports using status cells, it can be notified to use them by settings byte.
Settings byte contain following settings (bits referred by using MSB 0 scheme):
bit 0: number of cells; 0 = 46, 1 = 80. This is model based value
which cannot be changed. This is the most important setting, and it must be applied.
bit 1: switch left side and right side keys; 0 = no, 1 = yes.
Left, right, down3, up2, routing and secondRouting keys are not affected. Up2 and down3 are ignored because they are in the middle of the front panel of 80 model so they do not logically belong to left or right side. All other keys are switched with corresponding other side keys.
bit 2: place of status cells; 0 = left, 1 = right. Not implemented.
NVDA does not use status cells at the moment.
bit 3: all keys act as right side keys; 0 = no, 1 = yes.
Left, right, down3, up2, routing and secondRouting keys are not affected. Up2 and down3 are ignored because they are in the middle of the front panel of 80 model so they do not logically belong to left or right side. All other left side keys are assigned to corresponding right side keys.
bit 1 = 0 and bit 3 = 0: normal key layout.
bit 1 = 1 and bit 3 = 1: all keys act as corresponding left side keys.
Left, right, down3, up2, routing and secondRouting keys are not affected. Up2 and down3 are ignored because they are in the middle of the front panel of 80 model so they do not logically belong to left or right side. All other right side keys are assigned to corresponding left side keys.
bits 4 - 7: number of status cells. Not implemented.
NVDA does not use status cells at the moment.
@param data: Settings byte
- _handleKeyPresses(data: bytes)
Handles display button presses. In single ctrl-key presses and ctrl-key combinations the first key is also present as last one. For example, single ctrl-key press F1 is sent as “f1 f1”, and ctrl-key combination f1 + f2 + f3 + f4 is sent as “f1 f2 f3 f4 f1”. @param data: single byte which may be whole or partial key press
- _changeKeyValues(data: bytearray) bytes
Changes pressed keys values according to current key layout. @param data: pressed keys values. @return: pressed keys values based on current key layout.
- _keepConnected()
Keep display connected if nothing is sent for a while.
- _clearOldCells()
Whole display should be updated at next time.
- display(cells: List[int])
Prepare cell content for display. @param cells: List of cells content
- gestureMap: GlobalGestureMap | None = <inputCore.GlobalGestureMap object>
Global input gesture map for this display driver.
- _abc_impl = <_abc._abc_data object>
brailleDisplayDrivers.albatross.gestures module
Gesture handling for Tivomatic Caiku Albatross 46 and 80 display driver.
- class brailleDisplayDrivers.albatross.gestures.InputGestureKeys(*args, **kwargs)
Bases:
BrailleDisplayGesture
Changes display key presses to gestures for NVDA input system.
Constructor. @param key: set of pressed keys @param name: identifies gestures from this display
- _getRoutingIndex(key: int) Tuple[str, int] | None
Get the routing index, if the key is in a routing index range, returns the name of the range and the index within that range. See L{ROUTING_KEY_RANGES}. @param key: key which index to check @return: if the key is in a routing index range, returns the name of the range and the index within that range
- _abc_impl = <_abc._abc_data object>