Skip to content

Commit 049ea27

Browse files
authored
Merge 3a0a934 into 81d81dc
2 parents 81d81dc + 3a0a934 commit 049ea27

2 files changed

Lines changed: 147 additions & 0 deletions

File tree

source/bdDetect.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,7 @@ def driverSupportsAutoDetection(driver):
581581
"VID_10C4&PID_EA60", # SuperBraille 3.2
582582
})
583583

584+
# NattiqBraille
585+
addUsbDevices("nattiqbraille", KEY_SERIAL, {
586+
"VID_2341&PID_8036", # Atmel-based USB Serial
587+
})
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# brailleDisplayDrivers/nattiqbraille.py
2+
# A part of NonVisual Desktop Access (NVDA)
3+
# This file is covered by the GNU General Public License.
4+
# See the file COPYING for more details.
5+
# Copyright (C) 2020 NV Access Limited, <Mohammed Noman>
6+
7+
8+
import serial
9+
import braille
10+
import inputCore
11+
from logHandler import log
12+
import hwIo
13+
14+
BAUD_RATE = 10000000
15+
INIT_TAG = b"0"
16+
RESET_TAG = b"reset"
17+
# Initialization response id
18+
INIT_RESP = 0
19+
# Keys response id
20+
ROUTE_RESP = 1
21+
UP_KEY_RESP = 2
22+
DOWN_KEY_RESP = 3
23+
RIGHT_KEY_RESP = 4
24+
LEFT_KEY_RESP = 5
25+
# Keys pressed id
26+
UP_KEY_PRESS = 1
27+
DOWN_KEY_PRESS = 2
28+
RIGHT_KEY_PRESS = 3
29+
LEFT_KEY_PRESS = 4
30+
31+
32+
class BrailleDisplayDriver(braille.BrailleDisplayDriver):
33+
name = "nattiqbraille"
34+
# Translators: Names of braille displays
35+
description = _("Nattiq nBraille")
36+
isThreadSafe = True
37+
38+
@classmethod
39+
def getManualPorts(cls):
40+
return braille.getSerialPorts()
41+
42+
def __init__(self, port="auto"):
43+
super(BrailleDisplayDriver, self).__init__()
44+
self._serial = None
45+
for portType, portId, port, portInfo in self._getTryPorts(port):
46+
log.debug("Checking port %s for a Nattiq nBraille", port)
47+
try:
48+
self._serial = hwIo.Serial(
49+
port, baudrate=BAUD_RATE, timeout=self.timeout, writeTimeout=self.timeout,
50+
parity=serial.PARITY_NONE, onReceive=self._onReceive
51+
)
52+
except EnvironmentError:
53+
log.debugWarning("", exc_info=True)
54+
continue
55+
# Check for cell information
56+
if self._describe():
57+
log.debug("Nattiq nBraille found on %s with %d cells", port, self.numCells)
58+
break
59+
else:
60+
self._serial.close()
61+
else:
62+
raise RuntimeError("Can't find a Nattiq nBraille device (port = %s)" % port)
63+
64+
def terminate(self):
65+
try:
66+
super(BrailleDisplayDriver, self).terminate()
67+
finally:
68+
self._serial.write(RESET_TAG)
69+
self._serial.close()
70+
self._serial = None
71+
72+
def _describe(self):
73+
self.numCells = 0
74+
log.debug("Writing reset tag")
75+
self._serial.write(RESET_TAG)
76+
self._serial.waitForRead(self.timeout * 10)
77+
log.debug("Writing init tag")
78+
self._serial.write(INIT_TAG)
79+
self._serial.waitForRead(self.timeout * 10)
80+
# If a valid response was received, _onReceive will have set numCells.
81+
if self.numCells:
82+
return True
83+
log.debug("Not a Nattiq nBraille")
84+
return False
85+
86+
def _onReceive(self, command):
87+
if int(command) == INIT_RESP:
88+
CELLS_NUM = self._serial.read(2)
89+
self.numCells = int(CELLS_NUM)
90+
elif int(command) == ROUTE_RESP:
91+
ROUTE_KEY = self._serial.read(2)
92+
inputCore.manager.executeGesture(RoutingInputGesture(int(ROUTE_KEY)))
93+
elif int(command) == UP_KEY_RESP:
94+
inputCore.manager.executeGesture(InputGestureKeys(UP_KEY_PRESS))
95+
log.debug("Up Key Pressed")
96+
elif int(command) == DOWN_KEY_RESP:
97+
inputCore.manager.executeGesture(InputGestureKeys(DOWN_KEY_PRESS))
98+
log.debug("Down Key Pressed")
99+
elif int(command) == RIGHT_KEY_RESP:
100+
inputCore.manager.executeGesture(InputGestureKeys(RIGHT_KEY_PRESS))
101+
log.debug("Right Key Pressed")
102+
elif int(command) == LEFT_KEY_RESP:
103+
inputCore.manager.executeGesture(InputGestureKeys(LEFT_KEY_PRESS))
104+
log.debug("Left Key Pressed")
105+
106+
def display(self, cells):
107+
cells = b"-".join(cell.to_bytes(1, "little") for cell in cells)
108+
log.debug(cells)
109+
self._serial.write(cells)
110+
111+
gestureMap = inputCore.GlobalGestureMap({
112+
"globalCommands.GlobalCommands": {
113+
"braille_scrollBack": ("br(nattiqbraille):tback",),
114+
"braille_routeTo": ("br(nattiqbraille):routing",),
115+
"braille_scrollForward": ("br(nattiqbraille):tadvance",),
116+
"braille_previousLine": ("br(nattiqbraille):tprevious",),
117+
"braille_nextLine": ("br(nattiqbraille):tnext",),
118+
},
119+
})
120+
121+
122+
class InputGestureKeys(braille.BrailleDisplayGesture):
123+
source = BrailleDisplayDriver.name
124+
125+
def __init__(self, keys):
126+
super(InputGestureKeys, self).__init__()
127+
if keys == UP_KEY_PRESS:
128+
self.id = "tback"
129+
elif keys == DOWN_KEY_PRESS:
130+
self.id = "tadvance"
131+
elif keys == RIGHT_KEY_PRESS:
132+
self.id = "tnext"
133+
elif keys == LEFT_KEY_PRESS:
134+
self.id = "tprevious"
135+
136+
137+
class RoutingInputGesture(braille.BrailleDisplayGesture):
138+
source = BrailleDisplayDriver.name
139+
140+
def __init__(self, routingIndex):
141+
super(RoutingInputGesture, self).__init__()
142+
self.routingIndex = routingIndex
143+
self.id = "routing"

0 commit comments

Comments
 (0)