def xmodem_transive(blks: [bytes], ser: serial.Serial): ser.apply_settings({'timeout': 2.7}) tp1 = datetime.datetime.now() i = 0 rpt = 0 unit = b'' while True: # Each block of the transfer looks like: # <SOH><blk #><255-blk #><--128 data bytes--><cksum> xmd_idx = (i + 1) & 0xff blk = blks[i] unit = SOH + struct.pack( 'BB', xmd_idx, 255 - xmd_idx) + blk + calc_xmodem_crc_byte(blk) #incoming = ser.read_all() incoming = ser.read(1) # (reading) timeout expired, ACK/NAK get garbaged? # or NAK received, resent in both situation. if incoming == b'' or NAK in incoming: rpt += 1 print("{:03d}/{:03d} blocks repeating {}\r".format( i, len(blocks), '.' * rpt), end='') time.sleep(0.1 + (rpt / 70) * random.random()) # procced. elif ACK in incoming: i += 1 rpt = 0 print("{:03d}/{:03d} blocks transmited".format(i, len(blocks))) time.sleep(0.03) # quit loop if retry too much or finished. if 10 < rpt or i == len(blks): break ser.reset_input_buffer() ser.write(unit) # Note: no SENDRE EOT here, as RECIEVER will timeout. time.sleep(3) response = ser.read_all() tp2 = datetime.datetime.now() # TODO: failed when i != len(blocks)? # TODO: check XIC in response against calculated one, whether they two match. print("{:03d}/{:03d} blocks transmited in {} seconds".format( i, len(blocks), (tp2 - tp1).seconds)) print("response:<{}>".format(response))
def open_port(self,port_name,rd_callback=None,serial_setting=None): stop_try_count = 0 while self.get_args(port_name) is not None and stop_try_count < 2: self.stop_port(port_name) time.sleep(1) stop_try_count += 1 print ('start open',port_name,stop_try_count) ser = Serial(port_name,timeout=60) ser_info = ser.get_settings() print ('default ser_info',ser_info) #{'parity': 'N', 'baudrate': 9600, 'bytesize': 8, 'xonxoff': False, 'rtscts': False, 'timeout': 10, #'inter_byte_timeout': None, 'stopbits': 1, 'dsrdtr': False, 'write_timeout': None} if serial_setting is not None: try: print ('serial_setting',serial_setting) if 'showtime' in serial_setting and isinstance(serial_setting['showtime'],int): self._show_timestamp = True if serial_setting['showtime'] > 0 else False if 'localecho' in serial_setting and isinstance(serial_setting['localecho'],int): self._local_echo = True if serial_setting['localecho'] > 0 else False if 'baudrate' in serial_setting and serial_setting['baudrate'].isdigit(): ser_info['baudrate'] = int(serial_setting['baudrate']) if 'databit' in serial_setting and serial_setting['databit'].isdigit(): ser_info['bytesize'] = int(serial_setting['databit']) if 'stopbit' in serial_setting and serial_setting['stopbit'].count('.') <= 1: split_list = serial_setting['stopbit'].split('.') num_list = [n for n in split_list if n.isdigit()] if len(split_list) == len(num_list): ser_info['stopbits'] = float(serial_setting['stopbit']) if 'checkbit' in serial_setting and len(serial_setting['checkbit']) > 0: ser_info['parity'] = serial_setting['checkbit'][0] #if 'flowctrl' in serial_setting: # ser_info['rtscts'] = serial_setting['flowctrl'] print ('to apply setting',ser_info) ser.apply_settings(ser_info) except Exception as e: print ("set apply_settings err:%s"%e) pass #ser_info = ser.get_settings() print ('port %s setting ok',port_name) read_thread = Thread(target=self.port_thread_read,args=(port_name,)) read_thread.setDaemon(True) self.set_args(port_name, {'handle':ser,'start':False,'name':port_name,'type':'serial','exception':0,'read_callback':rd_callback,'thread':read_thread,'quit':False}) return (port_name,ser_info)