import can_iotv_v2_1 as iotv
import time

ADDR   = '0000'   # adreca vertebra digital (cadena de 4 bits)
STEP_S = 0.1      # interval entre passos de la sequencia (s)
POLL_S = 0.05     # interval del bucle principal (s)

# Estat compartit entre el callback (thread de fons) i el bucle principal
seq_running = False
last_di1    = None

# ── Helpers ───────────────────────────────────────────────────────────────────

def send_dout(value):
    iotv.dout(ADDR, 'A', value)

def send_dout_all_off():
    send_dout(0x00)

# ── Callback asincron (cridat pel thread de fons de can_iotv_v2_1) ─────────────
# Equivalent a onDinChangeCallback del firmware .ino
# val_a i val_b son bytes (0-255) amb els bits ja invertits

def on_din_change(addr, val_a, val_b):
    global seq_running, last_di1

    di1 = bool(val_b & 0x02)   # DI1 = bit 1 del costat B

    if di1 == last_di1:
        return                  # cap canvi real, ignorar

    last_di1 = di1

    if di1:
        print("[DIN] DI1=1 → sequencia INICIADA")
        seq_running = True
    else:
        print("[DIN] DI1=0 → sequencia ATURADA")
        seq_running = False
        send_dout_all_off()

# ── Sequencia DO7 → DO0 ───────────────────────────────────────────────────────

def run_sequence():
    bit = 7
    while bit >= 0:
        if not seq_running:
            return True         # DI1 ha baixat, aturar
        send_dout(1 << bit)
        count = 0
        while count < 2:        # 2 x POLL_S = STEP_S
            time.sleep(POLL_S)
            if not seq_running:
                return True
            count = count + 1
        bit = bit - 1
    return False

# ── Main ──────────────────────────────────────────────────────────────────────

def main():
    global seq_running, last_di1

    iotv.can_on()
    try:
        iotv.dsetup(ADDR, 'output', 'input')
        send_dout_all_off()
        print("[CFG] Vertebra 0000: A:output B:input. LEDs apagats.")

        # Registrar listener passiu — no fa polling, no col·lapsa el bus
        iotv.on_din_change(ADDR, on_din_change)
        print("[INFO] Head02TestRPi02 llest. Activa DI1 per iniciar la sequencia.")

        while True:
            if seq_running:
                stopped = run_sequence()
                if stopped:
                    seq_running = False
                    last_di1    = False
                    send_dout_all_off()
                    print("[SEQ] Sequencia aturada, LEDs apagats.")
            else:
                time.sleep(POLL_S)

    except KeyboardInterrupt:
        print("\n[INFO] Interrupcio de teclat.")
    finally:
        send_dout_all_off()
        iotv.off_din_change(ADDR)
        iotv.can_off()
        print("[CAN] Bus alliberat.")

main()
