secs4js 0.4.3 → 0.4.4

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/README.md CHANGED
@@ -51,7 +51,22 @@ pnpm dlx tsx examples/<example_file_name>.ts
51
51
  I provide a concise, clear, and efficient way to create SECS-II message types. You can use the following code to import the required items:
52
52
 
53
53
  ```ts
54
- import { B, U1, U2, U4, U8, I1, I2, I4, I8, F4, F8, A, L } from "secs4js";
54
+ import {
55
+ B,
56
+ BOOLEAN,
57
+ U1,
58
+ U2,
59
+ U4,
60
+ U8,
61
+ I1,
62
+ I2,
63
+ I4,
64
+ I8,
65
+ F4,
66
+ F8,
67
+ A,
68
+ L,
69
+ } from "secs4js";
55
70
  ```
56
71
 
57
72
  Using these items, you can easily create SECS-II message types. For example, to create a message containing L, A, and U1 items, you can use the following code:
@@ -159,6 +174,77 @@ const parsedBody = SmlParser.parseBody(smlBody);
159
174
  console.log(parsedBody?.toSml());
160
175
  ```
161
176
 
177
+ ### 3. Extracting Data from SECS-II Messages
178
+
179
+ Data extraction is performed using array indexers, and specific values are retrieved through the `.value` property.
180
+
181
+ We implement parsing conventions that align better with user expectations. For instance, `<BOOLEAN TRUE FALSE>` is parsed into a Boolean array `[true, false]`.
182
+
183
+ For single values, we return the value directly rather than wrapping it in an array. For example, `<U1 123>` is parsed as `123`.
184
+
185
+ For detailed usage, please refer to the code example below. Note that type assertions are required for each retrieved node to ensure TypeScript type safety.
186
+
187
+ ```ts
188
+ import {
189
+ A,
190
+ L,
191
+ Secs2ItemAscii,
192
+ Secs2ItemList,
193
+ Secs2ItemNumeric,
194
+ SmlParser,
195
+ } from "secs4js";
196
+
197
+ function getItemValue() {
198
+ const body = L(A("MDLN-A"), A("SOFTREV-1"));
199
+ const firstA = body?.[0] as Secs2ItemAscii;
200
+ console.log("MDLN: ", firstA.value);
201
+
202
+ const smlBody = `
203
+ <L
204
+ <A "OK" >
205
+ <U1 20 >
206
+ <U2 1000 2000 >
207
+ <U4 100000000 200000000 >
208
+ <U8 1000000000000000 2000000000000 >
209
+ <I1 10 20 >
210
+ <I2 1000 -2000 >
211
+ <I4 100 >
212
+ <I8 -1234567890123456 9973232131213124 >
213
+ <F4 3.14 -6.18 >
214
+ <F8 1.234567890123456 6.18 >
215
+ <B 0x10 0x20 >
216
+ <Boolean TRUE FALSE >
217
+ <L
218
+ <A "Nested" >
219
+ <F4 3.14 >
220
+ <L
221
+ <A "More Nested">
222
+ <Boolean F>
223
+ >
224
+ >
225
+ >
226
+ `;
227
+ const smlBodySecs2Items = SmlParser.parseBody(smlBody);
228
+ const zeroItem = smlBodySecs2Items?.[0] as Secs2ItemAscii;
229
+ const firstU1 = smlBodySecs2Items?.[1] as Secs2ItemNumeric;
230
+ const secondItem = smlBodySecs2Items?.[2] as Secs2ItemNumeric;
231
+ const eighthItem = smlBodySecs2Items?.[8] as Secs2ItemNumeric;
232
+ const tenthItem = smlBodySecs2Items?.[10] as Secs2ItemNumeric;
233
+ const twelfthItem = smlBodySecs2Items?.[12] as Secs2ItemNumeric;
234
+ const nestedList = smlBodySecs2Items?.[13] as Secs2ItemList;
235
+ const nestedListFirstItem = nestedList?.[0] as Secs2ItemAscii;
236
+ console.log("ASCII value: ", zeroItem.value);
237
+ console.log("U1 value: ", firstU1.value);
238
+ console.log("U2 value: ", secondItem.value);
239
+ console.log("I8 value: ", eighthItem.value);
240
+ console.log("F8 value: ", tenthItem.value);
241
+ console.log("BOOLEAN value: ", twelfthItem.value);
242
+ console.log("NESTED ASCII value: ", nestedListFirstItem.value);
243
+ }
244
+
245
+ getItemValue();
246
+ ```
247
+
162
248
  ## Sending and Replying to Messages
163
249
 
164
250
  In this library, you can actively send messages and passively reply to messages.
@@ -40,9 +40,9 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
40
40
  this.stream = stream;
41
41
  this.resetState();
42
42
  this.buffer = Buffer.alloc(0);
43
- this.logger.logState("SECS1", "NotConnected", "Connected");
43
+ this.logger.logState("SECS-I", "NotConnected", "Connected");
44
44
  stream.on("data", (data) => {
45
- this.logger.logBytes("Received", "SECS1", data, { chunkLength: data.length });
45
+ this.logger.logBytes("Received", "SECS-I", data, { chunkLength: data.length });
46
46
  this.buffer = Buffer.concat([this.buffer, data]);
47
47
  if (this.state === CommState.WAIT_BLOCK_LENGTH || this.state === CommState.WAIT_BLOCK_DATA) this.startT1();
48
48
  this.processBuffer();
@@ -51,7 +51,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
51
51
  this.rejectAllTransactions(/* @__PURE__ */ new Error("Stream closed"));
52
52
  this.stream = null;
53
53
  this.emit("disconnected");
54
- this.logger.logState("SECS1", "Connected", "NotConnected");
54
+ this.logger.logState("SECS-I", "Connected", "NotConnected");
55
55
  this.stopAllTimers();
56
56
  this.resetState();
57
57
  });
@@ -129,13 +129,13 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
129
129
  }, timeout);
130
130
  }
131
131
  handleT1Timeout() {
132
- this.logger.detail.warn({ protocol: "SECS1" }, "t1 timeout");
132
+ this.logger.detail.warn({ protocol: "SECS-I" }, "t1 timeout");
133
133
  this.t1Timer = null;
134
134
  this.emit("error", /* @__PURE__ */ new Error("T1 Timeout"));
135
135
  this.resetState();
136
136
  }
137
137
  handleT2Timeout() {
138
- this.logger.detail.warn({ protocol: "SECS1" }, "t2 timeout");
138
+ this.logger.detail.warn({ protocol: "SECS-I" }, "t2 timeout");
139
139
  this.t2Timer = null;
140
140
  if (this.state === CommState.WAIT_EOT) {
141
141
  this.retryCount++;
@@ -144,7 +144,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
144
144
  this.resetState();
145
145
  } else {
146
146
  this.logger.detail.info({
147
- protocol: "SECS1",
147
+ protocol: "SECS-I",
148
148
  retryCount: this.retryCount,
149
149
  retry: this.retry
150
150
  }, "retrying ENQ");
@@ -160,7 +160,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
160
160
  this.resetState();
161
161
  } else {
162
162
  this.logger.detail.info({
163
- protocol: "SECS1",
163
+ protocol: "SECS-I",
164
164
  retryCount: this.retryCount,
165
165
  retry: this.retry
166
166
  }, "retrying block");
@@ -171,7 +171,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
171
171
  this.resetState();
172
172
  }
173
173
  handleT4Timeout() {
174
- this.logger.detail.warn({ protocol: "SECS1" }, "t4 timeout");
174
+ this.logger.detail.warn({ protocol: "SECS-I" }, "t4 timeout");
175
175
  this.t4Timer = null;
176
176
  this.resetState();
177
177
  }
@@ -186,7 +186,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
186
186
  const stream = this.stream;
187
187
  if (stream && !stream.destroyed) {
188
188
  const buf = Buffer.from([byte]);
189
- this.logger.logBytes("Sent", "SECS1", buf);
189
+ this.logger.logBytes("Sent", "SECS-I", buf);
190
190
  stream.write(buf);
191
191
  }
192
192
  }
@@ -196,7 +196,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
196
196
  const byte = this.buffer[0];
197
197
  this.buffer = this.buffer.subarray(1);
198
198
  if (byte === ENQ) {
199
- this.logger.detail.debug({ protocol: "SECS1" }, "rx ENQ");
199
+ this.logger.detail.debug({ protocol: "SECS-I" }, "rx ENQ");
200
200
  this.sendByte(EOT);
201
201
  this.state = CommState.WAIT_BLOCK_LENGTH;
202
202
  this.receivedBlocks = [];
@@ -209,13 +209,13 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
209
209
  const byte = this.buffer[0];
210
210
  this.buffer = this.buffer.subarray(1);
211
211
  if (byte === EOT) {
212
- this.logger.detail.debug({ protocol: "SECS1" }, "rx EOT");
212
+ this.logger.detail.debug({ protocol: "SECS-I" }, "rx EOT");
213
213
  this.clearT2();
214
214
  this.currentBlockIndex = 0;
215
215
  this.sendCurrentBlock();
216
216
  } else if (byte === ENQ) {
217
217
  if (!this.isMaster) {
218
- this.logger.detail.debug({ protocol: "SECS1" }, "rx ENQ while waiting EOT");
218
+ this.logger.detail.debug({ protocol: "SECS-I" }, "rx ENQ while waiting EOT");
219
219
  this.clearT2();
220
220
  this.sendByte(EOT);
221
221
  this.state = CommState.WAIT_BLOCK_LENGTH;
@@ -230,7 +230,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
230
230
  const byte = this.buffer[0];
231
231
  this.buffer = this.buffer.subarray(1);
232
232
  if (byte === ACK) {
233
- this.logger.detail.debug({ protocol: "SECS1" }, "rx ACK");
233
+ this.logger.detail.debug({ protocol: "SECS-I" }, "rx ACK");
234
234
  this.clearT2();
235
235
  if (this.currentBlocks[this.currentBlockIndex].eBit) {
236
236
  this.currentBlocks = [];
@@ -242,7 +242,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
242
242
  this.sendCurrentBlock();
243
243
  }
244
244
  } else if (byte === NAK) {
245
- this.logger.detail.warn({ protocol: "SECS1" }, "rx NAK");
245
+ this.logger.detail.warn({ protocol: "SECS-I" }, "rx NAK");
246
246
  this.clearT2();
247
247
  this.handleT2Timeout();
248
248
  }
@@ -274,7 +274,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
274
274
  const block = new Secs1MessageBlock(fullBlockBuffer);
275
275
  if (block.isValid()) if (block.blockNumber !== this.expectedBlockNum) {
276
276
  this.logger.detail.warn({
277
- protocol: "SECS1",
277
+ protocol: "SECS-I",
278
278
  expected: this.expectedBlockNum,
279
279
  got: block.blockNumber
280
280
  }, "wrong block number");
@@ -300,7 +300,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
300
300
  }
301
301
  }
302
302
  else {
303
- this.logger.detail.warn({ protocol: "SECS1" }, "invalid checksum");
303
+ this.logger.detail.warn({ protocol: "SECS-I" }, "invalid checksum");
304
304
  this.sendByte(NAK);
305
305
  this.state = CommState.IDLE;
306
306
  this.resetState();
@@ -315,7 +315,7 @@ var Secs1Communicator = class extends AbstractSecsCommunicator {
315
315
  const stream = this.stream;
316
316
  const block = this.currentBlocks[this.currentBlockIndex];
317
317
  if (stream && !stream.destroyed) {
318
- this.logger.logBytes("Sent", "SECS1", block.buffer, {
318
+ this.logger.logBytes("Sent", "SECS-I", block.buffer, {
319
319
  blockNumber: block.blockNumber,
320
320
  eBit: block.eBit,
321
321
  systemBytes: block.systemBytes,
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1Communicator.js","names":[],"sources":["../../src/secs1/Secs1Communicator.ts"],"sourcesContent":["import { Duplex } from \"stream\";\nimport {\n\tAbstractSecsCommunicator,\n\tSecsCommunicatorConfig,\n} from \"../core/AbstractSecsCommunicator.js\";\nimport { SecsMessage } from \"../core/AbstractSecsMessage.js\";\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\nimport { Secs1Message } from \"./Secs1Message.js\";\nimport { Secs1MessageBlock } from \"./Secs1MessageBlock.js\";\n\nexport interface Secs1CommunicatorConfig extends SecsCommunicatorConfig {\n\tretry?: number;\n\tisMaster?: boolean;\n}\n\nconst ENQ = 0x05;\nconst EOT = 0x04;\nconst ACK = 0x06;\nconst NAK = 0x15;\n\nenum CommState {\n\tIDLE,\n\tWAIT_EOT,\n\tWAIT_ACK,\n\tWAIT_BLOCK_LENGTH,\n\tWAIT_BLOCK_DATA,\n}\n\nexport abstract class Secs1Communicator extends AbstractSecsCommunicator {\n\tpublic retry: number;\n\tpublic isMaster: boolean;\n\n\tprotected stream: Duplex | null = null;\n\n\tprivate state: CommState = CommState.IDLE;\n\tprivate buffer: Buffer = Buffer.alloc(0);\n\n\tprivate sendQueue: Buffer[] = [];\n\tprivate currentBlocks: Secs1MessageBlock[] = [];\n\tprivate currentBlockIndex = 0;\n\tprivate retryCount = 0;\n\n\tprivate receivedBlocks: Secs1MessageBlock[] = [];\n\tprivate expectedBlockNum = 1;\n\tprivate currentBlockLength = 0;\n\n\tprivate t1Timer: NodeJS.Timeout | null = null;\n\tprivate t2Timer: NodeJS.Timeout | null = null;\n\tprivate t4Timer: NodeJS.Timeout | null = null;\n\n\tconstructor(config: Secs1CommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.retry = config.retry ?? 3;\n\t\tthis.isMaster = config.isMaster ?? false;\n\t}\n\n\tprotected attachStream(stream: Duplex) {\n\t\tthis.stream = stream;\n\t\tthis.resetState();\n\t\tthis.buffer = Buffer.alloc(0);\n\t\tthis.logger.logState(\"SECS1\", \"NotConnected\", \"Connected\");\n\n\t\tstream.on(\"data\", (data: Buffer) => {\n\t\t\tthis.logger.logBytes(\"Received\", \"SECS1\", data, {\n\t\t\t\tchunkLength: data.length,\n\t\t\t});\n\t\t\tthis.buffer = Buffer.concat([this.buffer, data]);\n\t\t\tif (\n\t\t\t\tthis.state === CommState.WAIT_BLOCK_LENGTH ||\n\t\t\t\tthis.state === CommState.WAIT_BLOCK_DATA\n\t\t\t) {\n\t\t\t\tthis.startT1();\n\t\t\t}\n\t\t\tthis.processBuffer();\n\t\t});\n\n\t\tstream.on(\"close\", () => {\n\t\t\tthis.rejectAllTransactions(new Error(\"Stream closed\"));\n\t\t\tthis.stream = null;\n\t\t\tthis.emit(\"disconnected\");\n\t\t\tthis.logger.logState(\"SECS1\", \"Connected\", \"NotConnected\");\n\t\t\tthis.stopAllTimers();\n\t\t\tthis.resetState();\n\t\t});\n\n\t\tstream.on(\"error\", (err: Error) => {\n\t\t\tthis.emit(\"error\", err);\n\t\t});\n\n\t\tthis.emit(\"connected\");\n\t\tthis.processSendQueue();\n\t}\n\n\tprotected stop() {\n\t\tconst stream = this.stream;\n\t\tif (stream && !stream.destroyed) {\n\t\t\tstream.destroy();\n\t\t}\n\t\tthis.stream = null;\n\t\tthis.stopAllTimers();\n\t\tthis.resetState();\n\t}\n\n\tprotected override async sendBufferWithLogs(\n\t\tdirection: \"Sent\" | \"Received\",\n\t\tprotocol: string,\n\t\tbuffer: Buffer,\n\t\tmeta?: Record<string, unknown>,\n\t): Promise<void> {\n\t\tawait super.sendBufferWithLogs(\n\t\t\tdirection,\n\t\t\tprotocol === \"SECS\" ? \"SECS1\" : protocol,\n\t\t\tbuffer,\n\t\t\t{\n\t\t\t\tcommState: CommState[this.state],\n\t\t\t\t...meta,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override sendBuffer(buffer: Buffer): Promise<void> {\n\t\tthis.sendQueue.push(buffer);\n\t\tprocess.nextTick(() => this.processSendQueue());\n\t\treturn Promise.resolve();\n\t}\n\n\tprotected override createMessage(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null,\n\t\tsystemBytes: number,\n\t): SecsMessage {\n\t\treturn new Secs1Message(\n\t\t\tstream,\n\t\t\tfunc,\n\t\t\twBit,\n\t\t\tbody,\n\t\t\tsystemBytes,\n\t\t\tthis.deviceId,\n\t\t);\n\t}\n\n\tprivate clearT1() {\n\t\tif (this.t1Timer) {\n\t\t\tclearTimeout(this.t1Timer);\n\t\t\tthis.t1Timer = null;\n\t\t}\n\t}\n\n\tprivate clearT2() {\n\t\tif (this.t2Timer) {\n\t\t\tclearTimeout(this.t2Timer);\n\t\t\tthis.t2Timer = null;\n\t\t}\n\t}\n\n\tprivate clearT4() {\n\t\tif (this.t4Timer) {\n\t\t\tclearTimeout(this.t4Timer);\n\t\t\tthis.t4Timer = null;\n\t\t}\n\t}\n\n\tprivate stopAllTimers() {\n\t\tthis.clearT1();\n\t\tthis.clearT2();\n\t\tthis.clearT4();\n\t}\n\n\tprivate startT1() {\n\t\tthis.clearT1();\n\t\tif (this.timeoutT1 <= 0) return;\n\t\tthis.t1Timer = setTimeout(() => {\n\t\t\tthis.handleT1Timeout();\n\t\t}, this.timeoutT1 * 1000);\n\t}\n\n\tprivate startT2() {\n\t\tthis.clearT2();\n\t\tif (this.timeoutT2 <= 0) return;\n\t\tconst timeout = this.timeoutT2 * 1000;\n\t\tthis.t2Timer = setTimeout(() => {\n\t\t\tthis.handleT2Timeout();\n\t\t}, timeout);\n\t}\n\n\tprivate startT4() {\n\t\tthis.clearT4();\n\t\tif (this.timeoutT4 <= 0) return;\n\t\tconst timeout = this.timeoutT4 * 1000;\n\t\tthis.t4Timer = setTimeout(() => {\n\t\t\tthis.handleT4Timeout();\n\t\t}, timeout);\n\t}\n\n\tprivate handleT1Timeout() {\n\t\tthis.logger.detail.warn({ protocol: \"SECS1\" }, \"t1 timeout\");\n\t\tthis.t1Timer = null;\n\t\tthis.emit(\"error\", new Error(\"T1 Timeout\"));\n\t\tthis.resetState();\n\t}\n\n\tprivate handleT2Timeout() {\n\t\tthis.logger.detail.warn({ protocol: \"SECS1\" }, \"t2 timeout\");\n\t\tthis.t2Timer = null;\n\t\tif (this.state === CommState.WAIT_EOT) {\n\t\t\tthis.retryCount++;\n\t\t\tif (this.retryCount > this.retry) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Retry limit exceeded waiting for EOT\"));\n\t\t\t\tthis.resetState();\n\t\t\t} else {\n\t\t\t\tthis.logger.detail.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\t\tretryCount: this.retryCount,\n\t\t\t\t\t\tretry: this.retry,\n\t\t\t\t\t},\n\t\t\t\t\t\"retrying ENQ\",\n\t\t\t\t);\n\t\t\t\tthis.sendByte(ENQ);\n\t\t\t\tthis.startT2();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.state === CommState.WAIT_ACK) {\n\t\t\tthis.retryCount++;\n\t\t\tif (this.retryCount > this.retry) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Retry limit exceeded waiting for ACK\"));\n\t\t\t\tthis.resetState();\n\t\t\t} else {\n\t\t\t\tthis.logger.detail.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\t\tretryCount: this.retryCount,\n\t\t\t\t\t\tretry: this.retry,\n\t\t\t\t\t},\n\t\t\t\t\t\"retrying block\",\n\t\t\t\t);\n\t\t\t\tthis.sendCurrentBlock();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.resetState();\n\t}\n\n\tprivate handleT4Timeout() {\n\t\tthis.logger.detail.warn({ protocol: \"SECS1\" }, \"t4 timeout\");\n\t\tthis.t4Timer = null;\n\t\tthis.resetState();\n\t}\n\n\tprivate resetState() {\n\t\tthis.state = CommState.IDLE;\n\t\tthis.receivedBlocks = [];\n\t\tthis.expectedBlockNum = 1;\n\t\tthis.currentBlockLength = 0;\n\t\tthis.stopAllTimers();\n\t}\n\n\tprivate sendByte(byte: number) {\n\t\tconst stream = this.stream;\n\t\tif (stream && !stream.destroyed) {\n\t\t\tconst buf = Buffer.from([byte]);\n\t\t\tthis.logger.logBytes(\"Sent\", \"SECS1\", buf);\n\t\t\tstream.write(buf);\n\t\t}\n\t}\n\n\tprivate processBuffer() {\n\t\twhile (this.buffer.length > 0) {\n\t\t\tswitch (this.state) {\n\t\t\t\tcase CommState.IDLE: {\n\t\t\t\t\tconst byte = this.buffer[0];\n\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\tif (byte === ENQ) {\n\t\t\t\t\t\tthis.logger.detail.debug({ protocol: \"SECS1\" }, \"rx ENQ\");\n\t\t\t\t\t\tthis.sendByte(EOT);\n\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_LENGTH;\n\t\t\t\t\t\tthis.receivedBlocks = [];\n\t\t\t\t\t\tthis.expectedBlockNum = 1;\n\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_EOT: {\n\t\t\t\t\tconst byte = this.buffer[0];\n\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\tif (byte === EOT) {\n\t\t\t\t\t\tthis.logger.detail.debug({ protocol: \"SECS1\" }, \"rx EOT\");\n\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\tthis.currentBlockIndex = 0;\n\t\t\t\t\t\tthis.sendCurrentBlock();\n\t\t\t\t\t} else if (byte === ENQ) {\n\t\t\t\t\t\tif (!this.isMaster) {\n\t\t\t\t\t\t\tthis.logger.detail.debug(\n\t\t\t\t\t\t\t\t{ protocol: \"SECS1\" },\n\t\t\t\t\t\t\t\t\"rx ENQ while waiting EOT\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\t\tthis.sendByte(EOT);\n\t\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_LENGTH;\n\t\t\t\t\t\t\tthis.receivedBlocks = [];\n\t\t\t\t\t\t\tthis.expectedBlockNum = 1;\n\t\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_ACK: {\n\t\t\t\t\tconst byte = this.buffer[0];\n\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\tif (byte === ACK) {\n\t\t\t\t\t\tthis.logger.detail.debug({ protocol: \"SECS1\" }, \"rx ACK\");\n\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\tconst currentBlock = this.currentBlocks[this.currentBlockIndex];\n\t\t\t\t\t\tif (currentBlock.eBit) {\n\t\t\t\t\t\t\tthis.currentBlocks = [];\n\t\t\t\t\t\t\tthis.retryCount = 0;\n\t\t\t\t\t\t\tthis.state = CommState.IDLE;\n\t\t\t\t\t\t\tthis.processSendQueue();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.currentBlockIndex++;\n\t\t\t\t\t\t\tthis.sendCurrentBlock();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (byte === NAK) {\n\t\t\t\t\t\tthis.logger.detail.warn({ protocol: \"SECS1\" }, \"rx NAK\");\n\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\tthis.handleT2Timeout();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_BLOCK_LENGTH: {\n\t\t\t\t\tif (this.t4Timer) {\n\t\t\t\t\t\tthis.clearT4();\n\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t}\n\t\t\t\t\tconst len = this.buffer[0];\n\t\t\t\t\tif (len < 10) {\n\t\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.currentBlockLength = len;\n\t\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_DATA;\n\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_BLOCK_DATA: {\n\t\t\t\t\tif (this.buffer.length >= this.currentBlockLength + 2) {\n\t\t\t\t\t\tconst blockData = this.buffer.subarray(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tthis.currentBlockLength + 2,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.buffer = this.buffer.subarray(this.currentBlockLength + 2);\n\t\t\t\t\t\tthis.stopAllTimers();\n\n\t\t\t\t\t\tconst fullBlockBuffer = Buffer.alloc(1 + blockData.length);\n\t\t\t\t\t\tfullBlockBuffer[0] = this.currentBlockLength;\n\t\t\t\t\t\tblockData.copy(fullBlockBuffer, 1);\n\n\t\t\t\t\t\tconst block = new Secs1MessageBlock(fullBlockBuffer);\n\t\t\t\t\t\tif (block.isValid()) {\n\t\t\t\t\t\t\tif (block.blockNumber !== this.expectedBlockNum) {\n\t\t\t\t\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\t\t\t\t\t\texpected: this.expectedBlockNum,\n\t\t\t\t\t\t\t\t\t\tgot: block.blockNumber,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"wrong block number\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tthis.sendByte(NAK);\n\t\t\t\t\t\t\t\tthis.state = CommState.IDLE;\n\t\t\t\t\t\t\t\tthis.resetState();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.sendByte(ACK);\n\t\t\t\t\t\t\t\tthis.receivedBlocks.push(block);\n\t\t\t\t\t\t\t\tif (block.eBit) {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst msg = Secs1Message.fromBlocks(this.receivedBlocks);\n\t\t\t\t\t\t\t\t\t\tthis.handleMessage(msg);\n\t\t\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\t\t\t\t\te instanceof Error ? e : new Error(String(e)),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthis.resetState();\n\t\t\t\t\t\t\t\t\tthis.processSendQueue();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tthis.expectedBlockNum++;\n\t\t\t\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_LENGTH;\n\t\t\t\t\t\t\t\t\tthis.startT4();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t\t\t\t{ protocol: \"SECS1\" },\n\t\t\t\t\t\t\t\t\"invalid checksum\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthis.sendByte(NAK);\n\t\t\t\t\t\t\tthis.state = CommState.IDLE;\n\t\t\t\t\t\t\tthis.resetState();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate sendCurrentBlock() {\n\t\tif (this.currentBlockIndex >= this.currentBlocks.length) return;\n\t\tconst stream = this.stream;\n\t\tconst block = this.currentBlocks[this.currentBlockIndex];\n\t\tif (stream && !stream.destroyed) {\n\t\t\tthis.logger.logBytes(\"Sent\", \"SECS1\", block.buffer, {\n\t\t\t\tblockNumber: block.blockNumber,\n\t\t\t\teBit: block.eBit,\n\t\t\t\tsystemBytes: block.systemBytes,\n\t\t\t\tstream: block.stream,\n\t\t\t\tfunc: block.func,\n\t\t\t});\n\t\t\tstream.write(block.buffer);\n\t\t\tthis.state = CommState.WAIT_ACK;\n\t\t\tthis.startT2();\n\t\t}\n\t}\n\n\tprivate processSendQueue() {\n\t\tif (this.state !== CommState.IDLE) return;\n\t\tconst stream = this.stream;\n\t\tif (!stream || stream.destroyed) return;\n\t\tif (this.sendQueue.length === 0) return;\n\n\t\tconst buffer = this.sendQueue.shift();\n\t\tif (!buffer) return;\n\n\t\ttry {\n\t\t\tconst rBit = (buffer[0] & 0x80) === 0x80;\n\t\t\tconst deviceId = ((buffer[0] & 0x7f) << 8) | buffer[1];\n\t\t\tconst streamId = buffer[2] & 0x7f;\n\t\t\tconst wBit = (buffer[2] & 0x80) === 0x80;\n\t\t\tconst func = buffer[3];\n\t\t\tconst systemBytes = buffer.readUInt32BE(6);\n\t\t\tconst bodyBuffer = buffer.subarray(10);\n\n\t\t\tthis.currentBlocks = [];\n\t\t\tlet pos = 0;\n\t\t\tlet blockNum = 1;\n\n\t\t\tif (bodyBuffer.length === 0) {\n\t\t\t\tthis.currentBlocks.push(\n\t\t\t\t\tSecs1MessageBlock.fromParts(\n\t\t\t\t\t\tdeviceId,\n\t\t\t\t\t\tstreamId,\n\t\t\t\t\t\tfunc,\n\t\t\t\t\t\twBit,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\tblockNum,\n\t\t\t\t\t\tsystemBytes,\n\t\t\t\t\t\tBuffer.alloc(0),\n\t\t\t\t\t\trBit,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\twhile (pos < bodyBuffer.length) {\n\t\t\t\t\tconst remaining = bodyBuffer.length - pos;\n\t\t\t\t\tconst chunkSize = remaining > 244 ? 244 : remaining;\n\t\t\t\t\tconst chunk = bodyBuffer.subarray(pos, pos + chunkSize);\n\t\t\t\t\tconst isLast = pos + chunkSize >= bodyBuffer.length;\n\n\t\t\t\t\tthis.currentBlocks.push(\n\t\t\t\t\t\tSecs1MessageBlock.fromParts(\n\t\t\t\t\t\t\tdeviceId,\n\t\t\t\t\t\t\tstreamId,\n\t\t\t\t\t\t\tfunc,\n\t\t\t\t\t\t\twBit,\n\t\t\t\t\t\t\tisLast,\n\t\t\t\t\t\t\tblockNum,\n\t\t\t\t\t\t\tsystemBytes,\n\t\t\t\t\t\t\tchunk,\n\t\t\t\t\t\t\trBit,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tpos += chunkSize;\n\t\t\t\t\tblockNum++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.currentBlockIndex = 0;\n\t\t\tthis.retryCount = 0;\n\n\t\t\tthis.sendByte(ENQ);\n\t\t\tthis.state = CommState.WAIT_EOT;\n\t\t\tthis.startT2();\n\t\t} catch (e) {\n\t\t\tthis.emit(\"error\", e instanceof Error ? e : new Error(String(e)));\n\t\t\tthis.processSendQueue();\n\t\t}\n\t}\n\n\tprivate rejectAllTransactions(err: Error) {\n\t\tfor (const [systemBytes, tx] of this._transactions) {\n\t\t\tclearTimeout(tx.timer);\n\t\t\ttx.reject(err);\n\t\t\tthis._transactions.delete(systemBytes);\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAeA,MAAM,MAAM;AACZ,MAAM,MAAM;AACZ,MAAM,MAAM;AACZ,MAAM,MAAM;AAEZ,IAAK,kDAAL;AACC;AACA;AACA;AACA;AACA;;EALI;AAQL,IAAsB,oBAAtB,cAAgD,yBAAyB;CACxE,AAAO;CACP,AAAO;CAEP,AAAU,SAAwB;CAElC,AAAQ,QAAmB,UAAU;CACrC,AAAQ,SAAiB,OAAO,MAAM,EAAE;CAExC,AAAQ,YAAsB,EAAE;CAChC,AAAQ,gBAAqC,EAAE;CAC/C,AAAQ,oBAAoB;CAC5B,AAAQ,aAAa;CAErB,AAAQ,iBAAsC,EAAE;CAChD,AAAQ,mBAAmB;CAC3B,AAAQ,qBAAqB;CAE7B,AAAQ,UAAiC;CACzC,AAAQ,UAAiC;CACzC,AAAQ,UAAiC;CAEzC,YAAY,QAAiC;AAC5C,QAAM,OAAO;AACb,OAAK,QAAQ,OAAO,SAAS;AAC7B,OAAK,WAAW,OAAO,YAAY;;CAGpC,AAAU,aAAa,QAAgB;AACtC,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,SAAS,OAAO,MAAM,EAAE;AAC7B,OAAK,OAAO,SAAS,SAAS,gBAAgB,YAAY;AAE1D,SAAO,GAAG,SAAS,SAAiB;AACnC,QAAK,OAAO,SAAS,YAAY,SAAS,MAAM,EAC/C,aAAa,KAAK,QAClB,CAAC;AACF,QAAK,SAAS,OAAO,OAAO,CAAC,KAAK,QAAQ,KAAK,CAAC;AAChD,OACC,KAAK,UAAU,UAAU,qBACzB,KAAK,UAAU,UAAU,gBAEzB,MAAK,SAAS;AAEf,QAAK,eAAe;IACnB;AAEF,SAAO,GAAG,eAAe;AACxB,QAAK,sCAAsB,IAAI,MAAM,gBAAgB,CAAC;AACtD,QAAK,SAAS;AACd,QAAK,KAAK,eAAe;AACzB,QAAK,OAAO,SAAS,SAAS,aAAa,eAAe;AAC1D,QAAK,eAAe;AACpB,QAAK,YAAY;IAChB;AAEF,SAAO,GAAG,UAAU,QAAe;AAClC,QAAK,KAAK,SAAS,IAAI;IACtB;AAEF,OAAK,KAAK,YAAY;AACtB,OAAK,kBAAkB;;CAGxB,AAAU,OAAO;EAChB,MAAM,SAAS,KAAK;AACpB,MAAI,UAAU,CAAC,OAAO,UACrB,QAAO,SAAS;AAEjB,OAAK,SAAS;AACd,OAAK,eAAe;AACpB,OAAK,YAAY;;CAGlB,MAAyB,mBACxB,WACA,UACA,QACA,MACgB;AAChB,QAAM,MAAM,mBACX,WACA,aAAa,SAAS,UAAU,UAChC,QACA;GACC,WAAW,UAAU,KAAK;GAC1B,GAAG;GACH,CACD;;CAGF,AAAmB,WAAW,QAA+B;AAC5D,OAAK,UAAU,KAAK,OAAO;AAC3B,UAAQ,eAAe,KAAK,kBAAkB,CAAC;AAC/C,SAAO,QAAQ,SAAS;;CAGzB,AAAmB,cAClB,QACA,MACA,MACA,MACA,aACc;AACd,SAAO,IAAI,aACV,QACA,MACA,MACA,MACA,aACA,KAAK,SACL;;CAGF,AAAQ,UAAU;AACjB,MAAI,KAAK,SAAS;AACjB,gBAAa,KAAK,QAAQ;AAC1B,QAAK,UAAU;;;CAIjB,AAAQ,UAAU;AACjB,MAAI,KAAK,SAAS;AACjB,gBAAa,KAAK,QAAQ;AAC1B,QAAK,UAAU;;;CAIjB,AAAQ,UAAU;AACjB,MAAI,KAAK,SAAS;AACjB,gBAAa,KAAK,QAAQ;AAC1B,QAAK,UAAU;;;CAIjB,AAAQ,gBAAgB;AACvB,OAAK,SAAS;AACd,OAAK,SAAS;AACd,OAAK,SAAS;;CAGf,AAAQ,UAAU;AACjB,OAAK,SAAS;AACd,MAAI,KAAK,aAAa,EAAG;AACzB,OAAK,UAAU,iBAAiB;AAC/B,QAAK,iBAAiB;KACpB,KAAK,YAAY,IAAK;;CAG1B,AAAQ,UAAU;AACjB,OAAK,SAAS;AACd,MAAI,KAAK,aAAa,EAAG;EACzB,MAAM,UAAU,KAAK,YAAY;AACjC,OAAK,UAAU,iBAAiB;AAC/B,QAAK,iBAAiB;KACpB,QAAQ;;CAGZ,AAAQ,UAAU;AACjB,OAAK,SAAS;AACd,MAAI,KAAK,aAAa,EAAG;EACzB,MAAM,UAAU,KAAK,YAAY;AACjC,OAAK,UAAU,iBAAiB;AAC/B,QAAK,iBAAiB;KACpB,QAAQ;;CAGZ,AAAQ,kBAAkB;AACzB,OAAK,OAAO,OAAO,KAAK,EAAE,UAAU,SAAS,EAAE,aAAa;AAC5D,OAAK,UAAU;AACf,OAAK,KAAK,yBAAS,IAAI,MAAM,aAAa,CAAC;AAC3C,OAAK,YAAY;;CAGlB,AAAQ,kBAAkB;AACzB,OAAK,OAAO,OAAO,KAAK,EAAE,UAAU,SAAS,EAAE,aAAa;AAC5D,OAAK,UAAU;AACf,MAAI,KAAK,UAAU,UAAU,UAAU;AACtC,QAAK;AACL,OAAI,KAAK,aAAa,KAAK,OAAO;AACjC,SAAK,KAAK,yBAAS,IAAI,MAAM,uCAAuC,CAAC;AACrE,SAAK,YAAY;UACX;AACN,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,YAAY,KAAK;KACjB,OAAO,KAAK;KACZ,EACD,eACA;AACD,SAAK,SAAS,IAAI;AAClB,SAAK,SAAS;;AAEf;;AAGD,MAAI,KAAK,UAAU,UAAU,UAAU;AACtC,QAAK;AACL,OAAI,KAAK,aAAa,KAAK,OAAO;AACjC,SAAK,KAAK,yBAAS,IAAI,MAAM,uCAAuC,CAAC;AACrE,SAAK,YAAY;UACX;AACN,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,YAAY,KAAK;KACjB,OAAO,KAAK;KACZ,EACD,iBACA;AACD,SAAK,kBAAkB;;AAExB;;AAGD,OAAK,YAAY;;CAGlB,AAAQ,kBAAkB;AACzB,OAAK,OAAO,OAAO,KAAK,EAAE,UAAU,SAAS,EAAE,aAAa;AAC5D,OAAK,UAAU;AACf,OAAK,YAAY;;CAGlB,AAAQ,aAAa;AACpB,OAAK,QAAQ,UAAU;AACvB,OAAK,iBAAiB,EAAE;AACxB,OAAK,mBAAmB;AACxB,OAAK,qBAAqB;AAC1B,OAAK,eAAe;;CAGrB,AAAQ,SAAS,MAAc;EAC9B,MAAM,SAAS,KAAK;AACpB,MAAI,UAAU,CAAC,OAAO,WAAW;GAChC,MAAM,MAAM,OAAO,KAAK,CAAC,KAAK,CAAC;AAC/B,QAAK,OAAO,SAAS,QAAQ,SAAS,IAAI;AAC1C,UAAO,MAAM,IAAI;;;CAInB,AAAQ,gBAAgB;AACvB,SAAO,KAAK,OAAO,SAAS,EAC3B,SAAQ,KAAK,OAAb;GACC,KAAK,UAAU,MAAM;IACpB,MAAM,OAAO,KAAK,OAAO;AACzB,SAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,QAAI,SAAS,KAAK;AACjB,UAAK,OAAO,OAAO,MAAM,EAAE,UAAU,SAAS,EAAE,SAAS;AACzD,UAAK,SAAS,IAAI;AAClB,UAAK,QAAQ,UAAU;AACvB,UAAK,iBAAiB,EAAE;AACxB,UAAK,mBAAmB;AACxB,UAAK,SAAS;;AAEf;;GAED,KAAK,UAAU,UAAU;IACxB,MAAM,OAAO,KAAK,OAAO;AACzB,SAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,QAAI,SAAS,KAAK;AACjB,UAAK,OAAO,OAAO,MAAM,EAAE,UAAU,SAAS,EAAE,SAAS;AACzD,UAAK,SAAS;AACd,UAAK,oBAAoB;AACzB,UAAK,kBAAkB;eACb,SAAS,KACnB;SAAI,CAAC,KAAK,UAAU;AACnB,WAAK,OAAO,OAAO,MAClB,EAAE,UAAU,SAAS,EACrB,2BACA;AACD,WAAK,SAAS;AACd,WAAK,SAAS,IAAI;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,iBAAiB,EAAE;AACxB,WAAK,mBAAmB;AACxB,WAAK,SAAS;;;AAGhB;;GAED,KAAK,UAAU,UAAU;IACxB,MAAM,OAAO,KAAK,OAAO;AACzB,SAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,QAAI,SAAS,KAAK;AACjB,UAAK,OAAO,OAAO,MAAM,EAAE,UAAU,SAAS,EAAE,SAAS;AACzD,UAAK,SAAS;AAEd,SADqB,KAAK,cAAc,KAAK,mBAC5B,MAAM;AACtB,WAAK,gBAAgB,EAAE;AACvB,WAAK,aAAa;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,kBAAkB;YACjB;AACN,WAAK;AACL,WAAK,kBAAkB;;eAEd,SAAS,KAAK;AACxB,UAAK,OAAO,OAAO,KAAK,EAAE,UAAU,SAAS,EAAE,SAAS;AACxD,UAAK,SAAS;AACd,UAAK,iBAAiB;;AAEvB;;GAED,KAAK,UAAU,mBAAmB;AACjC,QAAI,KAAK,SAAS;AACjB,UAAK,SAAS;AACd,UAAK,SAAS;;IAEf,MAAM,MAAM,KAAK,OAAO;AACxB,QAAI,MAAM,GACT,MAAK,SAAS,KAAK,OAAO,SAAS,EAAE;SAC/B;AACN,UAAK,qBAAqB;AAC1B,UAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,UAAK,QAAQ,UAAU;AACvB,UAAK,SAAS;;AAEf;;GAED,KAAK,UAAU;AACd,QAAI,KAAK,OAAO,UAAU,KAAK,qBAAqB,GAAG;KACtD,MAAM,YAAY,KAAK,OAAO,SAC7B,GACA,KAAK,qBAAqB,EAC1B;AACD,UAAK,SAAS,KAAK,OAAO,SAAS,KAAK,qBAAqB,EAAE;AAC/D,UAAK,eAAe;KAEpB,MAAM,kBAAkB,OAAO,MAAM,IAAI,UAAU,OAAO;AAC1D,qBAAgB,KAAK,KAAK;AAC1B,eAAU,KAAK,iBAAiB,EAAE;KAElC,MAAM,QAAQ,IAAI,kBAAkB,gBAAgB;AACpD,SAAI,MAAM,SAAS,CAClB,KAAI,MAAM,gBAAgB,KAAK,kBAAkB;AAChD,WAAK,OAAO,OAAO,KAClB;OACC,UAAU;OACV,UAAU,KAAK;OACf,KAAK,MAAM;OACX,EACD,qBACA;AACD,WAAK,SAAS,IAAI;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,YAAY;YACX;AACN,WAAK,SAAS,IAAI;AAClB,WAAK,eAAe,KAAK,MAAM;AAC/B,UAAI,MAAM,MAAM;AACf,WAAI;QACH,MAAM,MAAM,aAAa,WAAW,KAAK,eAAe;AACxD,aAAK,cAAc,IAAI;gBACf,GAAG;AACX,aAAK,KACJ,SACA,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,CAC7C;;AAEF,YAAK,YAAY;AACjB,YAAK,kBAAkB;aACjB;AACN,YAAK;AACL,YAAK,QAAQ,UAAU;AACvB,YAAK,SAAS;;;UAGV;AACN,WAAK,OAAO,OAAO,KAClB,EAAE,UAAU,SAAS,EACrB,mBACA;AACD,WAAK,SAAS,IAAI;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,YAAY;;UAGlB;AAED;GAED,QACC;;;CAKJ,AAAQ,mBAAmB;AAC1B,MAAI,KAAK,qBAAqB,KAAK,cAAc,OAAQ;EACzD,MAAM,SAAS,KAAK;EACpB,MAAM,QAAQ,KAAK,cAAc,KAAK;AACtC,MAAI,UAAU,CAAC,OAAO,WAAW;AAChC,QAAK,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ;IACnD,aAAa,MAAM;IACnB,MAAM,MAAM;IACZ,aAAa,MAAM;IACnB,QAAQ,MAAM;IACd,MAAM,MAAM;IACZ,CAAC;AACF,UAAO,MAAM,MAAM,OAAO;AAC1B,QAAK,QAAQ,UAAU;AACvB,QAAK,SAAS;;;CAIhB,AAAQ,mBAAmB;AAC1B,MAAI,KAAK,UAAU,UAAU,KAAM;EACnC,MAAM,SAAS,KAAK;AACpB,MAAI,CAAC,UAAU,OAAO,UAAW;AACjC,MAAI,KAAK,UAAU,WAAW,EAAG;EAEjC,MAAM,SAAS,KAAK,UAAU,OAAO;AACrC,MAAI,CAAC,OAAQ;AAEb,MAAI;GACH,MAAM,QAAQ,OAAO,KAAK,SAAU;GACpC,MAAM,YAAa,OAAO,KAAK,QAAS,IAAK,OAAO;GACpD,MAAM,WAAW,OAAO,KAAK;GAC7B,MAAM,QAAQ,OAAO,KAAK,SAAU;GACpC,MAAM,OAAO,OAAO;GACpB,MAAM,cAAc,OAAO,aAAa,EAAE;GAC1C,MAAM,aAAa,OAAO,SAAS,GAAG;AAEtC,QAAK,gBAAgB,EAAE;GACvB,IAAI,MAAM;GACV,IAAI,WAAW;AAEf,OAAI,WAAW,WAAW,EACzB,MAAK,cAAc,KAClB,kBAAkB,UACjB,UACA,UACA,MACA,MACA,MACA,UACA,aACA,OAAO,MAAM,EAAE,EACf,KACA,CACD;OAED,QAAO,MAAM,WAAW,QAAQ;IAC/B,MAAM,YAAY,WAAW,SAAS;IACtC,MAAM,YAAY,YAAY,MAAM,MAAM;IAC1C,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM,UAAU;IACvD,MAAM,SAAS,MAAM,aAAa,WAAW;AAE7C,SAAK,cAAc,KAClB,kBAAkB,UACjB,UACA,UACA,MACA,MACA,QACA,UACA,aACA,OACA,KACA,CACD;AACD,WAAO;AACP;;AAIF,QAAK,oBAAoB;AACzB,QAAK,aAAa;AAElB,QAAK,SAAS,IAAI;AAClB,QAAK,QAAQ,UAAU;AACvB,QAAK,SAAS;WACN,GAAG;AACX,QAAK,KAAK,SAAS,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;AACjE,QAAK,kBAAkB;;;CAIzB,AAAQ,sBAAsB,KAAY;AACzC,OAAK,MAAM,CAAC,aAAa,OAAO,KAAK,eAAe;AACnD,gBAAa,GAAG,MAAM;AACtB,MAAG,OAAO,IAAI;AACd,QAAK,cAAc,OAAO,YAAY"}
1
+ {"version":3,"file":"Secs1Communicator.js","names":[],"sources":["../../src/secs1/Secs1Communicator.ts"],"sourcesContent":["import { Duplex } from \"stream\";\nimport {\n\tAbstractSecsCommunicator,\n\tSecsCommunicatorConfig,\n} from \"../core/AbstractSecsCommunicator.js\";\nimport { SecsMessage } from \"../core/AbstractSecsMessage.js\";\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\nimport { Secs1Message } from \"./Secs1Message.js\";\nimport { Secs1MessageBlock } from \"./Secs1MessageBlock.js\";\n\nexport interface Secs1CommunicatorConfig extends SecsCommunicatorConfig {\n\tretry?: number;\n\tisMaster?: boolean;\n}\n\nconst ENQ = 0x05;\nconst EOT = 0x04;\nconst ACK = 0x06;\nconst NAK = 0x15;\n\nenum CommState {\n\tIDLE,\n\tWAIT_EOT,\n\tWAIT_ACK,\n\tWAIT_BLOCK_LENGTH,\n\tWAIT_BLOCK_DATA,\n}\n\nexport abstract class Secs1Communicator extends AbstractSecsCommunicator {\n\tpublic retry: number;\n\tpublic isMaster: boolean;\n\n\tprotected stream: Duplex | null = null;\n\n\tprivate state: CommState = CommState.IDLE;\n\tprivate buffer: Buffer = Buffer.alloc(0);\n\n\tprivate sendQueue: Buffer[] = [];\n\tprivate currentBlocks: Secs1MessageBlock[] = [];\n\tprivate currentBlockIndex = 0;\n\tprivate retryCount = 0;\n\n\tprivate receivedBlocks: Secs1MessageBlock[] = [];\n\tprivate expectedBlockNum = 1;\n\tprivate currentBlockLength = 0;\n\n\tprivate t1Timer: NodeJS.Timeout | null = null;\n\tprivate t2Timer: NodeJS.Timeout | null = null;\n\tprivate t4Timer: NodeJS.Timeout | null = null;\n\n\tconstructor(config: Secs1CommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.retry = config.retry ?? 3;\n\t\tthis.isMaster = config.isMaster ?? false;\n\t}\n\n\tprotected attachStream(stream: Duplex) {\n\t\tthis.stream = stream;\n\t\tthis.resetState();\n\t\tthis.buffer = Buffer.alloc(0);\n\t\tthis.logger.logState(\"SECS-I\", \"NotConnected\", \"Connected\");\n\n\t\tstream.on(\"data\", (data: Buffer) => {\n\t\t\tthis.logger.logBytes(\"Received\", \"SECS-I\", data, {\n\t\t\t\tchunkLength: data.length,\n\t\t\t});\n\t\t\tthis.buffer = Buffer.concat([this.buffer, data]);\n\t\t\tif (\n\t\t\t\tthis.state === CommState.WAIT_BLOCK_LENGTH ||\n\t\t\t\tthis.state === CommState.WAIT_BLOCK_DATA\n\t\t\t) {\n\t\t\t\tthis.startT1();\n\t\t\t}\n\t\t\tthis.processBuffer();\n\t\t});\n\n\t\tstream.on(\"close\", () => {\n\t\t\tthis.rejectAllTransactions(new Error(\"Stream closed\"));\n\t\t\tthis.stream = null;\n\t\t\tthis.emit(\"disconnected\");\n\t\t\tthis.logger.logState(\"SECS-I\", \"Connected\", \"NotConnected\");\n\t\t\tthis.stopAllTimers();\n\t\t\tthis.resetState();\n\t\t});\n\n\t\tstream.on(\"error\", (err: Error) => {\n\t\t\tthis.emit(\"error\", err);\n\t\t});\n\n\t\tthis.emit(\"connected\");\n\t\tthis.processSendQueue();\n\t}\n\n\tprotected stop() {\n\t\tconst stream = this.stream;\n\t\tif (stream && !stream.destroyed) {\n\t\t\tstream.destroy();\n\t\t}\n\t\tthis.stream = null;\n\t\tthis.stopAllTimers();\n\t\tthis.resetState();\n\t}\n\n\tprotected override async sendBufferWithLogs(\n\t\tdirection: \"Sent\" | \"Received\",\n\t\tprotocol: string,\n\t\tbuffer: Buffer,\n\t\tmeta?: Record<string, unknown>,\n\t): Promise<void> {\n\t\tawait super.sendBufferWithLogs(\n\t\t\tdirection,\n\t\t\tprotocol === \"SECS\" ? \"SECS1\" : protocol,\n\t\t\tbuffer,\n\t\t\t{\n\t\t\t\tcommState: CommState[this.state],\n\t\t\t\t...meta,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override sendBuffer(buffer: Buffer): Promise<void> {\n\t\tthis.sendQueue.push(buffer);\n\t\tprocess.nextTick(() => this.processSendQueue());\n\t\treturn Promise.resolve();\n\t}\n\n\tprotected override createMessage(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null,\n\t\tsystemBytes: number,\n\t): SecsMessage {\n\t\treturn new Secs1Message(\n\t\t\tstream,\n\t\t\tfunc,\n\t\t\twBit,\n\t\t\tbody,\n\t\t\tsystemBytes,\n\t\t\tthis.deviceId,\n\t\t);\n\t}\n\n\tprivate clearT1() {\n\t\tif (this.t1Timer) {\n\t\t\tclearTimeout(this.t1Timer);\n\t\t\tthis.t1Timer = null;\n\t\t}\n\t}\n\n\tprivate clearT2() {\n\t\tif (this.t2Timer) {\n\t\t\tclearTimeout(this.t2Timer);\n\t\t\tthis.t2Timer = null;\n\t\t}\n\t}\n\n\tprivate clearT4() {\n\t\tif (this.t4Timer) {\n\t\t\tclearTimeout(this.t4Timer);\n\t\t\tthis.t4Timer = null;\n\t\t}\n\t}\n\n\tprivate stopAllTimers() {\n\t\tthis.clearT1();\n\t\tthis.clearT2();\n\t\tthis.clearT4();\n\t}\n\n\tprivate startT1() {\n\t\tthis.clearT1();\n\t\tif (this.timeoutT1 <= 0) return;\n\t\tthis.t1Timer = setTimeout(() => {\n\t\t\tthis.handleT1Timeout();\n\t\t}, this.timeoutT1 * 1000);\n\t}\n\n\tprivate startT2() {\n\t\tthis.clearT2();\n\t\tif (this.timeoutT2 <= 0) return;\n\t\tconst timeout = this.timeoutT2 * 1000;\n\t\tthis.t2Timer = setTimeout(() => {\n\t\t\tthis.handleT2Timeout();\n\t\t}, timeout);\n\t}\n\n\tprivate startT4() {\n\t\tthis.clearT4();\n\t\tif (this.timeoutT4 <= 0) return;\n\t\tconst timeout = this.timeoutT4 * 1000;\n\t\tthis.t4Timer = setTimeout(() => {\n\t\t\tthis.handleT4Timeout();\n\t\t}, timeout);\n\t}\n\n\tprivate handleT1Timeout() {\n\t\tthis.logger.detail.warn({ protocol: \"SECS-I\" }, \"t1 timeout\");\n\t\tthis.t1Timer = null;\n\t\tthis.emit(\"error\", new Error(\"T1 Timeout\"));\n\t\tthis.resetState();\n\t}\n\n\tprivate handleT2Timeout() {\n\t\tthis.logger.detail.warn({ protocol: \"SECS-I\" }, \"t2 timeout\");\n\t\tthis.t2Timer = null;\n\t\tif (this.state === CommState.WAIT_EOT) {\n\t\t\tthis.retryCount++;\n\t\t\tif (this.retryCount > this.retry) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Retry limit exceeded waiting for EOT\"));\n\t\t\t\tthis.resetState();\n\t\t\t} else {\n\t\t\t\tthis.logger.detail.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS-I\",\n\t\t\t\t\t\tretryCount: this.retryCount,\n\t\t\t\t\t\tretry: this.retry,\n\t\t\t\t\t},\n\t\t\t\t\t\"retrying ENQ\",\n\t\t\t\t);\n\t\t\t\tthis.sendByte(ENQ);\n\t\t\t\tthis.startT2();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.state === CommState.WAIT_ACK) {\n\t\t\tthis.retryCount++;\n\t\t\tif (this.retryCount > this.retry) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Retry limit exceeded waiting for ACK\"));\n\t\t\t\tthis.resetState();\n\t\t\t} else {\n\t\t\t\tthis.logger.detail.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS-I\",\n\t\t\t\t\t\tretryCount: this.retryCount,\n\t\t\t\t\t\tretry: this.retry,\n\t\t\t\t\t},\n\t\t\t\t\t\"retrying block\",\n\t\t\t\t);\n\t\t\t\tthis.sendCurrentBlock();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.resetState();\n\t}\n\n\tprivate handleT4Timeout() {\n\t\tthis.logger.detail.warn({ protocol: \"SECS-I\" }, \"t4 timeout\");\n\t\tthis.t4Timer = null;\n\t\tthis.resetState();\n\t}\n\n\tprivate resetState() {\n\t\tthis.state = CommState.IDLE;\n\t\tthis.receivedBlocks = [];\n\t\tthis.expectedBlockNum = 1;\n\t\tthis.currentBlockLength = 0;\n\t\tthis.stopAllTimers();\n\t}\n\n\tprivate sendByte(byte: number) {\n\t\tconst stream = this.stream;\n\t\tif (stream && !stream.destroyed) {\n\t\t\tconst buf = Buffer.from([byte]);\n\t\t\tthis.logger.logBytes(\"Sent\", \"SECS-I\", buf);\n\t\t\tstream.write(buf);\n\t\t}\n\t}\n\n\tprivate processBuffer() {\n\t\twhile (this.buffer.length > 0) {\n\t\t\tswitch (this.state) {\n\t\t\t\tcase CommState.IDLE: {\n\t\t\t\t\tconst byte = this.buffer[0];\n\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\tif (byte === ENQ) {\n\t\t\t\t\t\tthis.logger.detail.debug({ protocol: \"SECS-I\" }, \"rx ENQ\");\n\t\t\t\t\t\tthis.sendByte(EOT);\n\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_LENGTH;\n\t\t\t\t\t\tthis.receivedBlocks = [];\n\t\t\t\t\t\tthis.expectedBlockNum = 1;\n\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_EOT: {\n\t\t\t\t\tconst byte = this.buffer[0];\n\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\tif (byte === EOT) {\n\t\t\t\t\t\tthis.logger.detail.debug({ protocol: \"SECS-I\" }, \"rx EOT\");\n\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\tthis.currentBlockIndex = 0;\n\t\t\t\t\t\tthis.sendCurrentBlock();\n\t\t\t\t\t} else if (byte === ENQ) {\n\t\t\t\t\t\tif (!this.isMaster) {\n\t\t\t\t\t\t\tthis.logger.detail.debug(\n\t\t\t\t\t\t\t\t{ protocol: \"SECS-I\" },\n\t\t\t\t\t\t\t\t\"rx ENQ while waiting EOT\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\t\tthis.sendByte(EOT);\n\t\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_LENGTH;\n\t\t\t\t\t\t\tthis.receivedBlocks = [];\n\t\t\t\t\t\t\tthis.expectedBlockNum = 1;\n\t\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_ACK: {\n\t\t\t\t\tconst byte = this.buffer[0];\n\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\tif (byte === ACK) {\n\t\t\t\t\t\tthis.logger.detail.debug({ protocol: \"SECS-I\" }, \"rx ACK\");\n\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\tconst currentBlock = this.currentBlocks[this.currentBlockIndex];\n\t\t\t\t\t\tif (currentBlock.eBit) {\n\t\t\t\t\t\t\tthis.currentBlocks = [];\n\t\t\t\t\t\t\tthis.retryCount = 0;\n\t\t\t\t\t\t\tthis.state = CommState.IDLE;\n\t\t\t\t\t\t\tthis.processSendQueue();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.currentBlockIndex++;\n\t\t\t\t\t\t\tthis.sendCurrentBlock();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (byte === NAK) {\n\t\t\t\t\t\tthis.logger.detail.warn({ protocol: \"SECS-I\" }, \"rx NAK\");\n\t\t\t\t\t\tthis.clearT2();\n\t\t\t\t\t\tthis.handleT2Timeout();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_BLOCK_LENGTH: {\n\t\t\t\t\tif (this.t4Timer) {\n\t\t\t\t\t\tthis.clearT4();\n\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t}\n\t\t\t\t\tconst len = this.buffer[0];\n\t\t\t\t\tif (len < 10) {\n\t\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.currentBlockLength = len;\n\t\t\t\t\t\tthis.buffer = this.buffer.subarray(1);\n\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_DATA;\n\t\t\t\t\t\tthis.startT1();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CommState.WAIT_BLOCK_DATA: {\n\t\t\t\t\tif (this.buffer.length >= this.currentBlockLength + 2) {\n\t\t\t\t\t\tconst blockData = this.buffer.subarray(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tthis.currentBlockLength + 2,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.buffer = this.buffer.subarray(this.currentBlockLength + 2);\n\t\t\t\t\t\tthis.stopAllTimers();\n\n\t\t\t\t\t\tconst fullBlockBuffer = Buffer.alloc(1 + blockData.length);\n\t\t\t\t\t\tfullBlockBuffer[0] = this.currentBlockLength;\n\t\t\t\t\t\tblockData.copy(fullBlockBuffer, 1);\n\n\t\t\t\t\t\tconst block = new Secs1MessageBlock(fullBlockBuffer);\n\t\t\t\t\t\tif (block.isValid()) {\n\t\t\t\t\t\t\tif (block.blockNumber !== this.expectedBlockNum) {\n\t\t\t\t\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tprotocol: \"SECS-I\",\n\t\t\t\t\t\t\t\t\t\texpected: this.expectedBlockNum,\n\t\t\t\t\t\t\t\t\t\tgot: block.blockNumber,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"wrong block number\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tthis.sendByte(NAK);\n\t\t\t\t\t\t\t\tthis.state = CommState.IDLE;\n\t\t\t\t\t\t\t\tthis.resetState();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.sendByte(ACK);\n\t\t\t\t\t\t\t\tthis.receivedBlocks.push(block);\n\t\t\t\t\t\t\t\tif (block.eBit) {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst msg = Secs1Message.fromBlocks(this.receivedBlocks);\n\t\t\t\t\t\t\t\t\t\tthis.handleMessage(msg);\n\t\t\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\t\t\t\t\te instanceof Error ? e : new Error(String(e)),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthis.resetState();\n\t\t\t\t\t\t\t\t\tthis.processSendQueue();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tthis.expectedBlockNum++;\n\t\t\t\t\t\t\t\t\tthis.state = CommState.WAIT_BLOCK_LENGTH;\n\t\t\t\t\t\t\t\t\tthis.startT4();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t\t\t\t{ protocol: \"SECS-I\" },\n\t\t\t\t\t\t\t\t\"invalid checksum\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthis.sendByte(NAK);\n\t\t\t\t\t\t\tthis.state = CommState.IDLE;\n\t\t\t\t\t\t\tthis.resetState();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate sendCurrentBlock() {\n\t\tif (this.currentBlockIndex >= this.currentBlocks.length) return;\n\t\tconst stream = this.stream;\n\t\tconst block = this.currentBlocks[this.currentBlockIndex];\n\t\tif (stream && !stream.destroyed) {\n\t\t\tthis.logger.logBytes(\"Sent\", \"SECS-I\", block.buffer, {\n\t\t\t\tblockNumber: block.blockNumber,\n\t\t\t\teBit: block.eBit,\n\t\t\t\tsystemBytes: block.systemBytes,\n\t\t\t\tstream: block.stream,\n\t\t\t\tfunc: block.func,\n\t\t\t});\n\t\t\tstream.write(block.buffer);\n\t\t\tthis.state = CommState.WAIT_ACK;\n\t\t\tthis.startT2();\n\t\t}\n\t}\n\n\tprivate processSendQueue() {\n\t\tif (this.state !== CommState.IDLE) return;\n\t\tconst stream = this.stream;\n\t\tif (!stream || stream.destroyed) return;\n\t\tif (this.sendQueue.length === 0) return;\n\n\t\tconst buffer = this.sendQueue.shift();\n\t\tif (!buffer) return;\n\n\t\ttry {\n\t\t\tconst rBit = (buffer[0] & 0x80) === 0x80;\n\t\t\tconst deviceId = ((buffer[0] & 0x7f) << 8) | buffer[1];\n\t\t\tconst streamId = buffer[2] & 0x7f;\n\t\t\tconst wBit = (buffer[2] & 0x80) === 0x80;\n\t\t\tconst func = buffer[3];\n\t\t\tconst systemBytes = buffer.readUInt32BE(6);\n\t\t\tconst bodyBuffer = buffer.subarray(10);\n\n\t\t\tthis.currentBlocks = [];\n\t\t\tlet pos = 0;\n\t\t\tlet blockNum = 1;\n\n\t\t\tif (bodyBuffer.length === 0) {\n\t\t\t\tthis.currentBlocks.push(\n\t\t\t\t\tSecs1MessageBlock.fromParts(\n\t\t\t\t\t\tdeviceId,\n\t\t\t\t\t\tstreamId,\n\t\t\t\t\t\tfunc,\n\t\t\t\t\t\twBit,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\tblockNum,\n\t\t\t\t\t\tsystemBytes,\n\t\t\t\t\t\tBuffer.alloc(0),\n\t\t\t\t\t\trBit,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\twhile (pos < bodyBuffer.length) {\n\t\t\t\t\tconst remaining = bodyBuffer.length - pos;\n\t\t\t\t\tconst chunkSize = remaining > 244 ? 244 : remaining;\n\t\t\t\t\tconst chunk = bodyBuffer.subarray(pos, pos + chunkSize);\n\t\t\t\t\tconst isLast = pos + chunkSize >= bodyBuffer.length;\n\n\t\t\t\t\tthis.currentBlocks.push(\n\t\t\t\t\t\tSecs1MessageBlock.fromParts(\n\t\t\t\t\t\t\tdeviceId,\n\t\t\t\t\t\t\tstreamId,\n\t\t\t\t\t\t\tfunc,\n\t\t\t\t\t\t\twBit,\n\t\t\t\t\t\t\tisLast,\n\t\t\t\t\t\t\tblockNum,\n\t\t\t\t\t\t\tsystemBytes,\n\t\t\t\t\t\t\tchunk,\n\t\t\t\t\t\t\trBit,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tpos += chunkSize;\n\t\t\t\t\tblockNum++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.currentBlockIndex = 0;\n\t\t\tthis.retryCount = 0;\n\n\t\t\tthis.sendByte(ENQ);\n\t\t\tthis.state = CommState.WAIT_EOT;\n\t\t\tthis.startT2();\n\t\t} catch (e) {\n\t\t\tthis.emit(\"error\", e instanceof Error ? e : new Error(String(e)));\n\t\t\tthis.processSendQueue();\n\t\t}\n\t}\n\n\tprivate rejectAllTransactions(err: Error) {\n\t\tfor (const [systemBytes, tx] of this._transactions) {\n\t\t\tclearTimeout(tx.timer);\n\t\t\ttx.reject(err);\n\t\t\tthis._transactions.delete(systemBytes);\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAeA,MAAM,MAAM;AACZ,MAAM,MAAM;AACZ,MAAM,MAAM;AACZ,MAAM,MAAM;AAEZ,IAAK,kDAAL;AACC;AACA;AACA;AACA;AACA;;EALI;AAQL,IAAsB,oBAAtB,cAAgD,yBAAyB;CACxE,AAAO;CACP,AAAO;CAEP,AAAU,SAAwB;CAElC,AAAQ,QAAmB,UAAU;CACrC,AAAQ,SAAiB,OAAO,MAAM,EAAE;CAExC,AAAQ,YAAsB,EAAE;CAChC,AAAQ,gBAAqC,EAAE;CAC/C,AAAQ,oBAAoB;CAC5B,AAAQ,aAAa;CAErB,AAAQ,iBAAsC,EAAE;CAChD,AAAQ,mBAAmB;CAC3B,AAAQ,qBAAqB;CAE7B,AAAQ,UAAiC;CACzC,AAAQ,UAAiC;CACzC,AAAQ,UAAiC;CAEzC,YAAY,QAAiC;AAC5C,QAAM,OAAO;AACb,OAAK,QAAQ,OAAO,SAAS;AAC7B,OAAK,WAAW,OAAO,YAAY;;CAGpC,AAAU,aAAa,QAAgB;AACtC,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,SAAS,OAAO,MAAM,EAAE;AAC7B,OAAK,OAAO,SAAS,UAAU,gBAAgB,YAAY;AAE3D,SAAO,GAAG,SAAS,SAAiB;AACnC,QAAK,OAAO,SAAS,YAAY,UAAU,MAAM,EAChD,aAAa,KAAK,QAClB,CAAC;AACF,QAAK,SAAS,OAAO,OAAO,CAAC,KAAK,QAAQ,KAAK,CAAC;AAChD,OACC,KAAK,UAAU,UAAU,qBACzB,KAAK,UAAU,UAAU,gBAEzB,MAAK,SAAS;AAEf,QAAK,eAAe;IACnB;AAEF,SAAO,GAAG,eAAe;AACxB,QAAK,sCAAsB,IAAI,MAAM,gBAAgB,CAAC;AACtD,QAAK,SAAS;AACd,QAAK,KAAK,eAAe;AACzB,QAAK,OAAO,SAAS,UAAU,aAAa,eAAe;AAC3D,QAAK,eAAe;AACpB,QAAK,YAAY;IAChB;AAEF,SAAO,GAAG,UAAU,QAAe;AAClC,QAAK,KAAK,SAAS,IAAI;IACtB;AAEF,OAAK,KAAK,YAAY;AACtB,OAAK,kBAAkB;;CAGxB,AAAU,OAAO;EAChB,MAAM,SAAS,KAAK;AACpB,MAAI,UAAU,CAAC,OAAO,UACrB,QAAO,SAAS;AAEjB,OAAK,SAAS;AACd,OAAK,eAAe;AACpB,OAAK,YAAY;;CAGlB,MAAyB,mBACxB,WACA,UACA,QACA,MACgB;AAChB,QAAM,MAAM,mBACX,WACA,aAAa,SAAS,UAAU,UAChC,QACA;GACC,WAAW,UAAU,KAAK;GAC1B,GAAG;GACH,CACD;;CAGF,AAAmB,WAAW,QAA+B;AAC5D,OAAK,UAAU,KAAK,OAAO;AAC3B,UAAQ,eAAe,KAAK,kBAAkB,CAAC;AAC/C,SAAO,QAAQ,SAAS;;CAGzB,AAAmB,cAClB,QACA,MACA,MACA,MACA,aACc;AACd,SAAO,IAAI,aACV,QACA,MACA,MACA,MACA,aACA,KAAK,SACL;;CAGF,AAAQ,UAAU;AACjB,MAAI,KAAK,SAAS;AACjB,gBAAa,KAAK,QAAQ;AAC1B,QAAK,UAAU;;;CAIjB,AAAQ,UAAU;AACjB,MAAI,KAAK,SAAS;AACjB,gBAAa,KAAK,QAAQ;AAC1B,QAAK,UAAU;;;CAIjB,AAAQ,UAAU;AACjB,MAAI,KAAK,SAAS;AACjB,gBAAa,KAAK,QAAQ;AAC1B,QAAK,UAAU;;;CAIjB,AAAQ,gBAAgB;AACvB,OAAK,SAAS;AACd,OAAK,SAAS;AACd,OAAK,SAAS;;CAGf,AAAQ,UAAU;AACjB,OAAK,SAAS;AACd,MAAI,KAAK,aAAa,EAAG;AACzB,OAAK,UAAU,iBAAiB;AAC/B,QAAK,iBAAiB;KACpB,KAAK,YAAY,IAAK;;CAG1B,AAAQ,UAAU;AACjB,OAAK,SAAS;AACd,MAAI,KAAK,aAAa,EAAG;EACzB,MAAM,UAAU,KAAK,YAAY;AACjC,OAAK,UAAU,iBAAiB;AAC/B,QAAK,iBAAiB;KACpB,QAAQ;;CAGZ,AAAQ,UAAU;AACjB,OAAK,SAAS;AACd,MAAI,KAAK,aAAa,EAAG;EACzB,MAAM,UAAU,KAAK,YAAY;AACjC,OAAK,UAAU,iBAAiB;AAC/B,QAAK,iBAAiB;KACpB,QAAQ;;CAGZ,AAAQ,kBAAkB;AACzB,OAAK,OAAO,OAAO,KAAK,EAAE,UAAU,UAAU,EAAE,aAAa;AAC7D,OAAK,UAAU;AACf,OAAK,KAAK,yBAAS,IAAI,MAAM,aAAa,CAAC;AAC3C,OAAK,YAAY;;CAGlB,AAAQ,kBAAkB;AACzB,OAAK,OAAO,OAAO,KAAK,EAAE,UAAU,UAAU,EAAE,aAAa;AAC7D,OAAK,UAAU;AACf,MAAI,KAAK,UAAU,UAAU,UAAU;AACtC,QAAK;AACL,OAAI,KAAK,aAAa,KAAK,OAAO;AACjC,SAAK,KAAK,yBAAS,IAAI,MAAM,uCAAuC,CAAC;AACrE,SAAK,YAAY;UACX;AACN,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,YAAY,KAAK;KACjB,OAAO,KAAK;KACZ,EACD,eACA;AACD,SAAK,SAAS,IAAI;AAClB,SAAK,SAAS;;AAEf;;AAGD,MAAI,KAAK,UAAU,UAAU,UAAU;AACtC,QAAK;AACL,OAAI,KAAK,aAAa,KAAK,OAAO;AACjC,SAAK,KAAK,yBAAS,IAAI,MAAM,uCAAuC,CAAC;AACrE,SAAK,YAAY;UACX;AACN,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,YAAY,KAAK;KACjB,OAAO,KAAK;KACZ,EACD,iBACA;AACD,SAAK,kBAAkB;;AAExB;;AAGD,OAAK,YAAY;;CAGlB,AAAQ,kBAAkB;AACzB,OAAK,OAAO,OAAO,KAAK,EAAE,UAAU,UAAU,EAAE,aAAa;AAC7D,OAAK,UAAU;AACf,OAAK,YAAY;;CAGlB,AAAQ,aAAa;AACpB,OAAK,QAAQ,UAAU;AACvB,OAAK,iBAAiB,EAAE;AACxB,OAAK,mBAAmB;AACxB,OAAK,qBAAqB;AAC1B,OAAK,eAAe;;CAGrB,AAAQ,SAAS,MAAc;EAC9B,MAAM,SAAS,KAAK;AACpB,MAAI,UAAU,CAAC,OAAO,WAAW;GAChC,MAAM,MAAM,OAAO,KAAK,CAAC,KAAK,CAAC;AAC/B,QAAK,OAAO,SAAS,QAAQ,UAAU,IAAI;AAC3C,UAAO,MAAM,IAAI;;;CAInB,AAAQ,gBAAgB;AACvB,SAAO,KAAK,OAAO,SAAS,EAC3B,SAAQ,KAAK,OAAb;GACC,KAAK,UAAU,MAAM;IACpB,MAAM,OAAO,KAAK,OAAO;AACzB,SAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,QAAI,SAAS,KAAK;AACjB,UAAK,OAAO,OAAO,MAAM,EAAE,UAAU,UAAU,EAAE,SAAS;AAC1D,UAAK,SAAS,IAAI;AAClB,UAAK,QAAQ,UAAU;AACvB,UAAK,iBAAiB,EAAE;AACxB,UAAK,mBAAmB;AACxB,UAAK,SAAS;;AAEf;;GAED,KAAK,UAAU,UAAU;IACxB,MAAM,OAAO,KAAK,OAAO;AACzB,SAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,QAAI,SAAS,KAAK;AACjB,UAAK,OAAO,OAAO,MAAM,EAAE,UAAU,UAAU,EAAE,SAAS;AAC1D,UAAK,SAAS;AACd,UAAK,oBAAoB;AACzB,UAAK,kBAAkB;eACb,SAAS,KACnB;SAAI,CAAC,KAAK,UAAU;AACnB,WAAK,OAAO,OAAO,MAClB,EAAE,UAAU,UAAU,EACtB,2BACA;AACD,WAAK,SAAS;AACd,WAAK,SAAS,IAAI;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,iBAAiB,EAAE;AACxB,WAAK,mBAAmB;AACxB,WAAK,SAAS;;;AAGhB;;GAED,KAAK,UAAU,UAAU;IACxB,MAAM,OAAO,KAAK,OAAO;AACzB,SAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,QAAI,SAAS,KAAK;AACjB,UAAK,OAAO,OAAO,MAAM,EAAE,UAAU,UAAU,EAAE,SAAS;AAC1D,UAAK,SAAS;AAEd,SADqB,KAAK,cAAc,KAAK,mBAC5B,MAAM;AACtB,WAAK,gBAAgB,EAAE;AACvB,WAAK,aAAa;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,kBAAkB;YACjB;AACN,WAAK;AACL,WAAK,kBAAkB;;eAEd,SAAS,KAAK;AACxB,UAAK,OAAO,OAAO,KAAK,EAAE,UAAU,UAAU,EAAE,SAAS;AACzD,UAAK,SAAS;AACd,UAAK,iBAAiB;;AAEvB;;GAED,KAAK,UAAU,mBAAmB;AACjC,QAAI,KAAK,SAAS;AACjB,UAAK,SAAS;AACd,UAAK,SAAS;;IAEf,MAAM,MAAM,KAAK,OAAO;AACxB,QAAI,MAAM,GACT,MAAK,SAAS,KAAK,OAAO,SAAS,EAAE;SAC/B;AACN,UAAK,qBAAqB;AAC1B,UAAK,SAAS,KAAK,OAAO,SAAS,EAAE;AACrC,UAAK,QAAQ,UAAU;AACvB,UAAK,SAAS;;AAEf;;GAED,KAAK,UAAU;AACd,QAAI,KAAK,OAAO,UAAU,KAAK,qBAAqB,GAAG;KACtD,MAAM,YAAY,KAAK,OAAO,SAC7B,GACA,KAAK,qBAAqB,EAC1B;AACD,UAAK,SAAS,KAAK,OAAO,SAAS,KAAK,qBAAqB,EAAE;AAC/D,UAAK,eAAe;KAEpB,MAAM,kBAAkB,OAAO,MAAM,IAAI,UAAU,OAAO;AAC1D,qBAAgB,KAAK,KAAK;AAC1B,eAAU,KAAK,iBAAiB,EAAE;KAElC,MAAM,QAAQ,IAAI,kBAAkB,gBAAgB;AACpD,SAAI,MAAM,SAAS,CAClB,KAAI,MAAM,gBAAgB,KAAK,kBAAkB;AAChD,WAAK,OAAO,OAAO,KAClB;OACC,UAAU;OACV,UAAU,KAAK;OACf,KAAK,MAAM;OACX,EACD,qBACA;AACD,WAAK,SAAS,IAAI;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,YAAY;YACX;AACN,WAAK,SAAS,IAAI;AAClB,WAAK,eAAe,KAAK,MAAM;AAC/B,UAAI,MAAM,MAAM;AACf,WAAI;QACH,MAAM,MAAM,aAAa,WAAW,KAAK,eAAe;AACxD,aAAK,cAAc,IAAI;gBACf,GAAG;AACX,aAAK,KACJ,SACA,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,CAC7C;;AAEF,YAAK,YAAY;AACjB,YAAK,kBAAkB;aACjB;AACN,YAAK;AACL,YAAK,QAAQ,UAAU;AACvB,YAAK,SAAS;;;UAGV;AACN,WAAK,OAAO,OAAO,KAClB,EAAE,UAAU,UAAU,EACtB,mBACA;AACD,WAAK,SAAS,IAAI;AAClB,WAAK,QAAQ,UAAU;AACvB,WAAK,YAAY;;UAGlB;AAED;GAED,QACC;;;CAKJ,AAAQ,mBAAmB;AAC1B,MAAI,KAAK,qBAAqB,KAAK,cAAc,OAAQ;EACzD,MAAM,SAAS,KAAK;EACpB,MAAM,QAAQ,KAAK,cAAc,KAAK;AACtC,MAAI,UAAU,CAAC,OAAO,WAAW;AAChC,QAAK,OAAO,SAAS,QAAQ,UAAU,MAAM,QAAQ;IACpD,aAAa,MAAM;IACnB,MAAM,MAAM;IACZ,aAAa,MAAM;IACnB,QAAQ,MAAM;IACd,MAAM,MAAM;IACZ,CAAC;AACF,UAAO,MAAM,MAAM,OAAO;AAC1B,QAAK,QAAQ,UAAU;AACvB,QAAK,SAAS;;;CAIhB,AAAQ,mBAAmB;AAC1B,MAAI,KAAK,UAAU,UAAU,KAAM;EACnC,MAAM,SAAS,KAAK;AACpB,MAAI,CAAC,UAAU,OAAO,UAAW;AACjC,MAAI,KAAK,UAAU,WAAW,EAAG;EAEjC,MAAM,SAAS,KAAK,UAAU,OAAO;AACrC,MAAI,CAAC,OAAQ;AAEb,MAAI;GACH,MAAM,QAAQ,OAAO,KAAK,SAAU;GACpC,MAAM,YAAa,OAAO,KAAK,QAAS,IAAK,OAAO;GACpD,MAAM,WAAW,OAAO,KAAK;GAC7B,MAAM,QAAQ,OAAO,KAAK,SAAU;GACpC,MAAM,OAAO,OAAO;GACpB,MAAM,cAAc,OAAO,aAAa,EAAE;GAC1C,MAAM,aAAa,OAAO,SAAS,GAAG;AAEtC,QAAK,gBAAgB,EAAE;GACvB,IAAI,MAAM;GACV,IAAI,WAAW;AAEf,OAAI,WAAW,WAAW,EACzB,MAAK,cAAc,KAClB,kBAAkB,UACjB,UACA,UACA,MACA,MACA,MACA,UACA,aACA,OAAO,MAAM,EAAE,EACf,KACA,CACD;OAED,QAAO,MAAM,WAAW,QAAQ;IAC/B,MAAM,YAAY,WAAW,SAAS;IACtC,MAAM,YAAY,YAAY,MAAM,MAAM;IAC1C,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM,UAAU;IACvD,MAAM,SAAS,MAAM,aAAa,WAAW;AAE7C,SAAK,cAAc,KAClB,kBAAkB,UACjB,UACA,UACA,MACA,MACA,QACA,UACA,aACA,OACA,KACA,CACD;AACD,WAAO;AACP;;AAIF,QAAK,oBAAoB;AACzB,QAAK,aAAa;AAElB,QAAK,SAAS,IAAI;AAClB,QAAK,QAAQ,UAAU;AACvB,QAAK,SAAS;WACN,GAAG;AACX,QAAK,KAAK,SAAS,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;AACjE,QAAK,kBAAkB;;;CAIzB,AAAQ,sBAAsB,KAAY;AACzC,OAAK,MAAM,CAAC,aAAa,OAAO,KAAK,eAAe;AACnD,gBAAa,GAAG,MAAM;AACtB,MAAG,OAAO,IAAI;AACd,QAAK,cAAc,OAAO,YAAY"}
@@ -16,7 +16,7 @@ var Secs1OnTcpIpActiveCommunicator = class extends Secs1Communicator {
16
16
  this.on("disconnected", () => {
17
17
  if (!this.shouldStop) {
18
18
  this.logger.detail.warn({
19
- protocol: "SECS1",
19
+ protocol: "SECS-I-TCP/IP",
20
20
  ip: this.ip,
21
21
  port: this.port,
22
22
  timeoutT5: this.timeoutT5
@@ -44,7 +44,7 @@ var Secs1OnTcpIpActiveCommunicator = class extends Secs1Communicator {
44
44
  const onError = (err) => {
45
45
  socket.destroy();
46
46
  this.logger.detail.warn({
47
- protocol: "SECS1",
47
+ protocol: "SECS-I-TCP/IP",
48
48
  ip: this.ip,
49
49
  port: this.port,
50
50
  timeoutT5: this.timeoutT5,
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1OnTcpIpActiveCommunicator.js","names":[],"sources":["../../src/secs1/Secs1OnTcpIpActiveCommunicator.ts"],"sourcesContent":["import { Socket } from \"net\";\nimport {\n\tSecs1Communicator,\n\tSecs1CommunicatorConfig,\n} from \"./Secs1Communicator.js\";\n\nexport interface Secs1OnTcpIpActiveCommunicatorConfig extends Secs1CommunicatorConfig {\n\tip: string;\n\tport: number;\n}\n\nexport class Secs1OnTcpIpActiveCommunicator extends Secs1Communicator {\n\tpublic ip: string;\n\tpublic port: number;\n\n\tprivate shouldStop = false;\n\tprivate reconnectTimer: NodeJS.Timeout | null = null;\n\tprivate connectionPromiseResolver: (() => void) | null = null;\n\tprivate pendingSocket: Socket | null = null;\n\n\tconstructor(config: Secs1OnTcpIpActiveCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.ip = config.ip;\n\t\tthis.port = config.port;\n\t\tthis.on(\"disconnected\", () => {\n\t\t\tif (!this.shouldStop) {\n\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\t\tip: this.ip,\n\t\t\t\t\t\tport: this.port,\n\t\t\t\t\t\ttimeoutT5: this.timeoutT5,\n\t\t\t\t\t},\n\t\t\t\t\t\"connection lost; scheduling reconnect\",\n\t\t\t\t);\n\t\t\t\tthis.scheduleReconnect();\n\t\t\t}\n\t\t});\n\t}\n\n\tasync open(): Promise<void> {\n\t\tif (this.stream && !this.stream.destroyed) return;\n\t\tif (this.pendingSocket && !this.pendingSocket.destroyed) return;\n\n\t\tthis.shouldStop = false;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.connectionPromiseResolver = resolve;\n\t\t\tthis.connect();\n\t\t});\n\t}\n\n\tprivate connect() {\n\t\tif (this.shouldStop) return;\n\t\tif (this.stream && !this.stream.destroyed) return;\n\t\tif (this.pendingSocket && !this.pendingSocket.destroyed) return;\n\n\t\tconst socket = new Socket();\n\t\tsocket.setNoDelay(true);\n\t\tthis.pendingSocket = socket;\n\n\t\tconst onError = (err: Error) => {\n\t\t\tsocket.destroy();\n\t\t\tthis.logger.detail.warn(\n\t\t\t\t{\n\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\tip: this.ip,\n\t\t\t\t\tport: this.port,\n\t\t\t\t\ttimeoutT5: this.timeoutT5,\n\t\t\t\t\terr,\n\t\t\t\t},\n\t\t\t\t\"connection failed; scheduling reconnect\",\n\t\t\t);\n\t\t\tif (!this.shouldStop) {\n\t\t\t\tthis.scheduleReconnect();\n\t\t\t}\n\t\t};\n\n\t\tsocket.once(\"error\", onError);\n\n\t\tsocket.once(\"close\", () => {\n\t\t\tif (this.pendingSocket === socket) {\n\t\t\t\tthis.pendingSocket = null;\n\t\t\t}\n\t\t});\n\n\t\tsocket.connect(this.port, this.ip, () => {\n\t\t\tsocket.removeListener(\"error\", onError);\n\t\t\tif (this.pendingSocket === socket) {\n\t\t\t\tthis.pendingSocket = null;\n\t\t\t}\n\t\t\tthis.attachStream(socket);\n\n\t\t\tif (this.connectionPromiseResolver) {\n\t\t\t\tthis.connectionPromiseResolver();\n\t\t\t\tthis.connectionPromiseResolver = null;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate scheduleReconnect() {\n\t\tif (this.reconnectTimer) {\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t}\n\t\tthis.reconnectTimer = setTimeout(() => {\n\t\t\tthis.reconnectTimer = null;\n\t\t\tthis.connect();\n\t\t}, this.timeoutT5 * 1000);\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.shouldStop = true;\n\t\tif (this.reconnectTimer) {\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t\tthis.reconnectTimer = null;\n\t\t}\n\t\tif (this.pendingSocket) {\n\t\t\tthis.pendingSocket.destroy();\n\t\t\tthis.pendingSocket = null;\n\t\t}\n\t\tthis.stop();\n\t\tawait Promise.resolve();\n\t}\n}\n"],"mappings":";;;;AAWA,IAAa,iCAAb,cAAoD,kBAAkB;CACrE,AAAO;CACP,AAAO;CAEP,AAAQ,aAAa;CACrB,AAAQ,iBAAwC;CAChD,AAAQ,4BAAiD;CACzD,AAAQ,gBAA+B;CAEvC,YAAY,QAA8C;AACzD,QAAM,OAAO;AACb,OAAK,KAAK,OAAO;AACjB,OAAK,OAAO,OAAO;AACnB,OAAK,GAAG,sBAAsB;AAC7B,OAAI,CAAC,KAAK,YAAY;AACrB,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,IAAI,KAAK;KACT,MAAM,KAAK;KACX,WAAW,KAAK;KAChB,EACD,wCACA;AACD,SAAK,mBAAmB;;IAExB;;CAGH,MAAM,OAAsB;AAC3B,MAAI,KAAK,UAAU,CAAC,KAAK,OAAO,UAAW;AAC3C,MAAI,KAAK,iBAAiB,CAAC,KAAK,cAAc,UAAW;AAEzD,OAAK,aAAa;AAElB,SAAO,IAAI,SAAS,YAAY;AAC/B,QAAK,4BAA4B;AACjC,QAAK,SAAS;IACb;;CAGH,AAAQ,UAAU;AACjB,MAAI,KAAK,WAAY;AACrB,MAAI,KAAK,UAAU,CAAC,KAAK,OAAO,UAAW;AAC3C,MAAI,KAAK,iBAAiB,CAAC,KAAK,cAAc,UAAW;EAEzD,MAAM,SAAS,IAAI,QAAQ;AAC3B,SAAO,WAAW,KAAK;AACvB,OAAK,gBAAgB;EAErB,MAAM,WAAW,QAAe;AAC/B,UAAO,SAAS;AAChB,QAAK,OAAO,OAAO,KAClB;IACC,UAAU;IACV,IAAI,KAAK;IACT,MAAM,KAAK;IACX,WAAW,KAAK;IAChB;IACA,EACD,0CACA;AACD,OAAI,CAAC,KAAK,WACT,MAAK,mBAAmB;;AAI1B,SAAO,KAAK,SAAS,QAAQ;AAE7B,SAAO,KAAK,eAAe;AAC1B,OAAI,KAAK,kBAAkB,OAC1B,MAAK,gBAAgB;IAErB;AAEF,SAAO,QAAQ,KAAK,MAAM,KAAK,UAAU;AACxC,UAAO,eAAe,SAAS,QAAQ;AACvC,OAAI,KAAK,kBAAkB,OAC1B,MAAK,gBAAgB;AAEtB,QAAK,aAAa,OAAO;AAEzB,OAAI,KAAK,2BAA2B;AACnC,SAAK,2BAA2B;AAChC,SAAK,4BAA4B;;IAEjC;;CAGH,AAAQ,oBAAoB;AAC3B,MAAI,KAAK,eACR,cAAa,KAAK,eAAe;AAElC,OAAK,iBAAiB,iBAAiB;AACtC,QAAK,iBAAiB;AACtB,QAAK,SAAS;KACZ,KAAK,YAAY,IAAK;;CAG1B,MAAM,QAAuB;AAC5B,OAAK,aAAa;AAClB,MAAI,KAAK,gBAAgB;AACxB,gBAAa,KAAK,eAAe;AACjC,QAAK,iBAAiB;;AAEvB,MAAI,KAAK,eAAe;AACvB,QAAK,cAAc,SAAS;AAC5B,QAAK,gBAAgB;;AAEtB,OAAK,MAAM;AACX,QAAM,QAAQ,SAAS"}
1
+ {"version":3,"file":"Secs1OnTcpIpActiveCommunicator.js","names":[],"sources":["../../src/secs1/Secs1OnTcpIpActiveCommunicator.ts"],"sourcesContent":["import { Socket } from \"net\";\nimport {\n\tSecs1Communicator,\n\tSecs1CommunicatorConfig,\n} from \"./Secs1Communicator.js\";\n\nexport interface Secs1OnTcpIpActiveCommunicatorConfig extends Secs1CommunicatorConfig {\n\tip: string;\n\tport: number;\n}\n\nexport class Secs1OnTcpIpActiveCommunicator extends Secs1Communicator {\n\tpublic ip: string;\n\tpublic port: number;\n\n\tprivate shouldStop = false;\n\tprivate reconnectTimer: NodeJS.Timeout | null = null;\n\tprivate connectionPromiseResolver: (() => void) | null = null;\n\tprivate pendingSocket: Socket | null = null;\n\n\tconstructor(config: Secs1OnTcpIpActiveCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.ip = config.ip;\n\t\tthis.port = config.port;\n\t\tthis.on(\"disconnected\", () => {\n\t\t\tif (!this.shouldStop) {\n\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS-I-TCP/IP\",\n\t\t\t\t\t\tip: this.ip,\n\t\t\t\t\t\tport: this.port,\n\t\t\t\t\t\ttimeoutT5: this.timeoutT5,\n\t\t\t\t\t},\n\t\t\t\t\t\"connection lost; scheduling reconnect\",\n\t\t\t\t);\n\t\t\t\tthis.scheduleReconnect();\n\t\t\t}\n\t\t});\n\t}\n\n\tasync open(): Promise<void> {\n\t\tif (this.stream && !this.stream.destroyed) return;\n\t\tif (this.pendingSocket && !this.pendingSocket.destroyed) return;\n\n\t\tthis.shouldStop = false;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.connectionPromiseResolver = resolve;\n\t\t\tthis.connect();\n\t\t});\n\t}\n\n\tprivate connect() {\n\t\tif (this.shouldStop) return;\n\t\tif (this.stream && !this.stream.destroyed) return;\n\t\tif (this.pendingSocket && !this.pendingSocket.destroyed) return;\n\n\t\tconst socket = new Socket();\n\t\tsocket.setNoDelay(true);\n\t\tthis.pendingSocket = socket;\n\n\t\tconst onError = (err: Error) => {\n\t\t\tsocket.destroy();\n\t\t\tthis.logger.detail.warn(\n\t\t\t\t{\n\t\t\t\t\tprotocol: \"SECS-I-TCP/IP\",\n\t\t\t\t\tip: this.ip,\n\t\t\t\t\tport: this.port,\n\t\t\t\t\ttimeoutT5: this.timeoutT5,\n\t\t\t\t\terr,\n\t\t\t\t},\n\t\t\t\t\"connection failed; scheduling reconnect\",\n\t\t\t);\n\t\t\tif (!this.shouldStop) {\n\t\t\t\tthis.scheduleReconnect();\n\t\t\t}\n\t\t};\n\n\t\tsocket.once(\"error\", onError);\n\n\t\tsocket.once(\"close\", () => {\n\t\t\tif (this.pendingSocket === socket) {\n\t\t\t\tthis.pendingSocket = null;\n\t\t\t}\n\t\t});\n\n\t\tsocket.connect(this.port, this.ip, () => {\n\t\t\tsocket.removeListener(\"error\", onError);\n\t\t\tif (this.pendingSocket === socket) {\n\t\t\t\tthis.pendingSocket = null;\n\t\t\t}\n\t\t\tthis.attachStream(socket);\n\n\t\t\tif (this.connectionPromiseResolver) {\n\t\t\t\tthis.connectionPromiseResolver();\n\t\t\t\tthis.connectionPromiseResolver = null;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate scheduleReconnect() {\n\t\tif (this.reconnectTimer) {\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t}\n\t\tthis.reconnectTimer = setTimeout(() => {\n\t\t\tthis.reconnectTimer = null;\n\t\t\tthis.connect();\n\t\t}, this.timeoutT5 * 1000);\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.shouldStop = true;\n\t\tif (this.reconnectTimer) {\n\t\t\tclearTimeout(this.reconnectTimer);\n\t\t\tthis.reconnectTimer = null;\n\t\t}\n\t\tif (this.pendingSocket) {\n\t\t\tthis.pendingSocket.destroy();\n\t\t\tthis.pendingSocket = null;\n\t\t}\n\t\tthis.stop();\n\t\tawait Promise.resolve();\n\t}\n}\n"],"mappings":";;;;AAWA,IAAa,iCAAb,cAAoD,kBAAkB;CACrE,AAAO;CACP,AAAO;CAEP,AAAQ,aAAa;CACrB,AAAQ,iBAAwC;CAChD,AAAQ,4BAAiD;CACzD,AAAQ,gBAA+B;CAEvC,YAAY,QAA8C;AACzD,QAAM,OAAO;AACb,OAAK,KAAK,OAAO;AACjB,OAAK,OAAO,OAAO;AACnB,OAAK,GAAG,sBAAsB;AAC7B,OAAI,CAAC,KAAK,YAAY;AACrB,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,IAAI,KAAK;KACT,MAAM,KAAK;KACX,WAAW,KAAK;KAChB,EACD,wCACA;AACD,SAAK,mBAAmB;;IAExB;;CAGH,MAAM,OAAsB;AAC3B,MAAI,KAAK,UAAU,CAAC,KAAK,OAAO,UAAW;AAC3C,MAAI,KAAK,iBAAiB,CAAC,KAAK,cAAc,UAAW;AAEzD,OAAK,aAAa;AAElB,SAAO,IAAI,SAAS,YAAY;AAC/B,QAAK,4BAA4B;AACjC,QAAK,SAAS;IACb;;CAGH,AAAQ,UAAU;AACjB,MAAI,KAAK,WAAY;AACrB,MAAI,KAAK,UAAU,CAAC,KAAK,OAAO,UAAW;AAC3C,MAAI,KAAK,iBAAiB,CAAC,KAAK,cAAc,UAAW;EAEzD,MAAM,SAAS,IAAI,QAAQ;AAC3B,SAAO,WAAW,KAAK;AACvB,OAAK,gBAAgB;EAErB,MAAM,WAAW,QAAe;AAC/B,UAAO,SAAS;AAChB,QAAK,OAAO,OAAO,KAClB;IACC,UAAU;IACV,IAAI,KAAK;IACT,MAAM,KAAK;IACX,WAAW,KAAK;IAChB;IACA,EACD,0CACA;AACD,OAAI,CAAC,KAAK,WACT,MAAK,mBAAmB;;AAI1B,SAAO,KAAK,SAAS,QAAQ;AAE7B,SAAO,KAAK,eAAe;AAC1B,OAAI,KAAK,kBAAkB,OAC1B,MAAK,gBAAgB;IAErB;AAEF,SAAO,QAAQ,KAAK,MAAM,KAAK,UAAU;AACxC,UAAO,eAAe,SAAS,QAAQ;AACvC,OAAI,KAAK,kBAAkB,OAC1B,MAAK,gBAAgB;AAEtB,QAAK,aAAa,OAAO;AAEzB,OAAI,KAAK,2BAA2B;AACnC,SAAK,2BAA2B;AAChC,SAAK,4BAA4B;;IAEjC;;CAGH,AAAQ,oBAAoB;AAC3B,MAAI,KAAK,eACR,cAAa,KAAK,eAAe;AAElC,OAAK,iBAAiB,iBAAiB;AACtC,QAAK,iBAAiB;AACtB,QAAK,SAAS;KACZ,KAAK,YAAY,IAAK;;CAG1B,MAAM,QAAuB;AAC5B,OAAK,aAAa;AAClB,MAAI,KAAK,gBAAgB;AACxB,gBAAa,KAAK,eAAe;AACjC,QAAK,iBAAiB;;AAEvB,MAAI,KAAK,eAAe;AACvB,QAAK,cAAc,SAAS;AAC5B,QAAK,gBAAgB;;AAEtB,OAAK,MAAM;AACX,QAAM,QAAQ,SAAS"}
@@ -4,15 +4,21 @@ import { Secs1Communicator, Secs1CommunicatorConfig } from "./Secs1Communicator.
4
4
  interface Secs1OnTcpIpPassiveCommunicatorConfig extends Secs1CommunicatorConfig {
5
5
  ip: string;
6
6
  port: number;
7
+ timeoutRebind?: number;
7
8
  }
8
9
  declare class Secs1OnTcpIpPassiveCommunicator extends Secs1Communicator {
9
10
  ip: string;
10
11
  port: number;
11
12
  private server;
13
+ private shouldStop;
14
+ private serverLoopPromise;
15
+ private timeoutRebind;
12
16
  constructor(config: Secs1OnTcpIpPassiveCommunicatorConfig);
13
17
  open(): Promise<void>;
14
- close(): Promise<void>;
18
+ private runServerLoop;
19
+ private listenOnce;
15
20
  private handleIncomingSocket;
21
+ close(): Promise<void>;
16
22
  }
17
23
  //#endregion
18
24
  export { Secs1OnTcpIpPassiveCommunicator, Secs1OnTcpIpPassiveCommunicatorConfig };
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1OnTcpIpPassiveCommunicator.d.ts","names":[],"sources":["../../src/secs1/Secs1OnTcpIpPassiveCommunicator.ts"],"sourcesContent":[],"mappings":";;;UAMiB,qCAAA,SAA8C;;EAA9C,IAAA,EAAA,MAAA;AAKjB;AAMqB,cANR,+BAAA,SAAwC,iBAAA,CAMhC;EAMN,EAAA,EAAA,MAAA;EAsCL,IAAA,EAAA,MAAA;EAlD2C,QAAA,MAAA;EAAiB,WAAA,CAAA,MAAA,EAMjD,qCANiD;UAYvD;WAsCL"}
1
+ {"version":3,"file":"Secs1OnTcpIpPassiveCommunicator.d.ts","names":[],"sources":["../../src/secs1/Secs1OnTcpIpPassiveCommunicator.ts"],"sourcesContent":[],"mappings":";;;UAMiB,qCAAA,SAA8C;;EAA9C,IAAA,EAAA,MAAA;EAMJ,aAAA,CAAA,EAAA,MAAA;;AAkBE,cAlBF,+BAAA,SAAwC,iBAAA,CAkBtC;EA6IL,EAAA,EAAA,MAAA;EA/J2C,IAAA,EAAA,MAAA;EAAiB,QAAA,MAAA;;;;sBASjD;UASN;;;;WA6IL"}
@@ -6,50 +6,136 @@ var Secs1OnTcpIpPassiveCommunicator = class extends Secs1Communicator {
6
6
  ip;
7
7
  port;
8
8
  server = null;
9
+ shouldStop = false;
10
+ serverLoopPromise = null;
11
+ timeoutRebind = 5;
9
12
  constructor(config) {
10
13
  super(config);
11
14
  this.ip = config.ip;
12
15
  this.port = config.port;
16
+ if (config.timeoutRebind !== void 0) this.timeoutRebind = config.timeoutRebind;
13
17
  }
14
18
  async open() {
15
- if (this.server) return;
19
+ if (this.serverLoopPromise) return;
20
+ this.shouldStop = false;
21
+ let resolveFirstListen = null;
22
+ const firstListen = new Promise((resolve) => {
23
+ resolveFirstListen = resolve;
24
+ });
25
+ this.serverLoopPromise = this.runServerLoop(() => {
26
+ resolveFirstListen?.();
27
+ resolveFirstListen = null;
28
+ }).catch((err) => {
29
+ this.emit("error", err instanceof Error ? err : new Error(String(err)));
30
+ });
31
+ await firstListen;
32
+ }
33
+ async runServerLoop(onFirstListening) {
34
+ let first = true;
35
+ while (!this.shouldStop) {
36
+ try {
37
+ await this.listenOnce(first ? onFirstListening : null);
38
+ } catch (err) {
39
+ if (!this.shouldStop) this.emit("error", err instanceof Error ? err : new Error(String(err)));
40
+ if (!this.shouldStop) await new Promise((resolve) => setTimeout(resolve, this.timeoutRebind * 1e3));
41
+ }
42
+ first = false;
43
+ if (this.shouldStop) return;
44
+ }
45
+ }
46
+ async listenOnce(onListening) {
16
47
  return new Promise((resolve, reject) => {
17
- this.server = createServer((socket) => {
18
- if (this.stream && !this.stream.destroyed) {
19
- this.logger.detail.warn({
20
- protocol: "SECS1",
21
- remoteAddress: socket.remoteAddress,
22
- remotePort: socket.remotePort
23
- }, "rejecting new connection (single session)");
24
- socket.destroy();
48
+ const server = createServer((socket) => {
49
+ this.handleIncomingSocket(socket);
50
+ });
51
+ this.server = server;
52
+ let hasConnected = false;
53
+ let settled = false;
54
+ const cleanup = () => {
55
+ server.removeListener("error", onServerError);
56
+ server.removeListener("close", onServerClose);
57
+ this.removeListener("connected", onConnected);
58
+ this.removeListener("disconnected", onDisconnected);
59
+ };
60
+ const finish = (err) => {
61
+ if (settled) return;
62
+ settled = true;
63
+ if (this.server === server) this.server = null;
64
+ cleanup();
65
+ if (err) reject(err);
66
+ else resolve();
67
+ };
68
+ const closeServer = () => {
69
+ if (settled) return;
70
+ if (!server.listening) {
71
+ finish();
25
72
  return;
26
73
  }
27
- this.logger.detail.info({
28
- protocol: "SECS1",
74
+ server.close((closeErr) => {
75
+ if (closeErr) finish(closeErr);
76
+ else finish();
77
+ });
78
+ };
79
+ const onServerError = (_err) => {
80
+ closeServer();
81
+ };
82
+ const onServerClose = () => {
83
+ finish();
84
+ };
85
+ const onConnected = () => {
86
+ hasConnected = true;
87
+ };
88
+ const onDisconnected = () => {
89
+ if (!hasConnected) return;
90
+ closeServer();
91
+ };
92
+ server.on("error", onServerError);
93
+ server.on("close", onServerClose);
94
+ this.on("connected", onConnected);
95
+ this.on("disconnected", onDisconnected);
96
+ server.listen(this.port, this.ip, () => {
97
+ onListening?.();
98
+ });
99
+ });
100
+ }
101
+ handleIncomingSocket(socket) {
102
+ return new Promise((resolve) => {
103
+ if (this.stream && !this.stream.destroyed) {
104
+ this.logger.detail.warn({
105
+ protocol: "SECS-I-TCP/IP",
29
106
  remoteAddress: socket.remoteAddress,
30
107
  remotePort: socket.remotePort
31
- }, "accepted connection");
32
- this.handleIncomingSocket(socket);
33
- });
34
- this.server.on("error", (err) => {
35
- reject(err);
36
- });
37
- this.server.listen(this.port, this.ip, () => {
108
+ }, "rejecting new connection (single session)");
109
+ socket.destroy();
38
110
  resolve();
39
- });
111
+ return;
112
+ }
113
+ this.logger.detail.info({
114
+ protocol: "SECS-I-TCP/IP",
115
+ remoteAddress: socket.remoteAddress,
116
+ remotePort: socket.remotePort
117
+ }, "accepted connection");
118
+ this.attachStream(socket);
119
+ resolve();
40
120
  });
41
121
  }
42
122
  close() {
123
+ this.shouldStop = true;
43
124
  this.stop();
44
- if (this.server) {
45
- this.server.close();
46
- this.server = null;
125
+ const server = this.server;
126
+ if (server) return new Promise((resolve) => {
127
+ server.close(() => {
128
+ this.server = null;
129
+ resolve();
130
+ });
131
+ });
132
+ if (this.serverLoopPromise) {
133
+ const loop = this.serverLoopPromise;
134
+ this.serverLoopPromise = null;
135
+ return loop;
47
136
  }
48
137
  return Promise.resolve();
49
138
  }
50
- handleIncomingSocket(socket) {
51
- this.attachStream(socket);
52
- }
53
139
  };
54
140
 
55
141
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1OnTcpIpPassiveCommunicator.js","names":[],"sources":["../../src/secs1/Secs1OnTcpIpPassiveCommunicator.ts"],"sourcesContent":["import { Server, Socket, createServer } from \"net\";\nimport {\n\tSecs1Communicator,\n\tSecs1CommunicatorConfig,\n} from \"./Secs1Communicator.js\";\n\nexport interface Secs1OnTcpIpPassiveCommunicatorConfig extends Secs1CommunicatorConfig {\n\tip: string;\n\tport: number;\n}\n\nexport class Secs1OnTcpIpPassiveCommunicator extends Secs1Communicator {\n\tpublic ip: string;\n\tpublic port: number;\n\n\tprivate server: Server | null = null;\n\n\tconstructor(config: Secs1OnTcpIpPassiveCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.ip = config.ip;\n\t\tthis.port = config.port;\n\t}\n\n\tasync open(): Promise<void> {\n\t\tif (this.server) return;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.server = createServer((socket) => {\n\t\t\t\tif (this.stream && !this.stream.destroyed) {\n\t\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\t\t\t\tremotePort: socket.remotePort,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rejecting new connection (single session)\",\n\t\t\t\t\t);\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.logger.detail.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS1\",\n\t\t\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\t\t\tremotePort: socket.remotePort,\n\t\t\t\t\t},\n\t\t\t\t\t\"accepted connection\",\n\t\t\t\t);\n\t\t\t\tthis.handleIncomingSocket(socket);\n\t\t\t});\n\n\t\t\tthis.server.on(\"error\", (err) => {\n\t\t\t\treject(err);\n\t\t\t});\n\n\t\t\tthis.server.listen(this.port, this.ip, () => {\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.stop();\n\t\tif (this.server) {\n\t\t\tthis.server.close();\n\t\t\tthis.server = null;\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate handleIncomingSocket(socket: Socket) {\n\t\tthis.attachStream(socket);\n\t}\n}\n"],"mappings":";;;;AAWA,IAAa,kCAAb,cAAqD,kBAAkB;CACtE,AAAO;CACP,AAAO;CAEP,AAAQ,SAAwB;CAEhC,YAAY,QAA+C;AAC1D,QAAM,OAAO;AACb,OAAK,KAAK,OAAO;AACjB,OAAK,OAAO,OAAO;;CAGpB,MAAM,OAAsB;AAC3B,MAAI,KAAK,OAAQ;AAEjB,SAAO,IAAI,SAAS,SAAS,WAAW;AACvC,QAAK,SAAS,cAAc,WAAW;AACtC,QAAI,KAAK,UAAU,CAAC,KAAK,OAAO,WAAW;AAC1C,UAAK,OAAO,OAAO,KAClB;MACC,UAAU;MACV,eAAe,OAAO;MACtB,YAAY,OAAO;MACnB,EACD,4CACA;AACD,YAAO,SAAS;AAChB;;AAED,SAAK,OAAO,OAAO,KAClB;KACC,UAAU;KACV,eAAe,OAAO;KACtB,YAAY,OAAO;KACnB,EACD,sBACA;AACD,SAAK,qBAAqB,OAAO;KAChC;AAEF,QAAK,OAAO,GAAG,UAAU,QAAQ;AAChC,WAAO,IAAI;KACV;AAEF,QAAK,OAAO,OAAO,KAAK,MAAM,KAAK,UAAU;AAC5C,aAAS;KACR;IACD;;CAGH,QAAuB;AACtB,OAAK,MAAM;AACX,MAAI,KAAK,QAAQ;AAChB,QAAK,OAAO,OAAO;AACnB,QAAK,SAAS;;AAEf,SAAO,QAAQ,SAAS;;CAGzB,AAAQ,qBAAqB,QAAgB;AAC5C,OAAK,aAAa,OAAO"}
1
+ {"version":3,"file":"Secs1OnTcpIpPassiveCommunicator.js","names":["resolveFirstListen: (() => void) | null"],"sources":["../../src/secs1/Secs1OnTcpIpPassiveCommunicator.ts"],"sourcesContent":["import { Server, Socket, createServer } from \"net\";\nimport {\n\tSecs1Communicator,\n\tSecs1CommunicatorConfig,\n} from \"./Secs1Communicator.js\";\n\nexport interface Secs1OnTcpIpPassiveCommunicatorConfig extends Secs1CommunicatorConfig {\n\tip: string;\n\tport: number;\n\ttimeoutRebind?: number;\n}\n\nexport class Secs1OnTcpIpPassiveCommunicator extends Secs1Communicator {\n\tpublic ip: string;\n\tpublic port: number;\n\n\tprivate server: Server | null = null;\n\tprivate shouldStop = false;\n\tprivate serverLoopPromise: Promise<void> | null = null;\n\tprivate timeoutRebind = 5;\n\n\tconstructor(config: Secs1OnTcpIpPassiveCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.ip = config.ip;\n\t\tthis.port = config.port;\n\t\tif (config.timeoutRebind !== undefined) {\n\t\t\tthis.timeoutRebind = config.timeoutRebind;\n\t\t}\n\t}\n\n\tasync open(): Promise<void> {\n\t\tif (this.serverLoopPromise) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.shouldStop = false;\n\n\t\tlet resolveFirstListen: (() => void) | null = null;\n\t\tconst firstListen = new Promise<void>((resolve) => {\n\t\t\tresolveFirstListen = resolve;\n\t\t});\n\n\t\tthis.serverLoopPromise = this.runServerLoop(() => {\n\t\t\tresolveFirstListen?.();\n\t\t\tresolveFirstListen = null;\n\t\t}).catch((err: unknown) => {\n\t\t\tthis.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n\t\t});\n\n\t\tawait firstListen;\n\t}\n\n\tprivate async runServerLoop(onFirstListening: () => void): Promise<void> {\n\t\tlet first = true;\n\t\twhile (!this.shouldStop) {\n\t\t\ttry {\n\t\t\t\tawait this.listenOnce(first ? onFirstListening : null);\n\t\t\t} catch (err) {\n\t\t\t\tif (!this.shouldStop) {\n\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\terr instanceof Error ? err : new Error(String(err)),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!this.shouldStop) {\n\t\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\t\tsetTimeout(resolve, this.timeoutRebind * 1000),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfirst = false;\n\t\t\tif (this.shouldStop) return;\n\t\t}\n\t}\n\n\tprivate async listenOnce(onListening: (() => void) | null): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst server = createServer((socket) => {\n\t\t\t\tvoid this.handleIncomingSocket(socket);\n\t\t\t});\n\t\t\tthis.server = server;\n\n\t\t\tlet hasConnected = false;\n\t\t\tlet settled = false;\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tserver.removeListener(\"error\", onServerError);\n\t\t\t\tserver.removeListener(\"close\", onServerClose);\n\t\t\t\tthis.removeListener(\"connected\", onConnected);\n\t\t\t\tthis.removeListener(\"disconnected\", onDisconnected);\n\t\t\t};\n\n\t\t\tconst finish = (err?: Error) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tif (this.server === server) {\n\t\t\t\t\tthis.server = null;\n\t\t\t\t}\n\t\t\t\tcleanup();\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t};\n\n\t\t\tconst closeServer = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (!server.listening) {\n\t\t\t\t\tfinish();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tserver.close((closeErr) => {\n\t\t\t\t\tif (closeErr) finish(closeErr);\n\t\t\t\t\telse finish();\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst onServerError = (_err: Error) => {\n\t\t\t\tcloseServer();\n\t\t\t};\n\n\t\t\tconst onServerClose = () => {\n\t\t\t\tfinish();\n\t\t\t};\n\n\t\t\tconst onConnected = () => {\n\t\t\t\thasConnected = true;\n\t\t\t};\n\n\t\t\tconst onDisconnected = () => {\n\t\t\t\tif (!hasConnected) return;\n\t\t\t\tcloseServer();\n\t\t\t};\n\n\t\t\tserver.on(\"error\", onServerError);\n\t\t\tserver.on(\"close\", onServerClose);\n\t\t\tthis.on(\"connected\", onConnected);\n\t\t\tthis.on(\"disconnected\", onDisconnected);\n\n\t\t\tserver.listen(this.port, this.ip, () => {\n\t\t\t\tonListening?.();\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate handleIncomingSocket(socket: Socket): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tif (this.stream && !this.stream.destroyed) {\n\t\t\t\tthis.logger.detail.warn(\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol: \"SECS-I-TCP/IP\",\n\t\t\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\t\t\tremotePort: socket.remotePort,\n\t\t\t\t\t},\n\t\t\t\t\t\"rejecting new connection (single session)\",\n\t\t\t\t);\n\t\t\t\tsocket.destroy();\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.logger.detail.info(\n\t\t\t\t{\n\t\t\t\t\tprotocol: \"SECS-I-TCP/IP\",\n\t\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\t\tremotePort: socket.remotePort,\n\t\t\t\t},\n\t\t\t\t\"accepted connection\",\n\t\t\t);\n\t\t\tthis.attachStream(socket);\n\t\t\tresolve();\n\t\t});\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.shouldStop = true;\n\t\tthis.stop();\n\t\tconst server = this.server;\n\t\tif (server) {\n\t\t\treturn new Promise<void>((resolve) => {\n\t\t\t\tserver.close(() => {\n\t\t\t\t\tthis.server = null;\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t\tif (this.serverLoopPromise) {\n\t\t\tconst loop = this.serverLoopPromise;\n\t\t\tthis.serverLoopPromise = null;\n\t\t\treturn loop;\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1SerialCommunicator.d.ts","names":[],"sources":["../../src/secs1/Secs1SerialCommunicator.ts"],"sourcesContent":[],"mappings":";;;UAMiB,6BAAA,SAAsC;;EAAtC,QAAA,EAAA,MAAA;AAKjB;AAMqB,cANR,uBAAA,SAAgC,iBAAA,CAMxB;EAMN,QAAA,IAAA;EA4BC,IAAA,EAAA,MAAA;EAxC6B,QAAA,EAAA,MAAA;EAAiB,WAAA,CAAA,MAAA,EAMzC,6BANyC;UAY/C;WA4BC"}
1
+ {"version":3,"file":"Secs1SerialCommunicator.d.ts","names":[],"sources":["../../src/secs1/Secs1SerialCommunicator.ts"],"sourcesContent":[],"mappings":";;;UAMiB,6BAAA,SAAsC;;EAAtC,QAAA,EAAA,MAAA;AAKjB;AAMqB,cANR,uBAAA,SAAgC,iBAAA,CAMxB;EAON,QAAA,IAAA;EA4BC,IAAA,EAAA,MAAA;EAzC6B,QAAA,EAAA,MAAA;EAAiB,WAAA,CAAA,MAAA,EAMzC,6BANyC;UAa/C;WA4BC"}
@@ -8,6 +8,7 @@ var Secs1SerialCommunicator = class extends Secs1Communicator {
8
8
  baudRate;
9
9
  constructor(config) {
10
10
  super(config);
11
+ this.isMaster = config.isEquip;
11
12
  this.path = config.path;
12
13
  this.baudRate = config.baudRate;
13
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1SerialCommunicator.js","names":[],"sources":["../../src/secs1/Secs1SerialCommunicator.ts"],"sourcesContent":["import { SerialPort } from \"serialport\";\nimport {\n\tSecs1Communicator,\n\tSecs1CommunicatorConfig,\n} from \"./Secs1Communicator.js\";\n\nexport interface Secs1SerialCommunicatorConfig extends Secs1CommunicatorConfig {\n\tpath: string;\n\tbaudRate: number;\n}\n\nexport class Secs1SerialCommunicator extends Secs1Communicator {\n\tprivate port: SerialPort | null = null;\n\n\tpublic path: string;\n\tpublic baudRate: number;\n\n\tconstructor(config: Secs1SerialCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.path = config.path;\n\t\tthis.baudRate = config.baudRate;\n\t}\n\n\tasync open(): Promise<void> {\n\t\tif (this.port?.isOpen) return;\n\n\t\tconst port = new SerialPort({\n\t\t\tpath: this.path,\n\t\t\tbaudRate: this.baudRate,\n\t\t\tautoOpen: false,\n\t\t});\n\t\tthis.port = port;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst onError = (err: Error) => {\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tport.once(\"error\", onError);\n\t\t\tport.open((err) => {\n\t\t\t\tport.removeListener(\"error\", onError);\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.attachStream(port);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.stop();\n\n\t\tconst port = this.port;\n\t\tthis.port = null;\n\t\tif (!port) return;\n\n\t\tif (!port.isOpen) {\n\t\t\tport.destroy();\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tport.close((err) => {\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t});\n\t\t});\n\n\t\tport.destroy();\n\t}\n}\n"],"mappings":";;;;AAWA,IAAa,0BAAb,cAA6C,kBAAkB;CAC9D,AAAQ,OAA0B;CAElC,AAAO;CACP,AAAO;CAEP,YAAY,QAAuC;AAClD,QAAM,OAAO;AACb,OAAK,OAAO,OAAO;AACnB,OAAK,WAAW,OAAO;;CAGxB,MAAM,OAAsB;AAC3B,MAAI,KAAK,MAAM,OAAQ;EAEvB,MAAM,OAAO,IAAI,WAAW;GAC3B,MAAM,KAAK;GACX,UAAU,KAAK;GACf,UAAU;GACV,CAAC;AACF,OAAK,OAAO;AAEZ,SAAO,IAAI,SAAS,SAAS,WAAW;GACvC,MAAM,WAAW,QAAe;AAC/B,WAAO,IAAI;;AAGZ,QAAK,KAAK,SAAS,QAAQ;AAC3B,QAAK,MAAM,QAAQ;AAClB,SAAK,eAAe,SAAS,QAAQ;AACrC,QAAI,KAAK;AACR,YAAO,IAAI;AACX;;AAED,SAAK,aAAa,KAAK;AACvB,aAAS;KACR;IACD;;CAGH,MAAM,QAAuB;AAC5B,OAAK,MAAM;EAEX,MAAM,OAAO,KAAK;AAClB,OAAK,OAAO;AACZ,MAAI,CAAC,KAAM;AAEX,MAAI,CAAC,KAAK,QAAQ;AACjB,QAAK,SAAS;AACd;;AAGD,QAAM,IAAI,SAAe,SAAS,WAAW;AAC5C,QAAK,OAAO,QAAQ;AACnB,QAAI,IAAK,QAAO,IAAI;QACf,UAAS;KACb;IACD;AAEF,OAAK,SAAS"}
1
+ {"version":3,"file":"Secs1SerialCommunicator.js","names":[],"sources":["../../src/secs1/Secs1SerialCommunicator.ts"],"sourcesContent":["import { SerialPort } from \"serialport\";\nimport {\n\tSecs1Communicator,\n\tSecs1CommunicatorConfig,\n} from \"./Secs1Communicator.js\";\n\nexport interface Secs1SerialCommunicatorConfig extends Secs1CommunicatorConfig {\n\tpath: string;\n\tbaudRate: number;\n}\n\nexport class Secs1SerialCommunicator extends Secs1Communicator {\n\tprivate port: SerialPort | null = null;\n\n\tpublic path: string;\n\tpublic baudRate: number;\n\n\tconstructor(config: Secs1SerialCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.isMaster = config.isEquip;\n\t\tthis.path = config.path;\n\t\tthis.baudRate = config.baudRate;\n\t}\n\n\tasync open(): Promise<void> {\n\t\tif (this.port?.isOpen) return;\n\n\t\tconst port = new SerialPort({\n\t\t\tpath: this.path,\n\t\t\tbaudRate: this.baudRate,\n\t\t\tautoOpen: false,\n\t\t});\n\t\tthis.port = port;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst onError = (err: Error) => {\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tport.once(\"error\", onError);\n\t\t\tport.open((err) => {\n\t\t\t\tport.removeListener(\"error\", onError);\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.attachStream(port);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.stop();\n\n\t\tconst port = this.port;\n\t\tthis.port = null;\n\t\tif (!port) return;\n\n\t\tif (!port.isOpen) {\n\t\t\tport.destroy();\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tport.close((err) => {\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t});\n\t\t});\n\n\t\tport.destroy();\n\t}\n}\n"],"mappings":";;;;AAWA,IAAa,0BAAb,cAA6C,kBAAkB;CAC9D,AAAQ,OAA0B;CAElC,AAAO;CACP,AAAO;CAEP,YAAY,QAAuC;AAClD,QAAM,OAAO;AACb,OAAK,WAAW,OAAO;AACvB,OAAK,OAAO,OAAO;AACnB,OAAK,WAAW,OAAO;;CAGxB,MAAM,OAAsB;AAC3B,MAAI,KAAK,MAAM,OAAQ;EAEvB,MAAM,OAAO,IAAI,WAAW;GAC3B,MAAM,KAAK;GACX,UAAU,KAAK;GACf,UAAU;GACV,CAAC;AACF,OAAK,OAAO;AAEZ,SAAO,IAAI,SAAS,SAAS,WAAW;GACvC,MAAM,WAAW,QAAe;AAC/B,WAAO,IAAI;;AAGZ,QAAK,KAAK,SAAS,QAAQ;AAC3B,QAAK,MAAM,QAAQ;AAClB,SAAK,eAAe,SAAS,QAAQ;AACrC,QAAI,KAAK;AACR,YAAO,IAAI;AACX;;AAED,SAAK,aAAa,KAAK;AACvB,aAAS;KACR;IACD;;CAGH,MAAM,QAAuB;AAC5B,OAAK,MAAM;EAEX,MAAM,OAAO,KAAK;AAClB,OAAK,OAAO;AACZ,MAAI,CAAC,KAAM;AAEX,MAAI,CAAC,KAAK,QAAQ;AACjB,QAAK,SAAS;AACd;;AAGD,QAAM,IAAI,SAAe,SAAS,WAAW;AAC5C,QAAK,OAAO,QAAQ;AACnB,QAAI,IAAK,QAAO,IAAI;QACf,UAAS;KACb;IACD;AAEF,OAAK,SAAS"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secs4js",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "A simple, efficient, and user-friendly SECS/GEM protocol library implemented in TypeScript.",
5
5
  "repository": {
6
6
  "type": "git",