コード例 #1
0
    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
コード例 #2
0
 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
コード例 #3
0
        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
コード例 #4
0
    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
コード例 #5
0
 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
コード例 #6
0
 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
コード例 #7
0
 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)
コード例 #8
0
 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
コード例 #9
0
    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
コード例 #10
0
 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
コード例 #11
0
    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
コード例 #12
0
    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
コード例 #13
0
 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
コード例 #14
0
 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
コード例 #15
0
 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
コード例 #16
0
 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
コード例 #17
0
 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
コード例 #18
0
        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))
コード例 #19
0
 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
コード例 #20
0
 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)
コード例 #21
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)
コード例 #22
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
コード例 #23
0
 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))
コード例 #24
0
 async def cancel():
     verbose('CANCEL TRANSMISSION...')
     for _ in range(2):
         await self.aputc(CAN, 60)
         verbose('CAN -->')
         await asyncio.sleep(1)
コード例 #25
0
    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
コード例 #26
0
    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)