@samlab-corp/sfm-node 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +479 -0
- package/dist/commands/data.d.ts +29 -0
- package/dist/commands/data.d.ts.map +1 -0
- package/dist/commands/data.js +176 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/fingerprint.d.ts +132 -0
- package/dist/commands/fingerprint.d.ts.map +1 -0
- package/dist/commands/fingerprint.js +580 -0
- package/dist/commands/fingerprint.js.map +1 -0
- package/dist/commands/firmware.d.ts +37 -0
- package/dist/commands/firmware.d.ts.map +1 -0
- package/dist/commands/firmware.js +152 -0
- package/dist/commands/firmware.js.map +1 -0
- package/dist/commands/freescan.d.ts +68 -0
- package/dist/commands/freescan.d.ts.map +1 -0
- package/dist/commands/freescan.js +202 -0
- package/dist/commands/freescan.js.map +1 -0
- package/dist/commands/index.d.ts +88 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +104 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/system.d.ts +82 -0
- package/dist/commands/system.d.ts.map +1 -0
- package/dist/commands/system.js +191 -0
- package/dist/commands/system.js.map +1 -0
- package/dist/constants/crypto.d.ts +11 -0
- package/dist/constants/crypto.d.ts.map +1 -0
- package/dist/constants/crypto.js +10 -0
- package/dist/constants/crypto.js.map +1 -0
- package/dist/constants/index.d.ts +6 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +4 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/constants/packet.d.ts +17 -0
- package/dist/constants/packet.d.ts.map +1 -0
- package/dist/constants/packet.js +17 -0
- package/dist/constants/packet.js.map +1 -0
- package/dist/constants/protocol.d.ts +653 -0
- package/dist/constants/protocol.d.ts.map +1 -0
- package/dist/constants/protocol.js +422 -0
- package/dist/constants/protocol.js.map +1 -0
- package/dist/core/client.d.ts +118 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +320 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/crypto.d.ts +86 -0
- package/dist/core/crypto.d.ts.map +1 -0
- package/dist/core/crypto.js +248 -0
- package/dist/core/crypto.js.map +1 -0
- package/dist/core/errors.d.ts +25 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +66 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +15 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/packet.d.ts +126 -0
- package/dist/core/packet.d.ts.map +1 -0
- package/dist/core/packet.js +267 -0
- package/dist/core/packet.js.map +1 -0
- package/dist/core/serial.d.ts +123 -0
- package/dist/core/serial.d.ts.map +1 -0
- package/dist/core/serial.js +421 -0
- package/dist/core/serial.js.map +1 -0
- package/dist/core/tcp.d.ts +58 -0
- package/dist/core/tcp.d.ts.map +1 -0
- package/dist/core/tcp.js +219 -0
- package/dist/core/tcp.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SFM Serial Port Communication Module
|
|
3
|
+
*
|
|
4
|
+
* Based on Ghidra decompilation analysis - FUN_140010350 (Open), FUN_140010280 (Close),
|
|
5
|
+
* FUN_140010420 (Read), FUN_140010770 (Write)
|
|
6
|
+
*
|
|
7
|
+
* Serial settings:
|
|
8
|
+
* BaudRate: 115200 (0x1C200)
|
|
9
|
+
* ByteSize: 8
|
|
10
|
+
* Parity: None
|
|
11
|
+
* StopBits: 1
|
|
12
|
+
* FlowControl: RTS/CTS
|
|
13
|
+
*/
|
|
14
|
+
import { SerialPort } from 'serialport';
|
|
15
|
+
export interface SerialPortInfo {
|
|
16
|
+
path: string;
|
|
17
|
+
manufacturer: string;
|
|
18
|
+
serialNumber: string;
|
|
19
|
+
vendorId: string;
|
|
20
|
+
productId: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AutoReconnectOptions {
|
|
23
|
+
/** Enable auto-reconnect (default: false) */
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
/** Max retry count (default: 5, 0 = infinite) */
|
|
26
|
+
maxRetries?: number;
|
|
27
|
+
/** Retry interval in ms (default: 2000) */
|
|
28
|
+
interval?: number;
|
|
29
|
+
/** Reconnect attempt callback */
|
|
30
|
+
onRetry?: (attempt: number, maxRetries: number) => void;
|
|
31
|
+
/** Reconnect success callback */
|
|
32
|
+
onReconnected?: () => void;
|
|
33
|
+
/** Reconnect final failure callback */
|
|
34
|
+
onFailed?: (error: Error) => void;
|
|
35
|
+
}
|
|
36
|
+
export interface AutoReconnectCallbacks {
|
|
37
|
+
onRetry?: (attempt: number, maxRetries: number) => void;
|
|
38
|
+
onReconnected?: () => void;
|
|
39
|
+
onFailed?: (error: Error) => void;
|
|
40
|
+
}
|
|
41
|
+
export interface SfmSerialOptions {
|
|
42
|
+
path?: string;
|
|
43
|
+
baudRate?: number;
|
|
44
|
+
interCharTimeout?: number;
|
|
45
|
+
autoReconnect?: AutoReconnectOptions;
|
|
46
|
+
}
|
|
47
|
+
export declare class SfmSerial {
|
|
48
|
+
port: SerialPort | null;
|
|
49
|
+
portPath: string;
|
|
50
|
+
baudRate: number;
|
|
51
|
+
isOpen: boolean;
|
|
52
|
+
interCharTimeout: number;
|
|
53
|
+
private _readBuffer;
|
|
54
|
+
private _readResolve;
|
|
55
|
+
private _readReject;
|
|
56
|
+
private _readTimer;
|
|
57
|
+
private _interCharTimer;
|
|
58
|
+
private _onDisconnect;
|
|
59
|
+
private _autoReconnect;
|
|
60
|
+
private _reconnecting;
|
|
61
|
+
private _reconnectTimer;
|
|
62
|
+
constructor(options?: SfmSerialOptions);
|
|
63
|
+
/** Set auto-reconnect options (constructor/internal use) */
|
|
64
|
+
setAutoReconnect(options: AutoReconnectOptions | null): void;
|
|
65
|
+
/** Set auto-reconnect callbacks only (preserves existing enabled/maxRetries/interval) */
|
|
66
|
+
setAutoReconnectCallbacks(callbacks: AutoReconnectCallbacks): void;
|
|
67
|
+
/** Whether reconnection is in progress */
|
|
68
|
+
get isReconnecting(): boolean;
|
|
69
|
+
/** Set disconnect callback */
|
|
70
|
+
setOnDisconnect(callback: ((error?: Error) => void) | null): void;
|
|
71
|
+
/**
|
|
72
|
+
* List available serial ports
|
|
73
|
+
* (corresponds to registry HARDWARE\DEVICEMAP\SERIALCOMM)
|
|
74
|
+
*/
|
|
75
|
+
static listPorts(): Promise<SerialPortInfo[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Open serial port
|
|
78
|
+
* (FUN_140010350: CreateFileA + SetCommState + SetCommTimeouts)
|
|
79
|
+
*/
|
|
80
|
+
open(path?: string): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Close serial port
|
|
83
|
+
* (FUN_140010280: PurgeComm + CloseHandle)
|
|
84
|
+
*/
|
|
85
|
+
close(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Write data (chunked)
|
|
88
|
+
* (FUN_140010770: 64-byte chunk WriteFile)
|
|
89
|
+
*/
|
|
90
|
+
write(data: Buffer | Uint8Array): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Read data
|
|
93
|
+
* (FUN_140010420: ReadFile with timeout)
|
|
94
|
+
*/
|
|
95
|
+
read(expectedLength: number, timeoutMs?: number): Promise<Buffer>;
|
|
96
|
+
/**
|
|
97
|
+
* Read single byte (for handshake)
|
|
98
|
+
*/
|
|
99
|
+
readByte(timeoutMs?: number): Promise<number>;
|
|
100
|
+
/**
|
|
101
|
+
* Read until specific string (for firmware upgrade handshake)
|
|
102
|
+
*/
|
|
103
|
+
readUntil(marker: string, timeoutMs?: number): Promise<string>;
|
|
104
|
+
/**
|
|
105
|
+
* Clear RX buffer (PurgeComm(hFile, 0xA) - PURGE_RXABORT | PURGE_RXCLEAR)
|
|
106
|
+
* (FUN_1400101f0)
|
|
107
|
+
*/
|
|
108
|
+
purgeRX(): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* Clear TX buffer (PurgeComm(hFile, 0x5) - PURGE_TXABORT | PURGE_TXCLEAR)
|
|
111
|
+
* (FUN_140010230)
|
|
112
|
+
*/
|
|
113
|
+
purgeTX(): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Clear both TX/RX (PurgeComm(hFile, 0xF))
|
|
116
|
+
*/
|
|
117
|
+
purgeAll(): Promise<void>;
|
|
118
|
+
private _handleUnexpectedDisconnect;
|
|
119
|
+
private _attemptReconnect;
|
|
120
|
+
private _stopReconnect;
|
|
121
|
+
private _resolveRead;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=serial.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serial.d.ts","sourceRoot":"","sources":["../../src/core/serial.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SFM Serial Port Communication Module
|
|
3
|
+
*
|
|
4
|
+
* Based on Ghidra decompilation analysis - FUN_140010350 (Open), FUN_140010280 (Close),
|
|
5
|
+
* FUN_140010420 (Read), FUN_140010770 (Write)
|
|
6
|
+
*
|
|
7
|
+
* Serial settings:
|
|
8
|
+
* BaudRate: 115200 (0x1C200)
|
|
9
|
+
* ByteSize: 8
|
|
10
|
+
* Parity: None
|
|
11
|
+
* StopBits: 1
|
|
12
|
+
* FlowControl: RTS/CTS
|
|
13
|
+
*/
|
|
14
|
+
import { SerialPort } from 'serialport';
|
|
15
|
+
const DEFAULT_BAUD_RATE = 115200;
|
|
16
|
+
const WRITE_CHUNK_SIZE = 0x40; // 64 bytes per write chunk (from FUN_140010770)
|
|
17
|
+
const READ_TIMEOUT_MS = 3000;
|
|
18
|
+
const INTER_CHAR_TIMEOUT_MS = 50; // ReadIntervalTimeout (FUN_140010630 line 862)
|
|
19
|
+
const WRITE_STALL_LIMIT = 30; // 0x1e retries before abort (FUN_140010770 lines 773-775)
|
|
20
|
+
export class SfmSerial {
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this._reconnecting = false;
|
|
23
|
+
this._reconnectTimer = null;
|
|
24
|
+
this.port = null;
|
|
25
|
+
this.portPath = options.path || '';
|
|
26
|
+
this.baudRate = options.baudRate || DEFAULT_BAUD_RATE;
|
|
27
|
+
this.isOpen = false;
|
|
28
|
+
this._readBuffer = Buffer.alloc(0);
|
|
29
|
+
this._readResolve = null;
|
|
30
|
+
this._readReject = null;
|
|
31
|
+
this._readTimer = null;
|
|
32
|
+
this._interCharTimer = null;
|
|
33
|
+
this._onDisconnect = null;
|
|
34
|
+
this._autoReconnect = options.autoReconnect?.enabled ? options.autoReconnect : null;
|
|
35
|
+
// CommTimeouts detail settings (FUN_140010630 lines 860-868)
|
|
36
|
+
this.interCharTimeout = options.interCharTimeout ?? INTER_CHAR_TIMEOUT_MS;
|
|
37
|
+
}
|
|
38
|
+
/** Set auto-reconnect options (constructor/internal use) */
|
|
39
|
+
setAutoReconnect(options) {
|
|
40
|
+
this._autoReconnect = options?.enabled ? options : null;
|
|
41
|
+
if (!options?.enabled) {
|
|
42
|
+
this._stopReconnect();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Set auto-reconnect callbacks only (preserves existing enabled/maxRetries/interval) */
|
|
46
|
+
setAutoReconnectCallbacks(callbacks) {
|
|
47
|
+
if (this._autoReconnect) {
|
|
48
|
+
Object.assign(this._autoReconnect, callbacks);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Whether reconnection is in progress */
|
|
52
|
+
get isReconnecting() {
|
|
53
|
+
return this._reconnecting;
|
|
54
|
+
}
|
|
55
|
+
/** Set disconnect callback */
|
|
56
|
+
setOnDisconnect(callback) {
|
|
57
|
+
this._onDisconnect = callback;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* List available serial ports
|
|
61
|
+
* (corresponds to registry HARDWARE\DEVICEMAP\SERIALCOMM)
|
|
62
|
+
*/
|
|
63
|
+
static async listPorts() {
|
|
64
|
+
const ports = await SerialPort.list();
|
|
65
|
+
return ports.map(p => ({
|
|
66
|
+
path: p.path,
|
|
67
|
+
manufacturer: p.manufacturer || '',
|
|
68
|
+
serialNumber: p.serialNumber || '',
|
|
69
|
+
vendorId: p.vendorId || '',
|
|
70
|
+
productId: p.productId || '',
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Open serial port
|
|
75
|
+
* (FUN_140010350: CreateFileA + SetCommState + SetCommTimeouts)
|
|
76
|
+
*/
|
|
77
|
+
async open(path) {
|
|
78
|
+
if (this.isOpen) {
|
|
79
|
+
await this.close();
|
|
80
|
+
}
|
|
81
|
+
this.portPath = path || this.portPath;
|
|
82
|
+
if (!this.portPath) {
|
|
83
|
+
throw new Error('Port path must be specified');
|
|
84
|
+
}
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
this.port = new SerialPort({
|
|
87
|
+
path: this.portPath,
|
|
88
|
+
baudRate: this.baudRate,
|
|
89
|
+
dataBits: 8,
|
|
90
|
+
parity: 'none',
|
|
91
|
+
stopBits: 1,
|
|
92
|
+
rtscts: true, // RTS/CTS flow control (DCB bits 0xfffffcff | 3)
|
|
93
|
+
autoOpen: false,
|
|
94
|
+
});
|
|
95
|
+
this.port.on('data', (data) => {
|
|
96
|
+
this._readBuffer = Buffer.concat([this._readBuffer, data]);
|
|
97
|
+
if (this._readResolve) {
|
|
98
|
+
this._resolveRead();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
this.port.on('error', (err) => {
|
|
102
|
+
if (this._readReject) {
|
|
103
|
+
this._readReject(err);
|
|
104
|
+
this._readResolve = null;
|
|
105
|
+
this._readReject = null;
|
|
106
|
+
}
|
|
107
|
+
if (this.isOpen) {
|
|
108
|
+
this.isOpen = false;
|
|
109
|
+
this._readBuffer = Buffer.alloc(0);
|
|
110
|
+
this._handleUnexpectedDisconnect(err);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
this.port.on('close', () => {
|
|
114
|
+
if (this.isOpen) {
|
|
115
|
+
this.isOpen = false;
|
|
116
|
+
this._readBuffer = Buffer.alloc(0);
|
|
117
|
+
if (this._readReject) {
|
|
118
|
+
this._readReject(new Error('Serial port disconnected'));
|
|
119
|
+
this._readResolve = null;
|
|
120
|
+
this._readReject = null;
|
|
121
|
+
}
|
|
122
|
+
this._handleUnexpectedDisconnect();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
this.port.open((err) => {
|
|
126
|
+
if (err) {
|
|
127
|
+
this.port?.removeAllListeners();
|
|
128
|
+
this.port = null;
|
|
129
|
+
reject(new Error(`Failed to open port: ${err.message}`));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this.isOpen = true;
|
|
133
|
+
// DTR signal setup (FUN_140010630 line 886: EscapeCommFunction(handle, 5) = SETDTR)
|
|
134
|
+
this.port.set({ dtr: true }, () => {
|
|
135
|
+
// PurgeComm(hFile, 0xF) - Clear both TX/RX
|
|
136
|
+
this.purgeAll().then(() => resolve()).catch(() => resolve());
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Close serial port
|
|
143
|
+
* (FUN_140010280: PurgeComm + CloseHandle)
|
|
144
|
+
*/
|
|
145
|
+
async close() {
|
|
146
|
+
if (!this.isOpen || !this.port)
|
|
147
|
+
return;
|
|
148
|
+
this.isOpen = false; // Prevent _onDisconnect call from close event
|
|
149
|
+
this._stopReconnect(); // Clean up reconnect timer
|
|
150
|
+
// Clean up pending read timer/promise
|
|
151
|
+
if (this._readTimer) {
|
|
152
|
+
clearTimeout(this._readTimer);
|
|
153
|
+
this._readTimer = null;
|
|
154
|
+
}
|
|
155
|
+
if (this._interCharTimer) {
|
|
156
|
+
clearTimeout(this._interCharTimer);
|
|
157
|
+
this._interCharTimer = null;
|
|
158
|
+
}
|
|
159
|
+
if (this._readReject) {
|
|
160
|
+
this._readReject(new Error('Port closed'));
|
|
161
|
+
this._readResolve = null;
|
|
162
|
+
this._readReject = null;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
await this.purgeAll();
|
|
166
|
+
}
|
|
167
|
+
catch { /* port may already be in error state */ }
|
|
168
|
+
return new Promise((resolve) => {
|
|
169
|
+
this.port.removeAllListeners(); // Clean up event listeners
|
|
170
|
+
this.port.close(() => {
|
|
171
|
+
this._readBuffer = Buffer.alloc(0);
|
|
172
|
+
this.port = null; // Release reference
|
|
173
|
+
// Allow time for OS to fully release fd lock
|
|
174
|
+
setTimeout(resolve, 100);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Write data (chunked)
|
|
180
|
+
* (FUN_140010770: 64-byte chunk WriteFile)
|
|
181
|
+
*/
|
|
182
|
+
async write(data) {
|
|
183
|
+
if (!this.isOpen)
|
|
184
|
+
throw new Error('Port is not open');
|
|
185
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
186
|
+
let offset = 0;
|
|
187
|
+
while (offset < buf.length) {
|
|
188
|
+
const end = Math.min(offset + WRITE_CHUNK_SIZE, buf.length);
|
|
189
|
+
const chunk = buf.subarray(offset, end);
|
|
190
|
+
let retries = 0;
|
|
191
|
+
while (retries < WRITE_STALL_LIMIT) {
|
|
192
|
+
const written = await new Promise((resolve) => {
|
|
193
|
+
if (!this.port)
|
|
194
|
+
return resolve(false);
|
|
195
|
+
this.port.write(chunk, (err) => {
|
|
196
|
+
if (err || !this.port) {
|
|
197
|
+
return resolve(false);
|
|
198
|
+
}
|
|
199
|
+
this.port.drain((drainErr) => {
|
|
200
|
+
resolve(!drainErr);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
if (written) {
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
retries++;
|
|
208
|
+
if (retries >= WRITE_STALL_LIMIT) {
|
|
209
|
+
throw new Error(`Write stall detected: ${WRITE_STALL_LIMIT} consecutive failures at offset ${offset}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
offset = end;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Read data
|
|
217
|
+
* (FUN_140010420: ReadFile with timeout)
|
|
218
|
+
*/
|
|
219
|
+
async read(expectedLength, timeoutMs = READ_TIMEOUT_MS) {
|
|
220
|
+
if (!this.isOpen)
|
|
221
|
+
throw new Error('Port is not open');
|
|
222
|
+
// Return immediately if buffer already has enough data
|
|
223
|
+
if (this._readBuffer.length >= expectedLength) {
|
|
224
|
+
const result = this._readBuffer.subarray(0, expectedLength);
|
|
225
|
+
this._readBuffer = this._readBuffer.subarray(expectedLength);
|
|
226
|
+
return Buffer.from(result);
|
|
227
|
+
}
|
|
228
|
+
return new Promise((resolve, reject) => {
|
|
229
|
+
let settled = false;
|
|
230
|
+
const cleanup = () => {
|
|
231
|
+
if (this._readTimer)
|
|
232
|
+
clearTimeout(this._readTimer);
|
|
233
|
+
if (this._interCharTimer)
|
|
234
|
+
clearTimeout(this._interCharTimer);
|
|
235
|
+
this._readTimer = null;
|
|
236
|
+
this._interCharTimer = null;
|
|
237
|
+
this._readResolve = null;
|
|
238
|
+
this._readReject = null;
|
|
239
|
+
};
|
|
240
|
+
this._readResolve = () => {
|
|
241
|
+
if (settled)
|
|
242
|
+
return;
|
|
243
|
+
if (this._readBuffer.length >= expectedLength) {
|
|
244
|
+
settled = true;
|
|
245
|
+
cleanup();
|
|
246
|
+
const result = this._readBuffer.subarray(0, expectedLength);
|
|
247
|
+
this._readBuffer = this._readBuffer.subarray(expectedLength);
|
|
248
|
+
resolve(Buffer.from(result));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Inter-char timeout: if partial data arrived and no more data
|
|
252
|
+
// for interCharTimeout ms, return available data (ReadIntervalTimeout behavior)
|
|
253
|
+
if (this._readBuffer.length > 0 && this.interCharTimeout > 0) {
|
|
254
|
+
if (this._interCharTimer)
|
|
255
|
+
clearTimeout(this._interCharTimer);
|
|
256
|
+
this._interCharTimer = setTimeout(() => {
|
|
257
|
+
if (settled)
|
|
258
|
+
return;
|
|
259
|
+
if (this._readBuffer.length > 0 && this._readBuffer.length < expectedLength) {
|
|
260
|
+
settled = true;
|
|
261
|
+
cleanup();
|
|
262
|
+
const available = Buffer.from(this._readBuffer);
|
|
263
|
+
this._readBuffer = Buffer.alloc(0);
|
|
264
|
+
resolve(available);
|
|
265
|
+
}
|
|
266
|
+
}, this.interCharTimeout);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
this._readReject = (err) => {
|
|
270
|
+
if (settled)
|
|
271
|
+
return;
|
|
272
|
+
settled = true;
|
|
273
|
+
cleanup();
|
|
274
|
+
reject(err);
|
|
275
|
+
};
|
|
276
|
+
// Overall timeout
|
|
277
|
+
this._readTimer = setTimeout(() => {
|
|
278
|
+
if (settled)
|
|
279
|
+
return;
|
|
280
|
+
settled = true;
|
|
281
|
+
const available = Buffer.from(this._readBuffer);
|
|
282
|
+
this._readBuffer = Buffer.alloc(0);
|
|
283
|
+
cleanup();
|
|
284
|
+
if (available.length > 0) {
|
|
285
|
+
resolve(available);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
reject(new Error(`Read timeout (${timeoutMs}ms)`));
|
|
289
|
+
}
|
|
290
|
+
}, timeoutMs);
|
|
291
|
+
// Check if data already arrived
|
|
292
|
+
this._readResolve();
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Read single byte (for handshake)
|
|
297
|
+
*/
|
|
298
|
+
async readByte(timeoutMs = READ_TIMEOUT_MS) {
|
|
299
|
+
const buf = await this.read(1, timeoutMs);
|
|
300
|
+
return buf[0];
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Read until specific string (for firmware upgrade handshake)
|
|
304
|
+
*/
|
|
305
|
+
async readUntil(marker, timeoutMs = 5000) {
|
|
306
|
+
const startTime = Date.now();
|
|
307
|
+
let accumulated = '';
|
|
308
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
309
|
+
try {
|
|
310
|
+
const byte = await this.readByte(100);
|
|
311
|
+
accumulated += String.fromCharCode(byte);
|
|
312
|
+
if (accumulated.includes(marker)) {
|
|
313
|
+
return accumulated;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
// timeout on single byte, continue
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
throw new Error(`Marker wait timeout: "${marker}" (${timeoutMs}ms)`);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Clear RX buffer (PurgeComm(hFile, 0xA) - PURGE_RXABORT | PURGE_RXCLEAR)
|
|
324
|
+
* (FUN_1400101f0)
|
|
325
|
+
*/
|
|
326
|
+
async purgeRX() {
|
|
327
|
+
this._readBuffer = Buffer.alloc(0);
|
|
328
|
+
if (this.isOpen && this.port) {
|
|
329
|
+
return new Promise((resolve) => {
|
|
330
|
+
this.port.flush(() => {
|
|
331
|
+
resolve();
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Clear TX buffer (PurgeComm(hFile, 0x5) - PURGE_TXABORT | PURGE_TXCLEAR)
|
|
338
|
+
* (FUN_140010230)
|
|
339
|
+
*/
|
|
340
|
+
async purgeTX() {
|
|
341
|
+
if (this.isOpen && this.port) {
|
|
342
|
+
return new Promise((resolve) => {
|
|
343
|
+
this.port.drain(() => {
|
|
344
|
+
resolve();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Clear both TX/RX (PurgeComm(hFile, 0xF))
|
|
351
|
+
*/
|
|
352
|
+
async purgeAll() {
|
|
353
|
+
await this.purgeTX();
|
|
354
|
+
await this.purgeRX();
|
|
355
|
+
}
|
|
356
|
+
_handleUnexpectedDisconnect(error) {
|
|
357
|
+
if (this._autoReconnect) {
|
|
358
|
+
this._attemptReconnect(error);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
this._onDisconnect?.(error);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
async _attemptReconnect(originalError) {
|
|
365
|
+
if (this._reconnecting)
|
|
366
|
+
return;
|
|
367
|
+
this._reconnecting = true;
|
|
368
|
+
let attempt = 0;
|
|
369
|
+
const tryReconnect = async () => {
|
|
370
|
+
if (!this._reconnecting)
|
|
371
|
+
return; // stopReconnect called
|
|
372
|
+
const maxRetries = this._autoReconnect?.maxRetries ?? 5;
|
|
373
|
+
const interval = this._autoReconnect?.interval ?? 2000;
|
|
374
|
+
attempt++;
|
|
375
|
+
this._autoReconnect?.onRetry?.(attempt, maxRetries);
|
|
376
|
+
try {
|
|
377
|
+
await this.open();
|
|
378
|
+
if (!this._reconnecting)
|
|
379
|
+
return; // stopReconnect called during open()
|
|
380
|
+
this._reconnecting = false;
|
|
381
|
+
if (this._reconnectTimer) {
|
|
382
|
+
clearTimeout(this._reconnectTimer);
|
|
383
|
+
this._reconnectTimer = null;
|
|
384
|
+
}
|
|
385
|
+
this._autoReconnect?.onReconnected?.();
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
if (!this._reconnecting)
|
|
389
|
+
return; // stopReconnect called during open()
|
|
390
|
+
if (maxRetries > 0 && attempt >= maxRetries) {
|
|
391
|
+
this._reconnecting = false;
|
|
392
|
+
if (this._reconnectTimer) {
|
|
393
|
+
clearTimeout(this._reconnectTimer);
|
|
394
|
+
this._reconnectTimer = null;
|
|
395
|
+
}
|
|
396
|
+
const failError = new Error(`Reconnect failed: gave up after ${maxRetries} attempts (cause: ${originalError?.message || 'unknown'})`);
|
|
397
|
+
this._autoReconnect?.onFailed?.(failError);
|
|
398
|
+
this._onDisconnect?.(originalError);
|
|
399
|
+
}
|
|
400
|
+
else if (this._reconnecting) {
|
|
401
|
+
this._reconnectTimer = setTimeout(tryReconnect, interval);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const initialInterval = this._autoReconnect?.interval ?? 2000;
|
|
406
|
+
this._reconnectTimer = setTimeout(tryReconnect, initialInterval);
|
|
407
|
+
}
|
|
408
|
+
_stopReconnect() {
|
|
409
|
+
this._reconnecting = false;
|
|
410
|
+
if (this._reconnectTimer) {
|
|
411
|
+
clearTimeout(this._reconnectTimer);
|
|
412
|
+
this._reconnectTimer = null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
_resolveRead() {
|
|
416
|
+
if (this._readResolve) {
|
|
417
|
+
this._readResolve();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=serial.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serial.js","sourceRoot":"","sources":["../../src/core/serial.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SFM TCP/IP Communication Module
|
|
3
|
+
*
|
|
4
|
+
* Transmits the same packet protocol as serial port over TCP socket.
|
|
5
|
+
* Provides the same interface as SfmSerial (open, close, read, write)
|
|
6
|
+
* for transparent substitution in SfmClient.
|
|
7
|
+
*
|
|
8
|
+
* Decompilation analysis:
|
|
9
|
+
* - "TCP Port" @ 14004f280: TCP port configuration string
|
|
10
|
+
* - Protocol packet structure is identical to serial (13/15/35 bytes)
|
|
11
|
+
*/
|
|
12
|
+
export interface SfmTcpOptions {
|
|
13
|
+
host?: string;
|
|
14
|
+
port?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class SfmTcp {
|
|
17
|
+
private socket;
|
|
18
|
+
host: string;
|
|
19
|
+
port: number;
|
|
20
|
+
isOpen: boolean;
|
|
21
|
+
private _readBuffer;
|
|
22
|
+
private _readResolve;
|
|
23
|
+
private _readReject;
|
|
24
|
+
private _readTimer;
|
|
25
|
+
constructor(options?: SfmTcpOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Open TCP connection
|
|
28
|
+
*/
|
|
29
|
+
open(hostOrPath?: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Close TCP connection
|
|
32
|
+
*/
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Write data (TCP doesn't need chunking, but interface-compatible)
|
|
36
|
+
*/
|
|
37
|
+
write(data: Buffer | Uint8Array): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Read data (same interface as SfmSerial.read)
|
|
40
|
+
*/
|
|
41
|
+
read(expectedLength: number, timeoutMs?: number): Promise<Buffer>;
|
|
42
|
+
/**
|
|
43
|
+
* Read single byte
|
|
44
|
+
*/
|
|
45
|
+
readByte(timeoutMs?: number): Promise<number>;
|
|
46
|
+
/**
|
|
47
|
+
* Read until specific string
|
|
48
|
+
*/
|
|
49
|
+
readUntil(marker: string, timeoutMs?: number): Promise<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Clear RX buffer
|
|
52
|
+
*/
|
|
53
|
+
purgeRX(): Promise<void>;
|
|
54
|
+
purgeTX(): Promise<void>;
|
|
55
|
+
purgeAll(): Promise<void>;
|
|
56
|
+
private _resolveRead;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=tcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp.d.ts","sourceRoot":"","sources":["../../src/core/tcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAoB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAEhB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,UAAU,CAAuC;gBAE7C,OAAO,GAAE,aAAkB;IAWvC;;OAEG;IACG,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoE9C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAarD;;OAEG;IACG,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,SAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAsDhF;;OAEG;IACG,QAAQ,CAAC,SAAS,SAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK5D;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBlE;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,OAAO,CAAC,YAAY;CAKrB"}
|