import hid
import time
from typing import Optional

from tkinter import * 
from tkinter import ttk

from tkinter.filedialog import asksaveasfile

DEFAULT_HID_TIMEOUT = 10
BIGSCREEN_VID = 0x35BD
BEYOND_PID = 0x0101

READ_SIGNATURE =  ord('U')
ACK = ord('$')
ERROR = ord('E')

# "wait_for_response" is a helper function that waits for a specific message type
# the HID response packet (aka the HID report) has the message type as the first byte
# send the desired message types in a list of ints, any message that 
# matches one of the types in the list will be returned
# if timeout, returns empty bytes
#
# params:
# hmd_device -      A hid.Device object that is already connected to the HMD
# message_types -   List of ints, each int is a message type. If any message
#                   is received that matches one of the types, this function
#                   will return with that response packet
# timeout_ms -      An int with the desired timeout in milliseconds. Default 1000 
#
# Returns:  A bytes object. If timed out, will be empty bytes (b''). Otherwise
#           it will have the first message that matched one of the types given.

def wait_for_response(hmd_device: hid.Device, message_types:list, timeout_ms: int = 100) -> bytes:
    start_time = time.monotonic_ns()
    
    while( (start_time + (timeout_ms*1000000)) > time.monotonic_ns()):
        bytesout = hmd_device.read(65, timeout=DEFAULT_HID_TIMEOUT)
        if(len(bytesout) > 0):
            if(bytesout[0] in message_types):
                return bytesout
    
    return b''

def get_signature_region() -> Optional[bytearray]:
    beyond = hid.Device(vid=BIGSCREEN_VID, pid=BEYOND_PID)

    full_sig_region = bytearray()

    for i in range(16):
        this_sig_chunk = b''
        beyond.send_feature_report(bytes([0, READ_SIGNATURE, i]))
        resp = wait_for_response(beyond, [READ_SIGNATURE, ERROR], timeout_ms=500)
        if( (len(resp) > 0) and (resp[0] == READ_SIGNATURE)):
            chunk_len = resp[1]
            this_sig_chunk = resp[2:2+chunk_len]
        else:
            # retry one time
            beyond.send_feature_report(bytes([0, READ_SIGNATURE, i]))
            resp = wait_for_response(beyond, [READ_SIGNATURE, ERROR], timeout_ms=500)
            if( (len(resp) > 0) and (resp[0] == READ_SIGNATURE)):
                chunk_len = resp[1]
                this_sig_chunk = resp[2:2+chunk_len]
            else:
                # okay, fail out.
                return None
        full_sig_region.extend(this_sig_chunk)
    
    return full_sig_region

def saveconfigfile():
    files = [('All Files', '*.*'), 
             ('Text Document', '*.txt')]

    file = asksaveasfile(filetypes = files, defaultextension = files, initialfile='config.txt')

    sig_region = get_signature_region()

    for i in range(32):
        # print 16 bytes per line
        sig_slice = sig_region[i*16:(i+1)*16]
        for bb in sig_slice:
            file.write('{:02X} '.format(bb))
        file.write('\n')
    file.close()

if __name__ == '__main__':
    root = Tk()
    root.geometry('200x150')

    btn = ttk.Button(root, text = 'Dump Config Memory to File', command = lambda : saveconfigfile())
    btn.pack()

    root.mainloop()
    #print(get_signature_region())





