def animate(): teeth = False fps = False shadow = True pressed = False ms1 = utime.time_ms() with display.open() as disp: while True: t = utime.localtime() ms0 = ms1 ms1 = utime.time_ms() % 1000 disp.clear() volt = os.read_battery() charge = (volt - 3.4) / 0.8 draw_spring(disp, charge, shadow) draw_gears(disp, t, ms1, teeth, shadow) draw_hands(disp, t, shadow) if fps: disp.print("{:.1f} fps".format(1000.0 / (ms1 - ms0)), posx=100, posy=60) disp.update() butt = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) if butt == 0: pressed = False if not pressed and butt & buttons.BOTTOM_LEFT != 0: teeth = not teeth pressed = True if not pressed and butt & buttons.BOTTOM_RIGHT != 0: fps = not fps pressed = True if not pressed and butt & buttons.TOP_RIGHT != 0: shadow = not shadow pressed = True
def button_events(timeout=None): yield 0 v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) button_pressed = True if v != 0 else False if timeout is not None: timeout = int(timeout * 1000) next_tick = utime.time_ms() + timeout while True: if timeout is not None: current_time = utime.time_ms() if current_time > next_tick: next_tick = current_time + timeout yield TIMEOUT v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) if v == 0: button_pressed = False elif not button_pressed: for mask in (buttons.BOTTOM_LEFT, buttons.BOTTOM_RIGHT, buttons.TOP_RIGHT): if v & mask != 0: yield mask
def set_unix_time(t): global _offset_ms cur_t = _utime.time_ms() _utime.set_unix_time(t) new_t = _utime.time_ms() diff = cur_t - new_t _offset_ms += diff
def run(self): """Start the event-loop.""" try: timeout = self.scroll_speed if self.timeout is not None and self.timeout < self.scroll_speed: timeout = self.timeout for ev in button_events(timeout): if ev == buttons.BOTTOM_RIGHT: self.select_time = utime.time_ms() self.draw_menu(-8) self.idx = (self.idx + 1) % len(self.entries) try: self.on_scroll(self.entries[self.idx], self.idx) except _ExitMenuException: raise except Exception as e: print("Exception during menu.on_scroll():") sys.print_exception(e) elif ev == self.button_scroll_up: self.select_time = utime.time_ms() self.draw_menu(8) self.idx = (self.idx + len(self.entries) - 1) % len( self.entries) try: self.on_scroll(self.entries[self.idx], self.idx) except _ExitMenuException: raise except Exception as e: print("Exception during menu.on_scroll():") sys.print_exception(e) elif ev == self.button_select: try: self.on_select(self.entries[self.idx], self.idx) self.select_time = utime.time_ms() except _ExitMenuException: raise except Exception as e: print("Menu crashed!") sys.print_exception(e) self.error("Menu", "crashed") utime.sleep(1.0) self.draw_menu() if self.timeout is not None and (utime.time_ms() - self.select_time) > int( self.timeout * 1000): self.on_timeout() except _ExitMenuException: pass
def draw_entry(self, value, index, offset): """ Draw a single entry. This is an internal function; you can override it for customized behavior. :param value: The value for this entry. Use this to identify different entries. :param int index: A unique index per entry. Stable for a certain entry, but **not** an index into ``entries``. :param int offset: Y-offset for this entry. """ string = self.entry2name(value) if offset != 20 or len(string) < 10: string = " " + string + " " * 9 else: # Slowly scroll entry to the side time_offset = (utime.time_ms() - self.select_time) // int( self.scroll_speed * 1000) time_offset = time_offset % (len(string) - 7) - 1 time_offset = min(len(string) - 10, max(0, time_offset)) string = " " + string[time_offset:] self.disp.print( string, posy=offset, fg=self.color_text, bg=self.color_1 if index % 2 == 0 else self.color_2, )
def __init__(self, entries): if len(entries) == 0: raise ValueError("at least one entry is required") self.entries = entries self.idx = 0 self.select_time = utime.time_ms() self.disp = display.open()
def toggle_leds(): global led_mode, disp, pause_screen, leds, modes led_mode, display_args = next(modes) pause_screen = utime.time_ms() + 250 disp.clear(COLOR_BACKGROUND) disp.print("LEDs", posx=50, posy=20, fg=COLOR_TEXT) disp.print(**display_args, posy=40, fg=COLOR_TEXT) disp.update() leds.clear()
def toggle_bias(): global bias, disp, pause_screen if write > 0: pause_screen = utime.time_ms() + 500 disp.clear(COLOR_BACKGROUND) disp.print("Locked", posx=30, posy=30, fg=COLOR_TEXT) disp.update() return close_sensor() bias = not bias open_sensor()
def toggle_mode(): global current_mode, disp, pause_screen if write > 0: pause_screen = utime.time_ms() + 500 disp.clear(COLOR_BACKGROUND) disp.print("Locked", posx=30, posy=30, fg=COLOR_TEXT) disp.update() return close_sensor() current_mode = MODE_USB if current_mode == MODE_FINGER else MODE_FINGER open_sensor()
def __init__(self, entries): if len(entries) == 0: raise ValueError("at least one entry is required") self.entries = entries self.idx = 0 self.select_time = utime.time_ms() self.disp = display.open() self.button_scroll_up = (buttons.TOP_RIGHT if self.right_buttons_scroll else buttons.BOTTOM_LEFT) self.button_select = (buttons.BOTTOM_LEFT if self.right_buttons_scroll else buttons.TOP_RIGHT)
async def render_loop(self, root_view, screen): # type: (MGuiView, MGuiScreen) -> Coroutine[Any, Any, NoReturn] self.__context[C.CONTEXT_ROOT] = self self.__context[C.CONTEXT_ROOT_VIEW] = root_view try: self.__lasttime = time_ms() while self.__running: await self.render_once(root_view, screen) except KeyboardInterrupt: # print("Abort.") self.stop() pass
def draw_histogram(): global disp, history, current_mode, bias, write, pause_screen # skip rendering due to message beeing shown if pause_screen == -1: return elif pause_screen > 0: t = utime.time_ms() if t > pause_screen: pause_screen = 0 else: return disp.clear(COLOR_BACKGROUND) # get max value and calc scale value_max = 0 for value in history: if abs(value) > value_max: value_max = abs(value) scale = SCALE_FACTOR / (value_max if value_max > 0 else 1) # draw histogram old = False x = 0 samples = len(history) for i, value in enumerate(history): if old == False: old = (x, int(value * scale) + OFFSET) x += 1 continue elif i > samples - WIDTH: disp.line(old[0], old[1], x, int(value * scale) + OFFSET, col=COLOR_LINE) old = (x, int(value * scale) + OFFSET) x += 1 # draw text: mode/bias/write disp.print( current_mode + ("+Bias" if bias else ""), posx=0, posy=0, fg=(COLOR_MODE_FINGER if current_mode == MODE_FINGER else COLOR_MODE_USB), ) # announce writing ecg log if write > 0: t = utime.time() if write > 0 and t % 2 == 0: disp.print("LOG", posx=0, posy=60, fg=COLOR_WRITE_FG, bg=COLOR_WRITE_BG) disp.update()
def toggle_write(): global write, disp, pause_screen pause_screen = utime.time_ms() + 1000 disp.clear(COLOR_BACKGROUND) if write > 0: write_filebuffer() write = 0 disp.print("Stop", posx=50, posy=20, fg=COLOR_TEXT) disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) else: filebuffer = bytearray() write = utime.time() disp.print("Start", posx=45, posy=20, fg=COLOR_TEXT) disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) disp.update()
async def render_once(self, root_view, screen): s_w, s_h = screen.get_size() frame = screen.get_framebuffer() target_duration = 1000 // self.__context[C.CONTEXT_FRAME_RATE] now = time_ms() if now - self.__lasttime < target_duration: await asyncio.sleep(0.0) return self.__context[C.CONTEXT_FRAME_DURATION] = now - self.__lasttime self.__lasttime = now # print(self.__context[CONTEXT_FRAME_DURATION]) try: if root_view.need_render(self.__context): effect_area = await root_view.render(self.__context, frame, (0, 0, s_w, s_h)) await screen.refresh(self.__context, effect_area) except Exception as e: if is_debug: print_exception(e) self.stop() return
def toggle_write(): global write, disp, pause_screen, filebuffer, samples_since_start_of_write, write_time_string pause_screen = utime.time_ms() + 1000 disp.clear(COLOR_BACKGROUND) if write > 0: write_filebuffer() write = 0 disp.print("Stop", posx=50, posy=20, fg=COLOR_TEXT) disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) else: filebuffer = bytearray() write = utime.time() lt = utime.localtime(write) write_time_string = "{:04d}-{:02d}-{:02d}_{:02d}{:02d}{:02d}".format(*lt) samples_since_start_of_write = 0 try: os.mkdir("ecg_logs") except: pass disp.print("Start", posx=45, posy=20, fg=COLOR_TEXT) disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) disp.update()
def main(): global pause_histogram, histogram_offset # show button layout disp.clear(COLOR_BACKGROUND) disp.print(" BUTTONS ", posx=0, posy=0, fg=COLOR_TEXT) disp.print("Finger/USB>", posx=0, posy=20, fg=COLOR_MODE_FINGER) disp.print(" Bias >", posx=0, posy=40, fg=COLOR_MODE_USB) disp.print("< Write Log", posx=0, posy=60, fg=COLOR_WRITE_BG) disp.update() utime.sleep(3) # start ecg open_sensor() while True: button_pressed = {"BOTTOM_LEFT": 0, "BOTTOM_RIGHT": 0, "TOP_RIGHT": 0} while True: v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) # BOTTOM LEFT if button_pressed[ "BOTTOM_LEFT"] == 0 and v & buttons.BOTTOM_LEFT != 0: button_pressed["BOTTOM_LEFT"] = utime.time_ms() if not pause_histogram: toggle_write() else: l = len(history) histogram_offset += ECG_RATE / 2 if l - histogram_offset < WIDTH: histogram_offset = l - WIDTH if button_pressed[ "BOTTOM_LEFT"] > 0 and v & buttons.BOTTOM_LEFT == 0: duration = utime.time_ms() - button_pressed["BOTTOM_LEFT"] button_pressed["BOTTOM_LEFT"] = 0 # BOTTOM RIGHT if button_pressed[ "BOTTOM_RIGHT"] == 0 and v & buttons.BOTTOM_RIGHT != 0: button_pressed["BOTTOM_RIGHT"] = utime.time_ms() if not pause_histogram: toggle_bias() else: histogram_offset -= ECG_RATE / 2 histogram_offset -= histogram_offset % (ECG_RATE / 2) if histogram_offset < 0: histogram_offset = 0 if button_pressed[ "BOTTOM_RIGHT"] > 0 and v & buttons.BOTTOM_RIGHT == 0: duration = utime.time_ms() - button_pressed["BOTTOM_RIGHT"] button_pressed["BOTTOM_RIGHT"] = 0 # TOP RIGHT # down, and still pressed if button_pressed["TOP_RIGHT"] > 0 and v & buttons.TOP_RIGHT != 0: duration = utime.time_ms() - button_pressed["TOP_RIGHT"] if duration > 1000: button_pressed["TOP_RIGHT"] = -1 toggle_pause() # register down event elif button_pressed[ "TOP_RIGHT"] == 0 and v & buttons.TOP_RIGHT != 0: button_pressed["TOP_RIGHT"] = utime.time_ms() # register up event but event already called if button_pressed["TOP_RIGHT"] == -1 and v & buttons.TOP_RIGHT == 0: button_pressed["TOP_RIGHT"] = 0 # register normal up event elif button_pressed["TOP_RIGHT"] > 0 and v & buttons.TOP_RIGHT == 0: duration = utime.time_ms() - button_pressed["TOP_RIGHT"] button_pressed["TOP_RIGHT"] = 0 if pause_histogram: toggle_pause() else: toggle_mode()
def scroller(t): char_width = 15 # 180/11 offset = ft / 20.0 full = int(offset / float(char_width)) rest = char_width - (int(offset) % char_width) full = full % len(SCROLLER_TEXT) d.print(SCROLLER_TEXT[full:], posx=rest, posy=62) d.rect(0, 62, 15, 80, col=(0, 0, 0)) d.rect(145, 62, 160, 80, col=(0, 0, 0)) global_start = utime.time_ms() while True: t = utime.time_ms() - global_start ft = float(t) with display.open() as d: d.clear() # d.print("peng1", posy=0, fg=[100, 255, 255]) # d.update() # d.print("peng2", posy=0, fg=[100, 255, 255]) # d.update() # for y in range(HEIGHT): # for x in range(WIDTH): # d.pixel(x, y, col = (255, 255, 0)) offset = int(5.0 * math.sin(ft / 300.0)) start = utime.time_ms() akronyme_analogiker(d, offset)
def button_events(timeout=None): """ Iterate over button presses (event-loop). This is just a helper function used internally by the menu. But you can of course use it for your own scripts as well. It works like this: .. code-block:: python import simple_menu, buttons for ev in simple_menu.button_events(): if ev == buttons.BOTTOM_LEFT: # Left pass elif ev == buttons.BOTTOM_RIGHT: # Right pass elif ev == buttons.TOP_RIGHT: # Select pass .. versionadded:: 1.4 :param float,optional timeout: Timeout after which the generator should yield in any case. If a timeout is defined, the generator will periodically yield :py:data:`simple_menu.TIMEOUT`. .. versionadded:: 1.9 """ yield 0 v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) button_pressed = True if v != 0 else False if timeout is not None: timeout = int(timeout * 1000) next_tick = utime.time_ms() + timeout while True: if timeout is not None: current_time = utime.time_ms() if current_time >= next_tick: next_tick += timeout yield TIMEOUT v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) if v == 0: button_pressed = False if not button_pressed and v & buttons.BOTTOM_LEFT != 0: button_pressed = True yield buttons.BOTTOM_LEFT if not button_pressed and v & buttons.BOTTOM_RIGHT != 0: button_pressed = True yield buttons.BOTTOM_RIGHT if not button_pressed and v & buttons.TOP_RIGHT != 0: button_pressed = True yield buttons.TOP_RIGHT
def time_monotonic_ms(): return _utime.time_ms() + _offset_ms
def run_loop(): bat = [1, [0, 230, 00], [255, 215, 0], [255, 0, 0]] anim = 0 write_timer = 0 with display.open() as disp: disp.clear() disp.backlight(5) disp.print("@derfnull", posy=0) disp.update() disp.close() while True: pressed = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT) if pressed & buttons.BOTTOM_LEFT: anim += 1 if pressed & buttons.BOTTOM_RIGHT: anim += 2 if pressed: if anim > 4: anim = 0 if anim == 0: leds.clear() leds.set_rocket(0, 0) leds.set_rocket(1, 0) leds.set_rocket(2, 0) if anim == 1: leds.set_rocket(0, 0) leds.set_rocket(1, 0) leds.set_rocket(2, 0) leds.gay(0.2) if anim == 2: leds.clear() leds.set_rocket(0, 2) leds.set_rocket(1, 15) leds.set_rocket(2, 15) if anim == 3: leds.clear() leds.set_rocket(0, 15) leds.set_rocket(1, 15) leds.set_rocket(2, 15) if anim == 4: leds.clear() leds.set_rocket(0, 0) leds.set_rocket(1, 0) leds.set_rocket(2, 0) leds.set(11, [127, 127, 127]) leds.set(12, [127, 127, 127]) leds.set(13, [127, 127, 127]) leds.set(14, [127, 127, 127]) sensor_data = bme680.get_data() ambient_light = light_sensor.get_reading() battery_voltage = os.read_battery() with display.open() as disp: disp.clear() render_battery(disp, bat, battery_voltage) disp.print("@derfnull", posy=0) disp.print("{:2.1f} C {:2.0f} %".format(sensor_data[0], sensor_data[1]), posy=20) disp.print("{:5.1f} hPa ".format(sensor_data[2]), posy=40) disp.print("{:4.1f} kOhm ".format(sensor_data[3] / 1000), posy=60) disp.update() disp.close() write_timer += 1 if write_timer == 5: with open('sensorlog.txt', 'a') as f: f.write('{} {} {} {} {} {} {}\n'.format( utime.time_ms(), sensor_data[0], sensor_data[1], sensor_data[2], sensor_data[3], ambient_light, battery_voltage)) write_timer = 0 utime.sleep(2)
def time_ms(): return _utime.time_ms()
# shading=255: stars at z_max are black (no pop-up) WIDTH = 160 # screen width [px] HEIGHT = 80 # screen height [px] buttonState = 0 # button state toremove = [] # list of star indices marked for removal if __name__ == "__main__": # initialise starfield with stars at random positions, sorted back to front starfield = [[ urandom.randint(-x_max, x_max), urandom.randint(-y_max, y_max), z, -1, -1 ] for z in sorted([urandom.randint(0, z_max) for i in range(0, n_stars)], reverse=True)] # indefinite loop while True: # take cycle start time t0 = utime.time_ms() # read button states, process changes, save state for next cycle btns = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT) if btns & buttons.BOTTOM_LEFT == 0 and buttonState & buttons.BOTTOM_LEFT != 0: # reduce warp speed (bottom left button, falling edge) warp_target = max(int(warp) - 1, 0) if warp_target < int(warp): d_warp = -warp_step else: d_warp = 0 elif btns & buttons.BOTTOM_RIGHT == 0 and buttonState & buttons.BOTTOM_RIGHT != 0: # increase warp speed (bottom right button, falling edge) warp_target = min(int(warp) + 1, 9) if warp_target > int(warp): d_warp = +warp_step else:
def draw_histogram(): global disp, history, current_mode, bias, write, pause_screen, update_screen # skip rendering due to message beeing shown if pause_screen == -1: return elif pause_screen > 0: t = utime.time_ms() if t > pause_screen: pause_screen = 0 else: return disp.clear(COLOR_BACKGROUND) # offset in pause_histogram mode window_end = int(len(history) - histogram_offset) s_start = max(0, window_end - (ECG_RATE * 2)) s_end = max(0, window_end) s_draw = max(0, s_end - WIDTH) # get max value and calc scale value_max = max(abs(x) for x in history[s_start:s_end]) scale = SCALE_FACTOR / (value_max if value_max > 0 else 1) # draw histogram # values need to be inverted so high values are drawn with low pixel coordinates (at the top of the screen) draw_points = (int(-x * scale + OFFSET_Y) for x in history[s_draw:s_end]) prev = next(draw_points) for x, value in enumerate(draw_points): disp.line(x, prev, x + 1, value, col=COLOR_LINE) prev = value # draw text: mode/bias/write if pause_histogram: disp.print( "Pause" + (" -{:0.1f}s".format(histogram_offset / ECG_RATE) if histogram_offset > 0 else ""), posx=0, posy=0, fg=COLOR_TEXT, ) else: led_range = last_sample_count if last_sample_count > 5 else 5 draw_leds( min(history[-led_range:]) / value_max, max(history[-led_range:]) / value_max) if pulse < 0: disp.print( current_mode + ("+Bias" if bias else ""), posx=0, posy=0, fg=(COLOR_MODE_FINGER if current_mode == MODE_FINGER else COLOR_MODE_USB), ) else: disp.print( "BPM: {}".format(pulse), posx=0, posy=0, fg=(COLOR_MODE_FINGER if current_mode == MODE_FINGER else COLOR_MODE_USB), ) # announce writing ecg log if write > 0: t = utime.time() if write > 0 and t % 2 == 0: disp.print("LOG", posx=0, posy=60, fg=COLOR_WRITE_FG, bg=COLOR_WRITE_BG) disp.update() update_screen = 0
def main(): global pause_histogram, histogram_offset # show button layout disp.clear(COLOR_BACKGROUND) disp.print(" BUTTONS ", posx=0, posy=0, fg=COLOR_TEXT, font=display.FONT20) disp.line(0, 20, 159, 20, col=COLOR_LINE) disp.print(" Pause >", posx=0, posy=28, fg=COLOR_MODE_FINGER, font=display.FONT16) disp.print(" Mode/Bias >", posx=0, posy=44, fg=COLOR_MODE_USB, font=display.FONT16) disp.print("< LED/WriteLog", posx=0, posy=64, fg=COLOR_WRITE_BG, font=display.FONT16) disp.update() utime.sleep(3) # start ecg open_sensor() while True: button_pressed = {"BOTTOM_LEFT": 0, "BOTTOM_RIGHT": 0, "TOP_RIGHT": 0} while True: v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT) # TOP RIGHT # down if button_pressed["TOP_RIGHT"] == 0 and v & buttons.TOP_RIGHT != 0: button_pressed["TOP_RIGHT"] = utime.time_ms() toggle_pause() # up if button_pressed["TOP_RIGHT"] > 0 and v & buttons.TOP_RIGHT == 0: duration = utime.time_ms() - button_pressed["TOP_RIGHT"] button_pressed["TOP_RIGHT"] = 0 # BOTTOM LEFT # # on pause = shift view left # long = toggle write # short = toggle leds # down, and still pressed if (button_pressed["BOTTOM_LEFT"] > 0 and v & buttons.BOTTOM_LEFT != 0 and not pause_histogram): duration = utime.time_ms() - button_pressed["BOTTOM_LEFT"] if duration > 1000: button_pressed["BOTTOM_LEFT"] = -1 toggle_write() # register down event elif button_pressed[ "BOTTOM_LEFT"] == 0 and v & buttons.BOTTOM_LEFT != 0: button_pressed["BOTTOM_LEFT"] = utime.time_ms() # register up event but event already called if button_pressed[ "BOTTOM_LEFT"] == -1 and v & buttons.BOTTOM_LEFT == 0: button_pressed["BOTTOM_LEFT"] = 0 # register normal up event elif button_pressed[ "BOTTOM_LEFT"] > 0 and v & buttons.BOTTOM_LEFT == 0: duration = utime.time_ms() - button_pressed["BOTTOM_LEFT"] button_pressed["BOTTOM_LEFT"] = 0 if not pause_histogram: toggle_leds() else: l = len(history) histogram_offset += ECG_RATE / 2 if l - histogram_offset < WIDTH: histogram_offset = l - WIDTH # BOTTOM RIGHT # # on pause = shift view right # long = toggle bias # short = toggle mode (finger/usb) # down, and still pressed if (button_pressed["BOTTOM_RIGHT"] > 0 and v & buttons.BOTTOM_RIGHT != 0 and not pause_histogram): duration = utime.time_ms() - button_pressed["BOTTOM_RIGHT"] if duration > 1000: button_pressed["BOTTOM_RIGHT"] = -1 toggle_bias() # register down event elif button_pressed[ "BOTTOM_RIGHT"] == 0 and v & buttons.BOTTOM_RIGHT != 0: button_pressed["BOTTOM_RIGHT"] = utime.time_ms() # register up event but event already called if button_pressed[ "BOTTOM_RIGHT"] == -1 and v & buttons.BOTTOM_RIGHT == 0: button_pressed["BOTTOM_RIGHT"] = 0 # register normal up event elif button_pressed[ "BOTTOM_RIGHT"] > 0 and v & buttons.BOTTOM_RIGHT == 0: duration = utime.time_ms() - button_pressed["BOTTOM_RIGHT"] button_pressed["BOTTOM_RIGHT"] = 0 if pause_histogram: histogram_offset -= ECG_RATE / 2 histogram_offset -= histogram_offset % (ECG_RATE / 2) if histogram_offset < 0: histogram_offset = 0 else: toggle_mode()