| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | # Serial port management for firmware communication | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2017-09-18 21:41:00 -04:00
										 |  |  | # Copyright (C) 2016,2017  Kevin O'Connor <kevin@koconnor.net> | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | # | 
					
						
							|  |  |  | # This file may be distributed under the terms of the GNU GPLv3 license. | 
					
						
							| 
									
										
										
										
											2017-03-31 20:48:29 -04:00
										 |  |  | import logging, threading | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | import serial | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-09 19:04:30 -05:00
										 |  |  | import msgproto, chelper, util | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-08 21:24:27 -05:00
										 |  |  | class error(Exception): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | class SerialReader: | 
					
						
							| 
									
										
										
										
											2016-07-11 11:41:49 -04:00
										 |  |  |     BITS_PER_BYTE = 10. | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def __init__(self, reactor, serialport, baud): | 
					
						
							|  |  |  |         self.reactor = reactor | 
					
						
							|  |  |  |         self.serialport = serialport | 
					
						
							|  |  |  |         self.baud = baud | 
					
						
							|  |  |  |         # Serial port | 
					
						
							|  |  |  |         self.ser = None | 
					
						
							|  |  |  |         self.msgparser = msgproto.MessageParser() | 
					
						
							|  |  |  |         # C interface | 
					
						
							|  |  |  |         self.ffi_main, self.ffi_lib = chelper.get_ffi() | 
					
						
							|  |  |  |         self.serialqueue = None | 
					
						
							|  |  |  |         self.default_cmd_queue = self.alloc_command_queue() | 
					
						
							|  |  |  |         self.stats_buf = self.ffi_main.new('char[4096]') | 
					
						
							|  |  |  |         # Threading | 
					
						
							|  |  |  |         self.lock = threading.Lock() | 
					
						
							|  |  |  |         self.background_thread = None | 
					
						
							|  |  |  |         # Message handlers | 
					
						
							|  |  |  |         handlers = { | 
					
						
							| 
									
										
										
										
											2017-09-18 21:41:00 -04:00
										 |  |  |             '#unknown': self.handle_unknown, '#output': self.handle_output, | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |             'shutdown': self.handle_output, 'is_shutdown': self.handle_output | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-06-06 12:35:13 -04:00
										 |  |  |         self.handlers = { (k, None): v for k, v in handlers.items() } | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def _bg_thread(self): | 
					
						
							|  |  |  |         response = self.ffi_main.new('struct pull_queue_message *') | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             self.ffi_lib.serialqueue_pull(self.serialqueue, response) | 
					
						
							|  |  |  |             count = response.len | 
					
						
							|  |  |  |             if count <= 0: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             params = self.msgparser.parse(response.msg[0:count]) | 
					
						
							|  |  |  |             params['#sent_time'] = response.sent_time | 
					
						
							|  |  |  |             params['#receive_time'] = response.receive_time | 
					
						
							| 
									
										
										
										
											2017-09-15 13:58:05 -04:00
										 |  |  |             hdl = (params['#name'], params.get('oid')) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |             with self.lock: | 
					
						
							|  |  |  |                 hdl = self.handlers.get(hdl, self.handle_default) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 hdl(params) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 logging.exception("Exception in serial callback") | 
					
						
							|  |  |  |     def connect(self): | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |         # Initial connection | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         logging.info("Starting serial connect") | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |         while 1: | 
					
						
							| 
									
										
										
										
											2017-02-06 13:31:34 -05:00
										 |  |  |             starttime = self.reactor.monotonic() | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2017-05-08 10:29:59 -04:00
										 |  |  |                 if self.baud: | 
					
						
							|  |  |  |                     self.ser = serial.Serial( | 
					
						
							|  |  |  |                         self.serialport, self.baud, timeout=0) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     self.ser = open(self.serialport, 'rb+') | 
					
						
							| 
									
										
										
										
											2017-08-14 16:18:54 -04:00
										 |  |  |             except (OSError, IOError, serial.SerialException) as e: | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |                 logging.warn("Unable to open port: %s", e) | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |                 self.reactor.pause(starttime + 5.) | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2017-05-08 10:29:59 -04:00
										 |  |  |             if self.baud: | 
					
						
							|  |  |  |                 stk500v2_leave(self.ser, self.reactor) | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |             self.serialqueue = self.ffi_lib.serialqueue_alloc( | 
					
						
							|  |  |  |                 self.ser.fileno(), 0) | 
					
						
							|  |  |  |             self.background_thread = threading.Thread(target=self._bg_thread) | 
					
						
							|  |  |  |             self.background_thread.start() | 
					
						
							|  |  |  |             # Obtain and load the data dictionary from the firmware | 
					
						
							|  |  |  |             sbs = SerialBootStrap(self) | 
					
						
							|  |  |  |             identify_data = sbs.get_identify_data(starttime + 5.) | 
					
						
							|  |  |  |             if identify_data is None: | 
					
						
							|  |  |  |                 logging.warn("Timeout on serial connect") | 
					
						
							|  |  |  |                 self.disconnect() | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |         msgparser = msgproto.MessageParser() | 
					
						
							|  |  |  |         msgparser.process_identify(identify_data) | 
					
						
							|  |  |  |         self.msgparser = msgparser | 
					
						
							|  |  |  |         self.register_callback(self.handle_unknown, '#unknown') | 
					
						
							| 
									
										
										
										
											2017-12-21 18:18:18 -05:00
										 |  |  |         logging.info("Loaded %d commands (%s / %s)", | 
					
						
							|  |  |  |                      len(msgparser.messages_by_id), | 
					
						
							|  |  |  |                      msgparser.version, msgparser.build_versions) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |         logging.info("MCU config: %s", " ".join( | 
					
						
							|  |  |  |             ["%s=%s" % (k, v) for k, v in msgparser.config.items()])) | 
					
						
							| 
									
										
										
										
											2017-03-03 22:02:27 -05:00
										 |  |  |         # Setup baud adjust | 
					
						
							| 
									
										
										
										
											2018-01-29 10:10:27 -05:00
										 |  |  |         mcu_baud = msgparser.get_constant_float('SERIAL_BAUD', None) | 
					
						
							|  |  |  |         if mcu_baud is not None: | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |             baud_adjust = self.BITS_PER_BYTE / mcu_baud | 
					
						
							|  |  |  |             self.ffi_lib.serialqueue_set_baud_adjust( | 
					
						
							|  |  |  |                 self.serialqueue, baud_adjust) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def connect_file(self, debugoutput, dictionary, pace=False): | 
					
						
							|  |  |  |         self.ser = debugoutput | 
					
						
							|  |  |  |         self.msgparser.process_identify(dictionary, decompress=False) | 
					
						
							| 
									
										
										
										
											2016-07-11 11:41:49 -04:00
										 |  |  |         self.serialqueue = self.ffi_lib.serialqueue_alloc(self.ser.fileno(), 1) | 
					
						
							| 
									
										
										
										
											2017-09-18 21:41:00 -04:00
										 |  |  |     def set_clock_est(self, freq, last_time, last_clock): | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         self.ffi_lib.serialqueue_set_clock_est( | 
					
						
							| 
									
										
										
										
											2017-09-18 21:41:00 -04:00
										 |  |  |             self.serialqueue, freq, last_time, last_clock) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def disconnect(self): | 
					
						
							| 
									
										
										
										
											2017-03-08 22:01:52 -05:00
										 |  |  |         if self.serialqueue is not None: | 
					
						
							|  |  |  |             self.ffi_lib.serialqueue_exit(self.serialqueue) | 
					
						
							|  |  |  |             if self.background_thread is not None: | 
					
						
							|  |  |  |                 self.background_thread.join() | 
					
						
							|  |  |  |             self.ffi_lib.serialqueue_free(self.serialqueue) | 
					
						
							|  |  |  |             self.background_thread = self.serialqueue = None | 
					
						
							|  |  |  |         if self.ser is not None: | 
					
						
							|  |  |  |             self.ser.close() | 
					
						
							|  |  |  |             self.ser = None | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def stats(self, eventtime): | 
					
						
							|  |  |  |         if self.serialqueue is None: | 
					
						
							|  |  |  |             return "" | 
					
						
							| 
									
										
										
										
											2017-09-18 21:41:00 -04:00
										 |  |  |         self.ffi_lib.serialqueue_get_stats( | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |             self.serialqueue, self.stats_buf, len(self.stats_buf)) | 
					
						
							| 
									
										
										
										
											2017-09-18 21:41:00 -04:00
										 |  |  |         return self.ffi_main.string(self.stats_buf) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     # Serial response callbacks | 
					
						
							|  |  |  |     def register_callback(self, callback, name, oid=None): | 
					
						
							|  |  |  |         with self.lock: | 
					
						
							|  |  |  |             self.handlers[name, oid] = callback | 
					
						
							|  |  |  |     def unregister_callback(self, name, oid=None): | 
					
						
							|  |  |  |         with self.lock: | 
					
						
							|  |  |  |             del self.handlers[name, oid] | 
					
						
							|  |  |  |     # Command sending | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  |     def raw_send(self, cmd, minclock, reqclock, cmd_queue): | 
					
						
							|  |  |  |         self.ffi_lib.serialqueue_send( | 
					
						
							|  |  |  |             self.serialqueue, cmd_queue, cmd, len(cmd), minclock, reqclock) | 
					
						
							|  |  |  |     def send(self, msg, minclock=0, reqclock=0): | 
					
						
							|  |  |  |         cmd = self.msgparser.create_command(msg) | 
					
						
							|  |  |  |         self.raw_send(cmd, minclock, reqclock, self.default_cmd_queue) | 
					
						
							|  |  |  |     def lookup_command(self, msgformat, cq=None): | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         if cq is None: | 
					
						
							|  |  |  |             cq = self.default_cmd_queue | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  |         cmd = self.msgparser.lookup_command(msgformat) | 
					
						
							|  |  |  |         return SerialCommand(self, cq, cmd) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def alloc_command_queue(self): | 
					
						
							| 
									
										
										
										
											2016-11-30 01:58:45 -05:00
										 |  |  |         return self.ffi_main.gc(self.ffi_lib.serialqueue_alloc_commandqueue(), | 
					
						
							|  |  |  |                                 self.ffi_lib.serialqueue_free_commandqueue) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     # Dumping debug lists | 
					
						
							|  |  |  |     def dump_debug(self): | 
					
						
							| 
									
										
										
										
											2017-09-27 11:54:10 -04:00
										 |  |  |         out = [] | 
					
						
							|  |  |  |         out.append("Dumping serial stats: %s" % ( | 
					
						
							|  |  |  |             self.stats(self.reactor.monotonic()),)) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         sdata = self.ffi_main.new('struct pull_queue_message[1024]') | 
					
						
							|  |  |  |         rdata = self.ffi_main.new('struct pull_queue_message[1024]') | 
					
						
							|  |  |  |         scount = self.ffi_lib.serialqueue_extract_old( | 
					
						
							|  |  |  |             self.serialqueue, 1, sdata, len(sdata)) | 
					
						
							|  |  |  |         rcount = self.ffi_lib.serialqueue_extract_old( | 
					
						
							|  |  |  |             self.serialqueue, 0, rdata, len(rdata)) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:54:10 -04:00
										 |  |  |         out.append("Dumping send queue %d messages" % (scount,)) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         for i in range(scount): | 
					
						
							|  |  |  |             msg = sdata[i] | 
					
						
							|  |  |  |             cmds = self.msgparser.dump(msg.msg[0:msg.len]) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:54:10 -04:00
										 |  |  |             out.append("Sent %d %f %f %d: %s" % ( | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |                 i, msg.receive_time, msg.sent_time, msg.len, ', '.join(cmds))) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:54:10 -04:00
										 |  |  |         out.append("Dumping receive queue %d messages" % (rcount,)) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         for i in range(rcount): | 
					
						
							|  |  |  |             msg = rdata[i] | 
					
						
							|  |  |  |             cmds = self.msgparser.dump(msg.msg[0:msg.len]) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:54:10 -04:00
										 |  |  |             out.append("Receive: %d %f %f %d: %s" % ( | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |                 i, msg.receive_time, msg.sent_time, msg.len, ', '.join(cmds))) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:54:10 -04:00
										 |  |  |         return '\n'.join(out) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     # Default message handlers | 
					
						
							|  |  |  |     def handle_unknown(self, params): | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |         logging.warn("Unknown message type %d: %s", | 
					
						
							|  |  |  |                      params['#msgid'], repr(params['#msg'])) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def handle_output(self, params): | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |         logging.info("%s: %s", params['#name'], params['#msg']) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def handle_default(self, params): | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |         logging.warn("got %s", params) | 
					
						
							| 
									
										
										
										
											2016-11-30 01:58:45 -05:00
										 |  |  |     def __del__(self): | 
					
						
							|  |  |  |         self.disconnect() | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  | # Wrapper around command sending | 
					
						
							|  |  |  | class SerialCommand: | 
					
						
							|  |  |  |     def __init__(self, serial, cmd_queue, cmd): | 
					
						
							|  |  |  |         self.serial = serial | 
					
						
							|  |  |  |         self.cmd_queue = cmd_queue | 
					
						
							|  |  |  |         self.cmd = cmd | 
					
						
							|  |  |  |     def send(self, data=(), minclock=0, reqclock=0): | 
					
						
							|  |  |  |         cmd = self.cmd.encode(data) | 
					
						
							|  |  |  |         self.serial.raw_send(cmd, minclock, reqclock, self.cmd_queue) | 
					
						
							|  |  |  |     def send_with_response(self, data=(), response=None, response_oid=None): | 
					
						
							|  |  |  |         cmd = self.cmd.encode(data) | 
					
						
							|  |  |  |         src = SerialRetryCommand(self.serial, cmd, response, response_oid) | 
					
						
							|  |  |  |         return src.get_response() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | # Class to retry sending of a query command until a given response is received | 
					
						
							|  |  |  | class SerialRetryCommand: | 
					
						
							| 
									
										
										
										
											2017-03-08 21:24:27 -05:00
										 |  |  |     TIMEOUT_TIME = 5.0 | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     RETRY_TIME = 0.500 | 
					
						
							| 
									
										
										
										
											2017-03-05 15:00:15 -05:00
										 |  |  |     def __init__(self, serial, cmd, name, oid=None): | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         self.serial = serial | 
					
						
							|  |  |  |         self.cmd = cmd | 
					
						
							|  |  |  |         self.name = name | 
					
						
							| 
									
										
										
										
											2017-03-05 15:00:15 -05:00
										 |  |  |         self.oid = oid | 
					
						
							| 
									
										
										
										
											2016-11-28 14:52:22 -05:00
										 |  |  |         self.response = None | 
					
						
							| 
									
										
										
										
											2017-02-06 13:31:34 -05:00
										 |  |  |         self.min_query_time = self.serial.reactor.monotonic() | 
					
						
							| 
									
										
										
										
											2017-03-05 15:00:15 -05:00
										 |  |  |         self.serial.register_callback(self.handle_callback, self.name, self.oid) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         self.send_timer = self.serial.reactor.register_timer( | 
					
						
							|  |  |  |             self.send_event, self.serial.reactor.NOW) | 
					
						
							| 
									
										
										
										
											2017-03-08 21:24:27 -05:00
										 |  |  |     def unregister(self): | 
					
						
							| 
									
										
										
										
											2017-03-05 15:00:15 -05:00
										 |  |  |         self.serial.unregister_callback(self.name, self.oid) | 
					
						
							| 
									
										
										
										
											2017-03-08 21:24:27 -05:00
										 |  |  |         self.serial.reactor.unregister_timer(self.send_timer) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def send_event(self, eventtime): | 
					
						
							| 
									
										
										
										
											2016-11-28 14:52:22 -05:00
										 |  |  |         if self.response is not None: | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |             return self.serial.reactor.NEVER | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  |         self.serial.raw_send(self.cmd, 0, 0, self.serial.default_cmd_queue) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         return eventtime + self.RETRY_TIME | 
					
						
							|  |  |  |     def handle_callback(self, params): | 
					
						
							| 
									
										
										
										
											2016-11-28 14:52:22 -05:00
										 |  |  |         last_sent_time = params['#sent_time'] | 
					
						
							|  |  |  |         if last_sent_time >= self.min_query_time: | 
					
						
							|  |  |  |             self.response = params | 
					
						
							|  |  |  |     def get_response(self): | 
					
						
							| 
									
										
										
										
											2017-02-06 13:31:34 -05:00
										 |  |  |         eventtime = self.serial.reactor.monotonic() | 
					
						
							| 
									
										
										
										
											2016-11-28 14:52:22 -05:00
										 |  |  |         while self.response is None: | 
					
						
							|  |  |  |             eventtime = self.serial.reactor.pause(eventtime + 0.05) | 
					
						
							| 
									
										
										
										
											2017-03-08 21:24:27 -05:00
										 |  |  |             if eventtime > self.min_query_time + self.TIMEOUT_TIME: | 
					
						
							|  |  |  |                 self.unregister() | 
					
						
							|  |  |  |                 raise error("Timeout on wait for '%s' response" % (self.name,)) | 
					
						
							|  |  |  |         self.unregister() | 
					
						
							| 
									
										
										
										
											2016-11-28 14:52:22 -05:00
										 |  |  |         return self.response | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Code to start communication and download message type dictionary | 
					
						
							|  |  |  | class SerialBootStrap: | 
					
						
							|  |  |  |     RETRY_TIME = 0.500 | 
					
						
							|  |  |  |     def __init__(self, serial): | 
					
						
							|  |  |  |         self.serial = serial | 
					
						
							|  |  |  |         self.identify_data = "" | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  |         self.identify_cmd = self.serial.lookup_command( | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |             "identify offset=%u count=%c") | 
					
						
							|  |  |  |         self.is_done = False | 
					
						
							|  |  |  |         self.serial.register_callback(self.handle_identify, 'identify_response') | 
					
						
							|  |  |  |         self.serial.register_callback(self.handle_unknown, '#unknown') | 
					
						
							|  |  |  |         self.send_timer = self.serial.reactor.register_timer( | 
					
						
							|  |  |  |             self.send_event, self.serial.reactor.NOW) | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |     def get_identify_data(self, timeout): | 
					
						
							| 
									
										
										
										
											2017-02-06 13:31:34 -05:00
										 |  |  |         eventtime = self.serial.reactor.monotonic() | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |         while not self.is_done and eventtime <= timeout: | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |             eventtime = self.serial.reactor.pause(eventtime + 0.05) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         self.serial.unregister_callback('identify_response') | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |         self.serial.reactor.unregister_timer(self.send_timer) | 
					
						
							| 
									
										
										
										
											2016-11-29 17:44:37 -05:00
										 |  |  |         if not self.is_done: | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |         return self.identify_data | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def handle_identify(self, params): | 
					
						
							|  |  |  |         if self.is_done or params['offset'] != len(self.identify_data): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         msgdata = params['data'] | 
					
						
							|  |  |  |         if not msgdata: | 
					
						
							| 
									
										
										
										
											2016-11-27 17:45:58 -05:00
										 |  |  |             self.is_done = True | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |             return | 
					
						
							|  |  |  |         self.identify_data += msgdata | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  |         self.identify_cmd.send([len(self.identify_data), 40]) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     def send_event(self, eventtime): | 
					
						
							|  |  |  |         if self.is_done: | 
					
						
							|  |  |  |             return self.serial.reactor.NEVER | 
					
						
							| 
									
										
										
										
											2018-02-27 14:16:16 -05:00
										 |  |  |         self.identify_cmd.send([len(self.identify_data), 40]) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |         return eventtime + self.RETRY_TIME | 
					
						
							|  |  |  |     def handle_unknown(self, params): | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |         logging.debug("Unknown message %d (len %d) while identifying", | 
					
						
							|  |  |  |                       params['#msgid'], len(params['#msg'])) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Attempt to place an AVR stk500v2 style programmer into normal mode | 
					
						
							| 
									
										
										
										
											2016-11-28 13:14:56 -05:00
										 |  |  | def stk500v2_leave(ser, reactor): | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     logging.debug("Starting stk500v2 leave programmer sequence") | 
					
						
							| 
									
										
										
										
											2016-12-09 19:04:30 -05:00
										 |  |  |     util.clear_hupcl(ser.fileno()) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     origbaud = ser.baudrate | 
					
						
							|  |  |  |     # Request a dummy speed first as this seems to help reset the port | 
					
						
							| 
									
										
										
										
											2016-06-11 16:35:48 -04:00
										 |  |  |     ser.baudrate = 2400 | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     ser.read(1) | 
					
						
							|  |  |  |     # Send stk500v2 leave programmer sequence | 
					
						
							|  |  |  |     ser.baudrate = 115200 | 
					
						
							| 
									
										
										
										
											2017-02-06 13:31:34 -05:00
										 |  |  |     reactor.pause(reactor.monotonic() + 0.100) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     ser.read(4096) | 
					
						
							|  |  |  |     ser.write('\x1b\x01\x00\x01\x0e\x11\x04') | 
					
						
							| 
									
										
										
										
											2017-02-06 13:31:34 -05:00
										 |  |  |     reactor.pause(reactor.monotonic() + 0.050) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     res = ser.read(4096) | 
					
						
							| 
									
										
										
										
											2017-09-27 11:43:14 -04:00
										 |  |  |     logging.debug("Got %s from stk500v2", repr(res)) | 
					
						
							| 
									
										
										
										
											2016-05-25 11:37:40 -04:00
										 |  |  |     ser.baudrate = origbaud | 
					
						
							| 
									
										
										
										
											2017-03-08 22:26:10 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Attempt an arduino style reset on a serial port | 
					
						
							|  |  |  | def arduino_reset(serialport, reactor): | 
					
						
							| 
									
										
										
										
											2017-10-12 21:21:49 -04:00
										 |  |  |     # First try opening the port at a different baud | 
					
						
							|  |  |  |     ser = serial.Serial(serialport, 2400, timeout=0) | 
					
						
							| 
									
										
										
										
											2017-03-08 22:26:10 -05:00
										 |  |  |     ser.read(1) | 
					
						
							| 
									
										
										
										
											2017-03-31 20:48:29 -04:00
										 |  |  |     reactor.pause(reactor.monotonic() + 0.100) | 
					
						
							| 
									
										
										
										
											2017-10-12 21:21:49 -04:00
										 |  |  |     # Then toggle DTR | 
					
						
							| 
									
										
										
										
											2017-03-08 22:26:10 -05:00
										 |  |  |     ser.dtr = True | 
					
						
							| 
									
										
										
										
											2017-03-31 20:48:29 -04:00
										 |  |  |     reactor.pause(reactor.monotonic() + 0.100) | 
					
						
							| 
									
										
										
										
											2017-03-08 22:26:10 -05:00
										 |  |  |     ser.dtr = False | 
					
						
							| 
									
										
										
										
											2017-03-31 20:48:29 -04:00
										 |  |  |     reactor.pause(reactor.monotonic() + 0.100) | 
					
						
							| 
									
										
										
										
											2017-03-08 22:26:10 -05:00
										 |  |  |     ser.close() |