diff --git a/python_payload/apps/cap_touch_demo.py b/python_payload/apps/cap_touch_demo.py index 85fb4bfd2c9475fd9c5e3d85aa3bb36f6e6916e3..d22d3c995758c76230cb9015352713761cc317bd 100644 --- a/python_payload/apps/cap_touch_demo.py +++ b/python_payload/apps/cap_touch_demo.py @@ -7,25 +7,36 @@ from st3m import utils ctx = hardware.get_ctx() + def init(): pass + def run(): ctx.rgb(0, 0, 0).rectangle(-120, -120, 240, 240).fill() time.sleep_ms(30) for i in range(10): size = (hardware.get_captouch(i) * 4) + 4 - size += int(max(0, sum([hardware.captouch_get_petal_pad(i, x) for x in range(0, 3+1)]) / 8000)) - x = 70 + (hardware.captouch_get_petal_rad(i)/1000) - x += (hardware.captouch_get_petal_phi(i)/600)*1j + size += int( + max( + 0, + sum([hardware.captouch_get_petal_pad(i, x) for x in range(0, 3 + 1)]) + / 8000, + ) + ) + x = 70 + (hardware.captouch_get_petal_rad(i) / 1000) + x += (hardware.captouch_get_petal_phi(i) / 600) * 1j rot = cmath.exp(2j * math.pi * i / 10) x = x * rot col = (1.0, 0.0, 1.0) - if i%2: + if i % 2: col = (0.0, 1.0, 1.0) - ctx.rgb(*col).rectangle(-int(x.imag-(size/2)), -int(x.real-(size/2)), size, size).fill() + ctx.rgb(*col).rectangle( + -int(x.imag - (size / 2)), -int(x.real - (size / 2)), size, size + ).fill() hardware.display_update() + def foreground(): pass diff --git a/python_payload/apps/demo_mandelbrot.py b/python_payload/apps/demo_mandelbrot.py index 687ec86f8073595e4a2b463bf2eb6158c1604cd4..caae93c9278f67dfed95b64812ec134f502c711b 100644 --- a/python_payload/apps/demo_mandelbrot.py +++ b/python_payload/apps/demo_mandelbrot.py @@ -1,6 +1,7 @@ from st3m.application import Application import ui + class MandelbrotApp(Application): def on_init(self): pass @@ -9,23 +10,25 @@ class MandelbrotApp(Application): print("on foreground") ctx = self.ui.ctx - #center the text horizontally and vertically + # center the text horizontally and vertically ctx.text_align = ctx.CENTER ctx.text_baseline = ctx.MIDDLE - #ctx.rgb() expects individual values for the channels, so unpack a list/tuple with * - #operations on ctx can be chained - #create a blue background - ctx.rgb(*ui.RED).rectangle(-ui.WIDTH/2,-ui.HEIGHT/2,ui.WIDTH,ui.HEIGHT).fill() + # ctx.rgb() expects individual values for the channels, so unpack a list/tuple with * + # operations on ctx can be chained + # create a blue background + ctx.rgb(*ui.RED).rectangle( + -ui.WIDTH / 2, -ui.HEIGHT / 2, ui.WIDTH, ui.HEIGHT + ).fill() - #Write some text - ctx.move_to(0,0).rgb(*ui.WHITE).text("Mandelbrot") + # Write some text + ctx.move_to(0, 0).rgb(*ui.WHITE).text("Mandelbrot") def main_forground(): - - for x in range(-240,240): - for y in range(-240,240): + for x in range(-240, 240): + for y in range(-240, 240): pass -app=MandelbrotApp("Mandelbrot") -app.run() \ No newline at end of file + +app = MandelbrotApp("Mandelbrot") +app.run() diff --git a/python_payload/apps/demo_sparabo.py b/python_payload/apps/demo_sparabo.py index e4cf06b0a99e0c0f9f353122ecfc5da0e1213ff6..b7090502dcab6236cf904795ca345c3eac531bb0 100644 --- a/python_payload/apps/demo_sparabo.py +++ b/python_payload/apps/demo_sparabo.py @@ -1,12 +1,13 @@ -#python +# python import math -#badge23 -from st3m import event,application,ui -from st3m.system import hardware,audio +# badge23 +from st3m import event, application, ui +from st3m.system import hardware, audio from synth import tinysynth -popcorn = [9,7,9,5,0,5,-3,999] +popcorn = [9, 7, 9, 5, 0, 5, -3, 999] + def on_step(data): ctx = app.ui.ctx @@ -15,41 +16,39 @@ def on_step(data): if note != 999: synth.tone(note) synth.start() - - if not app.is_foreground(): return + + if not app.is_foreground(): + return ctx.text_align = ctx.CENTER ctx.text_baseline = ctx.MIDDLE - ctx.rgb(1,1,0).rectangle(-120,-120,240,240).fill() - (x,y) = ui.xy_from_polar(90,-2*math.pi/8*data["step"]+math.pi) - size=180 - ctx.rgb(0.8,0.8,0) - ctx.round_rectangle( - x-size/2, - y-size/2, - size,size,size//2 - ).fill() - ctx.move_to(x,y).rgb(0.5,0.5,0).text("{}".format(data["step"])) + ctx.rgb(1, 1, 0).rectangle(-120, -120, 240, 240).fill() + (x, y) = ui.xy_from_polar(90, -2 * math.pi / 8 * data["step"] + math.pi) + size = 180 + ctx.rgb(0.8, 0.8, 0) + ctx.round_rectangle(x - size / 2, y - size / 2, size, size, size // 2).fill() + ctx.move_to(x, y).rgb(0.5, 0.5, 0).text("{}".format(data["step"])) + class AppSparabo(application.Application): def on_init(self): audio.set_volume_dB(0) - - self.synth = tinysynth(440,1) + + self.synth = tinysynth(440, 1) self.synth.decay(25) - print ("here") + print("here") self.sequencer = event.Sequence(bpm=160, steps=8, action=on_step, loop=True) self.sequencer.start() if self.sequencer.repeat_event: self.add_event(self.sequencer.repeat_event) - + def on_foreground(self): self.sequencer.start() def on_exit(self): self.sequencer.stop() - + app = AppSparabo("sequencer") diff --git a/python_payload/apps/demo_worms.py b/python_payload/apps/demo_worms.py index e4009551592d76f6d41d31b4ad23325fb38acc3f..02cc495d1beb28cf9099edef96ba3a059470cbad 100644 --- a/python_payload/apps/demo_worms.py +++ b/python_payload/apps/demo_worms.py @@ -1,14 +1,14 @@ -#python imports +# python imports import random import time import math -#flow3r imports -from st3m import event,application,ui +# flow3r imports +from st3m import event, application, ui + # Subclass Application class AppWorms(application.Application): - def on_init(self): print("on init") @@ -19,32 +19,37 @@ class AppWorms(application.Application): self.frame_slack = None self.last_report = None - self.add_event(event.Event( - name="worms_control", - action=self.handle_input, - condition=lambda data: data.get("type","")=="captouch" and data.get("value")==1 and data["change"], + self.add_event( + event.Event( + name="worms_control", + action=self.handle_input, + condition=lambda data: data.get("type", "") == "captouch" + and data.get("value") == 1 + and data["change"], ) ) self.worms = [] for i in range(0): self.worms.append(Worm()) - + def on_foreground(self): print("on foreground") ctx = app.ui.ctx - #center the text horizontally and vertically + # center the text horizontally and vertically ctx.text_align = ctx.CENTER ctx.text_baseline = ctx.MIDDLE - #ctx.rgb() expects individual values for the channels, so unpack a list/tuple with * - #operations on ctx can be chained - #create a blue background - ctx.rgb(*ui.BLUE).rectangle(-ui.WIDTH/2,-ui.HEIGHT/2,ui.WIDTH,ui.HEIGHT).fill() + # ctx.rgb() expects individual values for the channels, so unpack a list/tuple with * + # operations on ctx can be chained + # create a blue background + ctx.rgb(*ui.BLUE).rectangle( + -ui.WIDTH / 2, -ui.HEIGHT / 2, ui.WIDTH, ui.HEIGHT + ).fill() - #Write some text - ctx.move_to(0,0).rgb(*ui.WHITE).text("touch me :)") + # Write some text + ctx.move_to(0, 0).rgb(*ui.WHITE).text("touch me :)") def on_draw(self): for w in self.worms: @@ -61,85 +66,88 @@ class AppWorms(application.Application): return if self.last_report is None or (now - self.last_report) > 1000: - fps = 1000/delta - print(f'fps: {fps:.3}, frame budget slack: {self.frame_slack:.3}ms') + fps = 1000 / delta + print(f"fps: {fps:.3}, frame budget slack: {self.frame_slack:.3}ms") self.last_report = now # Simulation is currently locked to FPS. for w in self.worms: w.move() - + self.last_render = now - def handle_input(self,data): + def handle_input(self, data): worms = self.worms - worms.append(Worm(data.get("index",0)*2*math.pi/10+math.pi )) - if len(worms)>10: + worms.append(Worm(data.get("index", 0) * 2 * math.pi / 10 + math.pi)) + if len(worms) > 10: worms.pop(0) -class Worm(): - def __init__(self,direction=None): +class Worm: + def __init__(self, direction=None): self.color = ui.randrgb() - + if direction: self.direction = direction else: - self.direction = random.random()*math.pi*2 - + self.direction = random.random() * math.pi * 2 + self.size = 50 - self.speed = self.size/5 - (x,y) = ui.xy_from_polar(100, self.direction) + self.speed = self.size / 5 + (x, y) = ui.xy_from_polar(100, self.direction) self.x = x - self.y= y - #(self.dx,self.dy) = xy_from_polar(1,self.direction) + self.y = y + # (self.dx,self.dy) = xy_from_polar(1,self.direction) self._lastdist = 0.0 - + def draw(self): app.ui.ctx.rgb(*self.color) app.ui.ctx.round_rectangle( - self.x-self.size/2, - self.y-self.size/2, - self.size,self.size,self.size//2 + self.x - self.size / 2, + self.y - self.size / 2, + self.size, + self.size, + self.size // 2, ).fill() def mutate(self): - self.color = ([max(0,min(1,x+((random.random()-0.5)*0.3))) for x in self.color]) - - + self.color = [ + max(0, min(1, x + ((random.random() - 0.5) * 0.3))) for x in self.color + ] + def move(self): - dist = math.sqrt(self.x**2+self.y**2) - target_size = (130-dist)/3 - - if self.size>target_size: self.size-=1 - - if self.size<target_size: self.size+=1 - - self.speed = self.size/5 - - self.direction += (random.random()-0.5)*math.pi/4 - - (dx,dy) = ui.xy_from_polar(self.speed,self.direction) - self.x+=dx - self.y+=dy - - - if dist>120-self.size/2 and dist>self._lastdist: - polar_position=math.atan2(self.y,self.x) - dx=dx*-abs(math.cos(polar_position)) - dy=dy*-abs(math.sin(polar_position)) - self.direction=-math.atan2(dy,dx) + dist = math.sqrt(self.x**2 + self.y**2) + target_size = (130 - dist) / 3 + + if self.size > target_size: + self.size -= 1 + + if self.size < target_size: + self.size += 1 + + self.speed = self.size / 5 + + self.direction += (random.random() - 0.5) * math.pi / 4 + + (dx, dy) = ui.xy_from_polar(self.speed, self.direction) + self.x += dx + self.y += dy + + if dist > 120 - self.size / 2 and dist > self._lastdist: + polar_position = math.atan2(self.y, self.x) + dx = dx * -abs(math.cos(polar_position)) + dy = dy * -abs(math.sin(polar_position)) + self.direction = -math.atan2(dy, dx) self.mutate() self._lastdist = dist - app = AppWorms("worms") # To run standalone: -#app.run() -#app.engine.eventloop() +# app.run() +# app.engine.eventloop() -#Known problems: -#ctx.rotate(math.pi) turns the display black until powercycled -#ctx.clip() causes crashes \ No newline at end of file +# Known problems: +# ctx.rotate(math.pi) turns the display black until powercycled +# ctx.clip() causes crashes diff --git a/python_payload/apps/flow3r/__init__.py b/python_payload/apps/flow3r/__init__.py index f96eb2b44d0ed3e493f25b717ea9ee7419b1b1df..4f18a15a63816894cd7d91a94d20e9ea10f8a2d2 100644 --- a/python_payload/apps/flow3r/__init__.py +++ b/python_payload/apps/flow3r/__init__.py @@ -1,11 +1,15 @@ from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info(f"running {__name__}") from st3m.application import Application + log.info(f"import app") from . import menu_main + log.info(f"import menu") + class myApp(Application): def on_init(self): self.menu = menu_main.get_menu() @@ -13,4 +17,5 @@ class myApp(Application): def on_foreground(self): self.menu.start() -app=myApp("flow3r", exit_on_menu_enter=False) + +app = myApp("flow3r", exit_on_menu_enter=False) diff --git a/python_payload/apps/flow3r/menu_crazysynth.py b/python_payload/apps/flow3r/menu_crazysynth.py index 9f41efcdaa054ca0c802694639d5cad70eecbcb6..63e557fb37228a717972917e6bef918ff83b5cab 100644 --- a/python_payload/apps/flow3r/menu_crazysynth.py +++ b/python_payload/apps/flow3r/menu_crazysynth.py @@ -1,94 +1,97 @@ from synth import tinysynth -from st3m import menu,event,control,ui -from st3m.system import hardware,audio +from st3m import menu, event, control, ui +from st3m.system import hardware, audio + +synths = [tinysynth(440, 0), tinysynth(440, 0), tinysynth(440, 0)] +# synth = tinysynth(440,0) -synths = [tinysynth(440,0),tinysynth(440,0),tinysynth(440,0)] -#synth = tinysynth(440,0) def set_play(value): - print ("set_controls_overlay") + print("set_controls_overlay") if value: - for synth in synths: synth.start() + for synth in synths: + synth.start() else: - for synth in synths: synth.stop() + for synth in synths: + synth.stop() + the_freq = 440 + def set_frequency(value): global the_freq the_freq = value for synth in synths: synth.freq(the_freq) - + + def set_pitch0(value): - synths[0].freq(the_freq+the_freq*value) - + synths[0].freq(the_freq + the_freq * value) + + def set_pitch1(value): - synths[1].freq(the_freq+the_freq*value) + synths[1].freq(the_freq + the_freq * value) + def set_pitch2(value): - synths[2].freq(the_freq+the_freq*value) + synths[2].freq(the_freq + the_freq * value) + def get_menu(): m = menu.Menu("crazysynth") - freq=control.ControlKnob( + freq = control.ControlKnob( name="freq", on_set=set_frequency, default=the_freq, - min=220,max=440*4,step=10 + min=220, + max=440 * 4, + step=10, + ) + # m.add_petal(menu.MenuItemControl("freq",freq), petal_index=7) + m.add(menu.MenuItemControl("freq", freq)) + + m.add( + menu.MenuItemControl( + "mute", + control.ControlSwitch( + name="mute", on_set=audio.set_mute, on_get=audio.get_mute + ), + ) ) - #m.add_petal(menu.MenuItemControl("freq",freq), petal_index=7) - m.add(menu.MenuItemControl("freq",freq)) - - m.add(menu.MenuItemControl("mute",control.ControlSwitch( - name="mute", - on_set=audio.set_mute, - on_get=audio.get_mute - ))) pitch0 = control.ControlSlide( - name="pitch", - on_set=set_pitch0, - default=0, - min=-0.5,max=0.5 + name="pitch", on_set=set_pitch0, default=0, min=-0.5, max=0.5 ) - m.add_petal(menu.MenuItemControl("pitch0",pitch0), petal_index=3) + m.add_petal(menu.MenuItemControl("pitch0", pitch0), petal_index=3) pitch1 = control.ControlSlide( - name="pitch", - on_set=set_pitch1, - default=0, - min=-0.5,max=0.5 + name="pitch", on_set=set_pitch1, default=0, min=-0.5, max=0.5 ) - m.add_petal(menu.MenuItemControl("pitch1",pitch1), petal_index=5) + m.add_petal(menu.MenuItemControl("pitch1", pitch1), petal_index=5) pitch2 = control.ControlSlide( - name="pitch", - on_set=set_pitch2, - default=0, - min=-0.5,max=0.5 + name="pitch", on_set=set_pitch2, default=0, min=-0.5, max=0.5 ) - m.add_petal(menu.MenuItemControl("pitch2",pitch2), petal_index=7) + m.add_petal(menu.MenuItemControl("pitch2", pitch2), petal_index=7) - vol = control.ControlKnob(name="vol", - on_mod=audio.adjust_volume_dB, - on_get=audio.get_volume_relative + vol = control.ControlKnob( + name="vol", on_mod=audio.adjust_volume_dB, on_get=audio.get_volume_relative ) - mi_vol = menu.MenuItemControl("volume",vol) + mi_vol = menu.MenuItemControl("volume", vol) m.add(mi_vol) - #m.add_petal(mi_vol,1) + # m.add_petal(mi_vol,1) + + play = control.ControlSwitch(name="play", on_set=set_play, default=False) + # m.add_petal(menu.MenuItemControl("play",play), petal_index=5) + m.add(menu.MenuItemControl("play", play)) - play = control.ControlSwitch(name="play",on_set=set_play,default=False) - #m.add_petal(menu.MenuItemControl("play",play), petal_index=5) - m.add(menu.MenuItemControl("play",play)) - m.ui.r = 60 return m - -m = get_menu() \ No newline at end of file +m = get_menu() diff --git a/python_payload/apps/flow3r/menu_main.py b/python_payload/apps/flow3r/menu_main.py index e13df1a0e7a14e0b1b7fbb44c588f15700e67293..3378e267214a82dd4479e99ec8283fa060896c17 100644 --- a/python_payload/apps/flow3r/menu_main.py +++ b/python_payload/apps/flow3r/menu_main.py @@ -1,28 +1,34 @@ -from st3m import menu,event,control +from st3m import menu, event, control from apps import demo_worms, cap_touch_demo from apps import demo_sparabo, melodic_demo, harmonic_demo -from apps.flow3r import menu_settings,menu_tinysynth,menu_crazysynth +from apps.flow3r import menu_settings, menu_tinysynth, menu_crazysynth import time + def get_menu(): - menu_main = menu.Menu("flow3r",has_back=False) + menu_main = menu.Menu("flow3r", has_back=False) menu_badge = menu.Menu("badge") menu_apps = menu.Menu("apps") menu_music = menu.Menu("music") - for app_module in [demo_sparabo,melodic_demo,harmonic_demo]: + for app_module in [demo_sparabo, melodic_demo, harmonic_demo]: menu_music.add(menu.MenuItemApp(app_module.app)) - for app_module in [demo_worms,cap_touch_demo,]: + for app_module in [ + demo_worms, + cap_touch_demo, + ]: menu_apps.add(menu.MenuItemApp(app_module.app)) testmenu = menu.Menu("test") item_add = menu.MenuItem("+") - item_add.action = lambda x: testmenu.add(menu.MenuItem("new {}".format(len(testmenu.items)))) + item_add.action = lambda x: testmenu.add( + menu.MenuItem("new {}".format(len(testmenu.items))) + ) item_sub = menu.MenuItem("-") item_sub.action = lambda x: testmenu.pop() if len(testmenu.items) > 4 else None @@ -41,4 +47,3 @@ def get_menu(): menu_music.add(menu.MenuItemSubmenu(menu_crazysynth.get_menu())) return menu_main - diff --git a/python_payload/apps/flow3r/menu_settings.py b/python_payload/apps/flow3r/menu_settings.py index 5436d933d5d1c34f4608cd9e3a0d32736996582b..60d180f7fc75784a02f552c81b6874e7fcb35a35 100644 --- a/python_payload/apps/flow3r/menu_settings.py +++ b/python_payload/apps/flow3r/menu_settings.py @@ -1,125 +1,178 @@ -from st3m import menu,event,control,ui -from st3m.system import audio,hardware +from st3m import menu, event, control, ui +from st3m.system import audio, hardware ui_input = ui.Icon("") + def render_input_data(data): ui_input.label = str(data["angle"]) print("xxx") ui_input.draw() + def set_controls_overlay(value): - print ("set_controls_overlay") + print("set_controls_overlay") if value: event_input_overlay = event.Event( - name="show input overlay", group_id="input-overlay", - #condition=lambda d: d['type'] in ["captouch","button"], - condition=lambda d: d['type'] in ["captouch"] and d['value']==1, - action=render_input_data + name="show input overlay", + group_id="input-overlay", + # condition=lambda d: d['type'] in ["captouch","button"], + condition=lambda d: d["type"] in ["captouch"] and d["value"] == 1, + action=render_input_data, ) else: print("REMOVE") event.the_engine.remove("input-overlay") + def set_volume(value): - db = int(value*60-40) - print("DB",db) + db = int(value * 60 - 40) + print("DB", db) audio.set_volume_dB(db) - + def get_menu(): m = menu.Menu("settings") - control_debug_input=control.ControlSwitch( - name="show inputs", - on_set=set_controls_overlay, - default=False + control_debug_input = control.ControlSwitch( + name="show inputs", on_set=set_controls_overlay, default=False ) item_input_overlay = menu.MenuItemControl("input overlay", control_debug_input) m.add(item_input_overlay) - - m_audio = menu.Menu("audio") m_speaker = menu.Menu("speaker") m_head = menu.Menu("headphones") - vol = control.ControlKnob(name="vol", - on_mod=audio.adjust_volume_dB, - on_get=audio.get_volume_relative + vol = control.ControlKnob( + name="vol", on_mod=audio.adjust_volume_dB, on_get=audio.get_volume_relative + ) + m_audio.add(menu.MenuItemControl("volume", vol)) + m_head.add( + menu.MenuItemControl( + "vol head", + control.ControlKnob( + name="vol", + on_mod=audio.headphones_adjust_volume_dB, + on_get=audio.headphones_get_volume_relative, + ), + ) + ) + + m_speaker.add( + menu.MenuItemControl( + "vol speaker", + control.ControlKnob( + name="vol", + on_mod=audio.speaker_adjust_volume_dB, + on_get=audio.speaker_get_volume_relative, + ), + ) + ) + + m_audio.add( + menu.MenuItemControl( + "mute", + control.ControlSwitch( + name="mute", on_set=audio.set_mute, on_get=audio.get_mute + ), + ) + ) + + m_head.add( + menu.MenuItemControl( + "mute head", + control.ControlSwitch( + name="mute", + on_set=audio.headphones_set_mute, + on_get=audio.headphones_get_mute, + ), + ) + ) + + m_head.add( + menu.MenuItemControl( + "detected headphones", + control.ControlSwitch( + name="connected?", on_get=audio.headphones_are_connected + ), + ) + ) + + m_speaker.add( + menu.MenuItemControl( + "mute speaker", + control.ControlSwitch( + name="mute", + on_set=audio.speaker_set_mute, + on_get=audio.speaker_get_mute, + ), + ) + ) + + m_speaker.add( + menu.MenuItemControl( + "min vol speaker", + control.ControlKnob( + name="min", + min=-40, + max=14, + step=1, + on_set=audio.speaker_set_minimum_volume_dB, + on_get=audio.speaker_get_minimum_volume_dB, + ), + ) + ) + + m_speaker.add( + menu.MenuItemControl( + "max vol speaker", + control.ControlKnob( + name="max", + min=-40, + max=14, + step=1, + on_set=audio.speaker_set_maximum_volume_dB, + on_get=audio.speaker_get_maximum_volume_dB, + ), + ) + ) + + m_head.add( + menu.MenuItemControl( + "min vol headphones", + control.ControlKnob( + name="min", + min=-40, + max=14, + step=1, + on_set=audio.headphones_set_minimum_volume_dB, + on_get=audio.headphones_get_minimum_volume_dB, + ), + ) + ) + + m_head.add( + menu.MenuItemControl( + "max vol headphones", + control.ControlKnob( + name="max", + min=-40, + max=14, + step=1, + on_set=audio.headphones_set_maximum_volume_dB, + on_get=audio.headphones_get_maximum_volume_dB, + ), + ) ) - m_audio.add(menu.MenuItemControl("volume",vol)) - m_head.add(menu.MenuItemControl("vol head",control.ControlKnob( - name="vol", - on_mod=audio.headphones_adjust_volume_dB, - on_get=audio.headphones_get_volume_relative - ))) - - m_speaker.add(menu.MenuItemControl("vol speaker",control.ControlKnob( - name="vol", - on_mod=audio.speaker_adjust_volume_dB, - on_get=audio.speaker_get_volume_relative - ))) - - m_audio.add(menu.MenuItemControl("mute",control.ControlSwitch( - name="mute", - on_set=audio.set_mute, - on_get=audio.get_mute - ))) - - m_head.add(menu.MenuItemControl("mute head",control.ControlSwitch( - name="mute", - on_set=audio.headphones_set_mute, - on_get=audio.headphones_get_mute - ))) - - m_head.add(menu.MenuItemControl("detected headphones",control.ControlSwitch( - name="connected?", - on_get=audio.headphones_are_connected - ))) - - - m_speaker.add(menu.MenuItemControl("mute speaker",control.ControlSwitch( - name="mute", - on_set=audio.speaker_set_mute, - on_get=audio.speaker_get_mute - ))) - - m_speaker.add(menu.MenuItemControl("min vol speaker",control.ControlKnob( - name="min", - min = -40, max =14, step=1, - on_set=audio.speaker_set_minimum_volume_dB, - on_get=audio.speaker_get_minimum_volume_dB - ))) - - m_speaker.add(menu.MenuItemControl("max vol speaker",control.ControlKnob( - name="max", - min = -40, max =14, step=1, - on_set=audio.speaker_set_maximum_volume_dB, - on_get=audio.speaker_get_maximum_volume_dB - ))) - - m_head.add(menu.MenuItemControl("min vol headphones",control.ControlKnob( - name="min", - min = -40, max =14, step=1, - on_set=audio.headphones_set_minimum_volume_dB, - on_get=audio.headphones_get_minimum_volume_dB - ))) - - m_head.add(menu.MenuItemControl("max vol headphones",control.ControlKnob( - name="max", - min = -40, max =14, step=1, - on_set=audio.headphones_set_maximum_volume_dB, - on_get=audio.headphones_get_maximum_volume_dB - ))) m.add(menu.MenuItemSubmenu(m_audio)) m_audio.add(menu.MenuItemSubmenu(m_speaker)) m_audio.add(menu.MenuItemSubmenu(m_head)) - return m + m = get_menu() diff --git a/python_payload/apps/flow3r/menu_tinysynth.py b/python_payload/apps/flow3r/menu_tinysynth.py index ec2d70e148df6dad14cfcfecfdd31ffea14d1542..ddf7346f9ed32110bb77bf83676d287213f7e530 100644 --- a/python_payload/apps/flow3r/menu_tinysynth.py +++ b/python_payload/apps/flow3r/menu_tinysynth.py @@ -1,71 +1,73 @@ from synth import tinysynth -from st3m import menu,event,control,ui -from st3m.system import hardware,audio +from st3m import menu, event, control, ui +from st3m.system import hardware, audio + +synth = tinysynth(440, 0) -synth = tinysynth(440,0) def set_play(value): - print ("set_controls_overlay") + print("set_controls_overlay") if value: synth.start() else: synth.stop() + the_freq = 440 + def set_frequency(value): global the_freq the_freq = value synth.freq(the_freq) - + + def set_pitch(value): - synth.freq(the_freq+the_freq*value) + synth.freq(the_freq + the_freq * value) print("value") - + def get_menu(): m = menu.Menu("tinysynth") - m.add(menu.MenuItemControl("mute",control.ControlSwitch( - name="mute", - on_set=audio.set_mute, - on_get=audio.get_mute - ))) - - freq=control.ControlKnob( + m.add( + menu.MenuItemControl( + "mute", + control.ControlSwitch( + name="mute", on_set=audio.set_mute, on_get=audio.get_mute + ), + ) + ) + + freq = control.ControlKnob( name="freq", on_set=set_frequency, default=the_freq, - min=220,max=440*4,step=10 + min=220, + max=440 * 4, + step=10, ) - m.add_petal(menu.MenuItemControl("freq",freq), petal_index=7) - + m.add_petal(menu.MenuItemControl("freq", freq), petal_index=7) pitch = control.ControlSlide( - name="pitch", - on_set=set_pitch, - default=0, - min=-0.5,max=0.5 + name="pitch", on_set=set_pitch, default=0, min=-0.5, max=0.5 ) - m.add_petal(menu.MenuItemControl("pitch",pitch), petal_index=9) + m.add_petal(menu.MenuItemControl("pitch", pitch), petal_index=9) - - vol = control.ControlKnob(name="vol", - on_mod=audio.adjust_volume_dB, - on_get=audio.get_volume_relative + vol = control.ControlKnob( + name="vol", on_mod=audio.adjust_volume_dB, on_get=audio.get_volume_relative ) - mi_vol = menu.MenuItemControl("volume",vol) + mi_vol = menu.MenuItemControl("volume", vol) + + # m.add(mi_vol) + m.add_petal(mi_vol, 1) - #m.add(mi_vol) - m.add_petal(mi_vol,1) + play = control.ControlSwitch(name="play", on_set=set_play, default=False) + m.add_petal(menu.MenuItemControl("play", play), petal_index=5) - play = control.ControlSwitch(name="play",on_set=set_play,default=False) - m.add_petal(menu.MenuItemControl("play",play), petal_index=5) - m.ui.r = 60 return m - m = get_menu() diff --git a/python_payload/apps/flow3roids.py b/python_payload/apps/flow3roids.py index 6209b8fa40d22b56dd356bcb8da2da69f0497b7f..09670fb7918a528638246aa5c0abbe8918df51cc 100644 --- a/python_payload/apps/flow3roids.py +++ b/python_payload/apps/flow3roids.py @@ -2,23 +2,30 @@ from st3m.application import SimpleApplication app = SimpleApplication("flow3rdroids") + def on_init(): - ship_position = complex(0,0) - ship_direction = complex(0,0) + ship_position = complex(0, 0) + ship_direction = complex(0, 0) + def on_tick(): - if abs(ship_position.real)>240: ship_position.real*=-1 - if abs(ship_position.imag)>240: ship_position.imag*=-1 - + if abs(ship_position.real) > 240: + ship_position.real *= -1 + if abs(ship_position.imag) > 240: + ship_position.imag *= -1 + ship_position += ship_direction + def on_draw(): - ui.Pointer(x=ship_position.imag,y=ship_position.real) + ui.Pointer(x=ship_position.imag, y=ship_position.real) + def on_scroll_step(direction): - #TODO: ship_direction += direction * angle + # TODO: ship_direction += direction * angle pass + def on_enter(): - #TODO:ship_direction += speed + # TODO:ship_direction += speed pass diff --git a/python_payload/apps/harmonic_demo.py b/python_payload/apps/harmonic_demo.py index e211bd92657339c43e589f3967cc86bc243f0877..e759439dc3205996d45c0eed7e8489a097ad7eb3 100644 --- a/python_payload/apps/harmonic_demo.py +++ b/python_payload/apps/harmonic_demo.py @@ -1,25 +1,26 @@ from synth import tinysynth from hardware import * -chords = [\ -[-4,0,3,8,10],\ -[-3,0,5,7,12],\ -[-1,2,5,7,11],\ -[0,3,7,12,14],\ -[3,7,10,14,15]\ +chords = [ + [-4, 0, 3, 8, 10], + [-3, 0, 5, 7, 12], + [-1, 2, 5, 7, 11], + [0, 3, 7, 12, 14], + [3, 7, 10, 14, 15], ] chord_index = 3 chord = chords[3] synths = [] + def set_chord(i): global chord_index global chord - if(i != chord_index): + if i != chord_index: chord_index = i for j in range(40): - hue = int(72*(i+0.5)) % 360 + hue = int(72 * (i + 0.5)) % 360 set_led_hsv(j, hue, 1, 0.2) chord = chords[i] update_leds() @@ -30,27 +31,29 @@ def run(): global chord global synths for i in range(10): - if(get_captouch(i)): - if(i%2): - k = int((i-1)/2) + if get_captouch(i): + if i % 2: + k = int((i - 1) / 2) set_chord(k) else: - k = int(i/2) + k = int(i / 2) synths[k].tone(chord[k]) synths[k].start() + def init(): global chord_index global chord global synths for i in range(5): - synths += [tinysynth(440,1)] + synths += [tinysynth(440, 1)] for synth in synths: synth.decay(100) synth.waveform(1) + def foreground(): global chord_index global chord @@ -59,17 +62,21 @@ def foreground(): chord_index = -1 set_chord(tmp) + from st3m.application import Application + + class HarmonicApp(Application): def on_init(self): init() - #foreground() - + # foreground() + def on_foreground(self): - #foreground() + # foreground() pass - + def main_foreground(self): run() -app=HarmonicApp("harmonic") \ No newline at end of file + +app = HarmonicApp("harmonic") diff --git a/python_payload/apps/melodic_demo.py b/python_payload/apps/melodic_demo.py index 6460bb623ff67c248bd11e7bc8653a1495a80279..ee7c54ec042cd98f4bfcf917c3eca79d4476f605 100644 --- a/python_payload/apps/melodic_demo.py +++ b/python_payload/apps/melodic_demo.py @@ -3,14 +3,16 @@ from hardware import * octave = 0 synths = [] -scale = [0,2,4,5,7,9,11] +scale = [0, 2, 4, 5, 7, 9, 11] + def highlight_bottom_petal(num, r, g, b): - start = 4 + 8*num + start = 4 + 8 * num for i in range(7): - set_led_rgb(((i+start)%40), r, g, b) + set_led_rgb(((i + start) % 40), r, g, b) + -def change_playing_field_color(r,g,b): +def change_playing_field_color(r, g, b): highlight_bottom_petal(0, r, g, b) highlight_bottom_petal(1, r, g, b) highlight_bottom_petal(3, r, g, b) @@ -22,60 +24,67 @@ def change_playing_field_color(r,g,b): set_led_rgb(28, 55, 0, 55) update_leds() + def adjust_playing_field_to_octave(): global octave - if(octave == -1): - change_playing_field_color(0,0,55) - elif(octave == 0): - change_playing_field_color(0,27,27) - elif(octave == 1): - change_playing_field_color(0,55,0) + if octave == -1: + change_playing_field_color(0, 0, 55) + elif octave == 0: + change_playing_field_color(0, 27, 27) + elif octave == 1: + change_playing_field_color(0, 55, 0) + def run(): global scale global octave global synths for i in range(10): - if(get_captouch(i)): - if(i == 4): + if get_captouch(i): + if i == 4: octave = -1 adjust_playing_field_to_octave() - elif(i == 5): + elif i == 5: octave = 0 adjust_playing_field_to_octave() - elif(i == 6): + elif i == 6: octave = 1 adjust_playing_field_to_octave() else: k = i - if(k>3): + if k > 3: k -= 10 k = 3 - k note = scale[k] + 12 * octave synths[0].tone(note) synths[0].start() + def init(): global synths for i in range(1): - synths += [tinysynth(440,1)] + synths += [tinysynth(440, 1)] for synth in synths: synth.decay(100) synth.waveform(1) + def foreground(): adjust_playing_field_to_octave() + from st3m.application import Application + class MelodicApp(Application): def on_init(self): init() - + def on_foreground(self): foreground() - + def main_foreground(self): run() -app=MelodicApp("melodic") \ No newline at end of file + +app = MelodicApp("melodic") diff --git a/python_payload/main.py b/python_payload/main.py index e2ba0258704aacb795a9b6abb6bca351c2d7001a..a1bc38a6b1f2ab194f7cd84b8bd5ca0a9109477e 100644 --- a/python_payload/main.py +++ b/python_payload/main.py @@ -1,22 +1,25 @@ -import gc,time +import gc, time from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info(f"starting main") log.info(f"free memory: {gc.mem_free()}") -from st3m import control,application,ui,menu +from st3m import control, application, ui, menu from apps import flow3r + log.info("import apps done") log.info(f"free memory: {gc.mem_free()}") -#TODO persistent settings -from st3m.system import hardware,audio +# TODO persistent settings +from st3m.system import hardware, audio + log.info("calibrating captouch, reset volume") hardware.captouch_autocalib() audio.set_volume_dB(0) -#Start default app +# Start default app default_app = flow3r.app log.info(f"running default app '{default_app.title}'") -default_app.run() \ No newline at end of file +default_app.run() diff --git a/python_payload/st3m/application.py b/python_payload/st3m/application.py index 60a5e2b2e73013db87a467ee9f5a296eb2dcaab9..bbf54f1405e6c57e0b4791c49bb49e38ba4e3c8e 100644 --- a/python_payload/st3m/application.py +++ b/python_payload/st3m/application.py @@ -1,7 +1,8 @@ from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info("import") -from . import ui,event,menu +from . import ui, event, menu STATE_OFF = 0 STATE_INIT = 10 @@ -10,8 +11,12 @@ STATE_FOREGROUND = 300 STATE_ERROR = 500 log.info("setting up application") -class Application(): - def __init__(self,title="badge23 app", author="someone@earth", exit_on_menu_enter=True): + + +class Application: + def __init__( + self, title="badge23 app", author="someone@earth", exit_on_menu_enter=True + ): log.info(f"__init__ app '{title}'") self.title = title self.author = author @@ -25,23 +30,27 @@ class Application(): self.engine = event.the_engine self.menu = None if exit_on_menu_enter: - self.add_event(event.Event( + self.add_event( + event.Event( name="exit", - action=self.exit, - condition=lambda e: e["type"]=="button" and e.get("from")==2 and e["change"] - )) - + action=self.exit, + condition=lambda e: e["type"] == "button" + and e.get("from") == 2 + and e["change"], + ) + ) + def __repr__(self): - return "App "+self.title + return "App " + self.title + def init(self): log.info(f"init app '{self.title}'") self.state = STATE_INIT self.on_init() if self.has_background: if self._events_background: - self._set_events(self._events_background,True) - engine.register_service_loop(self.main_always,True) - + self._set_events(self._events_background, True) + engine.register_service_loop(self.main_always, True) def run(self): log.info(f"run app '{self.title}' from state {self.state}") @@ -53,39 +62,39 @@ class Application(): elif self.has_background: self._to_background() else: - log.warning(f"App {self.title} has neither foreground nor background, not doing anything") + log.warning( + f"App {self.title} has neither foreground nor background, not doing anything" + ) - #start the eventloop if it is not already running + # start the eventloop if it is not already running if not event.the_engine.is_running: log.info("eventloop not yet running, starting") event.the_engine.eventloop() - - def exit(self,data={}): + def exit(self, data={}): log.info(f"exit app '{self.title}' from state {self.state}") self.on_exit() if self.state == STATE_FOREGROUND: self._to_background() - - + def kill(self): - #disable all events + # disable all events log.info(f"kill app '{self.title}' from state {self.state}") - engine.register_service_loop(self.main_always,False) - + engine.register_service_loop(self.main_always, False) + engine.foreground_app = None - self._set_events(self._events_background,False) - self._set_events(self._events_forground,False) + self._set_events(self._events_background, False) + self._set_events(self._events_forground, False) self.state = STATE_OFF def draw(self): self.ui.draw() self.on_draw() - + def tick(self): self.main_foreground() - def add_event(self,event,is_background=False): + def add_event(self, event, is_background=False): if not is_background: self._events_foreground.append(event) else: @@ -99,33 +108,33 @@ class Application(): if not self.has_foreground: log.error(f"app has no foreground!") return - + if self._events_background: - self._set_events(self_events_background,False) + self._set_events(self_events_background, False) self.state = STATE_FOREGROUND - + if self._events_foreground: - self._set_events(self._events_foreground,True) - - self.ui.ctx.rgb(*ui.BLACK).rectangle(-120,-120,240,240).fill() + self._set_events(self._events_foreground, True) + + self.ui.ctx.rgb(*ui.BLACK).rectangle(-120, -120, 240, 240).fill() self.icon.draw() - + self.on_foreground() - + self.engine.foreground_app = self - + def _to_background(self): log.info(f"to_background app '{self.title}' from state {self.state}") self.state = STATE_BACKGROUND if self._events_foreground: - self._set_events(self._events_foreground,False) + self._set_events(self._events_foreground, False) self.engine.foreground_app = None if self.has_background: self.state = STATE_BACKGROUND self.on_background() - - def _set_events(self,events,enabled=True): + + def _set_events(self, events, enabled=True): for e in events: e.set_enabled(enabled) @@ -137,11 +146,11 @@ class Application(): def on_background(self): log.info(f"app {self.title}: on_background()") - + def on_exit(self): log.info(f"app {self.title}: on_exit()") - def on_kill(self): + def on_kill(self): log.info(f"app {self.title}: on_kill()") def on_draw(self): @@ -149,10 +158,9 @@ class Application(): def main_foreground(self): pass - + def main_always(self): pass - def main(self): self.main_foreground() diff --git a/python_payload/st3m/control.py b/python_payload/st3m/control.py index 47bb02a8a779aa760288b4c299ff5583ac086daa..56322afa7d9e4e08a9abeb234447d48da56c207d 100644 --- a/python_payload/st3m/control.py +++ b/python_payload/st3m/control.py @@ -1,20 +1,22 @@ -from st3m import logging,menu -log = logging.Log(__name__,level=logging.INFO) +from st3m import logging, menu + +log = logging.Log(__name__, level=logging.INFO) log.info("import") from . import ui -class Control(): - def __init__(self,name, default=0, on_set=None, on_get=None, on_mod=None): - #TODO inheritance from Control() - self.name=name + +class Control: + def __init__(self, name, default=0, on_set=None, on_get=None, on_mod=None): + # TODO inheritance from Control() + self.name = name self.on_set = on_set self.on_get = on_get self.on_mod = on_mod if not self.on_get: self._value = default - self.ui = ui.IconValue(label=self.name,size=60, value=self.get_value()) + self.ui = ui.IconValue(label=self.name, size=60, value=self.get_value()) self.ui.get_value = self.get_normal_value self.menu = menu.MenuControl(self) @@ -25,10 +27,10 @@ class Control(): def get_normal_value(self): v = self.get_value() - n = min(1,max(0,v)) + n = min(1, max(0, v)) return n - def get_value(self,update=True): + def get_value(self, update=True): if update and self.on_get: self._value = self.on_get() return self._value @@ -38,45 +40,46 @@ class Control(): if do_trigger: if self.on_set: self.on_set(value) - - def mod_value(self,delta): + + def mod_value(self, delta): self._value = self.on_mod(delta) - def enter_menu(self): menu.submenu_push(self.menu) - - def scroll(self,delta): + + def scroll(self, delta): pass - def touch_1d(self,x,z): + def touch_1d(self, x, z): pass - + + class ControlSwitch(Control): def enter(self): self.set_value(not self.get_value()) self.draw() - def scroll(self,delta): + def scroll(self, delta): self.enter() - def touch_1d(self,x,z): - if z<0: #Release + def touch_1d(self, x, z): + if z < 0: # Release self.enter() class ControlFloat(Control): - def __init__(self, min=0.0,max=1.0,step=0.1, *args, **kwargs): - self.min=min - self.max=max - self.step=step + def __init__(self, min=0.0, max=1.0, step=0.1, *args, **kwargs): + self.min = min + self.max = max + self.step = step super().__init__(*args, **kwargs) def get_normal_value(self): v = self.get_value() - n = (v-self.min)/(self.max-self.min) + n = (v - self.min) / (self.max - self.min) return n + class ControlKnob(ControlFloat): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -84,63 +87,64 @@ class ControlKnob(ControlFloat): self._touch_started_here = False def enter(self): - #repeat action with current value + # repeat action with current value self.set_value(self.get_value()) self.draw() - def scroll(self,delta): + def scroll(self, delta): if self.on_mod: - #print("control: on mod") + # print("control: on mod") self.on_mod(delta) elif self.on_set: v = self.get_value() - v_new = max(self.min,min(self.max,v+delta*self.step)) + v_new = max(self.min, min(self.max, v + delta * self.step)) self.set_value(v_new) self.draw() - def touch_1d(self,x,z): - if z>0: #Inital Contact + def touch_1d(self, x, z): + if z > 0: # Inital Contact self._x_init = x - self._touch_started_here=True + self._touch_started_here = True - if z==0: #Continous contact - if not self._touch_started_here: + if z == 0: # Continous contact + if not self._touch_started_here: return - diff = self._x_init-x - self.scroll(5*diff) - - if z<0: #Release + diff = self._x_init - x + self.scroll(5 * diff) + + if z < 0: # Release self._touch_started_here = False class ControlSlide(ControlFloat): def __init__(self, do_reset=True, *args, **kwargs): - self.do_reset=do_reset + self.do_reset = do_reset self._saved_value = None super().__init__(*args, **kwargs) - def touch_1d(self,x,z): - if z>0: #Inital Contact + def touch_1d(self, x, z): + if z > 0: # Inital Contact self._saved_value = self.get_value() - if self._saved_value is None: return - + if self._saved_value is None: + return - if z==0: #Continous contact - - v = (self.max-self.min)*x+self.min + if z == 0: # Continous contact + v = (self.max - self.min) * x + self.min self.set_value(v) - #print("c",x,v,self.max,self.min) + # print("c",x,v,self.max,self.min) - if z<0: #Release + if z < 0: # Release if self.do_reset: self.set_value(self._saved_value) self._saved_value = None self.draw() + class ControlString(Control): pass -class ControlTextField(): - pass \ No newline at end of file + +class ControlTextField: + pass diff --git a/python_payload/st3m/event.py b/python_payload/st3m/event.py index 36e96f8aa52d445c4e4d33caeace9bcf929b995b..99982163815297e78a2ba67fc003918076e02ea6 100644 --- a/python_payload/st3m/event.py +++ b/python_payload/st3m/event.py @@ -1,21 +1,23 @@ from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info("import") from st3m.system import hardware -import time +import time import math import random EVENTTYPE_TIMED = 1 EVENTTYPE_INPUT = 2 -#EVENTTYPE_BUTTON = 2 -#EVENTTYPE_CAPTOUCH = 3 -#EVENTTYPE_CAPCROSS = 4 +# EVENTTYPE_BUTTON = 2 +# EVENTTYPE_CAPTOUCH = 3 +# EVENTTYPE_CAPCROSS = 4 + -class Engine(): +class Engine: def __init__(self): self.events_timed = [] self.events_input = [] @@ -26,109 +28,110 @@ class Engine(): self.foreground_app = None self.active_menu = None - def add(self,event): - if isinstance(event,EventTimed): + def add(self, event): + if isinstance(event, EventTimed): self.add_timed(event) - elif isinstance(event,Event): + elif isinstance(event, Event): self.add_input(event) - - def add_timed(self,event): + + def add_timed(self, event): self.events_timed.append(event) self._sort_timed() - def add_input(self,event): + def add_input(self, event): self.events_input.append(event) - def remove(self,group_id): + def remove(self, group_id): self.remove_input(group_id) self.remove_timed(group_id) - def remove_timed(self,group_id): - #print("before:",len(self.events_timed)) - self.events_timed = [event for event in self.events_timed if event.group_id!=group_id] + def remove_timed(self, group_id): + # print("before:",len(self.events_timed)) + self.events_timed = [ + event for event in self.events_timed if event.group_id != group_id + ] self._sort_timed() - #print("after",len(self.events_timed)) - - def remove_input(self,group_id): - self.events_input = [event for event in self.events_input if event.group_id!=group_id] + # print("after",len(self.events_timed)) + + def remove_input(self, group_id): + self.events_input = [ + event for event in self.events_input if event.group_id != group_id + ] def _sort_timed(self): - self.events_timed = sorted(self.events_timed, key = lambda event: event.deadline) + self.events_timed = sorted(self.events_timed, key=lambda event: event.deadline) - def _handle_timed(self): if not self.next_timed and self.events_timed: self.next_timed = self.events_timed.pop(0) - + now = time.ticks_ms() - + if self.next_timed: diff = time.ticks_diff(self.next_timed.deadline, now) if diff <= 0: - self.next_timed.trigger({"ticks_ms":now, "ticks_delay": -diff}) + self.next_timed.trigger({"ticks_ms": now, "ticks_delay": -diff}) self.next_timed = None - + def _handle_input(self): input_state = [] - #buttons - input_state.append({ - "type" : "button", - "index" : 0, - "value" : hardware.menu_button_get() - }) - - input_state.append({ - "type" : "button", - "index" : 1, - "value" : hardware.application_button_get() - }) - - #captouch - for i in range(0,10): - input_state.append({ - "type" : "captouch", - "index" : i, - "value" : hardware.get_captouch(i), - "radius" : hardware.captouch_get_petal_rad(i), - "angle" : hardware.captouch_get_petal_phi(i)/10000 - }) - - + # buttons + input_state.append( + {"type": "button", "index": 0, "value": hardware.menu_button_get()} + ) + + input_state.append( + {"type": "button", "index": 1, "value": hardware.application_button_get()} + ) + + # captouch + for i in range(0, 10): + input_state.append( + { + "type": "captouch", + "index": i, + "value": hardware.get_captouch(i), + "radius": hardware.captouch_get_petal_rad(i), + "angle": hardware.captouch_get_petal_phi(i) / 10000, + } + ) + if not self.last_input_state: - self.last_input_state=input_state - #tprint (input_state) + self.last_input_state = input_state + # tprint (input_state) return - + for i in range(len(input_state)): entry = input_state[i] last_entry = self.last_input_state[i] - - #update for all + + # update for all entry["ticks_ms"] = time.ticks_ms() if entry["value"] != last_entry["value"]: - #update only when value changed + # update only when value changed entry["change"] = True entry["from"] = last_entry["value"] else: - #update only when value did not change - entry["change"] = False + # update only when value did not change + entry["change"] = False - #find and trigger the events q - triggered_events = list(filter(lambda e: e.enabled and e.condition(entry),self.events_input)) - #print (triggered_events) - #map(lambda e: e.trigger(d), triggered_events) + # find and trigger the events q + triggered_events = list( + filter(lambda e: e.enabled and e.condition(entry), self.events_input) + ) + # print (triggered_events) + # map(lambda e: e.trigger(d), triggered_events) for e in triggered_events: e.trigger(entry) - - self.last_input_state=input_state - + + self.last_input_state = input_state + def _handle_userloop(self): if self.foreground_app: self.foreground_app.tick() - def _handle_draw(self): if self.foreground_app: self.foreground_app.draw() @@ -136,38 +139,44 @@ class Engine(): self.active_menu.draw() hardware.display_update() - - def _eventloop_single(self): self._handle_timed() self._handle_input() self._handle_userloop() - - + def eventloop(self): log.info("starting eventloop") if self.is_running: log.warning("eventloop already running, doing nothing") return - self.is_running=True + self.is_running = True last_draw = 0 while self.is_running: self._eventloop_single() now = time.ticks_ms() - diff = time.ticks_diff(now,last_draw) - #print("diff:",diff) - if diff>10: - #print("eventloop draw") + diff = time.ticks_diff(now, last_draw) + # print("diff:",diff) + if diff > 10: + # print("eventloop draw") self._handle_draw() last_draw = time.ticks_ms() - #self.deadline = time.ticks_add(time.ticks_ms(),ms) - + # self.deadline = time.ticks_add(time.ticks_ms(),ms) + time.sleep_ms(1) - -class Event(): - def __init__(self,name="unknown",data={},action=None,condition=None,group_id=None,enabled=False): - #print (action) + + +class Event: + def __init__( + self, + name="unknown", + data={}, + action=None, + condition=None, + group_id=None, + enabled=False, + ): + # print (action) self.name = name self.eventtype = None self.data = data @@ -176,22 +185,19 @@ class Event(): self.enabled = enabled if not condition: self.condition = lambda x: True - self.group_id=group_id - + self.group_id = group_id + if enabled: self.set_enabled() - - - - def trigger(self,triggerdata={}): - log.debug("triggered {} (with {})".format(self.name,triggerdata)) + def trigger(self, triggerdata={}): + log.debug("triggered {} (with {})".format(self.name, triggerdata)) if not self.action is None: triggerdata.update(self.data) self.action(triggerdata) - - def set_enabled(self,enabled=True): - self.enabled=enabled + + def set_enabled(self, enabled=True): + self.enabled = enabled if enabled: the_engine.add(self) else: @@ -200,27 +206,28 @@ class Event(): def remove(self): log.info(f"remove {self}") while self in the_engine.events_input: - #print ("from input") + # print ("from input") the_engine.events_input.remove(self) while self in the_engine.events_timed: - #print("from timed") + # print("from timed") the_engine.events_timed.remove(self) the_engine._sort_timed() + class EventTimed(Event): - def __init__(self,ms,name="timer", *args, **kwargs): - #super().__init__(name,data,action) - self.deadline = time.ticks_add(time.ticks_ms(),ms) - + def __init__(self, ms, name="timer", *args, **kwargs): + # super().__init__(name,data,action) + self.deadline = time.ticks_add(time.ticks_ms(), ms) + super().__init__(*args, **kwargs) - self.name=name - self.type=EVENTTYPE_TIMED - + self.name = name + self.type = EVENTTYPE_TIMED + def __repr__(self): - return ("event on tick {} ({})".format(self.deadline,self.name)) + return "event on tick {} ({})".format(self.deadline, self.name) -#hack, make this oo +# hack, make this oo def on_restart(data): print("loop sequence") obj = data["object"] @@ -228,40 +235,57 @@ def on_restart(data): obj.start() - -class Sequence(): - def __init__(self,bpm=60,loop=True,steps=16,action=None): - self.group_id = random.randint(0,100000000) +class Sequence: + def __init__(self, bpm=60, loop=True, steps=16, action=None): + self.group_id = random.randint(0, 100000000) self.bpm = bpm self.steps = steps self.repeat_event = None self.loop = loop self.events = [] self.is_running = False - + if not action: self.action = lambda data: log.info("step {}".format(data.get("step"))) else: self.action = action - + def start(self): - if self.is_running: self.stop() - stepsize_ms = int(60*1000/self.bpm) + if self.is_running: + self.stop() + stepsize_ms = int(60 * 1000 / self.bpm) for i in range(self.steps): log.debug(f"adding sequence event {i}") - self.events.append(EventTimed(stepsize_ms*i,name="seq{}".format(i),action=self.action, data={'step':i}, group_id=self.group_id,enabled=True)) + self.events.append( + EventTimed( + stepsize_ms * i, + name="seq{}".format(i), + action=self.action, + data={"step": i}, + group_id=self.group_id, + enabled=True, + ) + ) if self.loop: - self.repeat_event=EventTimed(stepsize_ms*self.steps,name="loop", group_id=self.group_id, enabled=True, action=on_restart, data={"object":self}) - self.is_running=True - + self.repeat_event = EventTimed( + stepsize_ms * self.steps, + name="loop", + group_id=self.group_id, + enabled=True, + action=on_restart, + data={"object": self}, + ) + self.is_running = True + def stop(self): - #for e in self.events: e.remove() + # for e in self.events: e.remove() log.info("sequence stop") the_engine.remove_timed(group_id=self.group_id) self.events = [] - if self.repeat_event: self.repeat_event.remove() - self.is_running=False - - + if self.repeat_event: + self.repeat_event.remove() + self.is_running = False + + global the_engine the_engine = Engine() diff --git a/python_payload/st3m/logging.py b/python_payload/st3m/logging.py index e2c19e4739d671b1df5352c66afdfb90cfddb955..69af2f4598a5d8ea3c8e65b43586f1f592e3a585 100644 --- a/python_payload/st3m/logging.py +++ b/python_payload/st3m/logging.py @@ -5,36 +5,38 @@ INFO = 1 WARNING = 2 ERROR = 3 -#this is so ugly, but works -levels = ["DEBUG","INFO","WARNING","ERROR"] +# this is so ugly, but works +levels = ["DEBUG", "INFO", "WARNING", "ERROR"] -class Log(): - def __init__(self,name="log",level=INFO): + +class Log: + def __init__(self, name="log", level=INFO): self.name = name self.level = level self.logstring = "{timestamp} {name} ({level}): {msg}" - - def debug(self,msg): - self.message(msg,DEBUG) - - def info(self,msg): - self.message(msg,INFO) - - def warning(self,msg): - self.message(msg,WARNING) - - def error(self,msg): - self.message(msg,ERROR) - - def message(self,msg,level): + def debug(self, msg): + self.message(msg, DEBUG) + + def info(self, msg): + self.message(msg, INFO) + + def warning(self, msg): + self.message(msg, WARNING) + + def error(self, msg): + self.message(msg, ERROR) + + def message(self, msg, level): if self.level <= level: - self._emit(self.logstring.format( - timestamp = time.ticks_ms()/1000, - name=self.name, - msg = msg, - level = levels[level]) - ) - - def _emit(self,line): - print(line) \ No newline at end of file + self._emit( + self.logstring.format( + timestamp=time.ticks_ms() / 1000, + name=self.name, + msg=msg, + level=levels[level], + ) + ) + + def _emit(self, line): + print(line) diff --git a/python_payload/st3m/menu.py b/python_payload/st3m/menu.py index 51d1de6ab729ca5c7452253987424d313d0c9794..203810339f60f92ec27741135e9270fef4fe98a7 100644 --- a/python_payload/st3m/menu.py +++ b/python_payload/st3m/menu.py @@ -1,8 +1,9 @@ from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info("import") -from . import ui,event +from . import ui, event import time @@ -10,34 +11,36 @@ import math menu_stack = [] -class Menu(): - def __init__(self,name="menu",has_back=True): - self.name=name - self.items=[] - self.items_petal=[None for i in range(10)] + +class Menu: + def __init__(self, name="menu", has_back=True): + self.name = name + self.items = [] + self.items_petal = [None for i in range(10)] self.__index = 0 self.ui = ui.GroupRing(r=80) - self.ui2 = ui.GroupPetals(r=100) #TODO(iggy) hack, this should be composed together in ui - self.icon = ui.IconFlower(label=name,size=80) + self.ui2 = ui.GroupPetals( + r=100 + ) # TODO(iggy) hack, this should be composed together in ui + self.icon = ui.IconFlower(label=name, size=80) self.ui.element_center = self.icon - + self.angle = 0 - self.angle_step= 0.2 + self.angle_step = 0.2 if has_back: self.add(MenuItemBack()) - def __repr__(self): return "{} ({}): {}".format(self.name, self.__index, self.items) def add(self, item): self.items.append(item) self.ui.add(item.ui) - + def add_petal(self, item, petal_index): - self.items_petal[petal_index]=item - self.ui2.children[petal_index]=item.ui + self.items_petal[petal_index] = item + self.ui2.children[petal_index] = item.ui def pop(self): self.items.pop() @@ -47,161 +50,164 @@ class Menu(): log.info(f"starting menu {self.name}") set_active_menu(self) - #def scroll(self, n=0): + # def scroll(self, n=0): # self.__index= (self.__index+n)%len(self.items) # return self.items[self.__index] - + def scroll_app(self, delta): - hovered=self.get_hovered_item() + hovered = self.get_hovered_item() if hasattr(hovered, "scroll"): hovered.scroll(delta) def scroll_menu(self, delta): - if self.angle_step<0.5: - self.angle_step+=0.025 + if self.angle_step < 0.5: + self.angle_step += 0.025 self.rotate_steps(delta) - def enter_menu(self,data={}): - hovered=self.get_hovered_item() + def enter_menu(self, data={}): + hovered = self.get_hovered_item() if hasattr(hovered, "enter_menu"): hovered.enter_menu() else: hovered.enter() - - def enter_app(self,data={}): - hovered=self.get_hovered_item() + + def enter_app(self, data={}): + hovered = self.get_hovered_item() if hasattr(hovered, "enter_app"): hovered.enter_app() else: hovered.enter() - def rotate_by(self,angle): - self.rotate_to(self.angle+angle) - + def rotate_by(self, angle): + self.rotate_to(self.angle + angle) + def rotate_to(self, angle): - self.angle = angle%(math.pi*2) + self.angle = angle % (math.pi * 2) self.ui.angle_offset = self.angle - #for child in self.ui.children: + # for child in self.ui.children: # child.angle_offset = self.angle*2 self.icon.phi_offset = self.angle - + def rotate_steps(self, steps=1): - self.rotate_by(-self.angle_step*steps) - + self.rotate_by(-self.angle_step * steps) + def _get_hovered_index(self): - index = round(-self.angle/(math.pi*2)*len(self.items)) - i = index%len(self.items) + index = round(-self.angle / (math.pi * 2) * len(self.items)) + i = index % len(self.items) return i def get_hovered_item(self): return self.items[self._get_hovered_index()] - - def _get_angle_for_index(self,index): - return (math.pi*2/len(self.items)*(index)+self.angle)%(math.pi*2) - def _get_topness_for_index(self,index): + def _get_angle_for_index(self, index): + return (math.pi * 2 / len(self.items) * (index) + self.angle) % (math.pi * 2) + + def _get_topness_for_index(self, index): angle = self._get_angle_for_index(index) - dist = min(angle,math.pi*2-angle) - topness = 1-(dist/math.pi) + dist = min(angle, math.pi * 2 - angle) + topness = 1 - (dist / math.pi) return topness - - def draw(self): - - #TODO this is more like a hack... - #if not self==active_menu: + # TODO this is more like a hack... + # if not self==active_menu: # active_menu.draw() # return - #print("draw",self.name) + # print("draw",self.name) hovered_index = self._get_hovered_index() for i in range(len(self.items)): item = self.items[i] - my_extra = abs(self._get_topness_for_index(i))*40 - + my_extra = abs(self._get_topness_for_index(i)) * 40 + if i == hovered_index: - item.ui.has_highlight=True - my_extra+=20 + item.ui.has_highlight = True + my_extra += 20 else: - item.ui.has_highlight=False - item.ui.size=30+my_extra - - #black background - #TODO transparent menu with compositing - ui.the_ctx.rectangle(-120,-120,240,240).rgb(*ui.BLACK).fill() - + item.ui.has_highlight = False + item.ui.size = 30 + my_extra + + # black background + # TODO transparent menu with compositing + ui.the_ctx.rectangle(-120, -120, 240, 240).rgb(*ui.BLACK).fill() + self.ui2.draw() self.ui.draw() + class MenuControl(Menu): - def __init__(self,control,*args,**kwargs): - super().__init__(*args,**kwargs) + def __init__(self, control, *args, **kwargs): + super().__init__(*args, **kwargs) self.control = control self.ui.element_center = self.control.ui def scroll_app(self, delta): - hovered=self.get_hovered_item() + hovered = self.get_hovered_item() if hasattr(hovered, "scroll"): hovered.scroll(delta) else: self.control.scroll(delta) - def enter_app(self,data={}): - hovered=self.get_hovered_item() + def enter_app(self, data={}): + hovered = self.get_hovered_item() if hasattr(hovered, "enter_app"): hovered.enter_app() else: self.control.enter() -class MenuItem(): - def __init__(self,name="item",action=None): - self.name= name - self.action= action + +class MenuItem: + def __init__(self, name="item", action=None): + self.name = name + self.action = action self.ui = ui.IconFlower(label=name) def __repr__(self): - return "item: {} (action: {})".format(self.name,"?") + return "item: {} (action: {})".format(self.name, "?") - def enter(self,data={}): + def enter(self, data={}): log.info("enter MenuItem {}".format(self.name)) if self.action: self.action(data) + class MenuItemApp(MenuItem): - def __init__(self,app): + def __init__(self, app): super().__init__(name=app.title) self.target = app - - def enter(self,data={}): + + def enter(self, data={}): if self.target: submenu_push(None) self.target.run() + class MenuItemSubmenu(MenuItem): - def __init__(self,submenu): + def __init__(self, submenu): super().__init__(name=submenu.name) self.ui = submenu.icon self.target = submenu - - def enter_menu(self,data={}): + + def enter_menu(self, data={}): log.info("item submenu enter") submenu_push(self.target) - + + class MenuItemBack(MenuItem): def __init__(self): super().__init__(name="") self.ui = ui.IconLabel(label="back") - - def enter_menu(self,data={}): - log.info (f"item back selected") + + def enter_menu(self, data={}): + log.info(f"item back selected") menu_back() + class MenuItemControl(MenuItem): - def __init__(self,name,control): + def __init__(self, name, control): super().__init__(name=name) - self.control=control - self.ui=control.ui + self.control = control + self.ui = control.ui def enter_menu(self): log.info(f"item {self.name} (MenuItemControl): enter_menu->enter") @@ -211,133 +217,154 @@ class MenuItemControl(MenuItem): log.info(f"item {self.name} (MenuItemControl): enter->enter menu") self.control.enter_menu() - def scroll(self,delta): + def scroll(self, delta): self.control.scroll(delta) - def touch_1d(self,x,z): - self.control.touch_1d(x,z) - + def touch_1d(self, x, z): + self.control.touch_1d(x, z) + + def on_scroll(d): active_menu = get_active_menu() if active_menu is None: return - if d["index"]==0:#right button + if d["index"] == 0: # right button active_menu.scroll_app(d["value"]) - else: #index=1, #left button + else: # index=1, #left button active_menu.scroll_menu(d["value"]) - def on_scroll_captouch(d): active_menu = get_active_menu() if active_menu is None: return - + return if abs(d["radius"]) < 10000: return - active_menu.rotate_to(d["angle"]+math.pi) + active_menu.rotate_to(d["angle"] + math.pi) + def on_release(d): active_menu = get_active_menu() - + if active_menu is None: return active_menu.angle_step = 0.2 - def on_touch_1d(d): active_menu = get_active_menu() - + if active_menu is None: return - v = min(1.0,max(0.0,((d["radius"]+25000.0)/50000.0))) + v = min(1.0, max(0.0, ((d["radius"] + 25000.0) / 50000.0))) z = 0 if d["change"]: - if d["value"] == 1: z=1 - else: z=-1 - + if d["value"] == 1: + z = 1 + else: + z = -1 + log.debug(f"menu: touch_1d ({v},{z})") - hovered=active_menu.get_hovered_item() - + hovered = active_menu.get_hovered_item() petal_idx = d["index"] petal_item = active_menu.items_petal[petal_idx] if petal_item: - petal_item.touch_1d(v,z) + petal_item.touch_1d(v, z) - if hasattr(hovered, "touch_1d"): - hovered.touch_1d(v,z) - + hovered.touch_1d(v, z) + def on_enter(d): active_menu = get_active_menu() - - #if active_menu is None: + + # if active_menu is None: # log.info("menu enter without active menu, opening last menu") # menu_back() # return if active_menu: - if d["index"]==0: #right button + if d["index"] == 0: # right button log.info("menu enter_app") active_menu.enter_app() - + else: log.info("menu enter_menu") active_menu.enter_menu() - - -event.Event(name="menu rotation button",group_id="menu", - condition=lambda e: e["type"] =="button" and not e["change"] and abs(e["value"])==1, - action=on_scroll, enabled=True + + +event.Event( + name="menu rotation button", + group_id="menu", + condition=lambda e: e["type"] == "button" + and not e["change"] + and abs(e["value"]) == 1, + action=on_scroll, + enabled=True, ) -#event.Event(name="menu rotation captouch",group_id="menu", +# event.Event(name="menu rotation captouch",group_id="menu", # condition=lambda e: e["type"] =="captouch" and not e["change"] and abs(e["value"])==1 and e["index"]==2, # action=on_scroll_captouch, enabled=True -#) +# ) -event.Event(name="menu rotation button release",group_id="menu", - condition=lambda e: e["type"] =="button" and e["change"] and e["value"] ==0, - action=on_release, enabled=True +event.Event( + name="menu rotation button release", + group_id="menu", + condition=lambda e: e["type"] == "button" and e["change"] and e["value"] == 0, + action=on_release, + enabled=True, ) -event.Event(name="menu 1d captouch",group_id="menu", - condition=lambda e: e["type"] =="captouch" and (e["value"]==1 or e["change"]) and e["index"]%2==1, - action=on_touch_1d, enabled=True +event.Event( + name="menu 1d captouch", + group_id="menu", + condition=lambda e: e["type"] == "captouch" + and (e["value"] == 1 or e["change"]) + and e["index"] % 2 == 1, + action=on_touch_1d, + enabled=True, ) -event.Event(name="menu button enter",group_id="menu", - condition=lambda e: e["type"] =="button" and e["change"] and e["from"] == 2, - action=on_enter, enabled=True +event.Event( + name="menu button enter", + group_id="menu", + condition=lambda e: e["type"] == "button" and e["change"] and e["from"] == 2, + action=on_enter, + enabled=True, ) def set_active_menu(menu): event.the_engine.active_menu = menu + def get_active_menu(): return event.the_engine.active_menu + def menu_back(): previous = menu_stack.pop() log.info(f"back to previous menu {previous.name} (Stack: {len(menu_stack)})") set_active_menu(previous) + def submenu_push(new_menu): active = get_active_menu() menu_stack.append(active) active.rotate_to(0) if new_menu: - log.info(f"enter submenu {new_menu.name} from {active.name} (Stack: {len(menu_stack)})") + log.info( + f"enter submenu {new_menu.name} from {active.name} (Stack: {len(menu_stack)})" + ) else: log.info(f"leaving menu from {active.name}") - set_active_menu(new_menu) \ No newline at end of file + set_active_menu(new_menu) diff --git a/python_payload/st3m/system/__init__.py b/python_payload/st3m/system/__init__.py index 2960c66a23714654ef01cabbbbcdb8d490e9ba20..9a2976b8449f699ec758a72f3ca811d6683383c2 100644 --- a/python_payload/st3m/system/__init__.py +++ b/python_payload/st3m/system/__init__.py @@ -1,22 +1,23 @@ import hardware as _hardware -class NamedObject(): - def __init__(self,name="foo"): + +class NamedObject: + def __init__(self, name="foo"): self.__name = name - + def __repr__(self): return self.__name + class MockObject(NamedObject): - - def __getattr__(self,attr): - attr_name = "{}.{}".format(str(self),attr) - print ("mock attr", attr_name) + def __getattr__(self, attr): + attr_name = "{}.{}".format(str(self), attr) + print("mock attr", attr_name) return MockObject(attr_name) - def __call__(self,*args,**kwargs): - call_name = "{}({}{})".format(str(self),args,kwargs) - print ("mock call",call_name) + def __call__(self, *args, **kwargs): + call_name = "{}({}{})".format(str(self), args, kwargs) + print("mock call", call_name) return MockObject(call_name) @@ -37,4 +38,4 @@ except ModuleNotFoundError: hardware = _hardware audio = _audio -ctx =hardware.get_ctx() \ No newline at end of file +ctx = hardware.get_ctx() diff --git a/python_payload/st3m/ui.py b/python_payload/st3m/ui.py index 063a9f4453d0dab5cfaec791032f05d5a41aa7c6..f81f45e6d45088501a0adf6813814ba9df55762a 100644 --- a/python_payload/st3m/ui.py +++ b/python_payload/st3m/ui.py @@ -1,86 +1,92 @@ from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info("import") from st3m.system import ctx import random import math import time -from math import sin,cos,pi +from math import sin, cos, pi import gc WIDTH = 240 HEIGHT = 240 -#Define a few RGB (0.0 to 1.0) colors -BLACK = (0,0,0) -RED = (1,0,0) -GREEN = (0,1,0) -BLUE = (0,0,1) -WHITE = (1,1,1) -GREY = (0.5,0.5,0.5) -GO_GREEN = (63/255,255/255,33/53) -PUSH_RED = (251/255,72/255,196/255) +# Define a few RGB (0.0 to 1.0) colors +BLACK = (0, 0, 0) +RED = (1, 0, 0) +GREEN = (0, 1, 0) +BLUE = (0, 0, 1) +WHITE = (1, 1, 1) +GREY = (0.5, 0.5, 0.5) +GO_GREEN = (63 / 255, 255 / 255, 33 / 53) +PUSH_RED = (251 / 255, 72 / 255, 196 / 255) the_ctx = ctx + # Utility functions -def xy_from_polar(r,phi): - return ( - r * math.sin(phi), #x - r * math.cos(phi) #y - ) +def xy_from_polar(r, phi): + return (r * math.sin(phi), r * math.cos(phi)) # x # y + -#def ctx_circle(self, x,y, radius, arc_from = -math.pi, arc_to = math.pi): +# def ctx_circle(self, x,y, radius, arc_from = -math.pi, arc_to = math.pi): # return self.arc(x,y,radius,arc_from,arc_to,True) -#the_ctx.circle = ctx_circle +# the_ctx.circle = ctx_circle + def randrgb(): - return ((random.random(),random.random(),random.random())) + return (random.random(), random.random(), random.random()) + -class UIElement(): - def __init__(self,origin=(0,0)): +class UIElement: + def __init__(self, origin=(0, 0)): self.children = [] self.origin = origin self.ctx = the_ctx - - def draw(self, offset=(0,0)): - pos = (self.origin[0]+offset[0],self.origin[1]+offset[1]) + + def draw(self, offset=(0, 0)): + pos = (self.origin[0] + offset[0], self.origin[1] + offset[1]) self._draw(pos) for child in self.children: child.draw(pos) - - - def _draw(self,pos): + def _draw(self, pos): pass def add(self, child): self.children.append(child) + class Viewport(UIElement): - def _draw(self,pos): + def _draw(self, pos): pass - #self.ctx.rgb(0.3,0.3,0.3).rectangle(-WIDTH/2,-HEIGHT/2,WIDTH,HEIGHT).fill() + # self.ctx.rgb(0.3,0.3,0.3).rectangle(-WIDTH/2,-HEIGHT/2,WIDTH,HEIGHT).fill() + class Circle(UIElement): - def __init__(self,radius,color=PUSH_RED,arc_from=-math.pi, arc_to=math.pi, *args, **kwargs): + def __init__( + self, radius, color=PUSH_RED, arc_from=-math.pi, arc_to=math.pi, *args, **kwargs + ): self.radius = radius self.color = color self.arc_from = arc_from self.arc_to = arc_to super().__init__() - - def _draw(self,pos): - (x,y)=pos - self.ctx.move_to(x,y).rgb(*self.color).arc(x,y,self.radius,self.arc_from,self.arc_to,True).fill() + + def _draw(self, pos): + (x, y) = pos + self.ctx.move_to(x, y).rgb(*self.color).arc( + x, y, self.radius, self.arc_from, self.arc_to, True + ).fill() class Text(UIElement): - def __init__(self,s="foo"): + def __init__(self, s="foo"): self.s = s super().__init__() @@ -88,101 +94,132 @@ class Text(UIElement): self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE self.ctx.font_size = 30 - self.ctx.rgb(1,1,1).move_to(pos[0],pos[1]).text(self.s) + self.ctx.rgb(1, 1, 1).move_to(pos[0], pos[1]).text(self.s) + class Icon(UIElement): - def __init__(self,label="?", size=60): - self.bg = (random.random(),random.random(),random.random()) + def __init__(self, label="?", size=60): + self.bg = (random.random(), random.random(), random.random()) self.fg = 0 - self.label=label - self.size=size + self.label = label + self.size = size self.has_highlight = False super().__init__() - def _draw(self,pos): + def _draw(self, pos): self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE - self.ctx.font_size=self.size/3 + self.ctx.font_size = self.size / 3 - (x,y)=pos + (x, y) = pos hs = 5 - - if self.has_highlight: - self.ctx.rgb(*GO_GREEN).arc(x,y, self.size/2+hs,-math.pi,math.pi,True).fill() - self.ctx.move_to(x,y).rgb(*self.bg).arc(x,y,self.size/2,-math.pi,math.pi,True).fill() - y += self.size/3 - width = max(self.size-10, self.ctx.text_width(self.label))+10 - height = self.size/3+8 if self.has_highlight: - self.ctx.rgb(*BLACK).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() - self.ctx.rgb(*GO_GREEN).move_to(x,y).text(self.label) + self.ctx.rgb(*GO_GREEN).arc( + x, y, self.size / 2 + hs, -math.pi, math.pi, True + ).fill() + self.ctx.move_to(x, y).rgb(*self.bg).arc( + x, y, self.size / 2, -math.pi, math.pi, True + ).fill() + + y += self.size / 3 + width = max(self.size - 10, self.ctx.text_width(self.label)) + 10 + height = self.size / 3 + 8 + if self.has_highlight: + self.ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle( + x - width / 2, y - height / 2, width, height, width // 2 + ).fill() + self.ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label) else: - self.ctx.rgb(*PUSH_RED).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() - self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) + self.ctx.rgb(*PUSH_RED).move_to(x, y - height / 2).round_rectangle( + x - width / 2, y - height / 2, width, height, width // 2 + ).fill() + self.ctx.rgb(*BLACK).move_to(x, y).text(self.label) + class IconLabel(Icon): - def _draw(self,pos): + def _draw(self, pos): self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE - self.ctx.font_size=self.size/2 + self.ctx.font_size = self.size / 2 - (x,y)=pos + (x, y) = pos hs = 5 - width = self.ctx.text_width(self.label)+10 - height = self.size/2 + width = self.ctx.text_width(self.label) + 10 + height = self.size / 2 if self.has_highlight: - self.ctx.rgb(*GO_GREEN).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() - self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) + self.ctx.rgb(*GO_GREEN).move_to(x, y - height / 2).round_rectangle( + x - width / 2, y - height / 2, width, height, width // 2 + ).fill() + self.ctx.rgb(*BLACK).move_to(x, y).text(self.label) else: - self.ctx.rgb(*PUSH_RED).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() - self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) + self.ctx.rgb(*PUSH_RED).move_to(x, y - height / 2).round_rectangle( + x - width / 2, y - height / 2, width, height, width // 2 + ).fill() + self.ctx.rgb(*BLACK).move_to(x, y).text(self.label) + class IconFlower(Icon): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.petal_count= random.randint(3,5) - #self.petal_count = 0 - self.petal_color = (random.random(),random.random(),random.random()) + self.petal_count = random.randint(3, 5) + # self.petal_count = 0 + self.petal_color = (random.random(), random.random(), random.random()) self.phi_offset = random.random() - self.size_offset = random.randint(0,20) - #self.bg=PUSH_RED - - def _draw(self,pos): + self.size_offset = random.randint(0, 20) + # self.bg=PUSH_RED + + def _draw(self, pos): self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE - self.ctx.font_size=self.size/3 + self.ctx.font_size = self.size / 3 - (x,y)=pos - petal_size=0 + (x, y) = pos + petal_size = 0 if self.petal_count: - petal_size=2.3*self.size/self.petal_count+self.size_offset + petal_size = 2.3 * self.size / self.petal_count + self.size_offset hs = 5 - + for i in range(self.petal_count): - phi = math.pi*2 / self.petal_count * i + self.phi_offset - r = self.size/2 - (x_,y_) = xy_from_polar(r, phi) - size_rnd = random.randint(-1,1) + phi = math.pi * 2 / self.petal_count * i + self.phi_offset + r = self.size / 2 + (x_, y_) = xy_from_polar(r, phi) + size_rnd = random.randint(-1, 1) if self.has_highlight: - self.ctx.move_to(x+x_,y+y_).rgb(*GO_GREEN).arc(x+x_,y+y_, petal_size/2+hs+size_rnd,-math.pi,math.pi,True).fill() - self.ctx.move_to(x+x_,y+y_).rgb(*self.petal_color).arc(x+x_,y+y_, petal_size/2+size_rnd,-math.pi,math.pi,True).fill() - - if self.has_highlight: - self.ctx.rgb(*GO_GREEN).arc(x,y, self.size/2+hs,-math.pi,math.pi,True).fill() - self.ctx.move_to(x,y).rgb(*self.bg).arc(x,y,self.size/2,-math.pi,math.pi,True).fill() + self.ctx.move_to(x + x_, y + y_).rgb(*GO_GREEN).arc( + x + x_, + y + y_, + petal_size / 2 + hs + size_rnd, + -math.pi, + math.pi, + True, + ).fill() + self.ctx.move_to(x + x_, y + y_).rgb(*self.petal_color).arc( + x + x_, y + y_, petal_size / 2 + size_rnd, -math.pi, math.pi, True + ).fill() - y += self.size/3 - width = max(self.size, self.ctx.text_width(self.label)+10) - height = self.size/3+8 if self.has_highlight: - self.ctx.rgb(*BLACK).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() - self.ctx.rgb(*GO_GREEN).move_to(x,y).text(self.label) + self.ctx.rgb(*GO_GREEN).arc( + x, y, self.size / 2 + hs, -math.pi, math.pi, True + ).fill() + self.ctx.move_to(x, y).rgb(*self.bg).arc( + x, y, self.size / 2, -math.pi, math.pi, True + ).fill() + + y += self.size / 3 + width = max(self.size, self.ctx.text_width(self.label) + 10) + height = self.size / 3 + 8 + if self.has_highlight: + self.ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle( + x - width / 2, y - height / 2, width, height, width // 2 + ).fill() + self.ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label) else: - self.ctx.rgb(*PUSH_RED).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() - self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) - + self.ctx.rgb(*PUSH_RED).move_to(x, y - height / 2).round_rectangle( + x - width / 2, y - height / 2, width, height, width // 2 + ).fill() + self.ctx.rgb(*BLACK).move_to(x, y).text(self.label) class IconValue(Icon): @@ -190,9 +227,9 @@ class IconValue(Icon): super().__init__(*args, **kwargs) self.value = value self.get_value = None - - def _draw(self,pos): - (x,y) = pos + + def _draw(self, pos): + (x, y) = pos v = self.value if self.get_value: @@ -201,50 +238,55 @@ class IconValue(Icon): self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE - self.ctx.font_size=self.size/3 + self.ctx.font_size = self.size / 3 if self.has_highlight: - self.ctx.move_to(x,y).rgb(*WHITE).arc(x,y,self.size/2+5,-pi,pi,True).fill() - - self.ctx.move_to(x,y).rgb(*PUSH_RED).arc(x,y,self.size/2,-pi,pi,True).fill() - self.ctx.move_to(x,y).rgb(*GO_GREEN).arc(x,y,self.size/2-5,v*2*pi,0,1).fill() - self.ctx.rgb(0,0,0).move_to(x,y).text(self.label) - + self.ctx.move_to(x, y).rgb(*WHITE).arc( + x, y, self.size / 2 + 5, -pi, pi, True + ).fill() + self.ctx.move_to(x, y).rgb(*PUSH_RED).arc( + x, y, self.size / 2, -pi, pi, True + ).fill() + self.ctx.move_to(x, y).rgb(*GO_GREEN).arc( + x, y, self.size / 2 - 5, v * 2 * pi, 0, 1 + ).fill() + self.ctx.rgb(0, 0, 0).move_to(x, y).text(self.label) class GroupStackedVertical(UIElement): pass - + class GroupRing(UIElement): - def __init__(self,r=100,origin=(0,0),element_center=None): + def __init__(self, r=100, origin=(0, 0), element_center=None): self.r = r self.angle_offset = 0 - self.element_center=element_center + self.element_center = element_center super().__init__(origin) - def draw(self, offset=(0,0)): - pos = (self.origin[0]+offset[0],self.origin[1]+offset[1]) + def draw(self, offset=(0, 0)): + pos = (self.origin[0] + offset[0], self.origin[1] + offset[1]) self._draw(pos) for index in range(len(self.children)): - #print("child",index) + # print("child",index) child = self.children[index] if not child: continue - angle = 2*math.pi/len(self.children)*index+self.angle_offset - #print(angle,self.r,pos[0]) - x = -math.sin(angle)*self.r+pos[0] - y = -math.cos(angle)*self.r+pos[1] - #print("pos",(x,y)) - child.draw(offset=(x,y)) - - def _draw(self,pos): + angle = 2 * math.pi / len(self.children) * index + self.angle_offset + # print(angle,self.r,pos[0]) + x = -math.sin(angle) * self.r + pos[0] + y = -math.cos(angle) * self.r + pos[1] + # print("pos",(x,y)) + child.draw(offset=(x, y)) + + def _draw(self, pos): if self.element_center: self.element_center.has_highlight = False self.element_center._draw(pos) + class GroupPetals(GroupRing): - def __init__(self,*args,**kwargs): - super().__init__(*args,**kwargs) - self.children = [None for i in range(10)] \ No newline at end of file + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.children = [None for i in range(10)] diff --git a/python_payload/st3m/utils.py b/python_payload/st3m/utils.py index 687835af5ba10217833798c636ad3a9fc2e6d6a4..6ba9eb48175fa9c3f6ec37b9b5856b828f71c2a6 100644 --- a/python_payload/st3m/utils.py +++ b/python_payload/st3m/utils.py @@ -1,5 +1,6 @@ from st3m import logging -log = logging.Log(__name__,level=logging.INFO) + +log = logging.Log(__name__, level=logging.INFO) log.info("import") import time @@ -10,33 +11,37 @@ RED = 0b1111100000000000 GREEN = 0b0000011111100000 BLUE = 0b0000000000011111 + def clear_all_leds(): for i in range(40): set_led_rgb(i, 0, 0, 0) update_leds() + def highlight_bottom_petal(num, RED, GREEN, BLUE): - start = 4 + 8*num + start = 4 + 8 * num for i in range(7): - set_led_rgb(((i+start)%40), RED, GREEN, BLUE) + set_led_rgb(((i + start) % 40), RED, GREEN, BLUE) update_leds() + def long_bottom_petal_captouch_blocking(num, ms): - if(get_captouch((num*2) + 1) == 1): + if get_captouch((num * 2) + 1) == 1: time.sleep_ms(ms) - if(get_captouch((num*2) + 1) == 1): + if get_captouch((num * 2) + 1) == 1: return True return False + def draw_volume_slider(ctx, volume): - length = int(96*volume) + length = int(96 * volume) - ctx.rgb(0,0,0)#dummy - ctx.round_rectangle(-49,41,98,8,3).fill()#dummy idk + ctx.rgb(0, 0, 0) # dummy + ctx.round_rectangle(-49, 41, 98, 8, 3).fill() # dummy idk - ctx.rgb(0,255,0) - ctx.round_rectangle(-51,49,102,12,3).fill() - ctx.rgb(0,0,0) - ctx.round_rectangle(-50,50,100,10,3).fill() - ctx.rgb(0,255,0) - ctx.round_rectangle(-48,52, length ,6,3).fill() + ctx.rgb(0, 255, 0) + ctx.round_rectangle(-51, 49, 102, 12, 3).fill() + ctx.rgb(0, 0, 0) + ctx.round_rectangle(-50, 50, 100, 10, 3).fill() + ctx.rgb(0, 255, 0) + ctx.round_rectangle(-48, 52, length, 6, 3).fill()