npm package: @raydotac/mcprotocol
Description: Mitsubishi MC Protocol implementation for Node.js - TypeScript and JavaScript versions. Inspired by pymcprotocol with support for iQ-R, Q, iQ-L, L, and QnA series PLCs.
Author: raydotac
Latest version: 1.0.4

# MC Protocol Library for Node.js

A comprehensive Node.js library for communicating with Mitsubishi PLCs using the MC Protocol. This library provides both JavaScript and TypeScript implementations, inspired by the popular Python `pymcprotocol` library.

## Features

✅ **Dual Implementation**: Both JavaScript and TypeScript versions  
✅ **Multiple PLC Support**: iQ-R, Q, iQ-L, L, and QnA series  
✅ **Frame Support**: 3E and 4E frame types  
✅ **Hexadecimal Addresses**: Full support for hex addresses like B41A, XFF, Y1A0  
✅ **Type Safety**: Full TypeScript support with type definitions  
✅ **Modern API**: Promise-based with async/await  
✅ **Batch Operations**: Optimized reading/writing of multiple registers  
✅ **Error Handling**: Comprehensive error reporting  
✅ **Production Ready**: Inspired by proven pymcprotocol library  

## Installation

```bash
npm install @raydotac/mcprotocol
```

## Quick Start

### TypeScript Usage (Recommended)

```typescript
import { MCProtocol } from '@raydotac/mcprotocol';

async function main() {
  const plc = new MCProtocol({
    host: '192.168.1.100',
    port: 5002,
    plcType: 'iQ-R'
  });

  try {
    await plc.connect();
    
    // Read single register
    const value = await plc.readRegister('D', 100);
    console.log('D100:', value);
    
    // Read hex address registers
    const hexValue = await plc.readRegister('B', '41A');
    console.log('B41A:', hexValue);
    
    // Read multiple registers (pymcprotocol style) - supports hex!
    const values = await plc.plcRead(['D0', 'D1', 'B41A', 'B23B', 'XFF']);
    console.log('Values:', values);
    
    // Batch read (optimized)
    const batchResult = await plc.batchReadWordUnits([
      { device: 'D', address: 100 },
      { device: 'D', address: 101 },
      { device: 'M', address: 0 }
    ]);
    
    // Write register
    await plc.writeRegister('D', 200, 12345);
    
  } finally {
    await plc.disconnect();
  }
}
```

### JavaScript Usage

```javascript
const { Type4E, PLC_TYPES } = require('@raydotac/mcprotocol');

async function main() {
  const plc = new Type4E(PLC_TYPES.iQR);
  
  try {
    await plc.connect('192.168.1.100', 5002);
    
    // Read 10 registers starting from D0
    const values = await plc.batchread_wordunits('D0', 10);
    console.log('D0-D9:', values);
    
  } finally {
    plc.close();
  }
}
```

## API Reference

### TypeScript API (MCProtocol class)

#### Constructor Options

```typescript
interface MCProtocolOptions {
  host: string;           // PLC IP address
  port: number;           // PLC port (usually 5002)
  timeout?: number;       // Connection timeout (default: 5000ms)
  plcType?: 'Q' | 'iQ-R' | 'iQ-L' | 'L' | 'QnA';  // PLC series
  frame?: '3E' | '4E';    // Frame type (default: '3E')
}
```

#### Methods

- `connect(): Promise<void>` - Connect to PLC
- `disconnect(): Promise<void>` - Disconnect from PLC
- `readRegister(device: string, address: number | string): Promise<number>` - Read single register
- `writeRegister(device: string, address: number | string, value: number): Promise<void>` - Write single register
- `plcRead(registers: string[]): Promise<number[]>` - Read multiple registers (pymcprotocol style)
- `batchReadWordUnits(addresses: DeviceAddress[]): Promise<ReadResult>` - Optimized batch read
- `batchWriteWordUnits(data: WriteData[]): Promise<void>` - Optimized batch write

### JavaScript API (Type4E class)

#### Constructor

```javascript
const plc = new Type4E(plcType);  // plcType: PLC_TYPES.iQR or PLC_TYPES.Q
```

#### Methods

- `connect(ip: string, port: number): Promise<void>` - Connect to PLC
- `close(): void` - Close connection
- `batchread_wordunits(device: string, count: number): Promise<number[]>` - Read word units

## Supported Devices

| Device | Description | Address Format | Example |
|--------|-------------|----------------|---------|
| **D** | Data registers | Decimal | D0, D100, D1000 |
| **R** | File registers | Decimal | R0, R100 |
| **ZR** | Extension file registers | Hexadecimal | ZR0, ZR100 |
| **M** | Internal relays | Decimal | M0, M100 |
| **X** | Input contacts | Hexadecimal | X0, XFF, X1A0 |
| **Y** | Output contacts | Hexadecimal | Y0, YFF, Y1A0 |
| **B** | Link relays | Hexadecimal | B0, B41A, B23B |
| **W** | Link registers | Hexadecimal | W0, WFF, W1000 |

## Hexadecimal Address Support 🆕

This library now supports hexadecimal addresses commonly used in real-world PLC applications. Many device types (like B, X, Y, W) use hexadecimal addressing in practice.

### Address Formats

```typescript
// Numeric addresses (traditional)
await plc.readRegister('D', 100);           // D100 (decimal)
await plc.readRegister('B', 1050);          // B1050 (decimal)

// String addresses with automatic base detection
await plc.readRegister('D', '100');         // D100 (decimal string)
await plc.readRegister('B', '41A');         // B41A (hex string → decimal 1050)

// Register strings (pymcprotocol style)
await plc.plcRead(['D100', 'B41A', 'B23B', 'XFF', 'Y1A0']);
```

### Supported Hex Devices

Devices that use **hexadecimal** addressing (base 16):
- **X, Y**: Input/Output contacts - `XFF`, `Y1A0`
- **B**: Link relays - `B41A`, `B23B`  
- **W**: Link registers - `WFF`, `W1000`
- **SB, SW**: Special registers - `SBFF`, `SWFF`
- **DX, DY**: Direct I/O - `DXFF`, `DYFF`
- **ZR**: Extension file registers - `ZR1000`

Devices that use **decimal** addressing (base 10):
- **D, R**: Data/File registers - `D100`, `R200`
- **M**: Internal relays - `M100`
- **T, C**: Timers/Counters - `T100`, `C200`

### Examples

```typescript
// Real-world hexadecimal addresses
const values = await plc.plcRead([
  'B41A',    // Link relay at hex 41A (decimal 1050)
  'B23B',    // Link relay at hex 23B (decimal 571)
  'XFF',     // Input contact at hex FF (decimal 255)
  'Y1A0',    // Output contact at hex 1A0 (decimal 416)
  'D100'     // Data register at decimal 100
]);

// Batch operations with mixed formats
await plc.batchReadWordUnits([
  { device: 'B', address: '41A' },   // Hex string
  { device: 'D', address: 100 },     // Numeric
  { device: 'X', address: 'FF' },    // Hex string
  { device: 'D', address: '200' }    // Decimal string
]);

// Case-insensitive hex addresses
await plc.readRegister('B', '41a');  // Same as 'B41A'
await plc.readRegister('B', '41A');  // Same as 'B41a'
```

## Supported PLC Series

- **iQ-R Series**: High-performance PLCs (default)
- **Q Series**: Standard PLCs
- **iQ-L Series**: Compact PLCs  
- **L Series**: Basic PLCs
- **QnA Series**: Legacy PLCs

## Error Handling

```typescript
import { MCProtocolError } from '@raydotac/mcprotocol';

try {
  await plc.readRegister('D', 0);
} catch (error) {
  if (error instanceof MCProtocolError) {
    console.log('PLC Error:', error.message);
    console.log('Error Code:', error.errorCode);
  }
}
```

## Examples

### Reading Multiple Device Types

```typescript
const results = await plc.batchReadWordUnits([
  { device: 'D', address: 0 },    // Data register
  { device: 'M', address: 0 },    // Internal relay  
  { device: 'X', address: 0 },    // Input contact
  { device: 'Y', address: 0 }     // Output contact
]);
```

### Batch Writing

```typescript
await plc.batchWriteWordUnits([
  { device: 'D', address: 100, value: 1234 },
  { device: 'D', address: 101, value: 5678 },
  { device: 'D', address: 102, value: 9012 }
]);
```

### Using with Different PLC Types

```typescript
// For Q Series PLC
const qPlc = new MCProtocol({
  host: '192.168.1.100',
  port: 5002,
  plcType: 'Q',
  frame: '3E'
});

// For iQ-L Series PLC  
const iqlPlc = new MCProtocol({
  host: '192.168.1.101', 
  port: 5002,
  plcType: 'iQ-L'
});
```

## Network Configuration

Ensure your PLC has MC Protocol enabled:

1. **iQ-R Series**: Enable "MC Protocol" in the Ethernet module settings
2. **Q Series**: Configure the Ethernet module for MC Protocol communication  
3. **Default Port**: 5002 (can be configured in PLC settings)

## Comparison with pymcprotocol

This library provides similar functionality to the Python `pymcprotocol`:

| Feature | pymcprotocol (Python) | This Library (Node.js) |
|---------|----------------------|------------------------|
| Device Support | ✅ D, M, X, Y, R, etc. | ✅ D, M, X, Y, R, etc. |
| PLC Series | ✅ iQ-R, Q, L | ✅ iQ-R, Q, iQ-L, L, QnA |
| Frame Types | ✅ 3E, 4E | ✅ 3E, 4E |
| Batch Operations | ✅ | ✅ Enhanced |
| Type Safety | ❌ | ✅ Full TypeScript |
| Error Handling | ✅ | ✅ Enhanced |

## Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests.

## License

MIT License - see LICENSE file for details.

## Acknowledgments

- Inspired by the excellent Python `pymcprotocol` library
- Mitsubishi Electric for MC Protocol specifications
- Community feedback and contributions

---

**Note**: This library requires an actual Mitsubishi PLC with MC Protocol enabled for real communication. For testing without hardware, consider using a PLC simulator.