Skip to content

Instantly share code, notes, and snippets.

@ThiefMaster
Last active December 3, 2015 22:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThiefMaster/6e0ed390707f57cb0c6a to your computer and use it in GitHub Desktop.
Save ThiefMaster/6e0ed390707f57cb0c6a to your computer and use it in GitHub Desktop.
Demo script for my "rotary board" - https://github.com/ThiefMaster/rotaryboard
#!py -3
import atexit
import re
import signal
import subprocess
import sys
from serial import Serial
from win32com.client import Dispatch
class Demo(object):
# the internal order of LEDs is not extremely intuitive so we
# use a different order to make this script a bit nicer
_LED_ORDER = '012387654'
def __init__(self, port):
self._active = True
self._port = port
self._shell = Dispatch('WScript.Shell')
self._serial = None
self._mode = 0
self._submode = 0
self._modesteps = 0
self._ticks = 0
atexit.register(self._close)
self._open()
signal.signal(signal.SIGINT, lambda num, frame: self._stop())
def run(self):
_MSG_RE = re.compile(r'([A-Z]+)(?:\.([0-9]))?(?:=(-?[0-9]+))?')
ready = False
# reset the board
self._send('RST')
while self._active:
line = self._recv()
if ready:
match = _MSG_RE.match(line)
if match is not None:
cmd, n, val = match.groups()
n = int(n) if n is not None else None
val = int(val) if val is not None else None
self._process(cmd, n, val)
self._tick()
elif line == 'READY':
ready = True
self._ready()
def _ready(self):
# once the board is ready, we turn off all LEDs
for n in range(9):
self._led(n, '0')
def _tick(self):
self._ticks += 1
# mode 0: fancy blinking unless a specific LED is selected
if self._mode == 0:
if self._submode == 0:
self._led(0, '0RGY'[(self._ticks // 3) % 4])
else:
self._led(0, 0)
# mode 1: notification blinkers
elif self._mode == 1 and self._modesteps == 0:
if self._submode == 0:
self._led(7, 0)
self._led(8, self._ticks % 2 == 0)
elif self._submode == 1:
self._led(7, self._ticks % 2 == 0)
self._led(8, self._ticks % 2 == 1)
# mode 2/3: powerpoint control. indicate direction using the multicolor LED
elif self._mode in (2, 3):
if self._submode == 5:
self._led(0, 0)
else:
self._led(0, 'RG'[self._mode - 2])
self._submode += 1
def _process(self, cmd, n, val):
# button pressed
if cmd == 'RBTN' and val:
self._submode = 0
if self._mode != n:
self._modesteps = 0
else:
self._modesteps += 1
self._mode = n
self._dark()
if self._mode == 1:
if self._modesteps > 0:
self._led(self._modesteps + 3, 1)
if self._modesteps >= 3:
self._led(0, 'G')
self._interactive()
self._process('RBTN', 0, 1) # back to mode 0
elif self._mode in (2, 3):
self._sendkeys(['{LEFT}', '{RIGHT}'][n - 2])
# rotart button turned
elif cmd == 'RVAL' and n == 0:
if self._mode == 0:
self._submode += 1 if val > 0 else -1
self._submode %= 9
self._dark()
if self._submode != 0:
self._led(self._submode, '1')
elif self._mode == 1:
self._submode += 1 if val > 0 else -1
self._submode %= 2
def _dark(self):
for n in range(9):
self._led(n, '0')
def _sendkeys(self, keys):
self._shell.SendKeys(keys)
def _interactive(self):
self._close()
subprocess.call(['f:/putty/putty.exe', '-load', 'rot'])
self._open()
self._dark()
def _stop(self):
self._dark()
self._active = False
def _close(self):
if self._serial is not None:
self._serial.close()
def _open(self):
self._close()
self._serial = Serial(self._port, 19200, timeout=0.1)
def _send(self, cmd, n=None, val=None):
if n is not None and val is not None:
line = '{}.{}={}\n'.format(cmd, n, int(val) if isinstance(val, bool) else val)
elif n is not None:
line = '{}.{}\n'.format(cmd, n)
else:
line = '{}\n'.format(cmd)
self._serial.write(bytes(line, 'ascii'))
def _led(self, n, color):
self._send('RLED', self._LED_ORDER[n], color)
def _recv(self):
return self._serial.readline().decode('ascii').lstrip('\0').strip()
if __name__ == '__main__':
Demo(sys.argv[1] if len(sys.argv) > 1 else 'COM3').run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment