import { ITransport, TRSMode, EConnectionErrorType, TDeviceStateHandler, TPortStateHandler, ITcpEmulatorTransportOptions, IRegisterDefinitions, IInfinityChangeParams } from '../../types/public.js'; import ModbusSlaveCore from './slave-core.js'; import { TrafficSniffer } from '../trackers/traffic-sniffer.js'; /** * Node.js TCP Emulator Transport. * * Implements the ITransport interface for emulating a Modbus TCP slave in a Node.js environment. * This transport wraps ModbusSlaveCore and adds proper Modbus TCP ADU framing * (MBAP Header + PDU). * * Features: * - Simulated network latency * - Full Modbus TCP/MBAP header handling * - Device and port state notifications via callbacks * - Direct access to the underlying slave core */ export default class NodeTcpEmulatorTransport implements ITransport { isOpen: boolean; private core; private logger; private responseLatencyMs; private _pendingResponse; private _sniffer; private _deviceStateHandler; private _portStateHandler; /** * Creates a new Modbus TCP Emulator Transport. * @param options - Configuration options for the TCP emulator */ constructor(options?: ITcpEmulatorTransportOptions); /** * Attaches a TrafficSniffer instance to monitor emulated Modbus TCP traffic. * @param sniffer - The TrafficSniffer instance to use for monitoring. */ setSniffer(sniffer: TrafficSniffer): void; /** * Establishes the emulator connection (simulated). * * Sets the transport to open state, triggers port and device state handlers, * and logs the connection event. */ connect(): Promise; /** * Closes the emulator connection. * * Clears any pending response and notifies handlers about the disconnection. */ disconnect(): Promise; /** * Writes a Modbus TCP request (ADU) to the emulator. * Parses the MBAP header, validates it, extracts the PDU, processes it through * the ModbusSlaveCore, and constructs a proper Modbus TCP response ADU. * @param buffer - Complete Modbus TCP ADU (MBAP Header + PDU) * @throws {Error} If the transport is not open */ write(buffer: Uint8Array): Promise; /** * Reads the pending response from the emulator. * Waits up to the specified timeout for a response to become available. * Returns the full Modbus TCP response ADU when ready. * @param length - Expected response length (kept for interface compatibility, not strictly used) * @param timeout - Maximum time to wait for response in milliseconds * @returns The complete Modbus TCP response ADU or an empty Uint8Array if timeout occurs * @throws {Error} If the transport is not open */ read(length: number, timeout?: number): Promise; /** * Flushes any pending response data. * Clears the internal pending response buffer. */ flush(): Promise; /** * Returns the communication mode used by this transport. * @returns Always returns 'TCP/IP' for this transport */ getRSMode(): TRSMode; /** * Sets the handler for device state changes (connected/disconnected). * @param handler - Callback function to be called when device state changes */ setDeviceStateHandler(handler: TDeviceStateHandler): void; /** * Sets the handler for port state changes (open/closed). * @param handler - Callback function to be called when port state changes */ setPortStateHandler(handler: TPortStateHandler): void; /** * Disables device tracking by removing the device state handler. */ disableDeviceTracking(): Promise; /** * Enables device tracking and optionally sets a new device state handler. * @param handler - Optional new device state handler */ enableDeviceTracking(handler?: TDeviceStateHandler): Promise; /** * Notifies that a device has connected. * @param slaveId - ID of the connected slave */ notifyDeviceConnected(slaveId: number): void; /** * Notifies that a device has disconnected with error details. * @param slaveId - ID of the disconnected slave * @param errorType - Type of disconnection error * @param errorMessage - Description of the disconnection reason */ notifyDeviceDisconnected(slaveId: number, errorType: EConnectionErrorType, errorMessage: string): void; /** * Returns the underlying ModbusSlaveCore instance. * Allows direct access to core features like register manipulation, * exception configuration, and infinity change tasks. * @returns The ModbusSlaveCore instance */ getCore(): ModbusSlaveCore; /** * Convenience method: adds registers to the underlying core. * @param defs - Register definitions * @see ModbusSlaveCore.addRegisters */ addRegisters(defs: IRegisterDefinitions): void; /** * Convenience method: starts infinite value change on a register. * @param params - Infinity change parameters * @see ModbusSlaveCore.infinityChange */ infinityChange(params: IInfinityChangeParams): void; /** * Convenience method: sets a custom exception for a specific function code and address. * @param fc - Modbus function code * @param addr - Register/coil address * @param code - Exception code to return * @see ModbusSlaveCore.setException */ setException(fc: number, addr: number, code: number): void; }