import bluetooth, time, struct

LOG = []
def log(s): LOG.append(s); print(s)

ble = bluetooth.BLE()
ble.active(True)
conn = None
notify_data = []
write_done_ev = False

def irq(ev, data):
    global conn, write_done_ev
    if ev == 7:
        c, at, addr = data; conn = c; log("CONN "+str(conn))
    elif ev == 8:
        conn = None; log("DISC")
    elif ev == 17:
        write_done_ev = True; log("WD "+str(tuple(data)))
    elif ev == 18:
        ch, vh, d = data
        nd = bytes(d)
        notify_data.append((vh, nd))
        log("NOTIFY vh={} {}b: {}".format(vh, len(nd), nd.hex()))

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("NO CONN")
    time.sleep_ms(50)
time.sleep_ms(600)

def wd(ms=4000):
    global write_done_ev
    write_done_ev = False
    t = time.ticks_ms()
    while not write_done_ev:
        if time.ticks_diff(time.ticks_ms(), t) > ms: return False
        time.sleep_ms(30)
    return True

ble.gattc_write(conn, 21, struct.pack("<H",0x0001), 1); wd(); log("CCCD1")
ble.gattc_write(conn, 24, struct.pack("<H",0x0001), 1); wd(); log("CCCD2")
time.sleep_ms(500)

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\xa2\x03" + struct.pack(">HHH", 1, crc16(payload), len(payload)+10) + payload
log("TX: "+frame.hex())
ble.gattc_write(conn, 18, frame, 1); r = wd(6000); log("WR:"+str(r))

t = time.ticks_ms()
while len(notify_data) == 0:
    if time.ticks_diff(time.ticks_ms(), t) > 12000: log("NO_NOTIFY1"); break
    time.sleep_ms(100)

if not notify_data:
    log("RETRY mode=0")
    ble.gattc_write(conn, 18, frame, 0)
    t = time.ticks_ms()
    while len(notify_data) == 0:
        if time.ticks_diff(time.ticks_ms(), t) > 10000: log("NO_NOTIFY2"); break
        time.sleep_ms(100)

log("DONE notifies="+str(len(notify_data)))
if conn: ble.gap_disconnect(conn)
with open("dtu_result.txt","w") as f:
    f.write("\n".join(LOG)+"\n")
