Skip to content

Commit

Permalink
Add hedo MobilLine USB braille display driver.
Browse files Browse the repository at this point in the history
Fixes #1897.
  • Loading branch information
Sebastian Kruber authored and jcsteh committed Dec 1, 2011
1 parent 5b82e25 commit a55e3bf
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 2 deletions.
2 changes: 1 addition & 1 deletion contributors.txt
Expand Up @@ -95,4 +95,4 @@ rumiana kamenska <rkamenska@gmail.com> - bulgarian localization
Gezim Rexha <gezimr@hotmail.com> with support from Člověk v tísni, o.p.s<http://clovekvtisni.cz> - albanian localization
Alberto Benassati <benassati@cavazza.it> - MDV Lilli braille display driver
Ondrej Rosík <ondrej.rosik@gmail.com> - slovak localization
Sebastian Kruber <sebastian.kruber@hedo.de> - hedo ProfiLine USB braille display driver
Sebastian Kruber <sebastian.kruber@hedo.de> - hedo braille display drivers
203 changes: 203 additions & 0 deletions source/brailleDisplayDrivers/hedoMobilLine.py
@@ -0,0 +1,203 @@
#A part of NonVisual Desktop Access (NVDA)
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
#Copyright (C) 2011 Sebastian Kruber <sebastian.kruber@hedo.de>

# Parts of this code are inherited from the baum braille driver
# written by James Teh <jamie@jantrid.net>

# This file represents the braille display driver for
# hedo MobilLine USB, a product from hedo Reha-Technik GmbH
# see www.hedo.de for more details

import time
import wx
import serial
import braille
import inputCore
import hwPortUtils
from logHandler import log

HEDO_MOBIL_USBID = "VID_0403&PID_DE58"
HEDO_MOBIL_TIMEOUT = 0.2
HEDO_MOBIL_BAUDRATE = 9600
HEDO_MOBIL_READ_INTERVAL = 50
HEDO_MOBIL_ACK = 0x30
HEDO_MOBIL_INIT = 0x01
HEDO_MOBIL_CR_BEGIN = 0x40
HEDO_MOBIL_CR_END = 0x67
HEDO_MOBIL_CELL_COUNT = 40
HEDO_MOBIL_STATUS_CELL_COUNT = 2

class BrailleDisplayDriver(braille.BrailleDisplayDriver):
name = "hedoMobilLine"
description = "hedo MobilLine USB"

numCells = HEDO_MOBIL_CELL_COUNT

@classmethod
def check(cls):
return True

def __init__(self):
super(BrailleDisplayDriver, self).__init__()

for portInfo in hwPortUtils.listComPorts(onlyAvailable=True):
port = portInfo["port"]
hwID = portInfo["hardwareID"]
# log.info("Found port {port} with hardwareID {hwID}".format(port=port, hwID=hwID))
if not hwID.startswith(r"FTDIBUS\COMPORT"):
continue
if HEDO_MOBIL_USBID not in hwID:
continue
# At this point, a port bound to this display has been found.
# Try talking to the display.
try:
self._ser = serial.Serial(port, baudrate=HEDO_MOBIL_BAUDRATE, timeout=HEDO_MOBIL_TIMEOUT, writeTimeout=HEDO_MOBIL_TIMEOUT, parity=serial.PARITY_ODD, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE)
except serial.SerialException:
continue

# Prepare a blank line
cells = chr(HEDO_MOBIL_INIT) + chr(0) * (HEDO_MOBIL_CELL_COUNT + HEDO_MOBIL_STATUS_CELL_COUNT)

# Send the blank line twice
self._ser.write(cells)
self._ser.flush()
self._ser.write(cells)
self._ser.flush()

# Read out the input buffer
ackS = self._ser.read(2)
if chr(HEDO_MOBIL_ACK) in ackS:
log.info("Found hedo MobilLine connected via {port}".format(port=port))
break

else:
raise RuntimeError("No display found")

self._readTimer = wx.PyTimer(self.handleResponses)
self._readTimer.Start(HEDO_MOBIL_READ_INTERVAL)

self._keysDown = set()
self._released_keys = set()

def terminate(self):
try:
super(BrailleDisplayDriver, self).terminate()
self._readTimer.Stop()
self._readTimer = None
finally:
# We absolutely must close the Serial object, as it does not have a destructor.
# If we don't, we won't be able to re-open it later.
self._ser.close()

def display(self, cells):
# every transmitted line consists of the preamble HEDO_MOBIL_INIT, the statusCells and the Cells
line = chr(HEDO_MOBIL_INIT) + chr(0) * HEDO_MOBIL_STATUS_CELL_COUNT + "".join(chr(cell) for cell in cells)
# cells are already padded up numCells
# thus the expected length of the line is 1 + HEDO_MOBIL_STATUS_CELL_COUNT + HEDO_MOBIL_CELL_COUNT
# ... just how it should be
self._ser.write(line)

def handleResponses(self, wait=False):
while wait or self._ser.inWaiting():
data = self._ser.read(1)
if data:
# do not handle acknowledge bytes
if data != chr(HEDO_MOBIL_ACK):
self.handleData(ord(data))
wait = False

def handleData(self, data):
if data >= HEDO_MOBIL_CR_BEGIN and data <= HEDO_MOBIL_CR_END:
# Routing key is pressed
try:
inputCore.manager.executeGesture(InputGestureRouting(data - HEDO_MOBIL_CR_BEGIN))
except inputCore.NoInputGestureAction:
log.debug("No Action for routing index " + index)
pass
return

# On every keypress or keyrelease information about all keys is sent
# There are three groups of keys thus three bytes will be sent on
# each keypress or release
# The 4 MSB of each byte mark the group
# Bytes of the form 0x0? include information for B1 to B3
# Bytes of the form 0x1? include information for B4 to B6
# Bytes of the form 0x2? include information for K1 to K3
# The 4 LSB mark the pressed buttons in the group
# Are all buttons of one group released, the 4 LSB are zero
if data & 0xF0 == 0x00:
# B1..B3
if data & 0x01:
self._keysDown.add("B1")
if data & 0x02:
self._keysDown.add("B2")
if data & 0x04:
self._keysDown.add("B3")
if data == 0x00:
self._released_keys.add("B1")

elif data & 0xF0 == 0x10:
# B4..B6
if data & 0x01:
self._keysDown.add("B4")
if data & 0x02:
self._keysDown.add("B5")
if data & 0x04:
self._keysDown.add("B6")
if data == 0x10:
self._released_keys.add("B4")

elif data & 0xF0 == 0x20:
# K1..K3
if data & 0x01:
self._keysDown.add("K1")
if data & 0x02:
self._keysDown.add("K2")
if data & 0x04:
self._keysDown.add("K3")
if data == 0x20:
self._released_keys.add("K1")

if "B1" in self._released_keys and "B4" in self._released_keys and "K1" in self._released_keys:
# all keys are released
keys = "+".join(self._keysDown)
self._keysDown = set()
self._released_keys = set()
try:
inputCore.manager.executeGesture(InputGestureKeys(keys))
except inputCore.NoInputGestureAction:
log.debug("No Action for keys " + keys)
pass

gestureMap = inputCore.GlobalGestureMap({
"globalCommands.GlobalCommands": {
"braille_scrollBack": ("br(hedoMobilLine):K1",),
"braille_toggleTether": ("br(hedoMobilLine):K2",),
"braille_scrollForward": ("br(hedoMobilLine):K3",),
"braille_previousLine": ("br(hedoMobilLine):B2",),
"braille_nextLine": ("br(hedoMobilLine):B5",),
"sayAll": ("br(hedoMobilLine):B6",),
"braille_routeTo": ("br(hedoMobilLine):routing",),
},
})

class InputGestureKeys(braille.BrailleDisplayGesture):

source = BrailleDisplayDriver.name

def __init__(self, keys):
super(InputGestureKeys, self).__init__()

self.id = keys

class InputGestureRouting(braille.BrailleDisplayGesture):

source = BrailleDisplayDriver.name

def __init__(self, index):
super(InputGestureRouting, self).__init__()

self.id = "routing"
self.routingIndex = index
2 changes: 1 addition & 1 deletion user_docs/en/changes.t2t
Expand Up @@ -12,7 +12,7 @@
- Bold, italic and underline are now indicated in braille using signs appropriate to the configured translation table. (#538)
- Braille now indicates selected text using dots 7 and 8. (#889)
- Braille now reports information about controls within documents such as links, buttons and headings. (#202)
- Support for the hedo ProfiLine USB braille display. (#1863)
- Support for the hedo ProfiLine and MobilLine USB braille displays. (#1863, #1897)
- NVDA now avoids splitting words in braille when possible. (#1890)
- It is now possible to have braille displayed by paragraphs instead of lines, which may allow for more fluent reading of large amounts of text. This is configurable using the Read by paragraphs option in the Braille Settings dialog. (#1891)
- In browse mode, you can activate the object under the cursor using a braille display. This is done by pressing the cursor routing key where the cursor is located (which means pressing it twice if the cursor is not already there). (#1893)
Expand Down
16 changes: 16 additions & 0 deletions user_docs/en/userGuide.t2t
Expand Up @@ -1105,6 +1105,22 @@ Please see the display's documentation for descriptions of where these keys can
| Say all | B6 |
%kc:endInclude

++ hedo MobilLine USB ++
The hedo MobilLine USB from [hedo Reha-Technik http://www.hedo.de/] is supported.
You must first install the USB drivers provided by the manufacturer.

Following are the key assignments for this display with NVDA.
Please see the display's documentation for descriptions of where these keys can be found.
%kc:beginInclude
|| Name | Key |
| Scroll braille display back | K1 |
| Scroll braille display forward | K3 |
| Move braille display to previous line | B2 |
| Move braille display to next line | B5 |
| Route to braille cell | routing |
| Toggle braille tethered to | K2 |
| Say all | B6 |
%kc:endInclude

++ BRLTTY ++
[BRLTTY http://mielke.cc/brltty/] is a separate program which can be used to support many more braille displays.
Expand Down

0 comments on commit a55e3bf

Please sign in to comment.