# -*- coding: UTF-8 -*- #brailleDisplayDrivers/seika.py #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) 2012 Ulf Beckmann # Parts of this code are inherited from the baum braille driver # written by James Teh # This file represents the braille display driver for # Seika3 V2.00, Seika80, a product from Nippon Telesoft # see www.seika-braille.com for more details # 18.08.2012 13:54 import time import wx import serial import braille import inputCore import hwPortUtils from logHandler import log TIMEOUT = 0.2 BAUDRATE = 9600 READ_INTERVAL = 50 class BrailleDisplayDriver(braille.BrailleDisplayDriver): name = "seika" # Translators: Names of braille displays. description = _("Seika braille displays") numCells = 0 @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.upper().startswith(r"USB\VID_10C4&PID_EA60"): # Seika USB to Serial, in XP it is lowercase, in Win7 uppercase 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=BAUDRATE, timeout=TIMEOUT, writeTimeout=TIMEOUT, parity=serial.PARITY_ODD, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE) except serial.SerialException: continue log.debug("serial port open {port}".format(port=port)) self._ser.write("\xFF\xFF\x1C") self._ser.flush() # Read out the input buffer versionS = self._ser.read(13) log.debug("receive {p}".format(p=versionS)) if versionS.startswith("seika80"): log.info("Found Seika80 connected via {port} Version {versionS}".format(port=port, versionS=versionS)) self.numCells = 80 break if versionS.startswith("seika3"): log.info("Found Seika40 connected via {port} Version {versionS}".format(port=port, versionS=versionS)) self.numCells = 40 self.s40 = "\xFF\xFF\x73\x65\x69\x6B\x61\x00" break # is it a old Seika3? log.debug("test if it is a old Seika3") self._ser.write("\xFF\xFF\x0A") self._ser.flush() # Read out the input buffer versionS = self._ser.read(12) log.debug("receive {p}".format(p=versionS)) if versionS.startswith("\x00\x05\x28\x08\x76\x35\x2E\x30\x01\x01\x01\x01") or versionS.startswith("\x00\x05\x28\x08\x73\x65\x69\x6b\x61\x00"): log.info("Found Seika3 old Version connected via {port} Version {versionS}".format(port=port, versionS=versionS)) self.numCells = 40 self.s40 = "\xFF\xFF\x04\x00\x63\x00\x50\x00" break self._ser.close() else: raise RuntimeError("No SEIKA40/80 display found") self._readTimer = wx.PyTimer(self.handleResponses) self._readTimer.Start(READ_INTERVAL) def terminate(self): try: super(BrailleDisplayDriver, self).terminate() self._readTimer.Stop() self._readTimer = None finally: self._ser.close() def display(self, cells): # every transmitted line consists of the preamble SEIKA_SENDHEADER and the Cells if self.numCells==80: line = "\xff\xff\x73\x38\x30\x00\x00\x00"+"".join(chr(cell) for cell in cells) else: line = self.s40+"".join("\0"+chr(cell) for cell in cells) self._ser.write(line) def handleResponses(self): if not self._ser.inWaiting(): return chars = [0,0] key = 0 keys= set() max = self.numCells / 4 # for 80 max is 20, for 40 cell max is 10 chars[0] = ord(self._ser.read()) chars[1] = ord(self._ser.read()) keytyp=1 if not chars[0] & 0x60: # a cursorrouting block is expected char = self._ser.read(max) chars = [ord(c) for c in char] keytyp=2 # log.info("Seika K {c}".format(c=chars)) if keytyp == 1: # normal key if chars[0] & 1: # LEFT keys.add("left") if chars[0] & 4: # RIGHT keys.add("right") if chars[1] & 2: # B1 keys.add("b1") if chars[1] & 8: keys.add("b2") if chars[1] & 16: keys.add("b3") if chars[0] & 16: keys.add("b4") if chars[0] & 8: keys.add("b5") if chars[0] & 2: keys.add("b6") data= "+".join(keys) try: inputCore.manager.executeGesture(InputGestureKeys(data)) except inputCore.NoInputGestureAction: log.debug("No Action for keys {keys}".format(keys=data)) pass else: i = 0 k = max / 2 while i < k: j = 0 while j < 8: if chars[5+i] & (1<