import serial import time import binascii import threading import struct import msvcrt PORT = 'COM26' BAUDRATE = 9600 REQUEST_HEX = "010313BA0006E0A9" # --- Funkcja CRC16 Modbus --- def modbus_crc(data: bytes) -> bytes: crc = 0xFFFF for pos in data: crc ^= pos for _ in range(8): if crc & 1: crc >>= 1 crc ^= 0xA001 else: crc >>= 1 return crc.to_bytes(2, byteorder='little') # --- Funkcja do konwersji float -> bytes --- def convert_float_to_hex(value: float, endian: str = "BE_SWAP") -> list[int]: """Zwraca listę 4 bajtów float w podanym kodowaniu endian. endian: "BE" – standardowy Big Endian (0x42 F6 E6 66) "LE" – standardowy Little Endian (0x66 E6 F6 42) "BE_SWAP" – Big Endian + byte swap (0xE6 0x66 0x42 0xF6) ← Twój przypadek "LE_SWAP" – Little Endian + byte swap """ raw = struct.pack('>f', value) # zawsze zaczynamy od Big Endian (IEEE754) b = list(raw) if endian == "BE": return b elif endian == "LE": return b[::-1] elif endian == "BE_SWAP": return [b[2], b[3], b[0], b[1]] # słowo niskie najpierw elif endian == "LE_SWAP": return [b[1], b[0], b[3], b[2]] else: raise ValueError("Invalid endian type") # --- Funkcja pomocnicza do tworzenia ramki Modbus --- def build_response_frame(values, endian="BE_SWAP"): """Tworzy ramkę odpowiedzi Modbus z listy wartości float.""" data = [0x01, 0x03, len(values) * 4 * 1.5] # 6 rejestrów → 12 bajtów data[2] = int(len(values) * 4) # liczba bajtów danych for val in values: data.extend(convert_float_to_hex(val, endian)) return bytes(data) paused = False # --- Wątek klawiatury (działa poprawnie) --- def keyboard_listener(): global paused while True: if msvcrt.kbhit(): key = msvcrt.getch().decode(errors="ignore").lower() if key == 'p': paused = not paused state = "PAUSED" if paused else "RUNNING" print(f"\n>>> Program {state}. Press 'P' again to toggle.") time.sleep(0.1) # --- Główna pętla --- def main(): global paused ser = serial.Serial(PORT, BAUDRATE, bytesize=8, parity='N', stopbits=1, timeout=0.05) print(f"Listening on {PORT} at {BAUDRATE} baud...") print("Press 'P' to pause/resume reception.") expected_request = bytes.fromhex(REQUEST_HEX) threading.Thread(target=keyboard_listener, daemon=True).start() # --- Ustal dane dynamicznie --- RESPONSE_DATA = build_response_frame([543.21, 123.45, 9.87], endian="BE_SWAP") try: while True: if paused: time.sleep(0.2) continue if ser.in_waiting: data = ser.read(ser.in_waiting) hex_data = binascii.hexlify(data).upper().decode() print(f"Received: {hex_data}") if data == expected_request: crc = modbus_crc(RESPONSE_DATA) frame = RESPONSE_DATA + crc ser.setRTS(True) time.sleep(0.05) ser.write(frame) ser.flush() time.sleep(0.05) ser.setRTS(False) print(f"Sent response: {binascii.hexlify(frame).upper().decode()}") else: print("Unexpected frame received.") time.sleep(0.05) except KeyboardInterrupt: print("\nExiting...") finally: ser.close() if __name__ == "__main__": main()