# Exercise detect longest button press
# Copyright by Anthony Vogelaar, Perth Scotland
# rev 0.10  2025-08-14  initial release
# rev 0.11	2025-08-21  bug removal main()

from	machine	import	Pin, Timer
import	time

# ============================ Hardware =============================

pin_btn_red    = 23;	pin_led_red    = 32
pin_btn_yellow = 13;	pin_led_yellow = 33
pin_btn_green  = 14;	pin_led_green  = 25
pin_btn_blue   = 27;	pin_led_blue   = 26

# ============================= Led =================================

class Led:
    
    # Instantiate a Led object
    def __init__(self, pin_nr):
        self.led = Pin(pin_nr, Pin.OUT, value=0)
        
        
    # set led on
    def on(self):
        self.led(1)
        
        
    # set led off
    def off(self):
        self.led(0)
        
# ============================= Btn =================================

class Btn:
    
    # Instantiate a button object
    def __init__(self, pin_nr):
        self.t1  = None										# t press in mSec
        self.t2  = None										# t release in mSec
        self.btn = Pin(pin_nr, Pin.IN, Pin.PULL_UP)
        self.btn.irq(self._onBtn, Pin.IRQ_FALLING | Pin.IRQ_RISING)


    # return pressed time or None
    def tPressed(self):
        if self.t1 != None and self.t2 != None:
            return time.ticks_diff(self.t2, self.t1)
        
        
    # return True while measuring
    def isPressed(self):
        return self.t1 and not self.t2
    
    
    # reset measured time
    def reset(self):
        self.t1 = None
        self.t2 = None
        

    # handling button IRQ
    def _onBtn(self, sender):
        if   self.t1 == None and not self.btn():
            self.t1 = time.ticks_ms()					# down edge detected
        elif self.t2 == None and self.btn():
            self.t2 = time.ticks_ms()					# up edge detected

# =========================== Section ===============================

class Section:
    
    # Instantiate a section containing a led and btn
    def __init__(self, pin_nr_led, pin_nr_btn):
        self.led       = Led(pin_nr_led)
        self.btn       = Btn(pin_nr_btn)
        
        
    # return pressed time or None, call continuously to update led
    def tPressed(self):
        self.led.on() if self.btn.isPressed() else self.led.off()
        return self.btn.tPressed()
    
    
    # reset measured time
    def reset(self):
        self.btn.reset()
        
    
    # set led on
    def ledOn(self):
        self.led.on()
    
# ============================= Kit =================================

class Kit:
    
    # istantiate the kit with 4 sections, each a led and a button
    def __init__(self, led_0, btn_0, led_1, btn_1, led_2, btn_2, led_3, btn_3):
        self.sections = [Section(led_0, btn_0), Section(led_1, btn_1),
                         Section(led_2, btn_2), Section(led_3, btn_3)]
        
        
    # return the index of section whre button was pressed longest
    # call continuously to update section
    def idxLongest(self):
        periods = [self.sections[0].tPressed(), self.sections[1].tPressed(),
                   self.sections[2].tPressed(), self.sections[3].tPressed()]
        if all(periods):
            t_max = max(periods)
            return periods.index(t_max)
        
        
    # set led in section idx to on
    def ledOn(self, idx):
        self.sections[idx].ledOn()
        
# ================================= tests ====================================

# test class Led --> flashing led 2 Sec on, 1 Sec off
def test1():
    led = Led(pin_led_red)
    print(led)
    while True:
        led.on()
        time.sleep(2)
        led.off()
        time.sleep(1)
        
    
# test class Btn, print '*' while pressed and print time on release
def test2():
    btn = Btn(pin_btn_green)
    while True:
        while not (t_pressed := btn.tPressed()):
            print('*', end='') if btn.isPressed() else print('.', end='')
            time.sleep_ms(200)
        print(f'\n{t_pressed/1000:.3f} Sec pressed')
        btn.reset()
            
            
# test section red, led on while pressed and print time on release
def test3():
    section = Section(pin_led_blue, pin_btn_blue)
    while True:
        if t_pressed := section.tPressed():
            print(f'\n{t_pressed/1000:.3f} Sec pressed')
            section.reset()
        time.sleep_ms(10)

# ============================ main =============================

# detect the longest button press of each section then switch its led on
def main():
    kit = Kit(pin_led_red,   pin_btn_red,   pin_led_yellow, pin_btn_yellow, 
              pin_led_green, pin_btn_green, pin_led_blue,   pin_btn_blue)
    while True:
        if (idx := kit.idxLongest()) != None:
            kit.ledOn(idx)
            return
        time.sleep_ms(10)
        
  
#test3()
main()

# ================================= end =====================================
