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

USBIO_DID = [
    USB2019, 
    USB2026
]
class AIReadValueApp:
    def __init__(self, master):
        self.master = master
        self.master.title("AI_ReadValue")
        self.master.geometry("760x400")

        self.usbio = USBIO()
        self.m_byAITotal =  c_char()

        self.create_widgets()

    def create_widgets(self):
        # Device ID
        ttk.Label(self.master, text="Device ID").place(x=10, y=10)
        self.cbx_devid = ttk.Combobox(self.master, values=["USB-2019", "USB-2026"], width=10)
        self.cbx_devid.place(x=70, y=10)
        self.cbx_devid.current(0)

        # Board ID
        ttk.Label(self.master, text="Board ID").place(x=10, y=40)
        self.txt_boardid = ttk.Entry(self.master, width=10)
        self.txt_boardid.place(x=70, y=40)
        self.txt_boardid.insert(0, "1")

        # Open/Close buttons
        ttk.Button(self.master, text="Open", command=self.on_open_device).place(x=10, y=70, width=60)
        ttk.Button(self.master, text="Close", command=self.on_close_device).place(x=80, y=70, width=60)

        # Information listbox
        self.lb_information = tk.Listbox(self.master, width=30, height=7)
        self.lb_information.place(x=10, y=100)

        # Read value buttons
        ttk.Button(self.master, text="Read Digital Value", command=self.on_read_digi_value).place(x=200, y=10, width=160)
        ttk.Button(self.master, text="Read Analog Value", command=self.on_read_ana_value).place(x=200, y=40, width=160)
        ttk.Button(self.master, text="Read Digital Value with Ch Status", command=self.on_read_digi_value_with_ch_sta).place(x=360, y=10, width=270)
        ttk.Button(self.master, text="Read Analog Value with Ch Status", command=self.on_read_ana_value_with_ch_sta).place(x=360, y=40, width=280)

        # Value listboxes
        ttk.Label(self.master, text="Digital Value").place(x=330, y=100)
        self.lb_digi_value = tk.Listbox(self.master, width=20, height=5)
        self.lb_digi_value.place(x=330, y=120)

        ttk.Label(self.master, text="Analog Value").place(x=330, y=230)
        self.lb_ana_value = tk.Listbox(self.master, width=20, height=5)
        self.lb_ana_value.place(x=330, y=250)

        ttk.Label(self.master, text="Channel Status").place(x=550, y=100)
        self.lb_ch_sta = tk.Listbox(self.master, width=20, height=10)
        self.lb_ch_sta.place(x=550, y=120)

    def on_open_device(self):
        board_id = int(self.txt_boardid.get())
        device_id =USBIO_DID[self.cbx_devid.current()]

        self.usbio.SetCommTimeout(500)
        err_code = self.usbio.OpenDevice(device_id, board_id)

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

    def update_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()  #c_ushort()
        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}")
#        self.lb_information.insert(tk.END, f"Version: {fw_ver.value}")

        device_nickname = (ctypes.c_char * USBIO_NICKNAME_LENGTH)()
        self.usbio.GetDeviceNickName(device_nickname)
        #nickname = ' '.join(f'{b:02x}' for b in device_nickname.value)
        nickname = ''.join([chr(i) for i in device_nickname.value]).rstrip('\x00')
        #nickname = nickname.decode('utf-8')
        self.lb_information.insert(tk.END, f"Description (hex): {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}")  #.decode()}")
        #self.lb_information.insert(tk.END, f"SN: {device_sn.value}")  #.decode()}")

        #sup_io_mask = ctypes.c_ubyte()
        #self.usbio.GetSupportIOMask(ctypes.byref(sup_io_mask))
        #self.lb_information.insert(tk.END, f"Support IO Mask: 0x{sup_io_mask.value:02X}")

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

        #ai_total = ctypes.c_ubyte()
        #self.usbio.GetAITotal(ctypes.byref(ai_total))
        #self.m_byAITotal = ai_total.value
        #self.lb_information.insert(tk.END, f"AI channels: {self.m_byAITotal}")

             #intvl=ord(bySupIOMask.value)                      
            #if SUPPORT_DO(intvl):
        self.usbio.GetAITotal(byref(self.m_byAITotal))
        self.lb_information.insert(tk.END, f"AI channels: {ord(self.m_byAITotal.value)}")          

    def on_close_device(self):
        err_code = self.usbio.CloseDevice()
        if err_code != 0:
            messagebox.showerror("Error", f"[{err_code}]")

        self.lb_information.delete(0, tk.END)
        self.lb_digi_value.delete(0, tk.END)
        self.lb_ana_value.delete(0, tk.END)
        self.lb_ch_sta.delete(0, tk.END)

    def on_read_digi_value(self):
        self.clear_value_listboxes()
        ai_value = (ctypes.c_ulong * USBIO_AI_MAX_CHANNEL)()
        err_code = self.usbio.AI_ReadValueDigital(ai_value)

        if err_code != 0:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            for idx in range(ord(self.m_byAITotal.value)):
                #print("DI",idx)
                #print(" val=",ai_value[idx])
                self.lb_digi_value.insert(tk.END, f"Ch{idx}: 0x{ai_value[idx]:08X}")

    def on_read_ana_value(self):
        self.clear_value_listboxes()
        ai_value = (ctypes.c_float * USBIO_AI_MAX_CHANNEL)()
        err_code = self.usbio.AI_ReadValueAnalog(ai_value)

        if err_code != 0:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            for idx in range(ord(self.m_byAITotal.value)):
                self.lb_ana_value.insert(tk.END, f"Ch{idx}: {ai_value[idx]:.6f}")

    def on_read_digi_value_with_ch_sta(self):
        self.clear_value_listboxes()
        ai_value = (ctypes.c_ulong * USBIO_AI_MAX_CHANNEL)()
        ai_ch_status = (ctypes.c_char * USBIO_AI_MAX_CHANNEL)()
        err_code = self.usbio.AI_ReadValueDigitalWithChSta(ai_value, ai_ch_status)

        if err_code != 0:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            for idx in range(ord(self.m_byAITotal.value)):
                self.lb_digi_value.insert(tk.END, f"Ch{idx}: 0x{ai_value[idx]:08X}")
                self.lb_ch_sta.insert(tk.END, f"Ch{idx}: 0x{ord(ai_ch_status[idx]):02X}")

    def on_read_ana_value_with_ch_sta(self):
        self.clear_value_listboxes()
        ai_value = (ctypes.c_float * USBIO_AI_MAX_CHANNEL)()
        ai_ch_status = (ctypes.c_char * USBIO_AI_MAX_CHANNEL)()
        err_code = self.usbio.AI_ReadValueAnalogWithChSta(ai_value, ai_ch_status)

        if err_code != 0:
            messagebox.showerror("Error", f"[{err_code}]")
        else:
            for idx in range(ord(self.m_byAITotal.value)):
                self.lb_ana_value.insert(tk.END, f"Ch{idx}: {ai_value[idx]:.6f}")
                self.lb_ch_sta.insert(tk.END, f"Ch{idx}: 0x{ord(ai_ch_status[idx]):02X}")

    def clear_value_listboxes(self):
        self.lb_digi_value.delete(0, tk.END)
        self.lb_ana_value.delete(0, tk.END)
        self.lb_ch_sta.delete(0, tk.END)

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