def __init__(self, port): self.arduino = ArduinoBoard(port, timeout=5.0, enable_dtr=False) self.commands = [["kAcknowledge", "i"], ["kError", "i*"], ["kUnknown", ""], ["kPing", "?"], ["kPingResult", "i"], ["kPong", ""], ["kPauseCalculations", "?"], ["kResumeCalculations", "?"], ["kUploadRedPattern", "?b*"], ["kUploadGreenPattern", "?b*"], ["kUploadBluePattern", "?b*"], ["kSavePattern", "?b"], ["kLoadPattern", "?b"], ["kGetBrightness", "?"], ["kGetBrightnessResult", "b"], ["kSetBrightness", "?b"], ["kSetPixel", "?bbbb"], ["kFillSolid", "?bbb"], ["kClearEeprom", "?"], ["kIsEepromReady", "?"], ["kIsEepromReadyResult", "?"], ["kResetEeprom", "?"], ["kReturnEeprom", "?"], ["kReturnEepromResult", "b*"], ["kJumpToDfu", "?"]] self.messenger = CmdMessenger(self.arduino, self.commands)
class NgalacArduinoController(): ''' NGALAC uses an arduino to control button presses and turn on various lights. Use pseudo terminal to test, ie: https://stackoverflow.com/questions/52187/virtual-serial-port-for-linux miniterm.py to spy ''' def __init__(self, serial_port="/dev/pts/2", baud_rate=9600): self.arduino = ArduinoBoard(serial_port, baud_rate) self.commands = dict(COMMANDS) self.c = CmdMessenger(self.arduino, COMMANDS) self.cmd_seq_num = 0 def _send_cmd(self, cmd, *args): if cmd in self.commands: self.c.send(cmd, *args) else: pass # heh, logging pls thx self.cmd_seq_num += 1 def _recv_cmd(self, cmd): try: msg = self.c.receive() except EOFError: # bad command format pass if msg: return _parse_msg(msg) else: pass def _parse_msg(self, msg): # self.last_cmd, value, self.exec_time = msg value = msg return value def ping(self): return self._send_cmd('ping') def is_player(self): return self._send_cmd('player') def lights(self, on=True): return self._send_cmd('lights', True) def get_state(self): return self._send_cmd('get_state') def release_latches(self): return self._send_cmd('release_latches') def open(self): self.arduino.open() def close(self): self.arduino.close()
class ArduinoController(): ''' NGALAC uses an arduino to control button presses and turn on various lights. Use pseudo terminal to test, ie: https://stackoverflow.com/questions/52187/virtual-serial-port-for-linux miniterm.py to spy soscat -d -d pty,raw,echo=0 pty,raw,echo=0 opens a tty connection with 2 ends. Device on 1, io on other ''' __firmware_version__ = (0, 1, 6) def __init__(self, serial_port="/dev/pts/2", baud_rate=9600): self.arduino = ArduinoBoard(serial_port, baud_rate) self.commands = dict(COMMANDS) self.c = CmdMessenger(self.arduino, COMMANDS) self.cmd_seq_num = 0 def _send_cmd(self, cmd, *args): if cmd in self.commands: self.c.send(cmd, *args) else: pass # heh, logging pls thx self.cmd_seq_num += 1 def _parse_msg(self, msg): cmd, value, self.exec_time = msg return (cmd, value) def _recv_cmd(self): msg = None try: msg = self.c.receive() except EOFError: # bad command format pass if msg: return self._parse_msg(msg) else: pass def get_firmware(self): self._send_cmd('req_firmware') cmd, board_firmware = self._recv_cmd() if cmd == 'send_firmware': return board_firmware else: # bad command handling pass return board_firmware def check_firmware(self): board_firmware = self.get_firmware() return all(self.__firmware_version__[i] == board_firmware[i] for i in range(0, 3)) def flush(self): while self._recv_cmd() is not None: pass def read(self): return self._recv_cmd() def ping(self): return self._send_cmd('ping') def is_player(self): return self._send_cmd('player') def on_air(self): return self._send_cmd("on_air") def off_air(self): return self._send_cmd("off_air") def lights(self, on=1): return self._send_cmd('lights', on) def get_state(self): return self._send_cmd('get_state') def release_latches(self): return self._send_cmd('release_latches') def open(self): self.arduino.open() def close(self): self.arduino.close()
def __init__(self, serial_port="/dev/pts/2", baud_rate=9600): self.arduino = ArduinoBoard(serial_port, baud_rate) self.commands = dict(COMMANDS) self.c = CmdMessenger(self.arduino, COMMANDS) self.cmd_seq_num = 0
class LedStripMessenger(object): def __init__(self, port): self.arduino = ArduinoBoard(port, timeout=5.0, enable_dtr=False) self.commands = [["kAcknowledge", "i"], ["kError", "i*"], ["kUnknown", ""], ["kPing", "?"], ["kPingResult", "i"], ["kPong", ""], ["kPauseCalculations", "?"], ["kResumeCalculations", "?"], ["kUploadRedPattern", "?b*"], ["kUploadGreenPattern", "?b*"], ["kUploadBluePattern", "?b*"], ["kSavePattern", "?b"], ["kLoadPattern", "?b"], ["kGetBrightness", "?"], ["kGetBrightnessResult", "b"], ["kSetBrightness", "?b"], ["kSetPixel", "?bbbb"], ["kFillSolid", "?bbb"], ["kClearEeprom", "?"], ["kIsEepromReady", "?"], ["kIsEepromReadyResult", "?"], ["kResetEeprom", "?"], ["kReturnEeprom", "?"], ["kReturnEepromResult", "b*"], ["kJumpToDfu", "?"]] self.messenger = CmdMessenger(self.arduino, self.commands) def __enter__(self): return self def __exit__(self, type, value, traceback): self.close() def send(self, request_ack, has_response, command, *args, arg_formats=None): logger.info("Sending {0:s}".format(command)) with DelayedKeyboardInterrupt(): self.messenger.send(command, *(request_ack, *args), arg_formats=arg_formats) if request_ack: acknowledgement = self.messenger.receive() if has_response: response = self.messenger.receive() if request_ack: try: assert (acknowledgement[0] == "kAcknowledge" and self.commands[acknowledgement[1][0]][0] == command) logger.info("Received kAcknowledge for {}".format(command)) except (AssertionError, TypeError): logger.error("Acknowledgement error") logger.error("Actual response was {}.".format(repr(acknowledgement))) if acknowledgement is not None: logger.error("Acknowledged Command was {}.".format(self.commands[acknowledgement[1][0]][0])) logger.error("Command was {}.".format(command)) if has_response: try: assert (response[0][:-6] == command and response[0][-6:] == "Result") except (AssertionError, TypeError): logger.error("Response error") logger.error("Actual response command was {}".format(repr(response))) logger.error("Command was {0:s}.".format(command)) if has_response and response is not None: return response[1] def close(self): self.arduino.close() def ping(self, attempts = 5): for i in range(attempts): response = self.send(False, True, "kPing") if response is not None and self.commands[response[0]][0] == "kPong": logger.info("Received kPong") break else: logger.error("Ping response was not pong") logger.error("Actual response command was {}".format(repr(response))) if i < attempts: logger.error("Trying again... {} tries remaining".format(attempts - i - 1)) def uploadPattern(self, r_pattern, g_pattern, b_pattern): PythonOpcode = Enum("PythonOpcode", ''' UNARY_POSITIVE UNARY_NEGATIVE UNARY_NOT UNARY_INVERT BINARY_POWER BINARY_MULTIPLY BINARY_MODULO BINARY_ADD BINARY_SUBTRACT BINARY_SUBSCR BINARY_FLOOR_DIVIDE BINARY_TRUE_DIVIDE BINARY_LSHIFT BINARY_RSHIFT BINARY_AND BINARY_XOR BINARY_OR RETURN_VALUE LOAD_CONST LOAD_NAME CALL_FUNCTION ''') def compilePattern(pattern): bytecode = compile(pattern, "<string>", "eval") rv = [] for i in dis.Bytecode(bytecode): argval = i.argval if type(argval) is str: if argval == "time": argval = 0 elif argval == "index": argval = 1 elif argval == "sin": argval = 2 elif argval == "cos": argval = 3 elif argval is None: argval = 0 else: argval = int(argval) rv.append(PythonOpcode[i.opname].value - 1) rv.append(argval) if len(rv) > 16: logger.error("Instruction set is greater than allowed, 16.") logger.error("Actual length is {}.".format(len(rv))) rv = [] return rv self.pauseCalculations() self.send(True, False, "kUploadRedPattern", *compilePattern(r_pattern)) self.send(True, False, "kUploadGreenPattern", *compilePattern(g_pattern)) self.send(True, False, "kUploadBluePattern", *compilePattern(b_pattern)) self.resumeCalculations() logger.info("Pattern uploaded") def savePattern(self, index): self.send(True, False, "kSavePattern", index) def loadPattern(self, index): self.send(True, False, "kLoadPattern", index) def pauseCalculations(self): self.send(True, False, "kPauseCalculations") def resumeCalculations(self): self.send(True, False, "kResumeCalculations") def getBrightness(self): return self.send(True, True, "kGetBrightness")[0] def setBrightness(self, brightness): self.send(True, False, "kSetBrightness", brightness) def setPixel(self, index, r, g, b): self.send(False, False, "kSetPixel", index, r, g, b) def fillSolid(self, r, g, b): self.send(False, False, "kFillSolid", r, g, b) def setDeltaHue(self, deltaHue): self.send(True, False, "kSetDeltaHue", deltaHue) def clearEeprom(self): self.send(True, False, "kClearEeprom") def isEepromReady(self): ready = self.send(True, True, "kIsEepromReady")[0] if ready: logger.info("Eeprom is ready") else: logger.error("Eeprom is not ready") return ready def resetEeprom(self): self.send(True, False, "kResetEeprom") def returnEeprom(self): eeprom = self.send(True, True, "kReturnEeprom") for i, byte in enumerate(eeprom): s = "" if i < 2 * 16 * 3 * 8: if i % (2 * 16) == 0: s += "Pattern[{}]".format(int(i / (2 * 16 * 3))) if i / (2 * 16) % 3 == 0: s += '["r"]' elif i / (2 * 16) % 3 == 1: s += '["g"]' elif i / (2 * 16) % 3 == 2: s += '["b"]' elif i == 768: s += "ready" elif i == 769: s += "currentPattern" elif i == 770: s += "currentBrightness" logger.info("{0:4d}: {1:3d}{2:s}".format(i, byte, " //" + s if s != "" else "")) return eeprom def jumpToDfu(self): self.send(False, False, "kJumpToDfu")