コード例 #1
0
async def do_usec(minutes):
    global gps
    tick = Message()
    print('Setting up GPS.')
    await us_setup(tick)
    print('Waiting for time data.')
    await gps.ready()
    max_us = 0
    min_us = 0
    sd = 0
    nsamples = 0
    count = 0
    terminate = Event()
    asyncio.create_task(killer(terminate, minutes))
    while not terminate.is_set():
        await tick
        usecs = tick.value()
        tick.clear()
        err = 1000000 - usecs
        count += 1
        print('Timing discrepancy is {:4d}μs {}'.format(
            err, '(skipped)' if count < 3 else ''))
        if count < 3:  # Discard 1st two samples from statistics
            continue  # as these can be unrepresentative
        max_us = max(max_us, err)
        min_us = min(min_us, err)
        sd += err * err
        nsamples += 1
    # SD: apply Bessel's correction for infinite population
    sd = int(math.sqrt(sd / (nsamples - 1)))
    print(
        'Timing discrepancy is: {:5d}μs max {:5d}μs min.  Standard deviation {:4d}μs'
        .format(max_us, min_us, sd))
コード例 #2
0
 def __init__(self, pin, callback, extended, *args):  # Optional args for callback
     self._ev_start = Message()
     self._callback = callback
     self._extended = extended
     self._addr = 0
     self.block_time = 80 if extended else 73  # Allow for some tx tolerance (?)
     self._args = args
     self._times = array('i',  (0 for _ in range(_EDGECOUNT + 1)))  # +1 for overrun
     pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
     self._edge = 0
     self._ev_start.clear()
     asyncio.create_task(self._run())
コード例 #3
0
async def run_message_test():
    print('Test Lock class')
    lock = asyncio.Lock()
    asyncio.create_task(run_lock(1, lock))
    asyncio.create_task(run_lock(2, lock))
    asyncio.create_task(run_lock(3, lock))
    print('Test Message class')
    message = Message()
    asyncio.create_task(messageset(message))
    await messagewait(message)  # run_message_test runs fast until this point
    print('Message status {}'.format('Incorrect' if message.is_set() else 'OK'))
    print('Tasks complete')
コード例 #4
0
 def __init__(self, conn_id, config, hardware, verbose):
     self.verbose = verbose
     self.initial = True
     self._status = False  # Server status
     self.wlock = asyncio.Lock()
     self.rxmsg = Message()  # rx data ready
     self.tim_boot = Delay_ms(func=self.reboot)
     config.insert(0, conn_id)
     config.append('cfg')  # Marker defines a config list
     self.cfg = ''.join((ujson.dumps(config), '\n'))
     i2c, syn, ack, rst = hardware
     self.chan = asi2c_i.Initiator(i2c, syn, ack, rst, verbose, self._go, (), self.reboot)
     self.sreader = asyncio.StreamReader(self.chan)
     self.swriter = asyncio.StreamWriter(self.chan, {})
     self.lqueue = []  # Outstanding lines
コード例 #5
0
 def __init__(self, pin, callback, extended,
              *args):  # Optional args for callback
     self._ev_start = Message()
     self._callback = callback
     self._extended = extended
     self._addr = 0
     self.block_time = 80 if extended else 73  # Allow for some tx tolerance (?)
     self._args = args
     self._times = array('i',
                         (0
                          for _ in range(_EDGECOUNT + 1)))  # +1 for overrun
     if platform == 'pyboard':
         ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin)
     else:  # PR5962 ESP8266 hard IRQ's not supported
         pin.irq(handler=self._cb_pin,
                 trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING))
     self._edge = 0
     self._ev_start.clear()
     asyncio.create_task(self._run())
コード例 #6
0
async def listner(trigger):
    global devs
    m = Message()
    trigger.set(True)

    async def poller(stream):
        sreader = asyncio.StreamReader(stream)
        i = 0
        while True:
            await scheduling.wait()  #and await disconnect.wait()
            b = await sreader.read(1)
            if b:
                try:
                    b.decode('utf-8')
                except UnicodeError:
                    await asyncio.sleep(0)
                    continue
                if (b == dfl.ESC_CHAR.encode()
                        and stream.__class__.__name__ == 'UART'
                        and not session.logging):
                    i += 1
                    if i > 2:
                        asyncio.create_task(session.login(m, stream))
                        session.logging = True
                elif (b == b'\x1b' and
                      (stream.__class__.__name__ == 'UART' and session.loggedin
                       or stream.__class__.__name__ == 'USB_VCP')
                      and not menu.interactive):
                    asyncio.create_task(menu.main(m, stream, devs))
                    m.set(b)  # Passes ESC to menu.
                    menu.interactive = True
                else:
                    m.set(b)
                    i = 0
            await asyncio.sleep_ms(100)

    asyncio.create_task(poller(pyb.USB_VCP()))  # Polls the usb vcp.
    while True:
        await trigger.wait()
        if trigger.value():
            polluart = asyncio.create_task(poller(pyb.UART(
                3, 9600)))  # Polls the modem uart.
        else:
            polluart.cancel()
        trigger.clear()
        await asyncio.sleep_ms(100)
コード例 #7
0
async def run_ack():
    message = Message()
    ack1 = asyncio.Event()
    ack2 = asyncio.Event()
    count = 0
    while True:
        asyncio.create_task(event_wait(message, ack1, 1))
        asyncio.create_task(event_wait(message, ack2, 2))
        message.set(count)
        count += 1
        print('message was set')
        await ack1.wait()
        ack1.clear()
        print('Cleared ack1')
        await ack2.wait()
        ack2.clear()
        print('Cleared ack2')
        message.clear()
        print('Cleared message')
        await asyncio.sleep(1)
コード例 #8
0
ファイル: device.py プロジェクト: microhomie/microhomie
from primitives import launch
from primitives.message import Message


def get_unique_id():
    if LINUX is False:
        from machine import unique_id
        return hexlify(unique_id()).decode()
    else:
        raise NotImplementedError(
            "Linux doesn't have a unique id. Provide the DEVICE_ID option in your settings.py."
        )


# Decorator to block async tasks until the device is in "ready" state
_MESSAGE = Message()
def await_ready_state(func):
    def new_gen(*args, **kwargs):
        # fmt: off
        await _MESSAGE
        await func(*args, **kwargs)
        # fmt: on

    return new_gen


class HomieDevice:

    """MicroPython implementation of the Homie MQTT convention for IoT."""

    def __init__(self, settings):
コード例 #9
0
import uasyncio as asyncio
from primitives.message import Message
from primitives.semaphore import Semaphore
from primitives.queue import Queue
import time
import os
import json
import _thread
import pyb
from configs import dfl, cfg

logger = True  # Prints out messages.

f_lock = asyncio.Lock()  # Data file lock.
alert = Message()  # Sms message.
trigger = Message()
timesync = asyncio.Event()  # Gps fix event.
scheduling = asyncio.Event()  # Scheduler event.
disconnect = asyncio.Event()  # Modem event.
u2_lock = asyncio.Lock() # Uart 2 lock.
u4_lock = asyncio.Lock() # Uart 4 lock.

def welcome_msg():
    print(
    '{:#^80}\n\r#{: ^78}#\n\r#{: ^78}#\n\r# {: <20}{: <57}#\n\r# {: <20}{: <57}#\n\r# {: <20}{: <57}#\n\r# {: <20}{: <57}#\n\r{:#^80}'.format(
        '',
        'WELCOME TO ' + cfg.HOSTNAME + ' ' + dfl.SW_NAME + ' ' + dfl.SW_VERSION,
        '',
        ' current time:',
        iso8601(time.time()),
コード例 #10
0
class NEC_IR():
    def __init__(self, pin, callback, extended,
                 *args):  # Optional args for callback
        self._ev_start = Message()
        self._callback = callback
        self._extended = extended
        self._addr = 0
        self.block_time = 80 if extended else 73  # Allow for some tx tolerance (?)
        self._args = args
        self._times = array('i',
                            (0
                             for _ in range(_EDGECOUNT + 1)))  # +1 for overrun
        if platform == 'pyboard':
            ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin)
        else:  # PR5962 ESP8266 hard IRQ's not supported
            pin.irq(handler=self._cb_pin,
                    trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING))
        self._edge = 0
        self._ev_start.clear()
        asyncio.create_task(self._run())

    async def _run(self):
        while True:
            await self._ev_start  # Wait until data collection has started
            # Compensate for asyncio latency
            latency = ticks_diff(ticks_ms(), self._ev_start.value())
            await asyncio.sleep_ms(self.block_time - latency
                                   )  # Data block should have ended
            self._decode()  # decode, clear event, prepare for new rx, call cb

    # Pin interrupt. Save time of each edge for later decode.
    def _cb_pin(self, line):
        t = ticks_us()
        # On overrun ignore pulses until software timer times out
        if self._edge <= _EDGECOUNT:  # Allow 1 extra pulse to record overrun
            if not self._ev_start.is_set():  # First edge received
                self._ev_start.set(ticks_ms())  # asyncio latency compensation
            self._times[self._edge] = t
            self._edge += 1

    def _decode(self):
        overrun = self._edge > _EDGECOUNT
        val = OVERRUN if overrun else BADSTART
        if not overrun:
            width = ticks_diff(self._times[1], self._times[0])
            if width > 4000:  # 9ms leading mark for all valid data
                width = ticks_diff(self._times[2], self._times[1])
                if width > 3000:  # 4.5ms space for normal data
                    if self._edge < _EDGECOUNT:
                        # Haven't received the correct number of edges
                        val = BADBLOCK
                    else:
                        # Time spaces only (marks are always 562.5µs)
                        # Space is 1.6875ms (1) or 562.5µs (0)
                        # Skip last bit which is always 1
                        val = 0
                        for edge in range(3, _EDGECOUNT - 2, 2):
                            val >>= 1
                            if ticks_diff(self._times[edge + 1],
                                          self._times[edge]) > 1120:
                                val |= 0x80000000
                elif width > 1700:  # 2.5ms space for a repeat code. Should have exactly 4 edges.
                    val = REPEAT if self._edge == 4 else BADREP
        addr = 0
        if val >= 0:  # validate. Byte layout of val ~cmd cmd ~addr addr
            addr = val & 0xff
            cmd = (val >> 16) & 0xff
            if addr == ((val >> 8) ^ 0xff) & 0xff:  # 8 bit address OK
                val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA
                self._addr = addr
            else:
                addr |= val & 0xff00  # pass assumed 16 bit address to callback
                if self._extended:
                    val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA
                    self._addr = addr
                else:
                    val = BADADDR
        if val == REPEAT:
            addr = self._addr  # Last valid addresss
        self._edge = 0  # Set up for new data burst and run user callback
        self._ev_start.clear()
        self._callback(val, addr, *self._args)
コード例 #11
0
async def run_message_test():
    message = Message()
    asyncio.create_task(wait_message(message))
    await asyncio.sleep(1)
    message.set('Hello world')
    await asyncio.sleep(1)
コード例 #12
0
class AppBase:
    def __init__(self, conn_id, config, hardware, verbose):
        self.verbose = verbose
        self.initial = True
        self._status = False  # Server status
        self.wlock = asyncio.Lock()
        self.rxmsg = Message()  # rx data ready
        self.tim_boot = Delay_ms(func=self.reboot)
        config.insert(0, conn_id)
        config.append('cfg')  # Marker defines a config list
        self.cfg = ''.join((ujson.dumps(config), '\n'))
        i2c, syn, ack, rst = hardware
        self.chan = asi2c_i.Initiator(i2c, syn, ack, rst, verbose, self._go, (), self.reboot)
        self.sreader = asyncio.StreamReader(self.chan)
        self.swriter = asyncio.StreamWriter(self.chan, {})
        self.lqueue = []  # Outstanding lines

    # Runs after sync acquired on 1st or subsequent ESP8266 boots.
    async def _go(self):
        self.verbose and print('Sync acquired, sending config')
        if not self.wlock.locked():  # May have been acquired in .reboot
            await self.wlock.acquire()
        self.verbose and print('Got lock, sending config', self.cfg)
        self.swriter.write(self.cfg)
        await self.swriter.drain()  # 1st message is config
        while self.lqueue:
            self.swriter.write(self.lqueue.pop(0))
            await self.swriter.drain()
        self.wlock.release()
        # At this point ESP8266 can handle the Pyboard interface but may not
        # yet be connected to the server
        if self.initial:
            self.initial = False
            self.start()  # User starts read and write tasks

    # **** API ****
    async def await_msg(self):
        while True:
            line = await self.sreader.readline()
            h, p = chr(line[0]), line[1:]  # Header char, payload
            if h == 'n':  # Normal message
                self.rxmsg.set(p)
            elif h == 'b':
                asyncio.create_task(self.bad_wifi())
            elif h == 's':
                asyncio.create_task(self.bad_server())
            elif h == 'r':
                asyncio.create_task(self.report(ujson.loads(p)))
            elif h == 'k':
                self.tim_boot.trigger(4000)  # hold off reboot (4s)
            elif h in ('u', 'd'):
                up = h == 'u'
                self._status = up
                asyncio.create_task(self.server_ok(up))
            else:
                raise ValueError('Unknown header:', h)

    async def write(self, line, qos=True, wait=True):
        ch = chr(0x30 + ((qos << 1) | wait))  # Encode args
        fstr =  '{}{}' if line.endswith('\n') else '{}{}\n'
        line = fstr.format(ch, line)
        try:
            await asyncio.wait_for(self.wlock.acquire(), 1)
            self.swriter.write(line)
            await self.swriter.drain()
        except asyncio.TimeoutError:  # Lock is set because ESP has crashed
            self.verbose and print('Timeout getting lock: queueing line', line)
            # Send line later. Can avoid message loss, but this
            self.lqueue.append(line)  # isn't a bomb-proof guarantee
        finally:
            if self.wlock.locked():
                self.wlock.release()

    async def readline(self):
        await self.rxmsg
        line = self.rxmsg.value()
        self.rxmsg.clear()
        return line

    # Stopped getting keepalives. ESP8266 crash: prevent user code from writing
    # until reboot sequence complete
    async def reboot(self):
        self.verbose and print('AppBase reboot')
        if self.chan.reset is None:  # No config for reset
            raise OSError('Cannot reset ESP8266.')
        asyncio.create_task(self.chan.reboot())  # Hardware reset board
        self.tim_boot.stop()  # No more reboots
        if not self.wlock.locked():  # Prevent user writes
            await self.wlock.acquire()

    def close(self):
        self.verbose and print('Closing channel.')
        self.chan.close()

    def status(self):  # Server status
        return self._status

    # **** For subclassing ****

    async def bad_wifi(self):
        await asyncio.sleep(0)
        raise OSError('No initial WiFi connection.')

    async def bad_server(self):
        await asyncio.sleep(0)
        raise OSError('No initial server connection.')

    async def report(self, data):
        await asyncio.sleep(0)
        print('Connects {} Count {} Mem free {}'.format(data[0], data[1], data[2]))

    async def server_ok(self, up):
        await asyncio.sleep(0)
        print('Server is {}'.format('up' if up else 'down'))
コード例 #13
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)
コード例 #14
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
コード例 #15
0
async def main(msg, uart, objs):
    global interactive
    board = False
    devices = False
    device = False
    dev = None
    logger = False  # Stops log stream.
    fw = Message()  # Forwards main uart to device.
    while True:
        await msg
        fw.set(msg.value())
        if not board:
            if not devices:
                if not device:
                    if msg.value() == ESC:
                        board = True
                        await board_menu()
                else:  # device
                    if msg.value() == b'0':
                        dev.toggle()
                        await device_menu(dev)
                    elif msg.value() == b'1':
                        fw.clear()  # Clears last byte.
                        asyncio.create_task(pass_through(dev, uart, fw))
                        #await device_menu(dev)
                    elif msg.value() == b'2':
                        pass
                    elif msg.value() == b'3':
                        await get_config(dev)
                        await device_menu(dev)
                    elif msg.value() in BACKSPACE:
                        device = False
                        devices = True
                        await devices_menu(objs)
                    elif msg.value() == ESC:
                        await device_menu(dev)
            else:  # devices
                if msg.value() == ESC:
                    await devices_menu(objs)
                elif msg.value() in BACKSPACE:
                    devices = False
                    board = True
                    await board_menu()
                else:
                    devices = False
                    device = True
                    try:
                        dev = objs[int(msg.value())]
                        await device_menu(dev)
                    except:
                        await devices_menu(objs)
        else:  # board
            if msg.value() == ESC:
                board = True
                await board_menu()
            elif msg.value() == b'0':
                board = False
                devices = True
                await devices_menu(objs)
            elif msg.value() == b'1':
                await data_files()
                await board_menu()
            elif msg.value() == b'2':
                await last_log()
                await board_menu()
            elif msg.value() in BACKSPACE:
                interactive = False
                logger = True
                msg.clear()
                return
        msg.clear()
        await asyncio.sleep(0)