423 lines
14 KiB
Python
423 lines
14 KiB
Python
# -*- coding: UTF-8 -*-
|
||
import zlib
|
||
from xmlrpc.client import Boolean
|
||
from utils.baseSerail import BaseSerial
|
||
import binascii
|
||
import utils.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 |