def __init__(self, dispatcher, devname): "Constructor. devname - serial port devname" self.dispatcher = dispatcher self.stream = SerialStream(devname) self._next_pkt_id = 0 self._devname = devname self._sendlock = Lock() self._calibrated = False Tasklet.new(self.auto_calibrate_baudrate)()
class Host(object): "Interface to the hardware" def __init__(self, dispatcher, devname): "Constructor. devname - serial port devname" self.dispatcher = dispatcher self.stream = SerialStream(devname) self._next_pkt_id = 0 self._devname = devname self._sendlock = Lock() self._calibrated = False Tasklet.new(self.auto_calibrate_baudrate)() def send_raw(self, buf): "Send raw data without any checksuming and headers" with self._sendlock: #print "%s sent: %s" % (self._devname, ", ".join(["0x%02x" % d for d in buf])) buf = ''.join([chr(a) for a in buf]) with self.stream.get_writer() as writer: writer.write_bytes(buf) writer.flush() def flush(self): self.stream.flush() def send(self, pkt): "Immediately push packet to the serial port" buf = [0x5a] _crc = 0 for data in [len(pkt)] + list(pkt): if type(data) == str and len(data) == 1: data = ord(data) _crc = crc(_crc, data) buf.append(data) buf.append(_crc) self.send_raw(buf) def ping(self): while True: if self._calibrated: pkt = [0xf2] for i in xrange(0, 8): pkt.append(random.randint(0, 255)) self.send(pkt) Tasklet.sleep(7) def loop(self): "Infinitely read serial input and parse packets" with self.stream.get_reader() as reader: while True: try: # wait for preamble while True: data = ord(reader.read_bytes(1)) if data == 0x5a: break # read packet length _crc = 0 pktlen = ord(reader.read_bytes(1)) _crc = crc(_crc, pktlen) # read packet data if pktlen > 0: data = [] try: with Timeout.push(1): for d in reader.read_bytes(pktlen): d = ord(d) data.append(d) _crc = crc(_crc, d) # read CRC _crc = crc(_crc, ord(reader.read_bytes(1))) except TimeoutError: pass else: # check CRC if _crc == 0: #print "%s recv: %s" % (self._devname, ", ".join(["0x%02x" % d for d in data])) if self._calibrated: if len(data) == 1 and (data[0] == ord('I') or data[0] == 0xf2): self._calibrated = False Tasklet.new(self.auto_calibrate_baudrate)() if self._calibrated or data[0] == 0xf0 or data[0] == ord('E'): self.dispatcher.receive(data) except Exception as e: logging.exception(e) def version(self): "Check host version (None if not available)" req = HostVersionRequest(self) try: return self.dispatcher.request(req, timeout=10) except TimeoutError: return None def calibrate_baudrate(self): "Perform baud rate calibration" req = BaudRateCalibrationRequest(self) try: res = self.dispatcher.request(req, timeout=3) if res: self._calibrated = True return res else: raise BaudRateCalibrationError() except TimeoutError: raise BaudRateCalibrationError() def auto_calibrate_baudrate(self): while True: try: print "%s calibrated: %s" % (self._devname, self.calibrate_baudrate()) except BaudRateCalibrationError: print "%s calibration failed" % self._devname else: self._calibrated = True break def next_pkt_id(self): self._next_pkt_id = (self._next_pkt_id + 1) % 256 return self._next_pkt_id