import tkinter as tk
from tkinter import ttk, Canvas
import serial.tools.list_ports
from threading import Thread

class MainWidget(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.protocol("WM_DELETE_WINDOW", self.on_closing)

        self.create_widgets()

    def on_closing(self):
        self.on_close()
        self.master.destroy()

    def create_widgets(self):
        self.devlist = serial.tools.list_ports.comports()
        self.s = serial.Serial(baudrate=115200, timeout=1);
        self.receiving = False
        self.sysenable = False

        self.frame_line1 = ttk.Frame(self.master)
        self.frame_line1.grid(column=0, row=0)

        self.frame_line11 = ttk.Frame(self.frame_line1)
        self.frame_line11.grid(column=0, row=0)

        self.devcombo = ttk.Combobox(self.frame_line11)
        self.devcombo['values'] = self.devlist
        self.devcombo.grid(column=0, row=0)

        self.open_btn = tk.Button(self.frame_line11, text = "Open",  command = self.on_open)
        self.open_btn.grid(column=1, row=0)
        
        self.info_btn_Front = tk.Button(self.frame_line11, text = "Front", bg = "green")
        self.info_btn_Front.grid(column=2, row=0)
        self.info_btn_Rear = tk.Button(self.frame_line11, text = "Rear", bg = "green")
        self.info_btn_Rear.grid(column=3, row=0)
        self.info_btn_IR = tk.Button(self.frame_line11, text = "IR", bg = "green")
        self.info_btn_IR.grid(column=4, row=0)
        self.info_btn_NUC = tk.Button(self.frame_line11, text = "NUC", bg = "green")
        self.info_btn_NUC.grid(column=5, row=0)

        self.frame_line12 = ttk.Frame(self.frame_line1)
        self.frame_line12.grid(column=0, row=1)

        self.sys_btn_mem = tk.Button(self.frame_line12, text = "Mem", bg = "green")
        self.sys_btn_mem.grid(column=0, row=0)
        self.sys_btn_log = tk.Button(self.frame_line12, text = "Log", bg = "green")
        self.sys_btn_log.grid(column=1, row=0)
        self.sys_btn_sen = tk.Button(self.frame_line12, text = "Sensor", bg = "green")
        self.sys_btn_sen.grid(column=2, row=0)
        self.sys_btn_pwr = tk.Button(self.frame_line12, text = "Power", bg = "green")
        self.sys_btn_pwr.grid(column=3, row=0)
        self.sys_btn_temp = tk.Button(self.frame_line12, text = "Temperature", bg = "green")
        self.sys_btn_temp.grid(column=4, row=0)
        self.sys_btn_pwm0 = tk.Button(self.frame_line12, text = "PWM0", bg = "green")
        self.sys_btn_pwm0.grid(column=5, row=0)
        self.sys_btn_pwm1 = tk.Button(self.frame_line12, text = "PWM1", bg = "green")
        self.sys_btn_pwm1.grid(column=6, row=0)
        self.sys_btn_key = tk.Button(self.frame_line12, text = "KEY", bg = "green")
        self.sys_btn_key.grid(column=7, row=0)
        self.sys_btn_vout = tk.Button(self.frame_line12, text = "VOUT", bg = "green")
        self.sys_btn_vout.grid(column=8, row=0)
        self.sys_btn_ms = tk.Button(self.frame_line12, text = "V0", bg = "green")
        self.sys_btn_ms.grid(column=9, row=0)
        self.sys_btn_ss = tk.Button(self.frame_line12, text = "V1", bg = "green")
        self.sys_btn_ss.grid(column=10, row=0)
        self.sys_btn_osd = tk.Button(self.frame_line12, text = "OSD", bg = "green")
        self.sys_btn_osd.grid(column=11, row=0)
        self.sys_btn_ser = tk.Button(self.frame_line12, text = "Serial", bg = "green")
        self.sys_btn_ser.grid(column=12, row=0)
        self.sys_btn_host = tk.Button(self.frame_line12, text = "Host", bg = "green")
        self.sys_btn_host.grid(column=13, row=0)

        self.frame_line13 = ttk.Frame(self.frame_line1)
        self.frame_line13.grid(column=0, row=2)

        self.sys_btn = tk.Button(self.frame_line13, text = "Enable",  command = self.on_sys)
        self.sys_btn.grid(column=0, row=0)

        self.label = tk.Label(self.frame_line13, text="Current:")
        self.label.grid(column=1, row=0)
        self.current = tk.StringVar()
        self.label = tk.Label(self.frame_line13, textvariable=self.current)
        self.label.grid(column=2, row=0)
        self.current.set("-")

        self.label = tk.Label(self.frame_line13, text="Temperature:")
        self.label.grid(column=3, row=0)
        self.temperature = tk.StringVar()
        self.label = tk.Label(self.frame_line13, textvariable=self.temperature)
        self.label.grid(column=4, row=0)
        self.temperature.set("-")
        
        self.label = tk.Label(self.frame_line13, text="CPU Usage:")
        self.label.grid(column=5, row=0)
        self.cpu_usage = tk.StringVar()
        self.label = tk.Label(self.frame_line13, textvariable=self.cpu_usage)
        self.label.grid(column=6, row=0)
        self.cpu_usage.set("-")

        self.label = tk.Label(self.frame_line13, text="Mem Usage:")
        self.label.grid(column=7, row=0)
        self.mem_usage = tk.StringVar()
        self.label = tk.Label(self.frame_line13, textvariable=self.mem_usage)
        self.label.grid(column=8, row=0)
        self.mem_usage.set("-")
        
    def on_open(self):
        curSel = self.devcombo.current()
        port = self.devlist[curSel].device
        if self.s.is_open:
            self.s.close()
        self.s.port = port
        self.s.open()

        if self.s.is_open:
            self.open_btn['text'] = "Close"
            self.open_btn['command'] = self.on_close
            self.rcvtd = Thread(target=self.rcv_cb)
            self.rcvtd.start()

    def on_close(self):
        if self.receiving:
            self.receiving = False
            self.rcvtd.join()
        if self.s.is_open:
            self.s.close()
        self.open_btn['text'] = "Open"
        self.open_btn['command'] = self.on_open
           
    def on_sys(self):
        if self.sysenable:
            self.sysenable = False
            self.sys_btn['text'] = "Enable"
            snd_data = "$SYS,0*"
            self.current.set("-")
            self.temperature.set("-")
            self.cpu_usage.set("-")
            self.mem_usage.set("-")
        else:
            self.sysenable = True
            self.sys_btn['text'] = "Disable"
            snd_data = "$SYS,1*"
        snd_byte = bytearray(snd_data, 'utf-8')
        snd_byte.append(0x00)
        if self.s.is_open:
            self.s.write(snd_byte)

    def rcv_cb(self):
        self.receiving = True
        rcv_data = bytearray()
        rcv_step = 0
        while self.receiving:
            rec = self.s.read(1)
            if len(rec) < 1:
                continue
            if rcv_step == 0 and rec[0] == 0x24:
                rcv_step = 1
            elif rcv_step == 1:
                if rec[0] == 0x2a:
                    rcv_step = 2
                else:
                    rcv_data.append(rec[0])
            elif rcv_step == 2:
                if rec[0] == 0 or rec[0] == 0x0d or rec[0] == 0x0a:
                    rcv_step = 3
            elif rcv_step == 3:
                rcv_step = 0
                rcvlist = rcv_data.decode().split(',')
                rcv_data = bytearray()
                if len(rcvlist) >= 4:
                    if rcvlist[0] == "KEY":
                        snd_data = "$KEYA,{0},{1}*".format(rcvlist[1], rcvlist[2])
                        snd_byte = bytearray(snd_data, 'utf-8')
                        snd_byte.append(0x00)
                        self.s.write(snd_byte)
                        keyval = int(rcvlist[2], 16)
                        if keyval & 0x1:
                            self.info_btn_Front.configure(bg = "red")
                        else:
                            self.info_btn_Front.configure(bg = "green")
                        if keyval & 0x2:
                            self.info_btn_Rear.configure(bg = "red")
                        else:
                            self.info_btn_Rear.configure(bg = "green")
                        if keyval & 0x4:
                            self.info_btn_IR.configure(bg = "red")
                        else:
                            self.info_btn_IR.configure(bg = "green")
                        if keyval & 0x8:
                            self.info_btn_NUC.configure(bg = "red")
                        else:
                            self.info_btn_NUC.configure(bg = "green")

                        sysbits = int(rcvlist[3], 16)
                        if sysbits & 0x1:
                            self.sys_btn_mem.configure(bg = "red")
                        else:
                            self.sys_btn_mem.configure(bg = "green")
                        if sysbits & 0x2:
                            self.sys_btn_log.configure(bg = "red")
                        else:
                            self.sys_btn_log.configure(bg = "green")
                        if sysbits & 0x4:
                            self.sys_btn_sen.configure(bg = "red")
                        else:
                            self.sys_btn_sen.configure(bg = "green")
                        if sysbits & 0x8:
                            self.sys_btn_pwr.configure(bg = "red")
                        else:
                            self.sys_btn_pwr.configure(bg = "green")
                        if sysbits & 0x10:
                            self.sys_btn_temp.configure(bg = "red")
                        else:
                            self.sys_btn_temp.configure(bg = "green")
                        if sysbits & 0x20:
                            self.sys_btn_pwm0.configure(bg = "red")
                        else:
                            self.sys_btn_pwm0.configure(bg = "green")
                        if sysbits & 0x40:
                            self.sys_btn_pwm1.configure(bg = "red")
                        else:
                            self.sys_btn_pwm1.configure(bg = "green")
                        if sysbits & 0x80:
                            self.sys_btn_key.configure(bg = "red")
                        else:
                            self.sys_btn_key.configure(bg = "green")
                        if sysbits & 0x100:
                            self.sys_btn_vout.configure(bg = "red")
                        else:
                            self.sys_btn_vout.configure(bg = "green")
                        if sysbits & 0x200:
                            self.sys_btn_ms.configure(bg = "red")
                        else:
                            self.sys_btn_ms.configure(bg = "green")
                        if sysbits & 0x400:
                            self.sys_btn_ss.configure(bg = "red")
                        else:
                            self.sys_btn_ss.configure(bg = "green")
                        if sysbits & 0x800:
                            self.sys_btn_osd.configure(bg = "red")
                        else:
                            self.sys_btn_osd.configure(bg = "green")
                        if sysbits & 0x1000:
                            self.sys_btn_ser.configure(bg = "red")
                        else:
                            self.sys_btn_ser.configure(bg = "green")
                        if sysbits & 0x2000:
                            self.sys_btn_host.configure(bg = "red")
                        else:
                            self.sys_btn_host.configure(bg = "green")
                    elif rcvlist[0] == "SYSA":
                        self.current.set(rcvlist[1])
                        self.temperature.set(rcvlist[2])
                        self.cpu_usage.set(rcvlist[3])
                        self.mem_usage.set(rcvlist[4])
            else:
                rcv_step = 0
        
if __name__ == "__main__":
    root = tk.Tk()
    mainwin = MainWidget(master = root)
    mainwin.mainloop()
