def _get_cfg(self): """Reads complete configuration data Reads the currently used hardware configuration, the head configuration, and the deployment configuration from the instrument. """ start = utime.time() while True: if self._timeout(start): break if self._break(): utils.verbose("=> GA", constants.VERBOSE) self.uart.write("GA") rx = self._get_reply() if self._ack(rx) and self.verify_checksum( rx[0:48]) and self.verify_checksum( rx[48:272]) and self.verify_checksum(rx[272:784]): try: with open("config/adcp.cfg", "wb") as cfg: cfg.write(rx) utils.log_file( "{} => retreived instrument config".format( self.__qualname__)) # DEBUG return True except: break utils.log_file("{} => unable to retreive instrument config".format( self.__qualname__)) # DEBUG return False
def _set_usr_cfg(self): """Uploads a deployment config to the instrument and sets up the device Activation_Rate and Warmup_Duration parameters according to the current deployment constants.""" start = utime.time() while True: if self._timeout(start): break if self._break(): try: with open(self.config["Adcp"]["Deployment_Config"], "rb") as pdc: cfg = pdc.read() rate = int.from_bytes(cfg[38:40], "little") self.config["Activation_Rate"] = rate self.config[ "Warmup_Duration"] = rate - self.config["Samples"] usr_cfg = cfg[0:48] + self._set_start() + cfg[54:510] checksum = self._calc_checksum(usr_cfg) tx = usr_cfg + ubinascii.unhexlify( hex(checksum)[-2:] + hex(checksum)[2:4]) self.uart.write(b"\x43\x43") self.uart.write(tx) utils.verbose("=> CC", constants.VERBOSE) rx = self._get_reply() if self._ack(rx): utils.log_file( "{} => uploaded deployment config".format( self.__qualname__)) # DEBUG return True except: break utils.log_file("{} => unable to upload deployment config".format( self.__qualname__)) # DEBUG return False
async def v_cksum(data, crc_mode): async def calc_cksum(data, cksum=0): return (sum(map(ord, data)) + cksum) % 256 # Calculates the 16 bit Cyclic Redundancy Check for a given block of data. async def calc_crc(data, crc=0): for c in bytearray(data): crctbl_idx = ((crc >> 8) ^ c) & 0xff crc = ((crc << 8) ^ CRC_TAB[crctbl_idx]) & 0xffff await asyncio.sleep(0) return crc & 0xffff if crc_mode: cksum = bytearray(data[-2:]) recv = (cksum[0] << 8) + cksum[1] data = data[:-2] calc = await calc_crc(data) valid = bool(recv == calc) if not valid: verbose('CRC FAIL EXPECTED({:04x}) GOT({:4x})'.format( recv, calc)) else: cksum = bytearray([data[-1]]) recv = cksum[0] data = data[:-1] calc = await calc_cksum(data) valid = recv == calc if not valid: verbose('CHECKSUM FAIL EXPECTED({:02x}) GOT({:2x})'.format( recv, calc)) return valid, data
def _set_clock(self): """Sets up the instrument RTC. mm ss DD hh YY MM (3 words of 2 bytes each) """ start = utime.time() while True: if self._timeout(start): utils.log_file("{} => unable to sync clock".format( self.__qualname__)) # DEBUG return False if self._break(): now = utime.localtime() tx = "{:02d}{:02d}{:02d}{:02d}{:02d}{:02d}".format( now[4], now[5], now[2], now[3], int(str(now[0])[2:]), now[1]) self.uart.write("SC") self.uart.write(ubinascii.unhexlify(tx)) utils.verbose("=> SC" + str(tx), constants.VERBOSE) if self._ack(self._get_reply()): utils.log_file( "{} => clock synced (dev: {} board: {})".format( self.__qualname__, self._get_clock(), utils.time_string(utime.mktime(now)))) # DEBUG return True
def _get_mode(self): """Gets current instrument mode.""" utils.verbose("=> II", constants.VERBOSE) self.uart.write("II") rx = self._get_reply() if self._ack(rx): return self.modes[rx[:-2]] return
async def reply(self, timeout=10): self.data = b'' try: self.data = await asyncio.wait_for(self.sreader.read(1024), timeout) verbose(self.data) except asyncio.TimeoutError: log(self.__qualname__, 'no answer') return False return True
def w_data(file, data, msg): tmp = file.replace(file.split('/')[-1], TPFX + file.split('/')[-1]) try: with open(tmp, 'ab') as s: self.nulls = data.count(PAD) s.write(data.replace(PAD, NULL)) msg.set(True) except: verbose('ERROR OPENING {}'.format(tmp)) msg.set(False)
async def cmd(self, cmd): await self.swriter.awrite(cmd) while await self.reply(): verbose(self.data) if (self.data.startswith(b'OK') or self.data.startswith(b'ERROR') or self.data.startswith(b'NO CARRIER') or self.data.startswith(b'NO ANSWER') or self.data.startswith(b'CONNECT') ): return True await asyncio.sleep_ms(10) return False
def verify_checksum(self, reply): """Verifies data checksum. Params: reply(bytes) Returns: True or False """ checksum = int.from_bytes(reply[-2:], "little") calc_checksum = self._calc_checksum(reply) if checksum == calc_checksum: return True utils.verbose("checksum {} calc_checksum {}".format( checksum, calc_checksum), constants.VERBOSE) # DEBUG return False
def _format_recorder(self): """Erase all recorded data if it reached the maximum allowed files number (31)""" start = utime.time() while True: if self._timeout(start): utils.log_file("{} => unable to format recorder".format( self.__qualname__)) # DEBUG return False if self._break(): utils.verbose("=> FO", constants.VERBOSE) self.uart.write(b"\x46\x4F\x12\xD4\x1E\xEF") if self._ack(self._get_reply()): utils.log_file("{} => recorder formatted".format( self.__qualname__)) # DEBUG return True
def _ack(self, rx): """Parses acknowledge bytes sequence. Params: reply(bytes) Returns: True or False """ if rx: if rx[-2:] == b"\x06\x06": utils.verbose("<= ACK", constants.VERBOSE) return True elif rx[-2:] == b"\x15\x15": utils.verbose("<= NAK", constants.VERBOSE) return False return
def _confirm(self): """Enters command mode Preceded by a break command, this command is sent to force the instrument to exit Measurement mode and enter Command mode. Returns: true or False """ utils.verbose("=> MC", constants.VERBOSE) self.uart.write("MC") rx = self._get_reply() if self._ack(rx): return True return False
def _break(self): """Sends break to instrument.""" utils.verbose("=> @@@@@@K1W%!Q", constants.VERBOSE) self.uart.write("@@@@@@") utime.sleep_ms(100) self.uart.write("K1W%!Q") start = utime.time() while True: if self._timeout(start): return False rx = self._get_reply() if self._ack(rx): if b"\x0a\x0d\x43\x6f\x6e\x66\x69\x72\x6d\x3a" in rx: self._confirm() else: utils.verbose(rx, constants.VERBOSE) return True
async def preamble(self, retry=10, timeout=10): #await asyncio.sleep(2) # Safely waits for remote getting ready. ec = 0 # Error counter. while ec < retry: if await self.aputc(cfg.HOSTNAME.lower()): verbose(cfg.HOSTNAME.lower() +' -->') try: res = await asyncio.wait_for(self.sreader.readexactly(1), timeout) if res == b'\x06': # ACK verbose('<-- ACK') return True else: ec += 1 except asyncio.TimeoutError: ec += 1 await asyncio.sleep(1) return False
def _acquire_data(self): """Starts a single measurement based on the current configuration of the instrument without storing data to the recorder. Instrument enters Power Down Mode when measurement has been made. """ utils.log_file("{} => acquiring 1 sample...".format( self.__qualname__)) # DEBUG start = utime.time() while True: if self._timeout(start): return False if self._break(): utils.verbose("=> AD", constants.VERBOSE) self.uart.write("AD") if self._ack(self._get_reply()): rx = self._get_reply() if self.verify_checksum(rx): return rx
def _get_head_cfg(self): """Retreives the current head config from the instrument.""" start = utime.time() while True: if self._timeout(start): utils.log_file("{} => unable to retreive head config".format( self.__qualname__)) # DEBUG return False if self._break(): utils.verbose("=> GH", constants.VERBOSE) self.uart.write("GH") rx = self._get_reply() if self._ack(rx): if self.verify_checksum(rx[:-2]): self.head_cfg = self._parse_head_cfg(rx) utils.log_file("{} => retreived head config".format( self.__qualname__)) # DEBUG return True
def _get_clock(self): """Reads the instrument RTC.""" start = utime.time() while True: if self._timeout(start): return False if self._break(): utils.verbose("=> RC", constants.VERBOSE) self.uart.write("RC") rx = self._get_reply() if self._ack(rx): rx = ubinascii.hexlify(rx) return "20{:2s}-{:2s}-{:2s} {:2s}:{:2s}:{:2s}".format( rx[8:10], # Year rx[10:12], # Month rx[4:6], # Day rx[6:8], # Hour rx[0:2], # Minute rx[2:4]) # Seconds
def totally_sent(file, sntf, tmpf): def is_new_day(file): today = time.time() - time.time() % 86400 try: last_file_write = os.stat( file)[8] - os.stat(file)[8] % 86400 if today - last_file_write >= 86400: return True return False except: return False if is_new_day(file): try: os.rename(file, sntf) try: os.remove(tmpf) except: verbose('UNABLE TO REMOVE FILE {}'.format(tmpf)) except: verbose('UNABLE TO RENAME FILE {}'.format(file))
def _start_delayed(self): """Starts a measurement at a specified time based on the current configuration of the instrument. Data is stored to a new file in the recorder. Data is output on the serial port only if specified in the configuration. """ start = utime.time() while True: if self._timeout(start): utils.log_file("{} => unable to start measurement".format( self.__qualname__)) # DEBUG return False if self._break(): utils.verbose("=> SD", constants.VERBOSE) self.uart.write("SD") rx = self._get_reply() if not self._ack(rx): self._format_recorder() else: utils.log_file("{} => measurement started".format( self.__qualname__)) # DEBUG return True
async def cts(): ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False c = await self.agetc(1, self.tout) if not c: verbose('TIMEOUT OCCURRED, RETRY...') ec += 1 elif c == C: verbose('<-- C') return True else: verbose('UNATTENDED CHAR {}, RETRY...'.format(c)) ec += 1 await asyncio.sleep(0)
async def ctr(): ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(C, self.tout): verbose('ERROR SENDING C, RETRY...') ec += 1 else: verbose('C -->') return True await asyncio.sleep(0)
async def sms(self, text, num): async with self.semaphore: self.disconnect.clear() self.trigger.set(False) self.init_uart() self.reply_timeout = self.at_timeout log(self.__qualname__,'sending sms...') for at in self.sms_ats1: if not await self.cmd(at): log(self.__qualname__,'sms failed', at) #self.disconnect.set() self.trigger.set(True) return False await asyncio.sleep(self.at_delay) await self.swriter.awrite(self.sms_ats2 + num + '\r') try: self.data = await asyncio.wait_for(self.sreader.readline(), self.reply_timeout) except asyncio.TimeoutError: log(self.__qualname__,'sms failed', num) #self.disconnect.set() self.trigger.set(True) return False if self.data.startswith(self.sms_ats2 + num + '\r'): verbose(self.data) try: self.data = await asyncio.wait_for(self.sreader.read(2), self.reply_timeout) except asyncio.TimeoutError: log(self.__qualname__,'sms failed') #self.disconnect.set() self.trigger.set(True) return False if self.data.startswith(b'>'): verbose(self.data) await self.swriter.awrite(text+'\r\n') try: self.data = await asyncio.wait_for(self.sreader.readline(), 60) except asyncio.TimeoutError: log(self.__qualname__,'sms failed') #self.disconnect.set() self.trigger.set(True) return False if self.data.startswith(text): verbose(self.data) if await self.cmd('\x1a'): #self.disconnect.set() self.trigger.set(True) return True log(self.__qualname__,'sms failed') #self.disconnect.set() self.trigger.set(True) return False
def finalize(file, length): tmp = file.replace(file.split('/')[-1], TPFX + file.split('/')[-1]) bkp = file.replace(file.split('/')[-1], BPFX + file.split('/')[-1]) sz = int(os.stat(tmp)[6]) + self.nulls if sz == length: try: os.rename(file, bkp) # Backups existing file. except: verbose('FILE {} NOT EXISTS'.format(file)) try: os.rename(tmp, file) except: verbose('UNABLE TO COMMIT FILE {}'.format(tmp)) os.remove(tmp) os.rename(bkp, file) # Restore original file. else: try: os.remove(tmp) except: verbose('UNABLE TO REMOVE FILE {}'.format(tmp))
async def cancel(): verbose('CANCEL TRANSMISSION...') for _ in range(2): await self.aputc(CAN, 60) verbose('CAN -->') await asyncio.sleep(1)
async def arecv(self, crc_mode=1): msg = Message() # Message to wait for threads completion. def finalize(file, length): tmp = file.replace(file.split('/')[-1], TPFX + file.split('/')[-1]) bkp = file.replace(file.split('/')[-1], BPFX + file.split('/')[-1]) sz = int(os.stat(tmp)[6]) + self.nulls if sz == length: try: os.rename(file, bkp) # Backups existing file. except: verbose('FILE {} NOT EXISTS'.format(file)) try: os.rename(tmp, file) except: verbose('UNABLE TO COMMIT FILE {}'.format(tmp)) os.remove(tmp) os.rename(bkp, file) # Restore original file. else: try: os.remove(tmp) except: verbose('UNABLE TO REMOVE FILE {}'.format(tmp)) # Writes out data to the passed file. # Runs in a separate thread to not block scheduler. def w_data(file, data, msg): tmp = file.replace(file.split('/')[-1], TPFX + file.split('/')[-1]) try: with open(tmp, 'ab') as s: self.nulls = data.count(PAD) s.write(data.replace(PAD, NULL)) msg.set(True) except: verbose('ERROR OPENING {}'.format(tmp)) msg.set(False) async def cancel(): verbose('CANCEL TRANSMISSION...') for _ in range(2): await self.aputc(CAN, 60) verbose('CAN -->') await asyncio.sleep(1) async def ack(): ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(ACK, self.tout): verbose('ERROR SENDING ACK, RETRY...') ec += 1 else: verbose('ACK -->') return True await asyncio.sleep(0) async def nak(): ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(NAK, self.tout): verbose('ERROR SENDING NAK, RETRY...') ec += 1 else: verbose('NAK -->') return True await asyncio.sleep(0) # Clear to receive. async def ctr(): ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(C, self.tout): verbose('ERROR SENDING C, RETRY...') ec += 1 else: verbose('C -->') return True await asyncio.sleep(0) # Validate checksum. async def v_cksum(data, crc_mode): async def calc_cksum(data, cksum=0): return (sum(map(ord, data)) + cksum) % 256 # Calculates the 16 bit Cyclic Redundancy Check for a given block of data. async def calc_crc(data, crc=0): for c in bytearray(data): crctbl_idx = ((crc >> 8) ^ c) & 0xff crc = ((crc << 8) ^ CRC_TAB[crctbl_idx]) & 0xffff await asyncio.sleep(0) return crc & 0xffff if crc_mode: cksum = bytearray(data[-2:]) recv = (cksum[0] << 8) + cksum[1] data = data[:-2] calc = await calc_crc(data) valid = bool(recv == calc) if not valid: verbose('CRC FAIL EXPECTED({:04x}) GOT({:4x})'.format( recv, calc)) else: cksum = bytearray([data[-1]]) recv = cksum[0] data = data[:-1] calc = await calc_cksum(data) valid = recv == calc if not valid: verbose('CHECKSUM FAIL EXPECTED({:02x}) GOT({:2x})'.format( recv, calc)) return valid, data ######################################################################## # Transaction starts here ######################################################################## ec = 0 # Error counter. verbose('REQUEST 16 BIT CRC') while True: if crc_mode: while True: if ec == (self.retry // 2): verbose('REQUEST STANDARD CHECKSUM') crc_mode = 0 break if not await self.aputc( C ): # Sends C to request 16 bit CRC as first choice. verbose('ERROR SENDING C, RETRY...') ec += 1 await asyncio.sleep(0) else: verbose('C -->') break if not crc_mode and ec < self.retry: if not await nak( ): # Sends NAK to request standard checksumum as fall back. return False # # Receives packets. # sz = 128 # Packet size. cc = 0 # Cancel counter. seq = 0 # Sequence counter. isz = 0 # Income size. while True: c = await self.agetc(1, self.tout) if ec == self.retry: verbose('TOO MANY ERRORS, ABORTING') await cancel() # Cancels transmission. return False elif not c: verbose('TIMEOUT OCCURRED WHILE RECEIVING') ec += 1 break # Resends start byte. elif c == CAN: verbose('<-- CAN') if cc: verbose('TRANSMISSION CANCELED BY SENDER') return False else: cc = 1 ec = 0 # Ensures to receive a second CAN. elif c == SOH: verbose('SOH <--') if sz != 128: sz = 128 verbose('USING 128 BYTES PACKET SIZE') elif c == STX: verbose('STX <--') if sz != 1024: sz = 1024 verbose('USING 1 KB PACKET SIZE') elif c == EOT: verbose('EOT <--') if not await ack(): # Acknowledges EOT. return False finalize(fname, length) seq = 0 isz = 0 if not await ctr(): # Clears to receive. return False ec = 0 await asyncio.sleep(0) continue else: verbose('UNATTENDED CHAR {}'.format(c)) ec += 1 await asyncio.sleep(0) continue # # Reads packet sequence. # ec = 0 while True: seq1 = await self.agetc(1, self.tout) if not seq1: verbose('FAILED TO GET FIRST SEQUENCE BYTE') seq2 = None else: seq1 = ord(seq1) seq2 = await self.agetc(1, self.tout) if not seq2: verbose('FAILED TO GET SECOND SEQUENCE BYTE') else: seq2 = 0xff - ord(seq2) verbose('PACKET {} <--'.format(seq)) if not (seq1 == seq2 == seq): verbose( 'SEQUENCE ERROR, EXPECTED {} GOT {}, DISCARD DATA'. format(seq, seq1)) await self.agetc(sz + 1 + crc_mode ) # Discards data packet. if seq1 == 0: # If receiving file name packet, clears for transmission. if not await ctr(): return False ec = 0 else: data = await self.agetc(sz + 1 + crc_mode, self.tout) valid, data = await v_cksum(data, crc_mode) if not valid: if not await nak(): # Requests retransmission. return False ec = 0 else: if seq == 0: # Sequence 0 contains file name. if data == bytearray( sz ): # Sequence 0 with null data state end of trasmission. if not await ack(): # Acknowledges EOT. return False await asyncio.sleep(1) verbose('END OF TRANSMISSION') return True ds = [] # Data string. df = '' # Data field. for b in data: if b != 0: df += chr(b) elif len(df) > 0: ds.append(df) df = '' fname = ds[0] length = int(ds[1].split(' ')[0]) verbose('RECEIVING FILE {}'.format(fname)) if not await ack(): # Acknowledges packet. return False if not await ctr(): # Clears for transmission. return False ec = 0 else: tn = isz - length # Counts trailing null chars. _thread.start_new_thread( w_data, (fname, data[:-tn], msg)) await asyncio.sleep_ms(10) await msg if not msg.value(): # Error opening file. if not await nak( ): # Requests retransmission. return False ec += 1 else: if not await ack(): return False isz += len(data) ec = 0 msg.clear() seq = (seq + 1) % 0x100 # Calcs next expected seq. break
async def asend(self, files): msg = Message() # Message to wait for threads completion. # Reads out n-bytes from the current file. def r_data(file, ptr, sz, msg): try: with open(file) as s: s.seek(ptr) data = s.read(sz) tptr = s.tell() except: pass msg.set((data, tptr)) # Saves last read byte. def set_lb(tmpf, ptr, msg): with open(tmpf, 'w') as t: t.write(str(ptr)) msg.set() # Gets last read byte. def get_lb(tmpf, msg): try: with open(tmpf) as t: ptr = int(t.read()) except: ptr = 0 # File not exists. msg.set(ptr) # Backups the current daily file for asyncronous access. async def bkp_f(file): bkp = file.replace(file.split('/')[-1], BPFX + file.split('/')[-1]) async with f_lock: shutil.copyfile(file, bkp) return bkp # Gets file info. def stat_f(file, msg): fstat = os.stat(file) msg.set(fstat) def mk_file_hdr(sz): b = [] if sz == 128: b.append(ord(SOH)) elif sz == 1024: b.append(ord(STX)) b.extend([0x00, 0xff]) return bytearray(b) def mk_data_hdr(seq, sz): assert sz in (128, 1024), sz b = [] if sz == 128: b.append(ord(SOH)) elif sz == 1024: b.append(ord(STX)) b.extend([seq, 0xff - seq]) return bytearray(b) # Makes the checksum for the current packet. def mk_cksum(data, crc_mode, msg): def calc_cksum(data, cksum=0): return (sum(map(ord, data)) + cksum) % 256 #Calculates the 16 bit Cyclic Redundancy Check for a given block of data. def calc_crc(data, crc=0): for c in bytearray(data): crctbl_idx = ((crc >> 8) ^ c) & 0xff crc = ((crc << 8) ^ CRC_TAB[crctbl_idx]) & 0xffff return crc & 0xffff b = [] if crc_mode: crc = calc_crc(data) b.extend([crc >> 8, crc & 0xff]) else: crc = calc_cksum(data) b.append(crc) msg.set(bytearray(b)) # Archives totally sent files. def totally_sent(file, sntf, tmpf): def is_new_day(file): today = time.time() - time.time() % 86400 try: last_file_write = os.stat( file)[8] - os.stat(file)[8] % 86400 if today - last_file_write >= 86400: return True return False except: return False if is_new_day(file): try: os.rename(file, sntf) try: os.remove(tmpf) except: verbose('UNABLE TO REMOVE FILE {}'.format(tmpf)) except: verbose('UNABLE TO RENAME FILE {}'.format(file)) # Clear to send. async def cts(): ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False c = await self.agetc(1, self.tout) if not c: verbose('TIMEOUT OCCURRED, RETRY...') ec += 1 elif c == C: verbose('<-- C') return True else: verbose('UNATTENDED CHAR {}, RETRY...'.format(c)) ec += 1 await asyncio.sleep(0) ######################################################################## # Transaction starts here ######################################################################## try: sz = dict(Ymodem=128, Ymodem1k=1024)[self.mode] # Packet size. except KeyError: raise ValueError('INVALID MODE {}'.format(self.mode)) # # Waits for receiver. # ec = 0 # Error counter. verbose('BEGIN TRANSACTION, PACKET SIZE {}'.format(sz)) while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False c = await self.agetc(1, self.tout) if not c: verbose( 'TIMEOUT OCCURRED WHILE WAITING FOR STARTING TRANSMISSION, RETRY...' ) ec += 1 elif c == C: verbose('<-- C') verbose('16 BIT CRC REQUESTED') crc_mode = 1 break elif c == NAK: verbose('<-- NAK') verbose('STANDARD CECKSUM REQUESTED') crc_mode = 0 break else: verbose('UNATTENDED CHAR {}, RETRY...'.format(c)) ec += 1 await asyncio.sleep(0) # # Iterates over file list. # fc = 0 # File counter. for f in files: # Temporary files store only the count of sent bytes. tmpf = f.replace(f.split('/')[-1], TPFX + f.split('/')[-1]) # Sent files get renamed in order to be archived. sntf = f.replace(f.split('/')[-1], SPFX + f.split('/')[-1]) fname = f.split('/')[-1] if f != '\x00': if f.split('/')[-1] == self.daily: # Daily file gets copied before being sent. f = await bkp_f(f) _thread.start_new_thread(get_lb, (tmpf, msg)) await asyncio.sleep_ms(10) await msg ptr = msg.value() msg.clear() if ptr == int(os.stat(f)[6]): # Check if eof. verbose('FILE {} ALREADY TRANSMITTED, SEND NEXT FILE...'. format(fname)) totally_sent(f, sntf, tmpf) continue fc += 1 # # If multiple files waits for clear to send. # if fc > 1: if not await cts(): return False # # Create file name packet # hdr = mk_file_hdr(sz) data = bytearray(fname + '\x00', 'utf8') # self.fname + space if f != '\x00': _thread.start_new_thread(stat_f, (f, msg)) await asyncio.sleep_ms(10) await msg fstat = msg.value() msg.clear() data.extend((str(fstat[6] - ptr) + ' ' + str( fstat[8])).encode('utf8')) # Sends data size and mod date. pad = bytearray(sz - len(data)) # Fills packet size with nulls. data.extend(pad) _thread.start_new_thread(mk_cksum, (data, crc_mode, msg)) await asyncio.sleep_ms(10) await msg cksum = msg.value() msg.clear() await asyncio.sleep(0.1) ec = 0 while True: # # Sends filename packet. # while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(hdr + data + cksum, self.tout): ec += 1 await asyncio.sleep(0) continue verbose('SENDING FILE {}'.format(fname)) break # # Waits for reply to filename paket. # cc = 0 # Cancel counter. ackd = 0 # Acked. while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False c = await self.agetc(1, self.tout) if not c: # handle rx erros verbose('TIMEOUT OCCURRED, RETRY...') ec += 1 await asyncio.sleep(0) continue elif c == ACK: verbose('<-- ACK TO FILE {}'.format(fname)) if data == bytearray(sz): verbose('TRANSMISSION COMPLETE, EXITING...') return True else: ackd = 1 break elif c == CAN: verbose('<-- CAN') if cc: verbose('TRANSMISSION CANCELED BY RECEIVER') return False else: cc = 1 await asyncio.sleep(0) continue # Waits for a second CAN else: verbose('UNATTENDED CHAR {}, RETRY...'.format(c)) ec += 1 break # Resends packet. if ackd: break # Waits for data. if f == '\x00': return True # # Waits for clear to send. # if not await cts(): return False # # Sends file. # sc = 0 # Succeded counter. pc = 0 # Packets counter. seq = 1 while True: _thread.start_new_thread(r_data, (f, ptr, sz, msg)) await asyncio.sleep_ms(10) await msg data, tptr = msg.value() msg.clear() if not data: verbose('EOF') break pc += 1 hdr = mk_data_hdr(seq, sz) fst = '{:' + PAD.decode('utf-8') + '<' + str( sz) + '}' # Right fills data with pad byte. data = fst.format(data) data = data.encode('utf8') _thread.start_new_thread(mk_cksum, (data, crc_mode, msg)) await asyncio.sleep_ms(10) await msg cksum = msg.value() msg.clear() ec = 0 while True: # # Send data packet. # while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(hdr + data + cksum, self.tout): ec += 1 await asyncio.sleep(0) continue # Resend packet. else: verbose('PACKET {} -->'.format(seq)) break # # Waits for reply. # cc = 0 ackd = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False c = await self.agetc(1, self.tout) if not c: # handle rx errors verbose('TIMEOUT OCCURRED, RETRY...') ec += 1 break elif c == ACK: verbose('<-- ACK TO PACKET {}'.format(seq)) ptr = tptr # Updates pointer. _thread.start_new_thread(set_lb, (tmpf, ptr, msg)) await asyncio.sleep_ms(10) await msg msg.clear() ackd = 1 sc += 1 seq = (seq + 1) % 0x100 break elif c == NAK: verbose('<-- NAK') ec += 1 break # Resends packet. elif c == CAN: verbose('<-- CAN') if cc: verbose('TRANSMISSION CANCELED BY RECEIVER') return False else: cc = 1 await asyncio.sleep(0) continue # Waits for a second CAN. else: verbose('UNATTENDED CHAR {}, RETRY...'.format(c)) ec += 1 break # Resends last packet. await asyncio.sleep(0) if ackd: break # Sends next packet # # End of transmission. # ec = 0 while True: if ec > self.retry: verbose('TOO MANY ERRORS, ABORTING...') return False if not await self.aputc(EOT, self.tout): ec += 1 await asyncio.sleep(0) continue # resend EOT verbose('EOT -->') c = await self.agetc(1, self.tout) # waiting for reply if not c: # handle rx errors verbose( 'TIMEOUT OCCURRED WHILE WAITING FOR REPLY TO EOT, RETRY...' ) ec += 1 elif c == ACK: verbose('<-- ACK TO EOT') verbose('FILE {} SUCCESSFULLY TRANSMITTED'.format(fname)) totally_sent(f, sntf, tmpf) break # Sends next file. else: verbose('UNATTENDED CHAR {}, RETRY...'.format(c)) ec += 1 await asyncio.sleep(0)