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)
        
    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_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))  
        pass

    def proccess_decode_cmd(self):   
        operator = {
            0x83: self.proccess_Key_cmd,
            0x81: self._handle_system_message,
            }
        # 检查帧头
        if self.rx_buffer[0] == 0x5A and self.rx_buffer[1] == 0xA5:
            '''
            # 处理按键消息
            if self.rx_buffer[3] == 0x83:
                self.proccess_Key_cmd()
            # 处理其他消息
            elif self.rx_buffer[3] == 0x81: #
                self._handle_system_message()
            '''
        else:
            pass
    
    def process_received_data(self):
        bPackStart = False
        bPackEnd = False
        # 清空rx_buffer缓冲区 
        self.rx_buffer = []
        while bPackEnd == False:
            """处理接收到的数据"""
            if self.uart.any():
                # 读取接收到的数据
                time.sleep(1)
                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()
                    return bPackEnd
    
    def _handle_key_press(self, key_data):
        """
        处理按键消息
        
        参数:
            key_data: 按键值
        """
        if key_data == 0xCC:
            # 系统复位
            import machine
            machine.reset()
        elif key_data == 0x10:
            # 开始测试
            self._handle_start_test()
        elif key_data == 0x11:
            # 停止测试
            self._handle_stop_test()
        elif key_data == 0x12:
            # 采集背景
            self._handle_capture_background()
        elif key_data == 0x13:
            # 采集样品
            self._handle_capture_sample()
    
    def _handle_system_message(self):
        """处理系统消息"""
        # 在这里添加系统消息处理代码
        pass
    
    def _handle_start_test(self):
        """处理开始测试"""
        # 在这里添加开始测试的代码
        pass
    
    def _handle_stop_test(self):
        """处理停止测试"""
        # 在这里添加停止测试的代码
        self.write_var_32(0x00, 0)  # 清零测试时间
    
    def _handle_capture_background(self):
        """处理采集背景"""
        # 在这里添加采集背景的代码
        pass
    
    def _handle_capture_sample(self):
        """处理采集样品"""
        # 在这里添加采集样品的代码
        pass
    
    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()