import struct import socket import threading from enum import Enum from queue import Queue class State(Enum): STX = 0 LEN = 1 DEVICE_ID = 2 DEVICE_SERIAL = 3 CLASS = 4 COMMAND = 5 DATA = 6 ETX = 7 class Packet: def __init__(self): self.stx = 0 self.len = 0 self.deviceId = 0 self.deviceSerial = 0 self.classType = 0 self.command = 0 self.data = [] self.etx = 0 class Protocol: DEVICE_ID = {"CCU": 0x1, "TTMU": 0x2, "PG": 0x3, "QC": 0x4, "DTS": 0x5} CLASS = { "DATA": 0x44, "GET": 0x47, "SET": 0x53, "EVENT": 0x45, "HEART_BIT": 0x48, } HEADER_LEN = 20 STX = 0x2 ETX = 0x3 def __init__(self, ip, port): self.state = State.STX self.dataIndex = 0 self.deviceId = 0 self.deviceSerial = 0 self.packet = Packet() self.maxLen = 0 self.recvCount = 0 self.classGetCallback = None self.classHeartBitCallback = None self.classDataCallback = None self.dataQueue = Queue() self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((ip, port)) recv_thread = threading.Thread(target=self._recvThread) recv_thread.daemon = True recv_thread.start() parsing_thread = threading.Thread(target=self._parsingThread) parsing_thread.daemon = True parsing_thread.start() def setMaxLen(self, len): self.maxLen = len def setDeviceId(self, deviceId): self.deviceId = deviceId def getDeviceId(self): return self.deviceId def setDeviceSerial(self, deviceSerial): self.deviceSerial = deviceSerial def getDeviceSerial(self): return self.deviceSerial def send(self, arg): print("Build: ", self._buildPacket(*arg)) # print("Build: ", int.from_bytes(self._buildPacket(*arg), byteorder='little')) self.sock.sendall(self._buildPacket(*arg)) def _buildPacket(self, classType, cmd, data=None): length = self.HEADER_LEN print(f"Build Packet: {classType} / {cmd}") payload = [] if data is not None: payload = data length = self.HEADER_LEN + 4 * len(payload) string_format = f"<{7+len(payload)}I" return struct.pack( string_format, self.STX, length, self.deviceId, self.deviceSerial, classType, cmd, *payload, self.ETX, ) def parsing(self, word): ret = False # print("[TEST] Parsing") switch_dict = { State.STX: self.case_stx, State.LEN: self.case_len, State.DEVICE_ID: self.case_producId, State.DEVICE_SERIAL: self.case_productSerial, State.CLASS: self.case_class, State.COMMAND: self.case_command, State.DATA: self.case_data, State.ETX: self.case_etx, } print(f"Parsing {self.state} / {word}") if self.state in switch_dict: ret = switch_dict[self.state](word) else: self.case_default() return ret def case_stx(self, word): if word == self.STX: self.dataIndex = 0 self.packet = Packet() self.packet.stx = word self.state = State.LEN return False def case_len(self, word): self.packet.len = word if 20 <= self.packet.len <= self.maxLen: self.state = State.DEVICE_ID else: self.state = State.STX return False def case_producId(self, word): self.packet.deviceId = word if self.packet.deviceId == self.deviceId: self.state = State.DEVICE_SERIAL else: self.state = State.STX return False def case_productSerial(self, word): self.packet.deviceSerial = word if self.packet.deviceSerial == self.deviceSerial: self.state = State.CLASS else: self.state = State.STX return False def case_class(self, word): self.packet.classType = word if self.packet.classType in self.CLASS.values(): self.state = State.COMMAND else: self.state = State.STX return False def case_command(self, word): self.packet.command = word if (self.packet.len - self.HEADER_LEN) == 0: self.state = State.ETX elif (self.packet.len - self.HEADER_LEN) > self.maxLen: self.state = State.STX else: self.state = State.DATA return False def case_data(self, word): self.packet.data.append(word) if (len(self.packet.data) * 4) >= (self.packet.len - self.HEADER_LEN): self.state = State.ETX return False def case_etx(self, word): ret = False self.packet.etx = word self.state = State.STX if self.packet.etx == self.ETX: ret = True return ret def case_default(self): self.state = State.STX def _recvThread(self): while True: recvData = self.sock.recv(16384) print(f"[REcived] {recvData}") self.recvCount += len(recvData) self.dataQueue.put(recvData) def _parsingThread(self): self.func1() def func1(self): oldArray = bytearray() while True: newArray = self.dataQueue.get() oldArray = oldArray + newArray endIdx = len(oldArray) - len(oldArray) % 4 dataArray = oldArray[:endIdx] oldArray = oldArray[endIdx:] for i in range(0, endIdx, 4): int_value = int.from_bytes(dataArray[i : i + 4], byteorder="little") print(f"[IntValue] {int_value}") if self.parsing(int_value) == True: self.commandProc() def func2(self): oldArray = bytearray() while True: newArray = self.dataQueue.get() if len(newArray) % 4 != 0: oldArray = oldArray + newArray return 0 else: oldArray = newArray string_format = f"<{int(len(oldArray)/4)}I" intArray = struct.unpack(string_format, oldArray) for i in range(len(intArray)): if self.parsing(intArray[i]) == True: self.commandProc() def commandProc(self): classType = self.packet.classType command = self.packet.command payload = self.packet.data if classType == self.CLASS["GET"]: print("GET") if self.classGetCallback != None: self.classGetCallback(command, payload) elif classType == self.CLASS["HEART_BIT"]: print("HearBeat") self._setHeartBit() if self.classHeartBitCallback != None: self.classHeartBitCallback() elif classType == self.CLASS["DATA"]: print("Data") if self.classDataCallback != None: self.classDataCallback(command, payload) def _setHeartBit(self): args = (self.CLASS["HEART_BIT"], self.CMD["HEART_BIT"]) print(self.CLASS["HEART_BIT"], "/" , self.CMD["HEART_BIT"]) self.send(args)