import bluetooth, time

DTU_ADDR = bytes([0x24, 0x19, 0x72, 0x61, 0x9D, 0x62])
log = []
conn_handle = None
done = False
step = "idle"
readable = []
notifiable = []
notify_data = []

def bt_irq(event, data):
    global conn_handle, done, step
    if event == 7:
        conn_handle = data[0]
        step = "connected"
        log.append(f"CONN {conn_handle}")
        ble.gattc_discover_services(conn_handle)
    elif event == 8:
        log.append(f"DISC err={data[2]}")
        done = True
    elif event == 9:
        conn, start, end, uuid = data
        log.append(f"SVC {uuid} {start}-{end}")
    elif event == 10:
        ble.gattc_discover_characteristics(conn_handle, 1, 65535)
    elif event == 11:
        conn, def_h, val_h, props, uuid = data
        log.append(f"CHAR {uuid} vh={val_h} props={props}")
        if props & 2: readable.append(val_h)
        if props & 16: notifiable.append(val_h)
    elif event == 12:
        step = "chars_done"
    elif event == 15:
        conn, val_h, char_data = data
        d = bytes(char_data)
        log.append(f"READ vh={val_h}: hex={d.hex()} ascii={d}")
        if readable:
            try: ble.gattc_read(conn_handle, readable.pop(0))
            except: step = "reads_done"
        else:
            step = "reads_done"
    elif event == 18:
        conn, val_h, notify_data_in = data
        d = bytes(notify_data_in)
        log.append(f"NOTIFY vh={val_h}: hex={d.hex()} ascii={d}")

ble = bluetooth.BLE()
ble.active(True)
ble.irq(bt_irq)
ble.gap_connect(0, DTU_ADDR)

for _ in range(15):
    if step == "chars_done": break
    time.sleep(1)

# Subscribe to all notifiable handles
for h in notifiable:
    try:
        # Write 0x0100 to CCCD (handle+1) to enable notifications
        ble.gattc_write(conn_handle, h + 1, bytes([0x01, 0x00]), 1)
        log.append(f"SUBSCRIBED notify vh={h}")
    except Exception as e:
        log.append(f"SUB_ERR vh={h}: {e}")

# Read all readable handles
if readable:
    try: ble.gattc_read(conn_handle, readable.pop(0))
    except: step = "reads_done"

for _ in range(15):
    if step == "reads_done": break
    time.sleep(1)

# Stay connected 10s listening for unsolicited notifications
time.sleep(10)

if conn_handle:
    try: ble.gap_disconnect(conn_handle)
    except: pass

with open("/dtu_sniff.txt","w") as f:
    f.write("\n".join(log))
print("SNIFF_DONE")
