# metronome.py

# Raspberry Pi Pico - demonstrate rhythmic servo motion like a metronome 

# This assumes a tiny 9G servo has been wired up to the Pico as follows:
#   Pico pin 40 (VBUS)  -> servo red   (+5V)
#   Pico pin 38 (GND)   -> servo brown (GND)
#   Pico pin 1  (GP0)   -> servo orange (SIG)
#--------------------------------------------------------------------------------
# Import standard modules.
import time

# Load the CircuitPython hardware definition module for pin definitions.
import board

# Import course modules.  These files should be copied to the top-level
# directory of the CIRCUITPY filesystem on the Pico.
import servo

#--------------------------------------------------------------------------------
class Metronome:
    def __init__(self, servo):
        """Implement a simple bang-bang metronome motion on a given servo.  Intended to
        run within an event loop. The servo moves once per beat.
        """
        self.servo = servo
        self.range = [45, 135]
        self.state = False
        self.update_timer = 0
        self.set_tempo(60)
            
    def poll(self, elapsed):
        """Polling function to be called as frequently as possible from the event loop
        with the nanoseconds elapsed since the last cycle."""
        self.update_timer -= elapsed
        if self.update_timer < 0:
            self.update_timer += self.update_interval
            if self.state:
                self.servo.write(self.range[0])
                self.state = False
            else:
                self.servo.write(self.range[1])
                self.state = True
                
    def set_tempo(self, bpm):
        """Set the metronome tempo in beats per minute."""
        # Calculate the cycle period in nanoseconds.
        self.update_interval = int(60e9 / bpm)

#--------------------------------------------------------------------------------
# Create an object to represent a servo on the given hardware pin.
servo = servo.Servo(board.GP0)

# Create a metronome controller attached to the servo.
metronome = Metronome(servo)

#---------------------------------------------------------------
# Main event loop to run each non-preemptive thread.

last_clock = time.monotonic_ns()

while True:
    # read the current nanosecond clock
    now = time.monotonic_ns()
    elapsed = now - last_clock
    last_clock = now

    # poll each thread
    metronome.poll(elapsed)    
    
