import bluetooth, time, struct

ble = bluetooth.BLE()
ble.active(True)

conn = None
_IRQ_PERIPHERAL_CONNECT    = 7
_IRQ_PERIPHERAL_DISCONNECT = 8
_IRQ_GATTC_WRITE_DONE      = 17
_IRQ_GATTC_NOTIFY          = 18

notify_data = []
write_done  = False

def irq(ev, data):
    global conn, write_done
    if ev == _IRQ_PERIPHERAL_CONNECT:
        c, at, addr = data; conn = c
        print("CONNECTED", conn)
    elif ev == _IRQ_PERIPHERAL_DISCONNECT:
        conn = None; print("DISCONNECTED")
    elif ev == _IRQ_GATTC_NOTIFY:
        ch, vh, d = data
        nd = bytes(d)
        notify_data.append((vh, nd.hex()))
        print("NOTIFY vh={} {}b: {}".format(vh, len(nd), nd.hex()))
    elif ev == _IRQ_GATTC_WRITE_DONE:
        write_done = True
    else:
        print("IRQ", ev)

ble.irq(irq)
ble.gap_connect(0, bytes([0x24,0x19,0x72,0x61,0x9D,0x62]))
t = time.ticks_ms()
while conn is None:
    if time.ticks_diff(time.ticks_ms(), t) > 10000: raise Exception("TIMEOUT")
    time.sleep_ms(50)
print("CONN OK"); time.sleep_ms(500)

def wwrite(vh, val):
    global write_done
    write_done = False
    ble.gattc_write(conn, vh, val, 1)
    t = time.ticks_ms()
    while not write_done:
        if time.ticks_diff(time.ticks_ms(), t) > 5000: break
        time.sleep_ms(50)

wwrite(21, struct.pack("<H", 0x0001)); print("CCCD1 OK")
wwrite(24, struct.pack("<H", 0x0001)); print("CCCD2 OK")
time.sleep_ms(300)

def crc16(data):
    crc = 0xFFFF
    for b in data:
        crc ^= b
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    return crc & 0xFFFF

SN = b"30000251257777051"
payload = b"\x0a" + bytes([len(SN)]) + SN
frame = b"HM\xa3\x03" + struct.pack(">HHH", 1, crc16(payload), len(payload)+10) + payload
print("TX:", frame.hex())
wwrite(18, frame); print("CMD sent, waiting...")

t = time.ticks_ms()
while len(notify_data) == 0:
    if time.ticks_diff(time.ticks_ms(), t) > 15000:
        print("NO NOTIFY"); break
    time.sleep_ms(100)

print("notifies:", len(notify_data))
for vh, d in notify_data: print("vh={} {}".format(vh, d))
if conn: ble.gap_disconnect(conn)
print("DONE")
