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 DI_API_TestApp:
    def __init__(self, master):
        self.master = master
        self.master.title("DI_API_Test_Program")
        self.master.geometry("600x550")

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

        self.create_widgets()

    def create_widgets(self):
        # Left side widgets
        left_frame = ttk.Frame(self.master)
        left_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nw")

        # Device ID
        ttk.Label(left_frame, text="Device ID").grid(row=0, column=0, sticky="w")
        self.cbx_did = ttk.Combobox(left_frame, 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)  # 调整宽度为18
        self.cbx_did.grid(row=0, column=1, sticky="w")
        self.cbx_did.current(0)

        # Board ID
        ttk.Label(left_frame, text="Board ID").grid(row=1, column=0, sticky="w")
        self.txt_bid = ttk.Entry(left_frame, width=8)
        self.txt_bid.grid(row=1, column=1, sticky="w")
        self.txt_bid.insert(0, "1")

        # Open and Close buttons
        ttk.Button(left_frame, text="Open", command=self.on_open_device).grid(row=2, column=0, sticky="w")
        ttk.Button(left_frame, text="Close", command=self.on_close_device).grid(row=2, column=1, sticky="w")

        # Default and Refresh buttons
        ttk.Button(left_frame, text="Default", command=self.on_load_default).grid(row=3, column=0, sticky="w")
        ttk.Button(left_frame, text="Refresh", command=self.on_refresh_info).grid(row=3, column=1, sticky="w")

        # Nickname
        ttk.Label(left_frame, text="Nickname").grid(row=4, column=0, sticky="w")
        self.txt_nickname = ttk.Entry(left_frame, width=8)
        self.txt_nickname.grid(row=4, column=1, sticky="w")
        ttk.Button(left_frame, text="Set", command=self.on_set_nickname).grid(row=5, column=1, sticky="w")

        # WDT
        ttk.Label(left_frame, text="WDT (ms)").grid(row=6, column=0, sticky="w")
        self.txt_timeout = ttk.Entry(left_frame, width=6)
        self.txt_timeout.grid(row=6, column=1, sticky="w")
        ttk.Label(left_frame, text="ms").grid(row=6, column=1, sticky="e")
        ttk.Button(left_frame, text="Set", command=self.on_set_wdt_timeout).grid(row=7, column=1, sticky="w")

        # Board ID (User Defined)
        ttk.Label(left_frame, text="Board ID").grid(row=8, column=0, sticky="w")
        self.txt_board_id = ttk.Entry(left_frame, width=8)
        self.txt_board_id.grid(row=8, column=1, sticky="w")
        ttk.Button(left_frame, text="Set", command=self.on_set_board_id).grid(row=9, column=1, sticky="w")

        # Module Info ListBox
        self.lb_module_info = tk.Listbox(left_frame, width=24, height=10)
        self.lb_module_info.grid(row=10, column=0, columnspan=2, sticky="w")

        # Right side widgets
        right_frame = ttk.Frame(self.master)
        right_frame.grid(row=0, column=1, padx=10, pady=10, sticky="n")

        # Getting functions group
        get_frame = ttk.LabelFrame(right_frame, text="Getting functions")
        get_frame.pack(pady=5, fill="x")

        # Digital Filter Width
        di_filter_frame = ttk.LabelFrame(get_frame, text="Digital Filter Width")
        di_filter_frame.pack(pady=5, padx=5, fill="x")
        ttk.Button(di_filter_frame, text="Get", command=self.on_get_di_filter_width).pack(pady=5)

        # DI Value Inverse
        di_value_frame = ttk.LabelFrame(get_frame, text="DI Value Inverse")
        di_value_frame.pack(pady=5, padx=5, fill="x")
        ttk.Button(di_value_frame, text="Get", command=self.on_get_di_val_inv).pack(pady=5)

        # Counter Edge Trig.
        edge_trig_frame = ttk.LabelFrame(get_frame, text="Counter Edge Trig.")
        edge_trig_frame.pack(pady=5, padx=5, fill="x")
        ttk.Button(edge_trig_frame, text="Get", command=self.on_get_edge_trig).pack(pady=5)

        # Setting functions group
        set_frame = ttk.LabelFrame(right_frame, text="Setting functions")
        set_frame.pack(pady=5)

        # Digital Filter Width
        filter_frame = ttk.LabelFrame(set_frame, text="Digital Filter Width")
        filter_frame.pack(pady=5, padx=5, fill="x")
        ttk.Label(filter_frame, text="Value").pack(side="left")
        self.txt_set_di_filter_width = ttk.Entry(filter_frame, width=5)
        self.txt_set_di_filter_width.pack(side="left")
        ttk.Label(filter_frame, text="* 100us").pack(side="left")
        ttk.Button(filter_frame, text="Set", command=self.on_set_di_filter_width).pack(side="left")

        # DI Value Inverse
        inverse_frame = ttk.LabelFrame(set_frame, text="DI Value Inverse")
        inverse_frame.pack(pady=5, padx=5, fill="x")
        self.di_val_inv_var = tk.StringVar(value="Disable")
        ttk.Radiobutton(inverse_frame, text="Disable", variable=self.di_val_inv_var, value="Disable").pack(side="left")
        ttk.Radiobutton(inverse_frame, text="Enable", variable=self.di_val_inv_var, value="Enable").pack(side="left")
        ttk.Button(inverse_frame, text="Set", command=self.on_set_di_val_inv).pack(side="left")

        # Counter Edge Trig.
        edge_frame = ttk.LabelFrame(set_frame, text="Counter Edge Trig.")
        edge_frame.pack(pady=5, padx=5, fill="x")
        self.cnt_edge_trig_var = tk.StringVar(value="Falling")
        ttk.Radiobutton(edge_frame, text="Falling", variable=self.cnt_edge_trig_var, value="Falling").pack(side="left")
        ttk.Radiobutton(edge_frame, text="Rising", variable=self.cnt_edge_trig_var, value="Rising").pack(side="left")
        ttk.Button(edge_frame, text="Set", command=self.on_set_cnt_edge_trig).pack(side="left")

    def on_open_device(self):
        bid = int(self.txt_bid.get())
        did = self.cbx_did.current()

        self.USBIO.SetCommTimeout(500)
        result = self.USBIO.OpenDevice(USBIO_DID[did], bid)

        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            self.refresh_module_info()

    def on_close_device(self):
        self.lb_module_info.delete(0, tk.END)
        result = self.USBIO.CloseDevice()
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")

    def on_load_default(self):
        result = self.USBIO.LoadDefault()
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")

    def on_refresh_info(self):
        result = self.USBIO.RefreshDeviceInfo()
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            self.refresh_module_info()

    def on_set_nickname(self):
        nickname = self.txt_nickname.get().encode()
        result = self.USBIO.SetDeviceNickName(nickname)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Success", "Operation completed successfully.")

    def on_set_wdt_timeout(self):
        timeout = int(self.txt_timeout.get())
        result = self.USBIO.SetSoftWDTTimeout(timeout)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Success", "Operation completed successfully.")
    def on_set_board_id(self):
        board_id = int(self.txt_board_id.get())
        result = self.USBIO.SetUserDefinedBoardID(board_id)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Success", "Operation completed successfully.")
    def on_get_di_filter_width(self):
        filter_width = ctypes.c_int()
        result = self.USBIO.DI_GetDigitalFilterWidth(ctypes.byref(filter_width))
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Information", f"Module digital filter width: {filter_width.value} * 100us")

    def on_get_di_val_inv(self):
        inverse = ctypes.c_ulong()
        result = self.USBIO.DI_GetDigitalValueInverse(ctypes.byref(inverse))
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            status = "disabled" if inverse.value == 0 else "enabled"
            messagebox.showinfo("Information", f"Module digital value inverse is {status}")

    def on_get_edge_trig(self):
        edge_trig = ctypes.c_ulong()
        result = self.USBIO.DI_GetCntEdgeTrigger(ctypes.byref(edge_trig))
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            status = "falling" if edge_trig.value == 0 else "rising"
            messagebox.showinfo("Information", f"Module counter edge trigger is {status}")

    def on_set_di_filter_width(self):
        filter_width = int(self.txt_set_di_filter_width.get())
        result = self.USBIO.DI_SetDigitalFilterWidth(filter_width)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Success", "Digital filter width set successfully")

    def on_set_di_val_inv(self):
        inverse = 1 if self.di_val_inv_var.get() == "Enable" else 0
        result = self.USBIO.DI_SetDigitalValueInverse(inverse)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Success", "Digital value inverse set successfully")

    def on_set_cnt_edge_trig(self):
        edge_trig = 1 if self.cnt_edge_trig_var.get() == "Rising" else 0
        result = self.USBIO.DI_SetCntEdgeTrigger(edge_trig)
        if result != 0:
            messagebox.showerror("Error", f"[{result}]")
        else:
            messagebox.showinfo("Success", "Counter edge trigger set successfully")

    def refresh_module_info(self):
        self.lb_module_info.delete(0, tk.END)

        wdt_timeout = ctypes.c_ulong()
        self.USBIO.GetSoftWDTTimeout(ctypes.byref(wdt_timeout))
        self.lb_module_info.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_module_info.insert(tk.END, f"Version: {little_endian_value}")

        device_nickname = (ctypes.c_char * USBIO_NICKNAME_LENGTH)()
        self.USBIO.GetDeviceNickName(device_nickname)
        nickname = ''.join([chr(i) for i in device_nickname.value]).rstrip('\x00')
        self.lb_module_info.insert(tk.END, f"Description: {nickname}")

        device_sn = (ctypes.c_char * USBIO_SN_LENGTH)()
        self.USBIO.GetDeviceSN(device_sn)
        sn = ''.join([chr(i) for i in device_sn.value]).rstrip('\x00')
        self.lb_module_info.insert(tk.END, f"SN: {sn}")

        bySupIOMask = c_char()
        self.USBIO.GetSupportIOMask(byref(bySupIOMask))
        self.lb_module_info.insert(tk.END, f"Support IO Mask: 0x{ord(bySupIOMask.value):02X}")   

        intvl=ord(bySupIOMask.value)  
        if SUPPORT_DI(intvl):
            di_total =  c_char()
            self.USBIO.GetDITotal(byref(di_total))
            self.i_di_total=ord(di_total.value)
            self.lb_module_info.insert(tk.END, f"DI channels: {self.i_di_total}")   

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