mbus-ffi 0.13.0

Native C FFI and browser WASM bindings for modbus-rs client APIs, with optional generated server bindings
Documentation
# modbus-rs

High-performance Modbus TCP/RTU/ASCII client, server, and gateway for Node.js, powered by Rust.

## Features

- **Async/Promise-based API** - All operations return Promises
- **TCP Client** - Full Modbus TCP/IP client implementation
- **Serial Client** - Modbus RTU and ASCII over serial port
- **TCP Server** - Build Modbus TCP servers with JavaScript handlers
- **TCP Gateway** - Route requests to multiple downstream servers based on unit ID
- **High Performance** - Native Rust core with napi-rs bindings
- **Type Safe** - Full TypeScript definitions included
- **Cross Platform** - Pre-built binaries for Linux, macOS, and Windows

## Installation

```bash
npm install modbus-rs
```

## Quick Start

### TCP Client

```javascript
const { AsyncTcpModbusClient } = require('modbus-rs');

async function main() {
  const client = await AsyncTcpModbusClient.connect({
    host: '127.0.0.1',
    port: 502,
    unitId: 1,
    timeoutMs: 5000,
  });

  try {
    // Read holding registers (FC03)
    const registers = await client.readHoldingRegisters({
      address: 0,
      quantity: 10,
    });
    console.log('Registers:', registers);

    // Write single register (FC06)
    await client.writeSingleRegister({
      address: 0,
      value: 12345,
    });
  } finally {
    await client.close();
  }
}

main().catch(console.error);
```

### Serial RTU Client

```javascript
const { AsyncSerialModbusClient } = require('modbus-rs');

async function main() {
  const client = await AsyncSerialModbusClient.connectRtu({
    portPath: '/dev/ttyUSB0',
    unitId: 1,
    baudRate: 19200,
    dataBits: 8,
    stopBits: 1,
    parity: 'even',
  });

  try {
    const registers = await client.readHoldingRegisters({
      address: 0,
      quantity: 10,
    });
    console.log('Registers:', registers);
  } finally {
    await client.close();
  }
}

main().catch(console.error);
```

### TCP Server

```javascript
const { AsyncTcpModbusServer } = require('modbus-rs');

const holdingRegisters = new Array(1000).fill(0);

async function main() {
  const server = await AsyncTcpModbusServer.bind(
    { host: '0.0.0.0', port: 502 },
    {
      onReadHoldingRegisters: (req) => {
        return holdingRegisters.slice(req.address, req.address + req.count);
      },
      onWriteSingleRegister: (req) => {
        holdingRegisters[req.address] = req.value;
        return true;
      },
    }
  );

  console.log('Server listening on port 502');
  
  process.on('SIGINT', async () => {
    await server.shutdown();
    process.exit(0);
  });
}

main().catch(console.error);
```

### TCP Gateway

```javascript
const { AsyncTcpGateway } = require('modbus-rs');

async function main() {
  const gateway = await AsyncTcpGateway.bind(
    { host: '0.0.0.0', port: 502 },
    {
      downstreams: [
        { host: '192.168.1.10', port: 502 },
        { host: '192.168.1.11', port: 502 },
      ],
      routes: [
        { unitId: 1, channel: 0 },
        { unitId: 2, channel: 1 },
      ],
    }
  );

  console.log('Gateway listening on port 502');
  
  process.on('SIGINT', async () => {
    await gateway.shutdown();
    process.exit(0);
  });
}

main().catch(console.error);
```

## API Reference

### AsyncTcpModbusClient

- `connect(opts: TcpClientOptions)` - Connect to a Modbus TCP server
- `close()` - Close the connection
- `readCoils(opts)` - FC01: Read Coils
- `readDiscreteInputs(opts)` - FC02: Read Discrete Inputs
- `readHoldingRegisters(opts)` - FC03: Read Holding Registers
- `readInputRegisters(opts)` - FC04: Read Input Registers
- `writeSingleCoil(opts)` - FC05: Write Single Coil
- `writeSingleRegister(opts)` - FC06: Write Single Register
- `writeMultipleCoils(opts)` - FC15: Write Multiple Coils
- `writeMultipleRegisters(opts)` - FC16: Write Multiple Registers
- `readWriteMultipleRegisters(opts)` - FC23: Read/Write Multiple Registers
- `readFileRecord(opts)` - FC20: Read File Record
- `writeFileRecord(opts)` - FC21: Write File Record
- `readFifoQueue(opts)` - FC24: Read FIFO Queue
- `readExceptionStatus()` - FC07: Read Exception Status
- `diagnostics(opts)` - FC08: Diagnostics
- `readDeviceIdentification(opts)` - FC43/14: Read Device Identification

### AsyncSerialModbusClient

Same methods as `AsyncTcpModbusClient`, with different connection options:

- `connectRtu(opts: SerialClientOptions)` - Connect using Modbus RTU
- `connectAscii(opts: SerialClientOptions)` - Connect using Modbus ASCII

### AsyncTcpModbusServer

- `bind(opts, handlers)` - Create and start a TCP server
- `shutdown()` - Stop the server

### AsyncTcpGateway

- `bind(opts, config)` - Create and start a gateway
- `shutdown()` - Stop the gateway

## Error Handling

All errors are thrown as JavaScript Error objects with descriptive messages:

```javascript
try {
  await client.readHoldingRegisters({ address: 0, count: 10 });
} catch (err) {
  if (err.message.includes('MODBUS_EXCEPTION')) {
    console.error('Modbus exception:', err.message);
  } else if (err.message.includes('MODBUS_TIMEOUT')) {
    console.error('Request timed out');
  } else {
    console.error('Error:', err.message);
  }
}
```

## Supported platforms

Pre-built binaries are published for:

- Linux x64 (glibc), Linux arm64 (glibc)
- macOS x64, macOS arm64
- Windows x64 (MSVC)
- WebAssembly `modbus-rs-wasm`

Other targets can be built locally via `cargo build -p mbus-ffi --features nodejs,full`
followed by `npm run build`.

## License

GPL-3.0-only — see [LICENSE](./LICENSE).
A commercial license is available for proprietary use; contact ch.raghava44@gmail.com.