import machine
import micropython
import time
from utime import sleep

micropython.alloc_emergency_exception_buf(100)

BUTTON_COUNT = 2
BUTTON_GPIO_START = 14
BUTTON_DEBOUNCE_DELAY_ms = 50
THRESHOLD_ms = 700

LED_COUNT = 2
LED_GPIO_START = 2

class Debouncer:
    inputs = []   # Noisy inputs.
    outputs = []  # Debounced outputs.
    risers = []   # Inputs that rose since they were last debounced.
    fallers = []  # Inputs that fell since they were last debounced.
    delay = 0     # Debounce delay.
    previousTimestamp = time.ticks_ms()

    def __init__(self, inputs, delay):
        self.inputs = inputs      # Assign with reference, i.e. pointer. These will be updated by the ISR.
        self.outputs = inputs[:]  # Assign without reference, i.e. copy.
        self.risers = [False] * len(inputs)
        self.fallers = [False] * len(inputs)
        self.delay = delay

    def Update(self):
        currentTimestamp = time.ticks_ms()
        sampledInputs = self.inputs[:]
        if sampledInputs[:] == self.outputs[:]:
            self.previousTimestamp = currentTimestamp
        elif currentTimestamp - self.previousTimestamp > self.delay:
            for i in range(len(self.inputs)):
                self.risers[i] = sampledInputs[i] == 1 and self.outputs[i] == 0
                self.fallers[i] = sampledInputs[i] == 0 and self.outputs[i] == 1
            self.outputs = sampledInputs[:]
            #print(f"inputs  = {sampledInputs}")
            #print(f"outputs = {self.outputs}")
            #print(f"risers  = {self.risers}")
            #print(f"fallers = {self.fallers}")
            self.previousTimestamp = currentTimestamp
            return
        self.risers = [False] * len(self.inputs)
        self.fallers = [False] * len(self.inputs)

# Get the pin ID from its description and convert it to an index.
#def PinId(pin):
#    return int(str(pin)[8:10]) - BUTTON_GPIO_START

# Get the pin ID from its index in the button array
def PinId(pin):
    return buttons.index(pin)

# Interrupt Service Routine (ISR) to update the inputs array with the button values.
def ISR_Button(pin):
    inputs[PinId(pin)] = pin.value()

# Array of button values which will be updated by the ISR.
inputs = []

# Initialise the buttons as pull-ups with an ISR that is triggered on rising or falling edges.
# Initialise the inputs with the button values.
buttons = []
for i in range(BUTTON_COUNT):
    button = machine.Pin(
        BUTTON_GPIO_START + i, machine.Pin.IN, machine.Pin.PULL_UP
    )
    button.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=ISR_Button)
    buttons.append(button)
    inputs.append(button.value())

# Initialise the output pins for the LEDs.
outputPins = []
for i in range(LED_COUNT):
    pin = machine.Pin(LED_GPIO_START + i, machine.Pin.OUT)
    outputPins.append(pin)

# Create the debouncer that points to the inputs. The inputs will be updated by the ISR.
debouncer = Debouncer(inputs, BUTTON_DEBOUNCE_DELAY_ms)

time.sleep(0.1)  # Wait for USB to become ready

print("Hello, Pi Pico!")

previousTimestamp = time.ticks_ms()

STATE_WAITING_FOR_PRESS = 1
STATE_WAITING_FOR_THRESHOLD = 2
STATE_WAITING_FOR_RELEASE = 3

state = STATE_WAITING_FOR_PRESS

while True:
    # INPUT LOGIC
    # Update the debouncer.
    debouncer.Update()
    risersOccurred = debouncer.risers != [False] * BUTTON_COUNT
    fallersOccurred = debouncer.fallers != [False] * BUTTON_COUNT
    currentTimestamp = time.ticks_ms()

    # OUTPUT LOGIC
    # Update the state of the LEDs with the debouncer outputs.
    for i in range(LED_COUNT):
        outputPins[i].value(debouncer.outputs[i])

    # STATE LOGIC
    if state == STATE_WAITING_FOR_PRESS:
        if fallersOccurred:
            # Reset the threshold timer.
            previousTimestamp = currentTimestamp
            state = STATE_WAITING_FOR_THRESHOLD
            print("Fallers occured. Waiting for threshold.")    

    elif state == STATE_WAITING_FOR_THRESHOLD:
        if risersOccurred:
            state = STATE_WAITING_FOR_RELEASE
            print("Risers occurred. Waiting for release.")
        elif fallersOccurred:
            # Reset the threshold timer.
            previousTimestamp = currentTimestamp
        elif currentTimestamp - previousTimestamp > THRESHOLD_ms:
            print("New function.")
            if debouncer.outputs[0] == 0 and debouncer.outputs[1] == 0:
                print("Tear")
            elif debouncer.outputs[0] == 0 and debouncer.outputs[1] == 1:
                print("Calibrate")
            elif debouncer.outputs[0] == 1 and debouncer.outputs[1] == 0:
                print("Cancel")
            
            state = STATE_WAITING_FOR_RELEASE
            print("Waiting for release.")

    elif state == STATE_WAITING_FOR_RELEASE:
        if debouncer.outputs == [1] * BUTTON_COUNT:
            print("All buttons released.")
            state = STATE_WAITING_FOR_PRESS
            print("Waiting for press.")

    sleep(0.001)
    
BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT