Files
pqAutomationApp/drivers/tvSerail.py
2026-04-20 11:48:38 +08:00

423 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: UTF-8 -*-
import zlib
from xmlrpc.client import Boolean
from drivers.baseSerail import BaseSerial
import binascii
import drivers.baseSerail as baseSerail
# 包头码(包引导码)
PHeader = {
"TV_Debug": 0xAA,
"TV_Return": 0xAB,
"TV_Panel_Debug": 0xAC,
"TV_Panel_Return": 0xAD,
"TV_Debug_Other": 0xAE,
"TV_Other_Return": 0xAF,
}
# 命令结果码;
RCode = {
"RC_OK": 0x0A, # 命令执行通过;
"RC_ERR": 0x0E, # 命令错误或无法执行;
"RC_LOSE": 0x0F, # 命令丢失(链路层出错);
}
# 命令的封装与解析;
class TvParse():
def __init__(self):
# 头引导码(默认1字节,0x86命令二字节);
self.Header = [PHeader['TV_Debug']]
# 包长(默认1字节,0x86长度二字节);
self.Length = [0x00]
# 命令码,1字节(int类型);
self.Command = [0x00]
# 子命令参数;
self.SubCommand = []
# 数据,bytearray格式;
self.Data = []
# crch,1字节;
self.CRCH = 0xFF
# crcl,1字节;
self.CRCL = 0xFF
# 是否是特殊命令;
self.FEFlag = False
# 是否是多参数命令;(同一个Command有多个含义的参数)
self.isMultipleParams = False
# 正确执行后的结果值bytearray格式的二维数组;
self.successData = []
def parseCommand(self, head: int, command: list[int], subCommand: list[int] = [], data: bytearray = bytearray(), isMultipleParams=False, FEFlag=False):
self.Header[0] = head
self.Command = command
self.SubCommand = subCommand
self.Data = data
self.FEFlag = FEFlag
self.isMultipleParams = isMultipleParams
if FEFlag:
self.Header.append(0xFE)
# 注意4 = crch + crcl + lenh + lenl
length = 4 + self.Header.__len__() + self.Data.__len__() + self.Command.__len__() + self.SubCommand.__len__()
# 高字节;
self.Length[0] = length >> 8
# 低字节;
self.Length.append(length & 0xFF)
else:
# 注意3 = crch + crcl + len
self.Length[0] = 3 + self.Header.__len__() + self.Data.__len__() + self.Command.__len__() + self.SubCommand.__len__()
# 生成package;
package = bytearray(self.Header + self.Length + self.Command + self.SubCommand) + self.Data
self.calculateCRC(package)
# 形成最终的命令;
package = bytearray(self.Header + self.Length + self.Command + self.SubCommand) + self.Data + bytearray([self.CRCH, self.CRCL])
# 打印最终命令的十六进制形式,每两个字符之间加一个空格
# hex_string = ' '.join(f'{byte:02X}' for byte in package)
# print("最终命令的十六进制形式:", hex_string)
return package
def calculateCRC(self, data: bytearray):
crc = baseSerail.crc16(data, data.__len__())
# 高字节;
self.CRCH = crc >> 8
# 低字节;
self.CRCL = crc & 0xFF
def parseCommandFc(self, head: int, command: list[int], subCommand: list[int] = [], data: bytearray = bytearray(), isMultipleParams=False):
self.Header[0] = head
self.Command = command
self.SubCommand = subCommand
self.Data = data
self.isMultipleParams = isMultipleParams
self.Length[0] = 3 + self.Header.__len__() + self.Data.__len__() + self.Command.__len__() + self.SubCommand.__len__()
package = bytearray(self.Header + self.Length + self.Command + self.SubCommand) + self.Data
self.calculateCRC(package)
package = bytearray(self.Header + self.Length + self.Command + self.SubCommand) + self.Data + bytearray([self.CRCH]) + bytearray([self.CRCL])
return package
# 成功返回AB 08 FC 08 EC 80 CR1 CR2
# 失败返回AB 08 FC 08 EC 00 CR1 CR2
def parseResultFc(self,data):
data = bytearray(data)
return False
def parseResult(self, data):
data = bytearray(data)
if data.__len__() < 5:
return False
retCode = 0
if self.Header[0] == PHeader['TV_Debug']:
retCode = PHeader['TV_Return']
elif self.Header[0] == PHeader['TV_Panel_Debug']:
retCode = PHeader['TV_Panel_Return']
elif self.Header[0] == PHeader['TV_Debug_Other']:
retCode = PHeader['TV_Other_Return']
if retCode != data[0]:
return False
package = []
tooken_len = 0
return True
def parseString(self, data):
data = bytearray(data)
if data.__len__() < 5:
return False
retCode = 0
if self.Header[0] == PHeader['TV_Debug']:
retCode = PHeader['TV_Return']
elif self.Header[0] == PHeader['TV_Panel_Debug']:
retCode = PHeader['TV_Panel_Return']
elif self.Header[0] == PHeader['TV_Debug_Other']:
retCode = PHeader['TV_Other_Return']
if retCode != data[0]:
return False
package = []
tooken_len = 0
while True:
if tooken_len >= data.__len__():
break
if self.FEFlag:
package_len = data[tooken_len + 1] << 8 + data[tooken_len + 2]
else:
package_len = data[tooken_len + 1]
package = data[tooken_len:tooken_len + package_len]
if package[0] != retCode:
print('Incorrect package head!\n')
return False
crc = crc16(package, package_len - 2)
CRCH = crc >> 8
CRCL = crc & 0xFF
if CRCH != package[-2] and CRCL != package[-1]:
return False
if tooken_len == 0:
if package[2] != RCode['RC_OK']:
return False
else:
if self.Command[0] == 0xFC:
pass
else:
if package[2] - 1 != self.Command[0]:
return False
if package[2] == 0xFE:
self.successData.append(package[5:-2])
else:
self.successData.append(package[3:-2])
tooken_len += package_len
# print('successData:', binascii.b2a_hex(bytearray(self.Command)), self.successData)
return self.successData
class tvSerial(BaseSerial):
def __init__(self):
BaseSerial.__init__(self)
def __del__(self):
self.close()
def checkport(self):
if not self.ser.is_open:
self.reOpen()
return self.ser.is_open
def sendcmd(self, cmd: list[int]):
self.write(bytearray(cmd))
return self.read()
'''协议模式发送命令'''
def sendcmdEx(self, head: int, command: list[int], subCommand: list[int] = [], data: bytearray = bytearray(), FEFlag: Boolean = False, returnParam: Boolean = False):
cmd = TvParse()
package = cmd.parseCommand(head, command, subCommand, data, returnParam, FEFlag)
if self.write(package):
package = self.read()
return cmd.parseResult(package)
return False
def sendcmdEx_string_return(self, head: int, command: list[int], subCommand: list[int] = [], data: bytearray = bytearray(), FEFlag: Boolean = False, returnParam: Boolean = False):
cmd = TvParse()
package = cmd.parseCommand(head, command, subCommand, data, returnParam, FEFlag)
if self.write(package):
package = self.read()
return cmd.parseString(package)
return ""
def sendcmdFc(self, head: int, command: list[int], subCommand: list[int] = [], data: bytearray = bytearray(), FEFlag: Boolean = False, returnParam: Boolean = False):
cmd = TvParse()
package = cmd.parseCommand(head, command, subCommand, data, returnParam, FEFlag)
if self.write(package):
package = self.read()
return cmd.parseResult(package)
return False
def gen_zzip(selfe,gm_file,save_file):
with open(gm_file, 'rb') as f:
data = f.read()
compressed_data = zlib.compress(data)
with open(save_file, 'wb') as f:
f.write(compressed_data)
'''发送pattern'''
def send_parttern(self, rgb: list[int]):
cmd = TvParse()
package = cmd.parseCommand(0xAA, [0x28], [], bytearray(rgb))
if self.write(package):
package = self.read()
return cmd.parseResult(package)
return False
# '''发送10bit-pattern'''
# def send_10_bit_parttern(self, rgb: list[int]):
# cmd = MokaParse()
# rgb16 = convert_rgb16(rgb)
# package = cmd.parseCommandFc(0xAA, [0xFC,0x07,0x06], [0xEC,0x01,0x86,0x00], rgb16)
# if self.write(package):
# package = self.read()
# return cmd.parseResult(package)
# return False
'''发送12bit-pattern'''
def send_12_bit_parttern(self, rgb: list[int]):
cmd = TvParse()
rgb16 = baseSerail.convert_rgb16(rgb)
package = cmd.parseCommand(0xAA, [0x28], [], rgb16)
if self.write(package):
package = self.read()
return cmd.parseResult(package)
return False
'''发送gamma文件'''
def send_gamma(self, file_path: str):
fp = open(file_path, 'rb')
cmd = TvParse()
data = fp.read()
# 生成命令包
package = cmd.parseCommand(0xAA, [0xE9], [0x02], data, False, True)
# 将命令包写入临时文件
if self.write(package):
package = self.read()
print(cmd.parseResult(package))
return cmd.parseResult(package)
'''激活gamma文件'''
def send_gamma_active(self, ini_file: str):
ini_fp = open(ini_file, 'rb')
ind_data = ini_fp.read()
ini_fp.close()
# 计算crc
crc = crc16(ind_data, ind_data.__len__())
CRC_GM = [crc >> 8, crc & 0xFF]
cmd = TvParse()
package = cmd.parseCommand(0xAA, [0x99], [0x06], bytearray(CRC_GM))
if self.write(package):
package = self.read()
print("---------------------")
print(cmd.parseResult(package))
return cmd.parseResult(package)
'''激活gamma文件-12bit版本'''
def send_gamma_active_12bit(self, ini_file: str):
ini_fp = open(ini_file, 'rb')
ind_data = ini_fp.read()
ini_fp.close()
# 计算crc
crc = baseSerail.crc16(ind_data, ind_data.__len__())
CRC_GM = [crc >> 8, crc & 0xFF]
cmd = TvParse()
package = cmd.parseCommandFc(0xAA, [0xFC,0x07], [0x0E], bytearray(CRC_GM))
if self.write(package):
package = self.read()
print("---------------------")
print(cmd.parseResult(package))
return cmd.parseResult(package)
'''进工厂模式'''
def enterFactory(self):
return self.sendcmdEx(0xAA, [0x10], [0x01])
'''白平衡初始化'''
def initWhiteBalance(self):
return self.sendcmdEx(0xAA, [0x16], [0x01])
'''关闭localdimming'''
def closeLocaldimming(self):
return self.sendcmdEx(0xAA, [0x9F,0x07], [0x00])
'''打开内置pattern'''
def openBuiltInPattern(self):
return self.sendcmdEx(0xAA, [0x27], [0x01])
'''关闭内置pattern'''
def closeBuiltInPattern(self):
return self.sendcmdEx(0xAA, [0x27], [0x00])
'''切换标准色温'''
def switchStdColorTemperature(self):
return self.sendcmdEx(0xAA, [0x31], [0x01])
'''切换冷色温'''
def switchColdColorTemperature(self):
return self.sendcmdEx(0xAA, [0x31], [0x02])
'''切换暖色温'''
def switchWarmColorTemperature(self):
return self.sendcmdEx(0xAA, [0x31], [0x03])
'''切换暖2色温'''
def switchWarm2ColorTemperature(self):
return self.sendcmdEx(0xAA, [0x31], [0x04])
'''初始化gamma'''
def initGamma(self):
return self.sendcmdEx(0xAA, [0x9F,0x09], [0x01])
'''进老化模式'''
def enterAgingMode(self):
return self.sendcmdEx(0xAA, [0x13], [0x01])
'''退出老化模式'''
def exitAgingMode(self):
return self.sendcmdEx(0xAA, [0x13], [0x00])
'''软件版本查询'''
def sendSoftwareVersionQuery(self):
return self.sendcmdEx_string_return(0xAA, [0x57], [0x00])
'''PID查询'''
def sendPIDQuery(self):
return self.sendcmdEx_string_return(0xAA, [0x84], [0x00])
def switchHDMI1(self):
"""切换到HDMI1信源"""
return self.sendcmdEx(0xAA, [0x25], [0x01])
def switchHDMI2(self):
"""切换到HDMI2信源"""
return self.sendcmdEx(0xAA, [0x25], [0x02])
def switchHDMI3(self):
"""切换到HDMI3信源"""
return self.sendcmdEx(0xAA, [0x25], [0x03])
def switchVGA(self):
"""切换到VGA信源"""
return self.sendcmdEx(0xAA, [0x24], [0x01])
def switchAV1(self):
"""切换到AV1信源"""
return self.sendcmdEx(0xAA, [0x22], [0x01])
def switchAV2(self):
"""切换到AV2信源"""
return self.sendcmdEx(0xAA, [0x22], [0x02])
def switchAV3(self):
"""切换到AV3信源"""
return self.sendcmdEx(0xAA, [0x22], [0x03])
def switchDisplayMode(self, mode="natural"):
"""切换图像预设模式 """
if mode == "natural":
return self.sendcmdEx(0xAA, [0x30], [0x01])
elif mode == "soft":
return self.sendcmdEx(0xAA, [0x30], [0x02])
elif mode == "bright":
return self.sendcmdEx(0xAA, [0x30], [0x03])
elif mode == "personal":
return self.sendcmdEx(0xAA, [0x30], [0x04])
elif mode == "cinematic":
return self.sendcmdEx(0xAA, [0x30], [0x05])
else:
raise ValueError("Invalid display mode. Use 'natural', 'soft', 'bright', 'personal', or 'cinematic'.")
if __name__ == "__main__":
pass