import { ITransport, TRSMode, IRtuEmulatorTransportOptions, EConnectionErrorType, TDeviceStateHandler, TPortStateHandler } from '../../types/public.js'; import ModbusSlaveCore from './slave-core.js'; import { TrafficSniffer } from '../trackers/traffic-sniffer.js'; /** * Node.js RTU Emulator Transport. * * This class implements the ITransport interface for emulating a Modbus RTU slave * in a Node.js environment. It wraps the ModbusSlaveCore and adds RTU-specific * framing (Slave ID + PDU + CRC16). * * It simulates real-world RTU behavior including response latency and proper ADU formatting. */ export default class NodeRtuEmulatorTransport implements ITransport { isOpen: boolean; private core; private logger; private responseLatencyMs; private _sniffer; private _responseAdu; private _deviceStateHandler; private _portStateHandler; /** * Creates a new Node.js RTU Emulator Transport. * @param options - Configuration options for the RTU emulator transport * @param options.slaveId - Modbus slave ID (passed to ModbusSlaveCore). Default: 1 * @param options.loggerEnabled - Enable/disable logging. Default: true * @param options.responseLatencyMs - Simulated response delay in milliseconds. Default: 30 * @param options.initialRegisters - Initial register values to load into the slave core */ constructor(options?: IRtuEmulatorTransportOptions); /** * Attaches a TrafficSniffer instance to monitor emulated Modbus RTU traffic. * This allows for real-time analysis of emulated requests and responses. * @param sniffer - The TrafficSniffer instance to use for monitoring. */ setSniffer(sniffer: TrafficSniffer): void; /** * Opens the transport (emulator connection). * Marks the transport as open and ready to receive requests. */ connect(): Promise; /** * Closes the transport (emulator connection). * Marks the transport as closed and clears any pending response. */ disconnect(): Promise; /** * Writes a Modbus RTU ADU (Application Data Unit) to the emulator. * Parses the incoming RTU frame, extracts Slave ID and PDU, processes it through * the ModbusSlaveCore, adds CRC16, and prepares the response. * @param buffer - Complete Modbus RTU request frame (Slave ID + PDU + CRC) * @throws {Error} If transport is not open or frame is too short */ write(buffer: Uint8Array): Promise; /** * Reads the response from the emulator. * Returns the prepared response ADU if available, otherwise returns an empty buffer * after a short delay (to simulate asynchronous behavior). * @param length - Expected response length (not used in emulator, kept for interface compatibility) * @param timeout - Read timeout in milliseconds (not used in this emulator) * @returns The full Modbus RTU response ADU or empty Uint8Array if no response is ready * @throws {Error} If transport is not open */ read(length: number, timeout?: number): Promise; /** * Flushes any pending response data. * Clears the internal response buffer. */ flush(): Promise; /** * Returns the RS mode used by this transport. * @returns Always returns 'RS485' for RTU emulator */ 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. * Useful for direct access to core functionality such as: * - Adding registers * - Setting exceptions * - Starting/stopping infinity change tasks * @returns The ModbusSlaveCore instance used by this transport */ getCore(): ModbusSlaveCore; }