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))
class RunInThread(Thread): """ """ def __init__(self, action, *args, **kwargs): """Инициализация потока""" log.info("Init:") # print("Thread Init") Thread.__init__(self) self.result = None self.event = Event() self.action = action self._args = args self._kwargs = kwargs def run(self): """Запуск потока""" # print("Thread Act Run") log.info("Act Run") try: self.result = self.action(*self._args, **self._kwargs) except Exception as e: # print("Err: thread Act: {}".format(e)) log.info("Act: ERROR {}".format(e)) pass self.event.set() # print("Thread Act Done") log.info("Act: Done")
async def main(): event = Event() asyncio.create_task(waiter(event)) await asyncio.sleep(2) print('Setting event') event.set() await asyncio.sleep(1) # Caller can check if event has been cleared print('Event is {}'.format('set' if event.is_set() else 'clear'))
def __init__(self, action, *args, **kwargs): """Инициализация потока""" log.info("Init:") # print("Thread Init") Thread.__init__(self) self.result = None self.event = Event() self.action = action self._args = args self._kwargs = kwargs
class Pending: def __init__(self): self._ev = Event() self._res = None async def get(self): await self._ev.wait() self._ev.clear() # TODO: race condition? if isinstance(self._res, OSError): raise self._res else: return self._res def signal(self, result): self._res = result self._ev.set()
async def do_time(minutes): global gps fstr = '{}ms Time: {:02d}:{:02d}:{:02d}:{:06d}' print('Setting up GPS.') gps = await setup() print('Waiting for time data.') await gps.ready() print('Setting RTC.') await gps.set_rtc() print('RTC is set.') terminate = Event() asyncio.create_task(killer(terminate, minutes)) while not terminate.is_set(): await asyncio.sleep(1) # In a precision app, get the time list without allocation: t = gps.get_t_split() print(fstr.format(gps.get_ms(), t[0], t[1], t[2], t[3]))
async def do_drift(minutes): global gps print('Setting up GPS.') gps = await setup() print('Waiting for time data.') await gps.ready() print('Setting RTC.') await gps.set_rtc() print('Measuring drift.') terminate = Event() asyncio.create_task(killer(terminate, minutes)) change = await drift_test(terminate, gps) ush = int(60 * change / minutes) spa = int(ush * 365 * 24 / 1000000) print('Rate of change {}μs/hr {}secs/year'.format(ush, spa))
class MQTTLog: _minlevel = ERROR _qmax = 1400 _q = [] _qlen = 0 _ev = Event() @classmethod def init(cls, minlevel=ERROR, maxsize=1400): global _dup _dup = cls cls._minlevel = minlevel cls.resize(maxsize) @classmethod def resize(cls, maxsize): cls._qmax = maxsize # first try to eliminate messages below warning level i = 0 while cls._qlen > maxsize and i < len(cls._q): if cls._q[i][0] < WARNING: cls._qlen -= len(cls._q[i][1]) del cls._q[i] i += 1 # if not there yet, eliminate other messages too while cls._qlen > maxsize: cls._qlen -= len(cls._q[0][1]) del cls._q[0] @classmethod def log(cls, level, msg): if level < cls._minlevel: return if len(msg) > MAX_LINE: msg = msg[:MAX_LINE] ll = len(msg) cls._q.append((level, msg)) cls._qlen += ll if cls._qlen > cls._qmax: cls.resize(cls._qmax) cls._ev.set() @classmethod async def push(cls, mqclient, topic): msg = cls._q[0][1] try: await mqclient.publish(topic, msg, qos=1, sync=False) except Exception as e: print("Exception", e) await sleep_ms(1000) cls._qlen -= len(msg) del cls._q[0] @classmethod async def run(cls, mqclient, topic): while True: while len(cls._q) > 0: await cls.push(mqclient, topic) cls._ev.clear() await cls._ev.wait() # connected is called when the first bropker connection is established, it flushes excess # saved messages while blocking further inits by other modules, then resizes the log storage, # and starts the regular runner/flusher @classmethod async def connected(cls, mqtt, config): topic = config["topic"] getLogger("main").info("Logging to %s", topic) # flush what we'd need cut due to resize maxsize = config.get("loop_sz", 1400) getLogger("main").info("Log buf: %d/%d bytes", cls._qlen, cls._qmax) while cls._qlen > maxsize*3//4: await cls.push(mqtt.client, topic) # re-init including resize MQTTLog.init( minlevel=config.get("loop_level", WARNING), maxsize=maxsize, ) getLogger("main").info("Log buf: %d/%d bytes", cls._qlen, cls._qmax) # launch regular flusher loop.create_task(MQTTLog.run(mqtt.client, topic))
async def set_after_timeout(event: uasyncio.Event, timeout: float): await uasyncio.sleep(timeout) event.set()
def __init__(self): self._ev = Event() self._res = None
class Screen: current_screen = None tft = None objtouch = None is_shutdown = Event() @classmethod def setup(cls, tft, objtouch=None): cls.objtouch = objtouch if objtouch is not None else tft cls.tft = tft @classmethod def _get_tft(cls, greyed_out=False): cls.tft.usegrey(greyed_out) return cls.tft @classmethod def set_grey_style(cls, *, desaturate=True, factor=2): cls.tft.dim(factor) cls.tft.desaturate(desaturate) if Screen.current_screen is not None: # Can call before instantiated for obj in Screen.current_screen.displaylist: if obj.visible and obj.greyed_out(): obj.redraw = True # Redraw static content obj.draw_border() obj.show() @classmethod def show(cls): for obj in cls.current_screen.displaylist: if obj.visible: # In a buttonlist only show visible button obj.redraw = True # Redraw static content obj.draw_border() obj.show() @classmethod def change(cls, cls_new_screen, *, forward=True, args=[], kwargs={}): init = cls.current_screen is None if init: Screen() # Instantiate a blank starting screen else: # About to erase an existing screen for entry in cls.current_screen.tasklist: if entry[1]: # To be cancelled on screen change entry[0].cancel() cs_old = cls.current_screen cs_old.on_hide() # Optional method in subclass if forward: if isinstance(cls_new_screen, type): new_screen = cls_new_screen(*args, **kwargs) # Instantiate new screen else: raise ValueError('Must pass Screen class or subclass (not instance)') new_screen.parent = cs_old cs_new = new_screen else: cs_new = cls_new_screen # An object, not a class cls.current_screen = cs_new cs_new.on_open() # Optional subclass method cs_new._do_open(cs_old) # Clear and redraw cs_new.after_open() # Optional subclass method if init: try: asyncio.run(Screen.monitor()) # Starts and ends uasyncio finally: asyncio.new_event_loop() @classmethod async def monitor(cls): await cls.is_shutdown.wait() cls.is_shutdown.clear() for entry in cls.current_screen.tasklist: entry[0].cancel() await asyncio.sleep_ms(0) # Allow subclass to cancel tasks cls.tft.clr_scr() cls.current_screen = None # Ensure another demo can run @classmethod def back(cls): parent = cls.current_screen.parent if parent is not None: cls.change(parent, forward = False) @classmethod def addobject(cls, obj): if cls.current_screen is None: raise OSError('You must create a Screen instance') if isinstance(obj, Touchable): cls.current_screen.touchlist.append(obj) cls.current_screen.displaylist.append(obj) @classmethod def shutdown(cls): cls.is_shutdown.set() # Tell monitor() to shutdown def __init__(self): self.touchlist = [] self.displaylist = [] self.tasklist = [] # Allow instance to register tasks for shutdown self.modal = False if Screen.current_screen is None: # Initialising class and task asyncio.create_task(Screen.objtouch.touchtest()) # One task only asyncio.create_task(self._garbage_collect()) Screen.current_screen = self self.parent = None def _do_open(self, old_screen): # Aperture overrides show_all = True tft = Screen._get_tft() # If opening a Screen from an Aperture just blank and redraw covered area if old_screen.modal: show_all = False x0, y0, x1, y1 = old_screen._list_dims() tft.fill_rectangle(x0, y0, x1, y1, SYS_BGCOLOR) # Blank to screen BG for obj in [z for z in self.displaylist if z.overlaps(x0, y0, x1, y1)]: if obj.visible: obj.redraw = True # Redraw static content obj.draw_border() obj.show() # Normally clear the screen and redraw everything else: tft.clr_scr() Screen.show() def on_open(self): # Optionally implemented in subclass return def after_open(self): # Optionally implemented in subclass return def on_hide(self): # Optionally implemented in subclass return def reg_task(self, task, on_change=False): # May be passed a coro or a Task if isinstance(task, type_coro): task = asyncio.create_task(task) self.tasklist.append([task, on_change]) async def _garbage_collect(self): while True: await asyncio.sleep_ms(100) gc.collect() gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())