
import serial
import serial.tools.list_ports
import threading
import time
import socket





def crc8(data:bytearray,seed:int=0xff):
    poly=0x0135
    crc=seed
    length=len(data)
    for i in range(length):
        d=data[i]
        for j in range(8):
            bit=(crc^d)&0x01
            crc>>= 1
            if(bit>0):
                crc^=poly
                crc=crc&0xff
            d>>=1
    return crc













# 把tcp封装为串口
class utcp:
    is_open=False
    def __init__(self,port:int)->None:
        self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.ser.bind(("",port))
        self.ser.settimeout(10)
        self.ser.listen(128)
        print("wait for mcu connect.")
        self.client,self.client_addr=self.ser.accept()
        print("client:",self.client_addr)
        self.is_open=True
    def read(self,len:int):
        return self.client.recv(len)
    def write(self,data:bytearray):
        return self.client.send(data)
    def close(self):
        self.client.close()
        self.ser.close()
        self.is_open=False



class port:
    def __init__(self) -> None:
        pass
    def open(self,name:str,bsp:int):
        if(name!="utcp"):
            self.ser = serial.Serial(port=name, baudrate=bsp,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,
                        stopbits=serial.STOPBITS_ONE,timeout=None)
        else:
            self.ser=utcp(9527)
    def start_recv(self):
        self.thread_ = threading.Thread(target=self.recv, args=())
        self.thread_.start()
    def recv(self):
        d=bytearray()
        while(True):
            try:
                d+=self.ser.read(1)
            except Exception as a:
                # print("err:",str(a))
                print("port closed")
                return 0,bytearray()
            if(d[0]!=0x23):
                d=d[1:]
            if((len(d)>=4) and (len(d)>=((d[2]<<8)|d[3]))):
                print("recv code:",d.hex(" "))
                return self.decode(d)
    def send(self,type:int,data:bytearray):
        print("send:",self.encode(type,data).hex(" "))
        self.ser.write(self.encode(type,data))
    def encode(self,type:int,data:bytearray):
        table=b"0123456789"
        d=bytearray()
        d.append(0x23)
        d.append(table[type])
        length=len(data)+7
        d.append((length>>8)&0xff)
        d.append(length&0xff)
        d+=data
        d.append(crc8(d))
        d.append(0x0d)
        d.append(0x0a)
        return d
    # 解码 返回指令类型,内容
    def decode(self,data:bytearray):
        d=data[0:-3]
        if(crc8(d)==data[-3]):
            return d[1]-0x30,d[4:]
        else:
            print("crc failed.")
            return 0,bytearray()
    def calc_shell_code(self,id:int):
        shell=bytearray()
        # shell+=b"58"
        shell+=b"61"
        shell+=b"30815A"
        shell+="{d:05d}".format(d=id).encode("utf-8")
        return shell
    # 打包pc到密码终端注码指令
    def pack_code_cmd(self,id_start:int,data_other:bytearray=bytearray()):
        d=bytearray()
        # d+=b"AD"
        d+=b"A0"
        d.append(0)
        d.append(10)
        for i in range(10):
            d.append(0)
            d.append(i+1)
            d.append(0)
            d.append(13)
            leng=len(data_other)
            d.append((leng>>8)&0xff)
            d.append((leng&0xff))
            shell_code=self.calc_shell_code(id_start+i)
            print("shell_code:",shell_code.decode("utf-8"))
            d+=shell_code
            d+=data_other
        return d
    # 打包pc到密码终端注码指令,生成uid
    def pack_code2_cmd(self,id_start:int,data_other:bytearray=bytearray()):
        d=bytearray()
        fact_chip=b"A0"
        year=b"23"
        d+=fact_chip
        d.append(0)
        d.append(10)
        for i in range(10):
            d.append(0)
            d.append(i+1)
            d.append(0)
            d.append(13)
            shell_code=self.calc_shell_code(id_start+i)
            uid_code=fact_chip+year+shell_code[0:2]+shell_code[3:]
            leng=len(uid_code)
            d.append((leng>>8)&0xff)
            d.append((leng&0xff))
            leng=len(data_other)
            d.append((leng>>8)&0xff)
            d.append((leng&0xff))
            d+=shell_code
            d+=uid_code
            d+=data_other
        return d
    # 根据管壳码生成uid和密码
    def pack_psw_cmd(self,data:bytearray,year:bytearray=b"23"):
        d=bytearray()
        fact_chip=data[0:2]
        num=(data[2]<<8)|data[3]
        data=data[4:]
        d+=fact_chip
        d.append((num>>8)&0xff)
        d.append(num&0xff)
        for i in range(num):
            index=(data[0]<<8)|data[1]
            shell_len=(data[2]<<8)|data[3]
            other_len=(data[4]<<8)|data[5]
            shell_code=data[6:6+shell_len]
            other=data[6+shell_len:6+shell_len+other_len]
            # print("shell code:",shell_code.decode("utf-8"))
            # print("other:",other.decode("utf-8"))
            # 一位年份扩展为两位年份，需考虑计划年份与生产时年份不同的情况
            # uid为16位，包含芯片厂家代码和两位年份
            uid_code=fact_chip+year+shell_code[0:2]+shell_code[3:]
            uid_len=len(uid_code)
            # 默认生成的密码
            psw_code=b"12345678"
            psw_len=len(psw_code)
            d.append((index>>8)&0xff)
            d.append(index&0xff)
            d.append((shell_len>>8)&0xff)
            d.append(shell_len&0xff)
            d.append((uid_len>>8)&0xff)
            d.append(uid_len&0xff)
            d.append((psw_len>>8)&0xff)
            d.append(psw_len&0xff)
            d.append((other_len>>8)&0xff)
            d.append(other_len&0xff)
            d+=shell_code
            d+=uid_code
            d+=psw_code
            d+=other
            data=data[6+shell_len+other_len:]
        return d
    # 根据管壳码密码注码，生成注码结果
    def code_write(self,data:bytearray):
        d=bytearray()
        fact_chip=data[0:2]
        num=(data[2]<<8)|data[3]
        data=data[4:]
        d+=fact_chip
        d.append((num>>8)&0xff)
        d.append(num&0xff)
        for i in range(num):
            index=(data[0]<<8)|data[1]
            shell_len=(data[2]<<8)|data[3]
            uid_len=(data[4]<<8)|data[5]
            psw_len=(data[6]<<8)|data[7]
            other_len=(data[8]<<8)|data[9]
            shell_code=data[10:10+shell_len]
            uid_code=data[10+shell_len:10+shell_len+uid_len]
            psw_code=data[10+shell_len+uid_len:10+shell_len+uid_len+psw_len]
            other=data[10+shell_len+uid_len+psw_len:10+shell_len+uid_len+psw_len+other_len]
            ack=bytearray([0])
            ack_len=len(ack)

            print("shell_code:",shell_code.decode("utf-8"))
            print("uid_code:",uid_code.decode("utf-8"))
            print("psw_code:",psw_code.decode("utf-8"))
            print("other:",other.decode("utf-8"))

            d.append((index>>8)&0xff)
            d.append(index&0xff)
            d.append((shell_len>>8)&0xff)
            d.append(shell_len&0xff)
            d.append((uid_len>>8)&0xff)
            d.append(uid_len&0xff)
            d.append((other_len>>8)&0xff)
            d.append(other_len&0xff)
            # d.append((ack_len>>8)&0xff)
            d.append(ack_len&0xff)
            d+=shell_code
            d+=uid_code
            d+=other
            d+=ack
            data=data[10+shell_len+uid_len+psw_len+other_len:]
        return d
    # 解析注码结果
    def code_wirte_end(self,data:bytearray):
        fact_chip=data[0:2]
        num=(data[2]<<8)|data[3]
        data=data[4:]
        print("fact_chip:",fact_chip)
        print("num:",num)
        for i in range(num):
            index=(data[0]<<8)|data[1]
            shell_len=(data[2]<<8)|data[3]
            uid_len=(data[4]<<8)|data[5]
            other_len=(data[6]<<8)|data[7]
            ack_len=(data[8]<<8)|data[9]
            shell_code=data[10:10+shell_len]
            uid_code=data[10+shell_len:10+shell_len+uid_len]
            other=data[10+shell_len+uid_len:10+shell_len+uid_len+other_len]
            ack=data[10+shell_len+uid_len+other_len:10+shell_len+uid_len+other_len+ack_len]


if __name__ == "__main__":
    p=port()
    # p.open("com11",115200)
    # print("生成透传任意指令")
    # d_send=p.encode(5,b"123456789aaaddddggd")
    # print(d_send.hex(" "))
    d_send=p.encode(6,b"987654321ssddffghhf")
    print(d_send.hex(" "))
    # print("解析透传任意指令")
    # typ,d_recv=p.decode(d_send)
    # print(typ,d_recv.hex(" "))

    print("生成管壳码注码命令")
    d_send=p.encode(1,p.pack_code_cmd(987,b"asdfgk"))
    print(d_send.hex(" "))
    # print("生成管壳码UID注码命令")
    # d_send=p.encode(7,p.pack_code2_cmd(0,b"asdfgk"))
    # print(d_send.hex(" "))
    # print("解析管壳码注码命令，生成UID密码注码命令")
    # typ,d_recv=p.decode(d_send)
    # d_send=p.encode(2,p.pack_psw_cmd(d_recv))
    # print(d_send.hex(" "))
    # while (True):
    #     typ,d_recv=p.recv()
    #     start = time.perf_counter()
    #     print("解析uid密码注码命令，生成注码结果")
    #     # d_send=p.encode(3,p.code_write(d_recv))
    #     # print(d_send.hex(" "))
    #     # time.sleep(0.1)
    #     if(typ==2):
    #         print("返回透传数据")
    #         p.send(6,b"sssss")
    #         print("发送注码成功")
    #         p.send(3,p.code_write(d_recv))
    #         end = time.perf_counter()
    #         print("赋码耗时:",end-start)
    #     elif(typ==5):
    #         print("返回透传数据")
    #         p.send(6,b"hello world.")
    #         end = time.perf_counter()
    #         print("透传耗时:",end-start)
