async def run_ack(): message = Message() ack1 = Message() ack2 = Message() count = 0 while True: asyncio.create_task(message_wait(message, ack1, 1)) asyncio.create_task(message_wait(message, ack2, 2)) message.set(count) count += 1 print('message was set') await ack1 ack1.clear() print('Cleared ack1') await ack2 ack2.clear() print('Cleared ack2') message.clear() print('Cleared message') await asyncio.sleep(1)
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)
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'))
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)
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)