import tkinter as tk
from tkinter import ttk, messagebox
from ctypes import * 
from ICPDAS_USBIO import *

USBIO_DID = [
    USB2026, 
    USB2051, 
    USB2055, 
    USB2060, 
    USB2051_32, 
    USB2055_32, 
    USB2068_18, 
    USB2255_32, 
    USB2255_64,
    USB2260_48,
    USB2260B_48,
    USB2260C_48,
    USB2260_24,
    USB2260B_24,
    USB2260C_24 
]

class Form_DI_ReadValue:
    def __init__(self, master):
        self.master = master
        self.master.title("DI_ReadValue")
        self.master.geometry("700x300")

        self.USBIO = USBIO()
        self.i_di_total = 0

        self.create_widgets()

    def create_widgets(self):
        # Configure grid
        for i in range(12):
            self.master.grid_columnconfigure(i, minsize=25)
        for i in range(8):
            self.master.grid_rowconfigure(i, minsize=22)

        # Device ID
        ttk.Label(self.master, text="Device ID").grid(row=0, column=0, columnspan=2, sticky="w", padx=5)
        self.cbx_device_id = ttk.Combobox(self.master, values=[
            "USB-2026", "USB-2051", "USB-2055", "USB-2060",
            "USB-2051-32", "USB-2055-32", "USB-2068-18", "USB-2255-32", "USB-2255-64",
            "USB-2260-48","USB-2260B-48","USB-2260C-48","USB-2260-24","USB-2260B-24",
            "USB-2260C-24",
        ], width=18)
        self.cbx_device_id.grid(row=0, column=2, columnspan=3, sticky="w")
        self.cbx_device_id.current(0)

        # Board ID
        ttk.Label(self.master, text="Board ID").grid(row=1, column=0, columnspan=2, sticky="w", padx=5)
        self.txt_board_id = ttk.Entry(self.master, width=10)
        self.txt_board_id.grid(row=1, column=2, columnspan=2, sticky="w")
        self.txt_board_id.insert(0, "1")

        # Open and Close buttons
        ttk.Button(self.master, text="Open", command=self.on_btn_open_device).grid(row=2, column=0, columnspan=2, sticky="w", padx=5)
        ttk.Button(self.master, text="Close", command=self.on_btn_close_device).grid(row=2, column=2, columnspan=2, sticky="w")

        # Information ListBox
        self.lb_information = tk.Listbox(self.master, width=24, height=7)
        self.lb_information.grid(row=3, column=0, rowspan=5, columnspan=4, sticky="w", padx=5)

        # Read Digital Value button
        self.btn_read_digital_value = ttk.Button(self.master, text="Read Digital Value", 
                                                 command=self.on_btn_read_digi_value, state="disabled")
        self.btn_read_digital_value.grid(row=0, column=5, columnspan=3, sticky="w")

        # Digital Value ListBox
        ttk.Label(self.master, text="Digital Value").grid(row=2, column=5, columnspan=3, sticky="w")
        self.lb_digi_value = tk.Listbox(self.master, width=12, height=7)
        self.lb_digi_value.grid(row=3, column=5, rowspan=5, columnspan=3, sticky="w")

        # Read Counter Value button
        self.btn_read_counter_value = ttk.Button(self.master, text="Read Counter Value", 
                                                 command=self.on_btn_read_cnt_value, state="disabled")
        self.btn_read_counter_value.grid(row=0, column=8, columnspan=4, sticky="w")

        # Counter Value ListBox
        ttk.Label(self.master, text="Counter Value").grid(row=2, column=8, columnspan=4, sticky="w")
        self.lb_counter_value = tk.Listbox(self.master, width=14, height=7)
        self.lb_counter_value.grid(row=3, column=8, rowspan=5, columnspan=4, sticky="w")

        # Clear Counter
        ttk.Label(self.master, text="Mask 0x").grid(row=1, column=8, columnspan=2, sticky="w")
        self.txt_cnt_clr_mask = ttk.Entry(self.master, width=5)
        self.txt_cnt_clr_mask.grid(row=1, column=10, sticky="w")
        self.btn_cnt_clr = ttk.Button(self.master, text="Clear", command=self.on_btn_cnt_clr, state="disabled")
        self.btn_cnt_clr.grid(row=1, column=11, sticky="w")

    def on_btn_open_device(self):
        board_id = int(self.txt_board_id.get())
        device_index = self.cbx_device_id.current()
        
        module_id = USBIO_DID[device_index]

        self.USBIO.SetCommTimeout(500)
        
        err_code = self.USBIO.OpenDevice(module_id, board_id)
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            self.update_module_info()
            self.btn_read_digital_value["state"] = "normal"
            self.btn_read_counter_value["state"] = "normal"
            self.btn_cnt_clr["state"] = "normal"

    def update_module_info(self):
        self.lb_information.delete(0, tk.END)
        
        wdt_timeout = ctypes.c_ulong()
        self.USBIO.GetSoftWDTTimeout(ctypes.byref(wdt_timeout))
        self.lb_information.insert(tk.END, f"SoftWDT: {wdt_timeout.value}")        
        
        fw_ver = ctypes.c_int()
        self.USBIO.GetFwVer(ctypes.byref(fw_ver))
        little_endian_value = int.from_bytes(fw_ver, byteorder='little')
        self.lb_information.insert(tk.END, f"Version: {little_endian_value}")        
         

        device_nickname = (ctypes.c_char * USBIO_SN_LENGTH)()
        self.USBIO.GetDeviceNickName(device_nickname)
        nickname = ctypes.cast(device_nickname, ctypes.c_char_p).value.decode('ascii').rstrip('\x00')
        self.lb_information.insert(tk.END, f"Description: {nickname}") 

        device_sn = (ctypes.c_char * USBIO_SN_LENGTH)()
        self.USBIO.GetDeviceSN(device_sn)
        sn = ''.join(chr(x) if x < 128 else '?' for x in device_sn.value).rstrip('\x00')
        self.lb_information.insert(tk.END, f"SN: {sn}")        
        
        bySupIOMask = c_char()
        self.USBIO.GetSupportIOMask(byref(bySupIOMask))
        self.lb_information.insert(tk.END, f"Support IO Mask: 0x{ord(bySupIOMask.value):02X}") 
        
        support_io_mask=ord(bySupIOMask.value)  
        if SUPPORT_DI(support_io_mask):
            di_total =  c_char()
            self.USBIO.GetDITotal(byref(di_total))
            self.i_di_total=ord(di_total.value)
            self.lb_information.insert(tk.END, f"DI channels: {self.i_di_total}")   

    def on_btn_close_device(self):
        err_code = self.USBIO.CloseDevice()
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        
        self.btn_read_digital_value["state"] = "disabled"
        self.btn_read_counter_value["state"] = "disabled"
        self.btn_cnt_clr["state"] = "disabled"
        
        self.lb_information.delete(0, tk.END)
        self.lb_digi_value.delete(0, tk.END)
        self.lb_counter_value.delete(0, tk.END)

    def on_btn_read_digi_value(self):
        DI_byte_count_arr = (c_char * ((USBIO_DI_MAX_CHANNEL + 7) // 8))() 

        self.lb_digi_value.delete(0, tk.END)
        
        result = self.USBIO.DI_ReadValue(DI_byte_count_arr)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            for idx in range((self.i_di_total + 7) // 8):
                self.lb_digi_value.insert(tk.END, f"Ch{idx*8}~{idx*8+7} : 0x{ord(DI_byte_count_arr[idx]):02x}")

    def on_btn_read_cnt_value(self):
        di_counter_array = (ctypes.c_ulong * USBIO_DI_MAX_CHANNEL)()

        self.lb_counter_value.delete(0, tk.END)
        
        result = self.USBIO.DI_ReadCounterValue(di_counter_array)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            for idx in range(self.i_di_total):
                self.lb_counter_value.insert(tk.END, f"Ch{idx} : {di_counter_array[idx]}")

    def on_btn_cnt_clr(self):
        cnt_clr_mask = int(self.txt_cnt_clr_mask.get(), 16)
        
        err_code = self.USBIO.DI_WriteClearCounters(cnt_clr_mask)
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            messagebox.showinfo("Success", "Counter cleared successfully.")

if __name__ == "__main__":
    root = tk.Tk()
    app = Form_DI_ReadValue(root)
    root.mainloop()
