feat: modbus enableCRC
This commit is contained in:
		
							parent
							
								
									051046e891
								
							
						
					
					
						commit
						d67cda3462
					
				
							
								
								
									
										10
									
								
								config.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								config.json
									
									
									
									
									
								
							| @ -1,8 +1,10 @@ | |||||||
| { | { | ||||||
|   "hostPort": "COM10", |   "hostPort": "/dev/cu.usbserial-350", | ||||||
|   "devicePort": "COM11", |   "devicePort": "/dev/cu.usbserial-230", | ||||||
|   "baudRate": 19200, |   "baudRate": 9600, | ||||||
|   "dataBits": 8, |   "dataBits": 8, | ||||||
|   "stopBits": 1, |   "stopBits": 1, | ||||||
|   "parity": "none" |   "parity": "none", | ||||||
|  |   "protocol": "custom", | ||||||
|  |   "enableCRC": false | ||||||
| } | } | ||||||
| @ -5,10 +5,11 @@ | |||||||
|   "bin": "dist/index.js", |   "bin": "dist/index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "build": "tsc", |     "build": "tsc", | ||||||
|     "dev": "ts-node src/idnex.ts", |     "dev": "ts-node src/index.ts", | ||||||
|     "start": "node dist/index.js", |     "start": "node dist/index.js", | ||||||
|     "exe": "nexe dist/index.js --build --resource /Users/daoyouyun/.codes/serial-proxy/nodejs/node-v20.18.0-win-x64.zip --output serial-proxy.exe", |     "exe": "nexe dist/index.js --build --resource /Users/daoyouyun/.codes/serial-proxy/nodejs/node-v20.18.0-win-x64.zip --output serial-proxy.exe", | ||||||
|     "pkg": "pkg . --targets=node18-win-x64 --output=serial-proxy.exe" |     "pkg": "pkg . --targets=node18-win-x64 --output=serial-proxy.exe", | ||||||
|  |     "pkg-arm": "pkg dist/index.js --targets=node18-win-arm64 --output=serial-proxy.exe" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "serialport": "^11.0.0" |     "serialport": "^11.0.0" | ||||||
|  | |||||||
							
								
								
									
										57
									
								
								src/index.ts
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								src/index.ts
									
									
									
									
									
								
							| @ -10,6 +10,8 @@ interface Config { | |||||||
|   dataBits: 8 | 5 | 6 | 7 | undefined; |   dataBits: 8 | 5 | 6 | 7 | undefined; | ||||||
|   stopBits: 1 | 2 | 1.5 | undefined; |   stopBits: 1 | 2 | 1.5 | undefined; | ||||||
|   parity: 'none' | 'even' | 'odd' | 'mark' | 'space'; |   parity: 'none' | 'even' | 'odd' | 'mark' | 'space'; | ||||||
|  |   protocol: 'custom' | 'modbus'; | ||||||
|  |   enableCRC?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function loadConfig(): Config { | function loadConfig(): Config { | ||||||
| @ -30,7 +32,9 @@ function loadConfig(): Config { | |||||||
|       logFile: raw.logFile || path.resolve(process.cwd(), 'serial.log'), |       logFile: raw.logFile || path.resolve(process.cwd(), 'serial.log'), | ||||||
|       dataBits: raw.dataBits || 8, |       dataBits: raw.dataBits || 8, | ||||||
|       stopBits: raw.stopBits || 1, |       stopBits: raw.stopBits || 1, | ||||||
|       parity: raw.parity || 'none' |       parity: raw.parity || 'none', | ||||||
|  |       protocol: raw.protocol === 'modbus' ? 'modbus' : 'custom', | ||||||
|  |       enableCRC: raw.enableCRC === true | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return config; |     return config; | ||||||
| @ -40,30 +44,52 @@ function loadConfig(): Config { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| function formatTime(date: Date): string { | function formatTime(date: Date): string { | ||||||
|   const pad = (n: number) => n.toString().padStart(2, '0'); |   const pad = (n: number) => n.toString().padStart(2, '0'); | ||||||
|   return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` |   return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` | ||||||
|        + `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; |        + `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function formatLogLine(direction: string, data: Buffer): string { | function formatLogLine(direction: string, data: Buffer, protocol: 'custom' | 'modbus'): string { | ||||||
|   const timestamp = formatTime(new Date()); |   const timestamp = formatTime(new Date()); | ||||||
|   const hex = data.toString('hex').toUpperCase().replace(/(.{2})/g, '$1 ').trim(); |   const hex = data.toString('hex').toUpperCase().replace(/(.{2})/g, '$1 ').trim(); | ||||||
|  | 
 | ||||||
|  |   if (protocol === 'modbus') { | ||||||
|  |     return `${timestamp} ${direction} HEX: ${hex}`; | ||||||
|  |   } else { | ||||||
|     const ascii = data.toString().replace(/[^\x20-\x7E]/g, '.'); |     const ascii = data.toString().replace(/[^\x20-\x7E]/g, '.'); | ||||||
|     return `${timestamp} ${direction} HEX: ${hex} ASCII: ${ascii}`; |     return `${timestamp} ${direction} HEX: ${hex} ASCII: ${ascii}`; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function logAndPrint(stream: fs.WriteStream, direction: string, data: Buffer) { | function logAndPrint(stream: fs.WriteStream, direction: string, data: Buffer, protocol: 'custom' | 'modbus') { | ||||||
|   const line = formatLogLine(direction, data); |   const line = formatLogLine(direction, data, protocol); | ||||||
|   stream.write(line + '\n'); |   stream.write(line + '\n'); | ||||||
|   console.log(line); |   console.log(line); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function calculateCRC16(buffer: Buffer): Buffer { | ||||||
|  |   let crc = 0xFFFF; | ||||||
|  | 
 | ||||||
|  |   for (let i = 0; i < buffer.length; i++) { | ||||||
|  |     crc ^= buffer[i]; | ||||||
|  |     for (let j = 0; j < 8; j++) { | ||||||
|  |       if ((crc & 0x0001) !== 0) { | ||||||
|  |         crc >>= 1; | ||||||
|  |         crc ^= 0xA001; | ||||||
|  |       } else { | ||||||
|  |         crc >>= 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const lo = crc & 0xFF; | ||||||
|  |   const hi = (crc >> 8) & 0xFF; | ||||||
|  |   return Buffer.from([lo, hi]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function startProxy(config: Config) { | function startProxy(config: Config) { | ||||||
| 
 |   const { hostPort, devicePort, baudRate, dataBits, stopBits, parity, logFile, protocol, enableCRC } = config; | ||||||
| 
 |  | ||||||
|   const { hostPort, devicePort, baudRate, dataBits, stopBits, parity, logFile } = config; |  | ||||||
| 
 | 
 | ||||||
|   const logStream = fs.createWriteStream(logFile, { flags: 'a' }); |   const logStream = fs.createWriteStream(logFile, { flags: 'a' }); | ||||||
| 
 | 
 | ||||||
| @ -71,12 +97,19 @@ function startProxy(config: Config) { | |||||||
|   const device = new SerialPort({ path: devicePort, baudRate, dataBits, stopBits, parity }); |   const device = new SerialPort({ path: devicePort, baudRate, dataBits, stopBits, parity }); | ||||||
| 
 | 
 | ||||||
|   host.on('data', data => { |   host.on('data', data => { | ||||||
|     logAndPrint(logStream, '[主机 → 设备]', data); |     let outData = data; | ||||||
|     device.write(data); | 
 | ||||||
|  |     if (protocol === 'modbus' && enableCRC) { | ||||||
|  |       const crc = calculateCRC16(data); | ||||||
|  |       outData = Buffer.concat([data, crc]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     logAndPrint(logStream, '[主机 → 设备]', outData, protocol); | ||||||
|  |     device.write(outData); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   device.on('data', data => { |   device.on('data', data => { | ||||||
|     logAndPrint(logStream, '[设备 → 主机]', data); |     logAndPrint(logStream, '[设备 → 主机]', data, protocol); | ||||||
|     host.write(data); |     host.write(data); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
| @ -87,6 +120,8 @@ function startProxy(config: Config) { | |||||||
|   主机端:${hostPort} |   主机端:${hostPort} | ||||||
|   设备端:${devicePort} |   设备端:${devicePort} | ||||||
|   波特率:${baudRate} |   波特率:${baudRate} | ||||||
|  |   协议类型:${protocol} | ||||||
|  |   CRC 校验:${enableCRC ? '启用' : '关闭'} | ||||||
|   日志文件:${logFile}`);
 |   日志文件:${logFile}`);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user