Skip to content
Merged
Changes from 3 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
c1784f0
Attempt to create a new hwIo class for USB bulk devices
Sep 25, 2017
dd6fae5
Merge branch 'bulk' into freedomscientific-native
bramd Sep 25, 2017
20da169
Native driver for Freedom Scientific braille displays, work in progre…
bramd Sep 25, 2017
882a307
Key and extended key handling
bramd Sep 27, 2017
52f041e
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Sep 28, 2017
bff76e8
Add support for routing and second row of buttons on older Focus/Pacm…
bramd Oct 1, 2017
2bddae8
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Oct 14, 2017
f17a225
Properly implement Freedom Scientific displays connected via Bluetooth
bramd Oct 14, 2017
a4b647a
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Oct 24, 2017
685d360
Fix output on Focus series 1 (44/70/84), improve initialization
bramd Oct 24, 2017
fd7e914
Add USB VID/PID for Focus/PAC mate displays
bramd Nov 4, 2017
e37038a
Code documentation and cleanup
bramd Nov 4, 2017
d49a493
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Nov 4, 2017
d60639f
Fix typo in br(breedomscientific]:leftBumerbarUp gesture. Fix merged …
bramd Nov 4, 2017
331e13d
Mark brailleDisplayDrivers/freedomScientific.py as UTF-8
bramd Nov 4, 2017
2249037
Fixed reference from numCells to self.numCells
bramd Nov 8, 2017
f54e54e
Merge branch 'master' into freedomscientific-native
bramd Aug 4, 2018
cef92d2
Enable auto detection of Freedom Scientific braille displays
bramd Aug 5, 2018
d783b49
Some code cleanup
bramd Aug 5, 2018
8364932
Fix mistake in display initialization introduced in the previous comm…
bramd Aug 5, 2018
4a50975
Fix key handling if multiple keys are released at the same time
bramd Aug 5, 2018
5ad6818
Don't set _awaitingAck manually in display method
bramd Aug 5, 2018
d0f6e6e
Merge branch 'master' into freedomscientific-native
bramd Sep 8, 2018
a3fb229
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Sep 29, 2018
4f4d6ce
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Oct 13, 2018
363ea52
Code cleanup
bramd Oct 14, 2018
224bdca
The Focus displays seem to switch to USB as soon as a USB cable is co…
bramd Oct 14, 2018
2194af1
The Focus displays seem to switch to USB as soon as a USB cable is co…
bramd Oct 14, 2018
4125f0f
Update UserGuide:Freedom Scientific displays support auto detection
bramd Oct 15, 2018
318439b
Add key bindings for win+tab and alt+shift+tab
bramd Oct 15, 2018
4a2020c
Support model specific gestures
bramd Oct 17, 2018
9da6213
Use self.timeout instead of the TIMEOUTconstant
bramd Oct 17, 2018
2422b3d
Review comment:use BytesIO instead of StringIO
bramd Oct 21, 2018
50c8a89
Handle bumper keys correctly (#8849)
bramd Oct 21, 2018
3cae439
Merge remote-tracking branch 'origin/master' into freedomscientific-n…
Dec 18, 2018
7baac86
Get rid of heavily confusing _resumeDetection method on the braille h…
Dec 18, 2018
78bdc84
Additional clarifying comment
Dec 18, 2018
f5984e4
Respect limitToDevices when bluetooth polling or when a rescan is tri…
Dec 18, 2018
82d2120
Also respect a dedetector without bluetooth when a new device is added
Dec 18, 2018
e43fa7a
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd Dec 27, 2018
1b7f7f3
Merge pull request #2 from leonardder/freedomChanges
bramd Dec 27, 2018
4a5f6c7
Fix double and
Dec 27, 2018
1778224
Fix top routing for Focus 2nd generation
Dec 27, 2018
7b29486
Improve python 3 compat
Dec 27, 2018
06d7efc
Make a constant for TOP_ROUTING_KEY_GROUP
Dec 27, 2018
0eccac8
isTopRow now treates the keygroup as a boolean. It looks like key gro…
Dec 27, 2018
bd6384d
Merge remote-tracking branch 'origin/master' into freedomscientific-n…
Mar 5, 2019
a88f6d9
Fixed issues in braille module
Mar 5, 2019
1719423
Review actions for bdDetect
Mar 25, 2019
72ce2f1
Merge remote-tracking branch 'origin/master' into freedomscientific-n…
Mar 25, 2019
f411a43
Review actions
bramd Mar 31, 2019
9beffd1
Use FS_BYTE_NULL instead of FS_DATA_EMPTY in string replacement for m…
bramd Apr 10, 2019
99cbc02
Use constants for offsets in INFO packet
bramd Apr 13, 2019
90447e1
Fix documentation ans usage of special translation table for Focus 1
bramd Apr 13, 2019
1545299
Improve documentation
bramd May 4, 2019
52dc60b
Documentation and code clarification.
feerrenrut May 6, 2019
2869c9e
Update source/brailleDisplayDrivers/freedomScientific.py
feerrenrut May 20, 2019
4cd583c
Merge pull request #3 from nvaccess/freedomscientific-native
bramd May 20, 2019
dc2913b
Merge remote-tracking branch 'upstream/master' into freedomscientific…
bramd May 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 72 additions & 39 deletions source/brailleDisplayDrivers/freedomScientific.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

"""
Braille display driver for Freedom Scientific braille displays.
A c(lang) reference implementation is available in brltty.
"""

from six import BytesIO, int2byte
Expand Down Expand Up @@ -37,6 +38,10 @@
}

#: Number of cells of Focus first generation displays
# The assumption is that any displays with the following cell counts are due to three cells at the
# beginning/end of the display are used as status cells, and an extra blank cell to separate status
# from normal cells. These devices require a special translation table: L{FOCUS_1_TRANSLATION_TABLE}
# This line of displays is known as the first generation Focus displays.
FOCUS_1_CELL_COUNTS = (44, 70, 84,)

# Packet types
Expand Down Expand Up @@ -70,6 +75,8 @@
FS_BYTE_NULL = b"\x00"
#: Empty data in the packet payload
FS_DATA_EMPTY = b""
#: Send extended key events, to be used with the FS_PKT_CONFIG
FS_CFG_EXTKEY = b"\x02"

# FS_PKT_INFO payload offsets
#: Start position of manufacturer in FS_PKT_INFO payload
Expand Down Expand Up @@ -135,7 +142,7 @@ def _translate(cells, translationTable):
"""
outCells = [0] * len(cells)
for i, cell in enumerate(cells):
outCells[i] = dotsTable[cell]
outCells[i] = translationTable[cell]
return outCells

#: Dots table used by first generation Focus displays
Expand All @@ -146,8 +153,11 @@ def _translate(cells, translationTable):
#: Braille translation table used by first generation Focus displays
FOCUS_1_TRANSLATION_TABLE = _makeTranslationTable(FOCUS_1_DOTS_TABLE)


class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
"Driver for Freedom Scientific braille displays"
"""
Driver for Freedom Scientific braille displays
"""
name = "freedomScientific"
# Translators: Names of braille displays.
description = _("Freedom Scientific Focus/PAC Mate series")
Expand Down Expand Up @@ -190,11 +200,23 @@ def __init__(self, port="auto"):
# Try talking to the display.
try:
if self.isUsb:
self._dev = hwIo.Bulk(port, 1, 0, self._onReceive, writeSize=0, onReceiveSize=56)
self._dev = hwIo.Bulk(
port,
epIn=1,
epOut=0,
onReceive=self._onReceive,
writeSize=0,
onReceiveSize=56
)
else:
self._dev = hwIo.Serial(
port, baudrate=BAUD_RATE, parity=PARITY,
timeout=self.timeout, writeTimeout=self.timeout, onReceive=self._onReceive)
port,
baudrate=BAUD_RATE,
parity=PARITY,
timeout=self.timeout,
writeTimeout=self.timeout,
onReceive=self._onReceive
)
except EnvironmentError:
log.debugWarning("", exc_info=True)
continue
Expand Down Expand Up @@ -291,24 +313,28 @@ def _handlePacket(self, packetType, arg1, arg2, arg3, payload):

The following packet types are handled:

* FS_PKT_ACK: See L{_handleAck}
* FS_PKT_NAK: Logged and handled as an ACK
* FS_PKT_INFO: Manufacturer, model and firmware version are extracted and set as
properties on the object. Cell count is determined based on L{MODELS}.
* arg1: length of payload
* payload: manufacturer, model, firmware version in a fixed width field string
* FS_PKT_WHEEL: The corresponding L{WheelGesture}s are sent for the wheel events.
* arg1: movement direction (up/down) and number of clicks moved
Bits: bbbaaa
* a: number of clicks the wheel has moved
* b: the wheel (left/right) and direction (up/down)
* FS_PKT_ACK: See L{_handleAck}
* FS_PKT_NAK: Logged and handled as an ACK
* FS_PKT_INFO: Manufacturer, model and firmware version are extracted and set as
properties on the object. Cell count is determined based on L{MODELS}.
* arg1: length of payload
* payload: manufacturer, model, firmware version in a fixed width field string
* FS_PKT_WHEEL: The corresponding L{WheelGesture}s are sent for the wheel events.
* arg1: movement direction (up/down) and number of clicks moved
Bits: BBBAAA (least significant)
* A: (bits 1-3) number of clicks the wheel has moved
* B: (bits 4-6) which wheel (left/right) and what direction (up/down)
* FS_PKT_BUTTON: the corresponding L{RoutingGesture} is sent
* arg1: number of routing button
* arg2: key press/release
* arg3: if this is a button on the second row of routing buttons
* arg1: number of routing button
* arg2: key press/release
* arg3: if this is a button on the second row of routing buttons
* FS_PKT_KEY: a key or button on the display is pressed/released (including the braille keyboard)
* arg 1, 2, 3, 4: These bytes form the value indicating which keys are pressed.
Key releases can be detected by comparing to the previous state, this work is done in L{_handleKeys}.
* arg 1, 2, 3, 4:
These bytes form the value indicating which of the 8 keys are pressed on the device.
Key releases can be detected by comparing to the previous state, this work is done in L{_handleKeys}.
* FS_PKT_EXT_KEY: ??
* payload: The 4 most significant bits from a single byte are used.
More investigation is required.
"""
if packetType == FS_PKT_ACK:
self._handleAck()
Expand All @@ -326,16 +352,21 @@ def _handlePacket(self, packetType, arg1, arg2, arg3, payload):
log.debug("Device info: manufacturer: %s model: %s, version: %s",
self._manufacturer, self._model, self._firmwareVersion)
elif packetType == FS_PKT_WHEEL:
# We use 0X7 to only get the last three bits
wheelNumber = ((ord(arg1) >> 3) & 0X7)
count = ord(arg1) & 0X7
if wheelNumber < 2:
isRight = False
else:
isRight = True
isDown = wheelNumber % 2 == 1
if isRight:
isDown = not isDown
threeLeastSigBitsMask = 0x7
count = ord(arg1) & threeLeastSigBitsMask
wheelNumber = ((ord(arg1) >> 3) & threeLeastSigBitsMask)
try:
# There are only two wheels, one on the left, one on the right.
# Either wheel could have moved up or down.
isDown, isRight = [
(False, False),
(True, False),
(True, True),
(False, True)
][wheelNumber]
except IndexError:
log.debugWarning("wheelNumber unknown")
return
for _i in xrange(count):
gesture = WizWheelGesture(self._model, isDown, isRight)
try:
Expand All @@ -344,7 +375,9 @@ def _handlePacket(self, packetType, arg1, arg2, arg3, payload):
pass
elif packetType == FS_PKT_BUTTON:
key = ord(arg1)
isPress = (ord(arg2) & 0X01) != 0
# the least significant bit is set when the key is pressed
leastSigBitMask = 0x01
isPress = bool(ord(arg2) & leastSigBitMask)
isTopRow = bool(ord(arg3))
if isPress:
# Ignore keypresses
Expand Down Expand Up @@ -426,7 +459,7 @@ def _handleExtendedKeys(self, keyBits):

@staticmethod
def _calculateChecksum(data):
"Calculate the checksum for extended packets"
"""Calculate the checksum for extended packets"""
checksum = 0
for byte in data:
checksum -= ord(byte)
Expand All @@ -438,7 +471,7 @@ def display(self, cells):
cells = _translate(cells, FOCUS_1_TRANSLATION_TABLE)
if not self._awaitingAck:
cells = b"".join([int2byte(x) for x in cells])
self._sendPacket(FS_PKT_WRITE, int2byte(self.numCells), 0, 0, cells)
self._sendPacket(FS_PKT_WRITE, int2byte(self.numCells), FS_BYTE_NULL, FS_BYTE_NULL, cells)
self._pendingCells = []
else:
self._pendingCells = cells
Expand All @@ -451,7 +484,7 @@ def _configureDisplay(self):
# Focus 2 or later. Make sure extended keys support is enabled.
log.debug("Activating extended keys on freedom Scientific display. Display name: %s, firmware version: %s.",
self._model, self._firmwareVersion)
self._sendPacket(FS_PKT_CONFIG, "\x02")
self._sendPacket(FS_PKT_CONFIG, FS_CFG_EXTKEY)

def script_toggleLeftWizWheelAction(self, _gesture):
action = self.leftWizWheelActionCycle.next()
Expand Down Expand Up @@ -507,15 +540,15 @@ def script_toggleRightWizWheelAction(self, _gesture):

# pylint: disable=abstract-method
class InputGesture(braille.BrailleDisplayGesture):
"Base gesture for this braille display"
"""Base gesture for this braille display"""
source = BrailleDisplayDriver.name

def __init__(self, model):
self.model = model.replace(" ", "")
super(InputGesture, self).__init__()

class KeyGesture(InputGesture, brailleInput.BrailleInputGesture):
"Handle keys and braille input for Freedom Scientific braille displays"
"""Handle keys and braille input for Freedom Scientific braille displays"""
keyLabels = [
# Braille keys (byte 1)
"dot1", "dot2", "dot3", "dot4", "dot5", "dot6", "dot7", "dot8",
Expand Down Expand Up @@ -549,7 +582,7 @@ def __init__(self, model, keyBits, extendedKeyBits):
self.space = True

class RoutingGesture(InputGesture):
"Gesture to handle cursor routing and second row of routing keys on older models"
"""Gesture to handle cursor routing and second row of routing keys on older models"""
def __init__(self, model, routingIndex, topRow=False):
if topRow:
# pylint: disable=invalid-name
Expand All @@ -561,7 +594,7 @@ def __init__(self, model, routingIndex, topRow=False):
super(RoutingGesture, self).__init__(model)

class WizWheelGesture(InputGesture):
"Gesture to handle wiz wheels movements"
"""Gesture to handle wiz wheels movements"""
def __init__(self, model, isDown, isRight):
which = "right" if isRight else "left"
direction = "Down" if isDown else "Up"
Expand Down