s7-server
Version:
TypeScript S7 PLC Server Simulator
436 lines (343 loc) • 12.9 kB
Markdown
# S7 PLC Server Simulator
A comprehensive TypeScript implementation of an S7 PLC server simulator. This server implements the complete Siemens S7 communication protocol and can simulate a real S7 PLC, responding to all standard S7 protocol requests from clients.
## Features
- **Complete S7 Protocol Implementation**: Full ISO-on-TCP (RFC 1006) and S7 PDU protocol support
- **Memory Area Management**: Support for all S7 memory areas (PE, PA, MK, CT, TM, DB)
- **Resourceless Mode**: Custom read/write handlers for dynamic data management
- **Event System**: Comprehensive event handling for server and client events
- **TypeScript**: Full type safety and IntelliSense support
- **Production Ready**: Thread-safe, error-handling, and production-grade code quality
- **Easy to Use**: Simple and intuitive API for S7 server operations
## Installation
```bash
npm install
npm run build
```
## Quick Start
### Basic Server
```typescript
import { S7Server, S7Area } from './src/index';
const server = new S7Server({
localPort: 102,
maxClients: 8,
pduRequest: 960
});
// Register memory areas
const dbBuffer = Buffer.alloc(200);
server.registerArea(S7Area.DB, 1, dbBuffer);
// Start server
await server.start();
```
### Resourceless Server
```typescript
import { S7Server, RWAreaCallback, Operation } from './src/index';
const server = new S7Server();
server.setResourceless(true);
const rwCallback: RWAreaCallback = (sender, operation, tag, buffer, callback) => {
if (operation === Operation.Read) {
// Handle read request
buffer.fill(0x42); // Example data
callback(buffer);
} else {
// Handle write request
console.log('Data written:', buffer);
callback();
}
};
server.setRWAreaCallback(rwCallback);
await server.start();
```
## S7 Protocol Implementation
### Protocol Stack
The implementation follows the complete S7 protocol stack:
```
┌─────────────────────────────────────┐
│ Application Layer │ ← S7 PDU (Protocol Data Unit)
├─────────────────────────────────────┤
│ Presentation Layer │ ← ISO-on-TCP (RFC 1006)
├─────────────────────────────────────┤
│ Session Layer │ ← ISO-on-TCP Connection
├─────────────────────────────────────┤
│ Transport Layer │ ← TCP
├─────────────────────────────────────┤
│ Network Layer │ ← IP
├─────────────────────────────────────┤
│ Data Link Layer │ ← Ethernet
└─────────────────────────────────────┘
```
### ISO-on-TCP Protocol (RFC 1006)
The transport layer implements ISO-on-TCP as specified in RFC 1006:
- **Connection Establishment**: ISO-on-TCP connection negotiation
- **TPDU Handling**: Transport Protocol Data Unit management
- **Connection State Management**: Proper connection lifecycle handling
- **Error Handling**: Connection error detection and recovery
#### Connection Parameters
- **Local TSAP**: Source Transport Service Access Point
- **Remote TSAP**: Destination Transport Service Access Point
- **PDU Size**: Maximum Protocol Data Unit size (default: 960 bytes)
### S7 PDU (Protocol Data Unit)
The S7 PDU implementation handles all S7 protocol messages:
#### Request Types
1. **PDU Negotiation** (`0xF0`): Client-server PDU size negotiation
2. **Read Request** (`0x04`): Read data from memory areas
3. **Write Request** (`0x05`): Write data to memory areas
4. **Control Request** (`0x28`): PLC control operations
#### Response Types
1. **Negotiate Response** (`0xF0`): PDU negotiation response
2. **Read Response** (`0x04`): Read data response with return codes
3. **Write Response** (`0x05`): Write operation confirmation
4. **Control Response** (`0x28`): Control operation result
#### Message Structure
**S7 Request Header (10 bytes)**
```
Offset Size Description
0 1 Protocol ID (0x32)
1 1 Job Type (Request=0x01, Response=0x03)
2 2 Redundancy ID
4 2 Protocol Data Unit Reference
6 2 Parameter Length
8 2 Data Length
```
**S7 Response Header (12 bytes)**
```
Offset Size Description
0 1 Protocol ID (0x32)
1 1 Job Type (Request=0x01, Response=0x03)
2 2 Redundancy ID
4 2 Protocol Data Unit Reference
6 2 Parameter Length
8 2 Data Length
10 1 Error Class
11 1 Error Code
```
### Memory Areas
The server supports all standard S7 memory areas:
| Area | Code | Description | Access |
|------|------|-------------|---------|
| `S7Area.PE` | 0x81 | Process Inputs | Read |
| `S7Area.PA` | 0x82 | Process Outputs | Write |
| `S7Area.MK` | 0x83 | Merkers (Memory) | Read/Write |
| `S7Area.DB` | 0x84 | Data Blocks | Read/Write |
| `S7Area.CT` | 0x1C | Counters | Read/Write |
| `S7Area.TM` | 0x1D | Timers | Read/Write |
### Data Types and Word Lengths
| Word Length | Code | Size | Description |
|-------------|------|------|-------------|
| `S7WordLength.Bit` | 0x01 | 1 bit | Single bit access |
| `S7WordLength.Byte` | 0x02 | 1 byte | Byte access |
| `S7WordLength.Char` | 0x03 | 1 byte | Character access |
| `S7WordLength.Word` | 0x04 | 2 bytes | Word access (16-bit) |
| `S7WordLength.Int` | 0x05 | 2 bytes | Integer access |
| `S7WordLength.DWord` | 0x06 | 4 bytes | Double word access (32-bit) |
| `S7WordLength.DInt` | 0x07 | 4 bytes | Double integer access |
| `S7WordLength.Real` | 0x08 | 4 bytes | Real number access (IEEE 754) |
| `S7WordLength.Counter` | 0x1C | 2 bytes | Counter access |
| `S7WordLength.Timer` | 0x1D | 2 bytes | Timer access |
### Transport Sizes
| Transport Size | Code | Description |
|----------------|------|-------------|
| `TS_RES_BIT` | 0x03 | Bit data |
| `TS_RES_BYTE` | 0x04 | Byte data |
| `TS_RES_INT` | 0x05 | Integer data |
| `TS_RES_REAL` | 0x07 | Real number data |
| `TS_RES_OCTET` | 0x09 | Octet string data |
### Address Format
S7 addresses use a 3-byte format:
- **Byte 0**: High byte of address
- **Byte 1**: Middle byte of address
- **Byte 2**: Low byte of address + bit index (bits 0-2)
The byte address is calculated as: `(address >> 3)`
The bit index is: `(address & 0x07)`
### Communication Flow
#### 1. Connection Establishment
```
Client Server
| |
|------ Connect TCP ----->|
|<----- TCP Accept -------|
| |
|-- ISO-on-TCP Connect -->|
|<- ISO-on-TCP Accept ----|
| |
|---- PDU Negotiate ----->|
|<--- PDU Response -------|
```
#### 2. Read Operation
```
Client Server
| |
|---- S7 Read Request --->|
| | (Process request)
|<--- S7 Read Response ---|
```
#### 3. Write Operation
```
Client Server
| |
|---- S7 Write Request -->|
| | (Process request)
|<--- S7 Write Response --|
```
### Error Handling
The server implements comprehensive error handling:
#### Return Codes
- `0xFF`: Success
- `0x01`: Hardware error
- `0x03`: Access denied
- `0x05`: Invalid address
- `0x06`: Data type not supported
- `0x07`: Data type inconsistent
- `0x0A`: Object not available
- `0x0D`: Insufficient memory
#### Error Recovery
- Automatic connection cleanup on errors
- Proper resource deallocation
- Graceful error responses to clients
- Comprehensive logging for debugging
## API Reference
### S7Server Class
#### Constructor
```typescript
new S7Server(config?: Partial<ServerConfig>)
```
#### Methods
**Server Control**
- `start(): Promise<boolean>` - Start the server
- `startTo(address: string): Promise<boolean>` - Start server on specific address
- `stop(): Promise<boolean>` - Stop the server
**Memory Management**
- `registerArea(areaCode: S7Area, index: number, buffer: Buffer): boolean`
- `unregisterArea(areaCode: S7Area, index: number): boolean`
- `getArea(areaCode: S7Area, index: number): Buffer | null`
- `setArea(areaCode: S7Area, index: number, buffer: Buffer): boolean`
- `lockArea(areaCode: S7Area, index: number): boolean`
- `unlockArea(areaCode: S7Area, index: number): boolean`
**Configuration**
- `setResourceless(value: boolean): boolean`
- `getParam(paramNumber: ServerParam): number | false`
- `setParam(paramNumber: ServerParam, value: number): boolean`
- `getEventsMask(): number`
- `setEventsMask(mask: number): void`
**Status**
- `serverStatus(): ServerStatus`
- `clientsCount(): number`
- `getCpuStatus(): CpuStatus`
- `setCpuStatus(status: CpuStatus): boolean`
- `lastError(): number`
**Events**
- `on('event', callback: EventCallback)` - Server events
- `setRWAreaCallback(callback: RWAreaCallback)` - Read/write callback
## Examples
### Basic Server Example
```bash
npm run start:server
```
### Client Example
```bash
npm run start:client
```
## Running Examples
```bash
# Build the project
npm run build
# Run server example
npm run start:server
# Run client example (in another terminal)
npm run start:client
```
## Testing with S7 Clients
You can test the server with any S7-compatible client:
1. **TIA Portal**: Use the S7 communication blocks
2. **WinCC**: Connect as an S7 client
3. **Custom Applications**: Use libraries like snap7, libnodave, or similar
4. **SCADA Systems**: Most SCADA systems support S7 protocol
### Connection Parameters
- **IP Address**: `127.0.0.1` (localhost)
- **Port**: `102` (default S7 port)
- **Rack**: `0`
- **Slot**: `1`
## Development
### Building
```bash
npm run build
```
### Development Mode
```bash
npm run dev
```
### Testing
```bash
npm test
```
### Linting
```bash
npm run lint
npm run lint:fix
```
### Code Formatting
```bash
npm run format
npm run format:check
```
## Architecture
The TypeScript S7 Server consists of several key components:
### Core Components
1. **S7Server** (`src/server/s7-server.ts`)
- Main server class that manages memory areas and handles high-level operations
- Event system for server and client events
- Configuration and parameter management
2. **S7Protocol** (`src/protocol/s7-protocol.ts`)
- Low-level protocol handler that manages TCP connections and S7 PDU parsing
- Handles read/write requests and responses
- Manages client connections and PDU negotiation
3. **S7PDUParser** (`src/protocol/s7-pdu.ts`)
- Parses and creates S7 Protocol Data Units
- Handles all S7 message types (negotiate, read, write, control)
- Manages address parsing and data type conversion
4. **ConnectionManager** (`src/protocol/connection-manager.ts`)
- Manages client connections and connection state
- Handles ISO-on-TCP protocol implementation
- Connection lifecycle management
5. **ISOTCPProtocol** (`src/protocol/iso-tcp.ts`)
- Implements ISO-on-TCP (RFC 1006) transport protocol
- Handles TPDU (Transport Protocol Data Unit) management
- Connection establishment and teardown
6. **MemoryManager** (`src/memory/memory-manager.ts`)
- Thread-safe memory area management
- Memory locking and synchronization
- Area registration and data access
7. **S7Types** (`src/types/s7-types.ts`)
- Comprehensive type definitions for all S7 protocol elements
- Enums for areas, word lengths, and status codes
- Interface definitions for all data structures
### Protocol Flow
```
Client Request
↓
TCP Socket
↓
ISOTCPProtocol (RFC 1006)
↓
ConnectionManager
↓
S7Protocol
↓
S7PDUParser
↓
S7Server
↓
MemoryManager
↓
Response Back to Client
```
## License
MIT License - see LICENSE file for details.
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Run linting and formatting
6. Submit a pull request
## Acknowledgments
This project implements the Siemens S7 communication protocol specification and RFC 1006 (ISO-on-TCP) from scratch, providing a complete TypeScript solution for S7 PLC server simulation.