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

class AO_WriteValueForm:
    def __init__(self, master):
        self.master = master
        master.title("AO_WriteValue")
        master.geometry("820x450")  # 增加窗口高度以适应更大的间距

        self.usbio = USBIO()
        self.i_ao_total = 0

        # Device ID
        ttk.Label(master, text="Device ID").place(x=7, y=10)
        self.cbx_device_id = ttk.Combobox(master, values=["USB-2026"], width=8)
        self.cbx_device_id.place(x=90, y=10)
        self.cbx_device_id.current(0)

        # Board ID
        ttk.Label(master, text="Board ID").place(x=7, y=50)  # 增加y坐标
        self.txt_board_id = ttk.Entry(master, width=7)
        self.txt_board_id.place(x=90, y=50)  # 增加y坐标
        self.txt_board_id.insert(0, "1")

        # Open/Close buttons
        ttk.Button(master, text="Open", command=self.on_open_device, width=8).place(x=7, y=90)  # 增加y坐标
        ttk.Button(master, text="Close", command=self.on_close_device, width=8).place(x=100, y=90)  # 增加y坐标

        # Digital Write
        ttk.Button(master, text="Write to All Channels (Hex)", command=self.on_write_value_digital).place(x=200, y=10)
        ttk.Button(master, text="Write to One Channel (Hex)", command=self.on_write_ch_value_digital).place(x=450, y=10)
        
        ttk.Label(master, text="CH").place(x=200, y=50)  # 增加y坐标
        self.txt_digital_ch = ttk.Entry(master, width=5)
        self.txt_digital_ch.place(x=225, y=50)  # 增加y坐标
        
        ttk.Label(master, text="Value 0x").place(x=300, y=50)  # 增加y坐标
        self.txt_digital_val = ttk.Entry(master, width=6)
        self.txt_digital_val.place(x=370, y=50)  # 增加y坐标

        # Analog Write
        ttk.Button(master, text="Write to All Channels (float)", command=self.on_write_value_analog).place(x=200, y=90)  # 增加y
        ttk.Button(master, text="Write to One Channel (float)", command=self.on_write_ch_value_analog).place(x=450, y=90)  # 增加y
        
        ttk.Label(master, text="CH").place(x=200, y=120)  # 增加y坐标
        self.txt_analog_ch = ttk.Entry(master, width=5)
        self.txt_analog_ch.place(x=225, y=120)  # 增加y坐标
        
        ttk.Label(master, text="Value").place(x=300, y=120)  # 增加y坐标
        self.txt_analog_val = ttk.Entry(master, width=6)
        self.txt_analog_val.place(x=370, y=120)  # 增加y坐标

        # Information label
        ttk.Label(master, text="Information").place(x=7, y=150)

        # Information, Expect Value, and Current Value listboxes
        self.lb_information = tk.Listbox(master, width=30, height=10)
        self.lb_information.place(x=7, y=170)
        
        ttk.Label(master, text="Expect Value").place(x=250, y=150)
        self.lb_exp_value = tk.Listbox(master, width=30, height=10)
        self.lb_exp_value.place(x=250, y=170)
        
        ttk.Label(master, text="Current Value").place(x=500, y=150)
        self.lb_cur_value = tk.Listbox(master, width=30, height=10)
        self.lb_cur_value.place(x=500, y=170)

    def on_open_device(self):
        device_id = USBIO_MINPID + self.cbx_device_id.current() + 26
        board_id = int(self.txt_board_id.get())
        
        self.usbio.SetCommTimeout(500)
        err_code = self.usbio.OpenDevice(device_id, board_id)
        
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            self.show_device_info()

    def on_close_device(self):
        err_code = self.usbio.CloseDevice()
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        
        self.lb_information.delete(0, tk.END)
        self.lb_exp_value.delete(0, tk.END)
        self.lb_cur_value.delete(0, tk.END)

    def show_device_info(self):
        self.lb_information.delete(0, tk.END)
        
        soft_wdt_timeout = ctypes.c_ulong()
        self.usbio.GetSoftWDTTimeout(ctypes.byref(soft_wdt_timeout))
        self.lb_information.insert(tk.END, f"SoftWDT: {soft_wdt_timeout.value}")
        
        fw_ver = ctypes.c_int()
        self.usbio.GetFwVer(ctypes.byref(fw_ver))
        self.lb_information.insert(tk.END, f"Version: {fw_ver.value}")
        
        device_nickname = ctypes.create_string_buffer(USBIO_NICKNAME_LENGTH)
        self.usbio.GetDeviceNickName(device_nickname)
        self.lb_information.insert(tk.END, f"Description: {device_nickname.value.decode()}")
        
        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_information.insert(tk.END, f"SN: {sn}")

        #device_sn = ctypes.create_string_buffer(USBIO_SN_LENGTH)
        #self.usbio.GetDeviceSN(device_sn)
        #self.lb_information.insert(tk.END, f"SN: {device_sn.value.decode()}")
        
        bySupIOMask = c_char()
        self.usbio.GetSupportIOMask(byref(bySupIOMask))
        self.lb_information.insert(tk.END, f"Support IO Mask: 0x{ord(bySupIOMask.value):02X}")
        
        intvl=ord(bySupIOMask.value) 
        if SUPPORT_AO(intvl):
            ao_total = ctypes.c_char()
            self.usbio.GetAOTotal(byref(ao_total))
            self.i_ao_total =ord(ao_total.value)
            self.lb_information.insert(tk.END, f"AO channels: {self.i_ao_total}")

    def show_value(self):
        self.lb_exp_value.delete(0, tk.END)
        self.lb_cur_value.delete(0, tk.END)
        
        ao_exp_value_digital = (ctypes.c_ulong * USBIO_AO_MAX_CHANNEL)()
        ao_exp_value_analog = (ctypes.c_float * USBIO_AO_MAX_CHANNEL)()
        ao_cur_value_digital = (ctypes.c_ulong * USBIO_AO_MAX_CHANNEL)()
        ao_cur_value_analog = (ctypes.c_float * USBIO_AO_MAX_CHANNEL)()
        
        err_code = self.usbio.AO_ReadExpValueDigital(ao_exp_value_digital)
        if err_code == ERR_NO_ERR:
            err_code = self.usbio.AO_ReadExpValueAnalog(ao_exp_value_analog)
        
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            for idx in range(self.i_ao_total):
                self.lb_exp_value.insert(tk.END, f"Ch{idx}: 0x{ao_exp_value_digital[idx]:04X} / {ao_exp_value_analog[idx]:.4f}")
        
        err_code = self.usbio.AO_ReadCurValueDigital(ao_cur_value_digital)
        if err_code == ERR_NO_ERR:
            err_code = self.usbio.AO_ReadCurValueAnalog(ao_cur_value_analog)
        
        if err_code != ERR_NO_ERR:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            for idx in range(self.i_ao_total):
                self.lb_cur_value.insert(tk.END, f"Ch{idx}: 0x{ao_cur_value_digital[idx]:04X} / {ao_cur_value_analog[idx]:.4f}")

    def on_write_value_digital(self):
        value = self.txt_digital_val.get()
        if value:
            ao_value = (ctypes.c_ulong * USBIO_AO_MAX_CHANNEL)()
            tmp_value = int(value, 16)
            for idx in range(self.i_ao_total):
                ao_value[idx] = tmp_value
            
            err_code = self.usbio.AO_WriteValueDigital(ao_value)
            if err_code != ERR_NO_ERR:
                messagebox.showerror("Error", f"[{err_code}]")
            
            self.show_value()
            self.txt_digital_ch.delete(0, tk.END)
        else:
            messagebox.showerror("Error", "Please enter the AO Value!")

    def on_write_ch_value_digital(self):
        ch = self.txt_digital_ch.get()
        value = self.txt_digital_val.get()
        if ch and value:
            ao_value = int(value, 16)
            channel = int(ch)
            
            err_code = self.usbio.AO_WriteChannelValueDigital(channel, ao_value)
            if err_code != ERR_NO_ERR:
                messagebox.showerror("Error", f"[{err_code}]")
            
            self.show_value()
        else:
            messagebox.showerror("Error", "Please enter the AO Channel and Value!")

    def on_write_value_analog(self):
        value = self.txt_analog_val.get()
        if value:
            ao_value = (ctypes.c_float * USBIO_AO_MAX_CHANNEL)()
            tmp_value = float(value)
            for idx in range(self.i_ao_total):
                ao_value[idx] = tmp_value
            
            err_code = self.usbio.AO_WriteValueAnalog(ao_value)
            if err_code != ERR_NO_ERR:
                messagebox.showerror("Error", f"[{err_code}]")
            
            self.show_value()
            self.txt_analog_ch.delete(0, tk.END)
        else:
            messagebox.showerror("Error", "Please enter the AO Value!")

    def on_write_ch_value_analog(self):
        ch = self.txt_analog_ch.get()
        value = self.txt_analog_val.get()
        if ch and value:
            ao_value = float(value)
            channel = int(ch)
            
            err_code = self.usbio.AO_WriteChannelValueAnalog(channel, ao_value)
            if err_code != ERR_NO_ERR:
                messagebox.showerror("Error", f"[{err_code}]")
            
            self.show_value()
        else:
            messagebox.showerror("Error", "Please enter the AO Channel and Value!")

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