# core/serial_manager.py import serial import serial.tools.list_ports from utils.logger import logger class SerialManager: def __init__(self): self.serial_port = serial.Serial() self.serial_port.BaudRate = 115200 # 协议规定 self.serial_port.timeout = 1 def get_available_ports(self): """ 扫描并返回当前系统中所有可用的串口端口名 """ ports = serial.tools.list_ports.comports() return [port.device for port in ports] def _send_command(self, command_bytes): """ 核心方法:发送指令到串口 :param command_bytes: 完整的指令字节列表,例如 [0x80, 0x74, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] """ if self.serial_port.is_open: try: # 协议规定:连接命令盒时,需要发送8位数据,首字节是0x80 # 我们这里统一按连接命令盒的方式处理 self.serial_port.write(bytes(command_bytes)) print(f"✅ 指令已发送: {['0x{:02X}'.format(b) for b in command_bytes]}") return True except Exception as e: print(f"❌ 串口发送失败: {e}") return False return False # --- 以下为具体功能的指令封装 --- # 1. 开关机相关 def power_on_all(self): """所有屏开机""" # 协议:全选 + 开机 return self._send_command([0x80, 0x74, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) and \ self._send_command([0x80, 0x74, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) def power_off_all(self): """所有屏关机""" return self._send_command([0x80, 0x74, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) and \ self._send_command([0x80, 0x74, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) def power_on_single(self, panel_number): """单屏开机""" return self._send_command([0x80, 0x74, 0x19, panel_number, 0xFF, 0xFF, 0xFF, 0xFF]) and \ self._send_command([0x80, 0x74, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) # 2. 切换信号源相关 def switch_source_all(self, source_type, source_id): """ 切换所有屏信号源 :param source_type: 0x31(VGA), 0x32(AV), 0x33(HDMI), 0x34(YPbPr), 0x35(DVI) :param source_id: 信号源ID,例如 AV1=0x01, AV2=0x02 """ # 协议:0x80 0x94 0x83 SourceType Sourceld 0xFF 0xFF 0xFF command = [0x80, 0x94, 0x83, source_type, source_id, 0xFF, 0xFF, 0xFF] return self._send_command(command) def switch_source_single(self, panel_number, source_type): """ 切换单屏信号源 :param panel_number: 屏编号 :param source_type: 信号源类型 """ # 协议:单选 + 切换信号源 return self._send_command([0x80, 0x74, 0x19, panel_number, 0xFF, 0xFF, 0xFF, 0xFF]) and \ self._send_command([0x80, 0x94, 0x82, source_type, panel_number, 0xFF, 0xFF, 0xFF]) # 3. 拼接操作 def matrix_layout(self, start, v_count, h_count, big_pic_id, source_type, source_id): """ 执行拼接操作 :param start: 拼接开始位置 (左上角第一块屏的 PanelNumber-1) :param v_count: 垂直方向屏个数 :param h_count: 水平方向屏个数 :param big_pic_id: 拼接大画面序列号 :param source_type: 信号源类型 :param source_id: 信号源ID """ # 协议:取消全选 + 设置拼接数据 + 设置标志 + 切换信号源 return (self._send_command([0x80, 0x74, 0x46, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) and self._send_command([0x80, 0xD6, 0x10, start, v_count, h_count, big_pic_id, 0xFF]) and self._send_command([0x80, 0x94, 0x5F, big_pic_id, 0xFF, 0xFF, 0xFF, 0xFF]) and self._send_command([0x80, 0x94, 0x81, source_type, source_id, 0xFF, 0xFF, 0xFF])) # 4. 单屏操作 def single_screen(self, start, v_count, h_count, big_pic_id): """ 执行单屏操作 (还原拼接) """ # 协议:设置单屏数据 + 空命令 + 还原信号源 return (self._send_command([0x80, 0xD6, 0x11, start, v_count, h_count, big_pic_id, 0xFF]) and self._send_command([0x80, 0x94, 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) and self._send_command([0x80, 0xD6, 0x12, start, v_count, h_count, big_pic_id, 0xFF]))