from machine import UART
import time
import _thread
import struct

class DWIN:
    """DWIN 串口屏幕控制类"""
    
    def __init__(self, uart_id=1, tx_pin=10, rx_pin=9, baudrate=115200):
        """
        初始化DWIN显示屏
        
        参数:
            uart_id: UART端口号 (ESP32的UART1)
            tx_pin: 发送引脚 (ESP32 UART1默认TX=10)
            rx_pin: 接收引脚 (ESP32 UART1默认RX=9)
            baudrate: 波特率
        """
        self.uart = UART(uart_id, baudrate)
        self.uart.init(baudrate=baudrate, tx=tx_pin, rx=rx_pin)
        self._lock = _thread.allocate_lock()
        self.rx_buffer = bytearray(20)
        
        self._handle_stop_test  = None
        self._handle_start_test = None
        
        self._handle_capture_background = None    
        self._handle_capture_sample 	= None
        self._write_eeprom				= None

    def _send_bytes(self, data):
        """发送字节数据到显示屏"""
        with self._lock:
            self.uart.write(bytes(data))
            time.sleep_ms(2)  # 等待数据发送完成
    
    def put_string(self, data, length):
        """发送字符串数据到显示屏"""
        if isinstance(data, (bytes, bytearray)):
            self._send_bytes(data[:length])
        else:
            self._send_bytes(bytes(data[:length]))
    
    def jump_page(self, page_id):
        """
        切换到指定页面
        
        参数:
            page_id: 页面ID
        """
        data = bytearray([0x5A, 0xA5, 0x04, 0x80, 0x03, page_id >> 8, page_id & 0xFF])
        self.put_string(data, len(data))
    
    def read_reg(self, reg_addr):
        """
        读取寄存器值
        
        参数:
            reg_addr: 寄存器地址
        """
        data = bytearray([0x5A, 0xA5, 0x03, 0x81, reg_addr, 0x07])
        self.put_string(data, len(data))
    
    def write_reg(self, reg_addr, value):
        """
        写入寄存器值
        
        参数:
            reg_addr: 寄存器地址
            value: 要写入的值
        """
        data = bytearray([0x5A, 0xA5, 0x04, 0x80, reg_addr, value >> 8, value & 0xFF])
        self.put_string(data, len(data))
    
    def write_var(self, addr, value):
        """
        写入变量值到LCD显示
        
        参数:
            addr: 变量地址
            value: 要写入的值（16位整数）
        """
        data = bytearray([0x5A, 0xA5, 0x05, 0x82, 
                         addr >> 8, addr & 0xFF,
                         value >> 8, value & 0xFF])
        self.put_string(data, len(data))
    
    def write_var_32(self, addr, value):
        """
        写入32位变量值到LCD显示
        
        参数:
            addr: 变量地址
            value: 要写入的值（32位整数）
        """
        data = bytearray([0x5A, 0xA5, 0x07, 0x82,
                         addr >> 8, addr & 0xFF,
                         (value >> 24) & 0xFF,
                         (value >> 16) & 0xFF,
                         (value >> 8) & 0xFF,
                         value & 0xFF])
        self.put_string(data, len(data))
    
    def init_lcd(self, eeprom_data=None):
        """
        初始化LCD显示
        
        参数:
            eeprom_data: EEPROM数据读取函数，如果不提供则跳过EEPROM初始化
        """
        if eeprom_data is None:
            return
            
        data = bytearray([0x5A, 0xA5, 0x05, 0x82, 0x00, 0x00, 0x00, 0x00])
        
        for addr in range(0xFF):
            data[5] = addr
            data[6] = eeprom_data(addr * 2)
            data[7] = eeprom_data(addr * 2 + 1)
            self.put_string(data, 8)
            
    def proccess_Get_Reg_value(self,addr):
        var_width = self.rx_buffer[6]*2
        var_Value = short(var_width); #把var_Value 强制转换为short类型

        for i in range(var_width):
            var_Value<<=8
            var_Value |= self.rx_buffer[i+7]
            var_Value = (short)var_Value
        if(self._write_eeprom!=None):
            self._write_eeprom(var_width,addr*var_width,var_Value)
        print(("process register Value var_width {:02X} addr:{:02X} = {:02X}!\r\n").format(var_width,addr,var_Value))
        pass
    
    def proccess_Key_cmd(self):
        cmd_addr = (self.rx_buffer[4] << 8) + self.rx_buffer[5]
        if cmd_addr == 0x00DF:  # 按键消息
            key_data = self.rx_buffer[8]
            self._handle_key_press(key_data) 
            print(("process Key command {:02X} successed!\r\n").format(key_data))
        else:
            # 保存参数
            self.proccess_Get_Reg_value(cmd_addr)
            pass
        

    def proccess_decode_cmd(self):   
        operator = {
            0x83: self.proccess_Key_cmd,    # 处理按键消息
            0x81: self._handle_system_date_message,# 处理系统消息
            }
        # 检查帧头
        if self.rx_buffer[0] == 0x5A and self.rx_buffer[1] == 0xA5:
            key = self.rx_buffer[3]
            if key in operator:
                operator[key]()
            else:
                print('Unknown Command')
        else:
            pass
    
    def process_received_data(self):
        bPackStart = False
        bPackEnd = False
        iTimeout = 10
        # 清空rx_buffer缓冲区 
        self.rx_buffer = []
        while bPackEnd == False:
            """处理接收到的数据"""
            iTimeout-=1
            time.sleep_ms(1)
            if self.uart.any():
                # 读取接收到的数据
                received = self.uart.read()
                if received:
                    bPackStart = True
                    # 保存接收到的数据开始拼接到rx_buffer缓冲区 
                    if len(received) > 0:
                        self.rx_buffer += received 
            else:
                if bPackStart== True:
                    bPackEnd = True 
                    print('Input Key value: ' + ' '.join('{:02X}'.format(x) for x in self.rx_buffer))
                    self.proccess_decode_cmd()
                    break
            if iTimeout==0:
                break
        return bPackEnd
                
    def _Reset(self): 
        import machine
        machine.reset()
        
    def _handle_key_press(self, key_data):
        """
        处理按键消息
        
        参数:
            key_data: 按键值
        """
        operator = {
            0x01: self._handle_start_test,# 开始测试
            0x02: self._handle_stop_test,# 停止测试
            0x12: self._handle_capture_background,# 采集背景            
            0x13: self._handle_capture_sample,#    采集样品
            0xCC: self._Reset,    # 系统复位
            }
        if key_data in operator: 
            operator[key_data]()
            print('dwin-->_handle_key_press key_data ={:02X}'.format(key_data) )
        else: 
            pass
 
    
    def _handle_system_date_message(self):
        """处理系统消息"""
        # 在这里添加系统消息处理代码 
        print(("dwin-->_handle_system_date_message !\r\n"))
        pass
    
    def reg_callback(self, reg_addr, value):
        """
        注册回调函数，当寄存器发生变化时会被调用
        
        参数:
            reg_addr: 寄存器地址
            value: 新值
        """ 
        dic_callback = {
            '_handle_start_test': self._handle_start_test,
            '_handle_stop_test': self._handle_stop_test
        }
        if(reg_addr == '_handle_start_test'):
            self._handle_start_test = value
        if(reg_addr == '_handle_stop_test'):
            self._handle_stop_test = value 
        if(reg_addr == '_write_eeprom'):
            self._write_eeprom = value
            
        print(f"Reg changed: {reg_addr}, new value: {value}")
        

    def run(self):
        """运行主循环"""
        self.init_lcd()
        # 切换到页面 0
        #self.jump_page(0)  # 跳转到初始页面
        
        while True:
            self.process_received_data() 

# 使用示例
def example():
    # 创建DWIN实例
    dwin = DWIN(uart_id=1)
    
    # 写入一些测试数据
    dwin.write_var(0x10, 250)  		# 写入16位数据
    dwin.write_var(0x11, 251)  		# 写入16位数据
    dwin.write_var(0x12, 0)  		# 写入16位数据
    dwin.write_var_32(0x20, 255255)  	# 写入32位数据
     
    
    # 运行主循环
    dwin.run()

if __name__ == '__main__': 
    example()