secs4js 0.4.0 → 0.4.2
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.md +20 -20
- package/README.md +526 -442
- package/lib/core/AbstractSecsMessage.js.map +1 -1
- package/lib/core/enums/HsmsSsControlType.js.map +1 -1
- package/lib/core/enums/RejectReason.js.map +1 -1
- package/lib/core/enums/SecsItemType.js.map +1 -1
- package/lib/core/enums/SelectStatus.js.map +1 -1
- package/lib/core/secs2item/AbstractSecs2Item.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemAscii.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemBinary.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemBoolean.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemFactory.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemList.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemNumeric.js.map +1 -1
- package/lib/core/secs2item/Secs2ItemParser.js.map +1 -1
- package/lib/gem/Clock.js.map +1 -1
- package/lib/gem/Gem.js.map +1 -1
- package/lib/helper/Secs2ItemHelper.js.map +1 -1
- package/lib/hsms/HsmsMessage.js.map +1 -1
- package/lib/hsms/HsmsPassiveCommunicator.js.map +1 -1
- package/lib/hsms/enums/HsmsControlType.js.map +1 -1
- package/lib/hsms/enums/RejectReason.js.map +1 -1
- package/lib/hsms/enums/SelectStatus.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +2 -1
- package/lib/secs1/Secs1Message.js.map +1 -1
- package/lib/secs1/Secs1MessageBlock.js.map +1 -1
- package/lib/secs1/Secs1SerialCommunicator.js.map +1 -1
- package/lib/sml/SmlParser.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,442 +1,526 @@
|
|
|
1
|
-
<h1 align="center">Secs4js</h1>
|
|
2
|
-
|
|
3
|
-
<p align="center">A simple, efficient, and user-friendly SECS/GEM protocol library implemented in TypeScript.</p>
|
|
4
|
-
|
|
5
|
-
## Introduction
|
|
6
|
-
|
|
7
|
-
This project is a TypeScript implementation of the SECS/GEM protocol, inspired by [pysemisecs](https://github.com/kenta-shimizu/pysemisecs).
|
|
8
|
-
|
|
9
|
-
A special thanks to the author **kenta-shimizu** for their open-source contribution.
|
|
10
|
-
|
|
11
|
-
Secs4js is a simple, efficient, and user-friendly SECS/GEM protocol library implemented in TypeScript. It provides a straightforward way to communicate with SECS/GEM devices, enabling you to easily read and write data using the SECS/GEM protocol.
|
|
12
|
-
|
|
13
|
-
## Supported Features
|
|
14
|
-
|
|
15
|
-
- SECS-I (SEMI-E4)
|
|
16
|
-
- SECS-I Virtual Serial Port (SECS-I on TCP/IP)
|
|
17
|
-
- SECS-II (SEMI-E5)
|
|
18
|
-
- GEM (SEMI-E30)
|
|
19
|
-
- HSMS-SS (SEMI-E37.1)
|
|
20
|
-
- **No HSMS-GS (SEMI-E37.2)**
|
|
21
|
-
|
|
22
|
-
## Installation
|
|
23
|
-
|
|
24
|
-
```shell
|
|
25
|
-
npm i secs4js
|
|
26
|
-
|
|
27
|
-
pnpm add secs4js
|
|
28
|
-
|
|
29
|
-
yarn add secs4js
|
|
30
|
-
|
|
31
|
-
bun add secs4js
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Getting Started from Source
|
|
35
|
-
|
|
36
|
-
If you want to run some examples, they can be found in the `examples` directory.
|
|
37
|
-
|
|
38
|
-
Run the following commands to start these examples:
|
|
39
|
-
|
|
40
|
-
```shell
|
|
41
|
-
pnpm dlx tsx examples/gem_example.ts
|
|
42
|
-
|
|
43
|
-
# ...
|
|
44
|
-
pnpm dlx tsx examples/<example_file_name>.ts
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Usage
|
|
48
|
-
|
|
49
|
-
### 1. Creating SECS-II Messages
|
|
50
|
-
|
|
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
|
-
|
|
53
|
-
```ts
|
|
54
|
-
import { B, U1, U2, U4, U8, I1, I2, I4, I8, F4, F8, A, L } from "secs4js";
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
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:
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import { L, A, U1, SecsMessage } from "secs4js";
|
|
61
|
-
|
|
62
|
-
const body: AbstractSecs2Item = L(A("Hello, SECS/GEM!"), U1(123));
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Doesn't this highly resemble SML text syntax?
|
|
66
|
-
|
|
67
|
-
All SECS-II messages are derived from the `AbstractSecs2Item` class, so you can use it to declare any SECS-II message of unknown type.
|
|
68
|
-
|
|
69
|
-
If you don't like this approach, you can also use SML text syntax or the factory methods we provide to create SECS-II messages.
|
|
70
|
-
|
|
71
|
-
Factory methods:
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
import { Secs2ItemFactory } from "secs4js";
|
|
75
|
-
|
|
76
|
-
// Create a message containing L, A, and U1 items
|
|
77
|
-
const newMsg = Secs2ItemFactory.createListItem(
|
|
78
|
-
Secs2ItemFactory.createAsciiItem("Hello World"),
|
|
79
|
-
Secs2ItemFactory.createU1Item(123),
|
|
80
|
-
);
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
SML Conversion Support:
|
|
84
|
-
|
|
85
|
-
You can use the `toSml` method of the `AbstractSecs2Item` class to convert SECS-II messages to SML text. For example:
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
console.log(newMsg.toSml());
|
|
89
|
-
|
|
90
|
-
// Output:
|
|
91
|
-
// <L
|
|
92
|
-
// <A "Hello World">
|
|
93
|
-
// <U1 123>
|
|
94
|
-
// >.
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### 2. Creating SECS Messages
|
|
98
|
-
|
|
99
|
-
We provide two ways to create SECS-II messages:
|
|
100
|
-
|
|
101
|
-
1. Use the `SecsMessage` class to create SECS-II messages.
|
|
102
|
-
2. Create SECS-II messages by parsing SML syntax text. You can use the `SmlParser` static class to parse SML text and create corresponding SECS-II messages.
|
|
103
|
-
|
|
104
|
-
#### new SecsMessage(...)
|
|
105
|
-
|
|
106
|
-
> You can use the `SecsMessage` class to create SECS-II messages. The class constructor accepts the following parameters:
|
|
107
|
-
>
|
|
108
|
-
> - `stream`: Stream number, one byte, range 0-255.
|
|
109
|
-
> - `function`: Function number, one byte, range 0-255.
|
|
110
|
-
> - `wBit`: W-bit, a boolean indicating whether to enable W-bit (i.e., whether a reply is required).
|
|
111
|
-
> - `body`: SECS-II message body, an `AbstractSecs2Item` instance.
|
|
112
|
-
> - We will automatically generate the message's `length` and `systemBytes`, so you don't need to manage them manually.
|
|
113
|
-
|
|
114
|
-
```ts
|
|
115
|
-
import { SecsMessage } from "secs4js";
|
|
116
|
-
|
|
117
|
-
const newMsg = new SecsMessage(1, 13, true, L(L(A("Hello World"), U1(123))));
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
#### SmlParser
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
import { SmlParser } from "secs4js";
|
|
124
|
-
|
|
125
|
-
// Complete SML text
|
|
126
|
-
const sml = `
|
|
127
|
-
S1F13 W
|
|
128
|
-
<L
|
|
129
|
-
<B 0x20>
|
|
130
|
-
<A "Hello World">
|
|
131
|
-
>.
|
|
132
|
-
`;
|
|
133
|
-
|
|
134
|
-
// SML text containing only the message body
|
|
135
|
-
const smlBody = `
|
|
136
|
-
<L
|
|
137
|
-
<B 0x20>
|
|
138
|
-
<A "Hello World">
|
|
139
|
-
>.
|
|
140
|
-
`;
|
|
141
|
-
|
|
142
|
-
// Parse complete SML text into a SecsMessage instance using the parse method
|
|
143
|
-
const parsedMessage = SmlParser.parse(sml);
|
|
144
|
-
const firstBodyItem =
|
|
145
|
-
parsedMessage.body instanceof Secs2ItemList
|
|
146
|
-
? parsedMessage.body.value[0]
|
|
147
|
-
: null;
|
|
148
|
-
const bytes =
|
|
149
|
-
firstBodyItem instanceof Secs2ItemBinary ? firstBodyItem.value : null;
|
|
150
|
-
console.log(
|
|
151
|
-
parsedMessage.stream,
|
|
152
|
-
parsedMessage.func,
|
|
153
|
-
parsedMessage.wBit,
|
|
154
|
-
bytes,
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
// Parse SML text containing only the message body into an AbstractSecs2Item instance using the parseBody method
|
|
158
|
-
const parsedBody = SmlParser.parseBody(smlBody);
|
|
159
|
-
console.log(parsedBody?.toSml());
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
##
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
active.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
//
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
1
|
+
<h1 align="center">Secs4js</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">A simple, efficient, and user-friendly SECS/GEM protocol library implemented in TypeScript.</p>
|
|
4
|
+
|
|
5
|
+
## Introduction
|
|
6
|
+
|
|
7
|
+
This project is a TypeScript implementation of the SECS/GEM protocol, inspired by [pysemisecs](https://github.com/kenta-shimizu/pysemisecs).
|
|
8
|
+
|
|
9
|
+
A special thanks to the author **kenta-shimizu** for their open-source contribution.
|
|
10
|
+
|
|
11
|
+
Secs4js is a simple, efficient, and user-friendly SECS/GEM protocol library implemented in TypeScript. It provides a straightforward way to communicate with SECS/GEM devices, enabling you to easily read and write data using the SECS/GEM protocol.
|
|
12
|
+
|
|
13
|
+
## Supported Features
|
|
14
|
+
|
|
15
|
+
- SECS-I (SEMI-E4)
|
|
16
|
+
- SECS-I Virtual Serial Port (SECS-I on TCP/IP)
|
|
17
|
+
- SECS-II (SEMI-E5)
|
|
18
|
+
- GEM (SEMI-E30)
|
|
19
|
+
- HSMS-SS (SEMI-E37.1)
|
|
20
|
+
- **No HSMS-GS (SEMI-E37.2)**
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```shell
|
|
25
|
+
npm i secs4js
|
|
26
|
+
|
|
27
|
+
pnpm add secs4js
|
|
28
|
+
|
|
29
|
+
yarn add secs4js
|
|
30
|
+
|
|
31
|
+
bun add secs4js
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Getting Started from Source
|
|
35
|
+
|
|
36
|
+
If you want to run some examples, they can be found in the `examples` directory.
|
|
37
|
+
|
|
38
|
+
Run the following commands to start these examples:
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
pnpm dlx tsx examples/gem_example.ts
|
|
42
|
+
|
|
43
|
+
# ...
|
|
44
|
+
pnpm dlx tsx examples/<example_file_name>.ts
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### 1. Creating SECS-II Messages
|
|
50
|
+
|
|
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
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { B, U1, U2, U4, U8, I1, I2, I4, I8, F4, F8, A, L } from "secs4js";
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
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:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { L, A, U1, SecsMessage } from "secs4js";
|
|
61
|
+
|
|
62
|
+
const body: AbstractSecs2Item = L(A("Hello, SECS/GEM!"), U1(123));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Doesn't this highly resemble SML text syntax?
|
|
66
|
+
|
|
67
|
+
All SECS-II messages are derived from the `AbstractSecs2Item` class, so you can use it to declare any SECS-II message of unknown type.
|
|
68
|
+
|
|
69
|
+
If you don't like this approach, you can also use SML text syntax or the factory methods we provide to create SECS-II messages.
|
|
70
|
+
|
|
71
|
+
Factory methods:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { Secs2ItemFactory } from "secs4js";
|
|
75
|
+
|
|
76
|
+
// Create a message containing L, A, and U1 items
|
|
77
|
+
const newMsg = Secs2ItemFactory.createListItem(
|
|
78
|
+
Secs2ItemFactory.createAsciiItem("Hello World"),
|
|
79
|
+
Secs2ItemFactory.createU1Item(123),
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
SML Conversion Support:
|
|
84
|
+
|
|
85
|
+
You can use the `toSml` method of the `AbstractSecs2Item` class to convert SECS-II messages to SML text. For example:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
console.log(newMsg.toSml());
|
|
89
|
+
|
|
90
|
+
// Output:
|
|
91
|
+
// <L
|
|
92
|
+
// <A "Hello World">
|
|
93
|
+
// <U1 123>
|
|
94
|
+
// >.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 2. Creating SECS Messages
|
|
98
|
+
|
|
99
|
+
We provide two ways to create SECS-II messages:
|
|
100
|
+
|
|
101
|
+
1. Use the `SecsMessage` class to create SECS-II messages.
|
|
102
|
+
2. Create SECS-II messages by parsing SML syntax text. You can use the `SmlParser` static class to parse SML text and create corresponding SECS-II messages.
|
|
103
|
+
|
|
104
|
+
#### new SecsMessage(...)
|
|
105
|
+
|
|
106
|
+
> You can use the `SecsMessage` class to create SECS-II messages. The class constructor accepts the following parameters:
|
|
107
|
+
>
|
|
108
|
+
> - `stream`: Stream number, one byte, range 0-255.
|
|
109
|
+
> - `function`: Function number, one byte, range 0-255.
|
|
110
|
+
> - `wBit`: W-bit, a boolean indicating whether to enable W-bit (i.e., whether a reply is required).
|
|
111
|
+
> - `body`: SECS-II message body, an `AbstractSecs2Item` instance.
|
|
112
|
+
> - We will automatically generate the message's `length` and `systemBytes`, so you don't need to manage them manually.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { SecsMessage } from "secs4js";
|
|
116
|
+
|
|
117
|
+
const newMsg = new SecsMessage(1, 13, true, L(L(A("Hello World"), U1(123))));
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### SmlParser
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { SmlParser } from "secs4js";
|
|
124
|
+
|
|
125
|
+
// Complete SML text
|
|
126
|
+
const sml = `
|
|
127
|
+
S1F13 W
|
|
128
|
+
<L
|
|
129
|
+
<B 0x20>
|
|
130
|
+
<A "Hello World">
|
|
131
|
+
>.
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
// SML text containing only the message body
|
|
135
|
+
const smlBody = `
|
|
136
|
+
<L
|
|
137
|
+
<B 0x20>
|
|
138
|
+
<A "Hello World">
|
|
139
|
+
>.
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
// Parse complete SML text into a SecsMessage instance using the parse method
|
|
143
|
+
const parsedMessage = SmlParser.parse(sml);
|
|
144
|
+
const firstBodyItem =
|
|
145
|
+
parsedMessage.body instanceof Secs2ItemList
|
|
146
|
+
? parsedMessage.body.value[0]
|
|
147
|
+
: null;
|
|
148
|
+
const bytes =
|
|
149
|
+
firstBodyItem instanceof Secs2ItemBinary ? firstBodyItem.value : null;
|
|
150
|
+
console.log(
|
|
151
|
+
parsedMessage.stream,
|
|
152
|
+
parsedMessage.func,
|
|
153
|
+
parsedMessage.wBit,
|
|
154
|
+
bytes,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Parse SML text containing only the message body into an AbstractSecs2Item instance using the parseBody method
|
|
158
|
+
const parsedBody = SmlParser.parseBody(smlBody);
|
|
159
|
+
console.log(parsedBody?.toSml());
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Sending and Replying to Messages
|
|
163
|
+
|
|
164
|
+
In this library, you can actively send messages and passively reply to messages.
|
|
165
|
+
|
|
166
|
+
For actively sent messages, a new `SystemBytes` will be automatically generated. For reply messages, the `SystemBytes` from the primary message will be automatically read and used for the reply.
|
|
167
|
+
|
|
168
|
+
- **Send:** `send(stream: number, func: number, wBit: boolean, body?: AbstractSecs2Item)`
|
|
169
|
+
- **Reply:** `reply(primaryMsg: SecsMessage, stream: number, func: number, body?: AbstractSecs2Item)`
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
active.on("message", (msg: SecsMessage) => {
|
|
173
|
+
void (async () => {
|
|
174
|
+
console.log(`Active received: ${msg.toSml()}`);
|
|
175
|
+
|
|
176
|
+
await active.send(2, 18, true, L());
|
|
177
|
+
|
|
178
|
+
if (msg.stream === 1 && msg.func === 1) {
|
|
179
|
+
await active.reply(msg, 1, 2, L(A("MDLN-A"), A("SOFTREV-1")));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (msg.stream === 1 && msg.func === 13) {
|
|
183
|
+
await active.reply(msg, 1, 14, L(A("ACK")));
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## HSMS-SS
|
|
190
|
+
|
|
191
|
+
For HSMS-SS protocol support, you can act as the passive end (Equipment) or the active end (HOST/EAP).
|
|
192
|
+
|
|
193
|
+
### Active
|
|
194
|
+
|
|
195
|
+
Quick start:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
const active = new HsmsActiveCommunicator({
|
|
199
|
+
ip: "127.0.0.1",
|
|
200
|
+
port: 5000,
|
|
201
|
+
deviceId: 10,
|
|
202
|
+
isEquip: false,
|
|
203
|
+
// If you need to customize the timeout values, you can add additional parameters
|
|
204
|
+
// timeoutT1: 10,
|
|
205
|
+
// ...
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
active.on("connected", () => console.log("Active TCP Connected"));
|
|
209
|
+
active.on("disconnected", () => console.log("Active Disconnected"));
|
|
210
|
+
active.on("selected", () => console.log("Active Selected (HSMS Ready)"));
|
|
211
|
+
|
|
212
|
+
await active.open();
|
|
213
|
+
console.log("Active opened");
|
|
214
|
+
|
|
215
|
+
// Active will automatically send SelectReq and start heartbeat
|
|
216
|
+
|
|
217
|
+
await active.untilConnected(); // Wait for Select success
|
|
218
|
+
|
|
219
|
+
// When you need to receive and process messages, you can listen for the "message" event
|
|
220
|
+
active.on("message", (msg: SecsMessage) => {
|
|
221
|
+
void (async () => {
|
|
222
|
+
console.log(`Active received: ${msg.toSml()}`);
|
|
223
|
+
if (msg.stream === 1 && msg.func === 1) {
|
|
224
|
+
await active.reply(msg, 1, 2, L(A("MDLN-A"), A("SOFTREV-1")));
|
|
225
|
+
}
|
|
226
|
+
if (msg.stream === 1 && msg.func === 13) {
|
|
227
|
+
await active.reply(msg, 1, 14, L(A("ACK")));
|
|
228
|
+
}
|
|
229
|
+
})();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const reply = await active.send(1, 1, true);
|
|
233
|
+
console.log(`Active received reply: ${reply?.toSml()}`);
|
|
234
|
+
|
|
235
|
+
// Interaction results with the simulator
|
|
236
|
+
// Our reply message:
|
|
237
|
+
// 2025-12-30 01:26:44.866:onReceivedEvent[TOOL] DeviceID=[10] SB=[6110]
|
|
238
|
+
// S1F2
|
|
239
|
+
// <L[2/1]
|
|
240
|
+
// <A[6/1] "MDLN-A">
|
|
241
|
+
// <A[9/1] "SOFTREV-1">
|
|
242
|
+
// >.
|
|
243
|
+
|
|
244
|
+
// Message actively sent by the simulator:
|
|
245
|
+
// 2025-12-30 01:26:44.864:OnSent[TOOL] DeviceID=[1] SB=[6110]
|
|
246
|
+
|
|
247
|
+
// S1F1 W.
|
|
248
|
+
// 2025-12-30 01:26:44.864:Send the Message successfully.
|
|
249
|
+
|
|
250
|
+
// Message replied by the simulator:
|
|
251
|
+
// 2025-12-30 01:26:40.449:OnSent[TOOL] DeviceID=[10] SB=[2]
|
|
252
|
+
// S1F2
|
|
253
|
+
// <L[0/1]>.
|
|
254
|
+
|
|
255
|
+
// Message we actively sent:
|
|
256
|
+
// 2025-12-30 01:26:40.445:Do not find Tool in QutoReply List by Tool[TOOL] SFName=[S1F1]
|
|
257
|
+
// 2025-12-30 01:26:40.444:onReceivedEvent[TOOL] DeviceID=[10] SB=[2]
|
|
258
|
+
// S1F1 W.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Passive
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
import {
|
|
265
|
+
HsmsPassiveCommunicator,
|
|
266
|
+
SecsMessage,
|
|
267
|
+
CommAck,
|
|
268
|
+
OnlAck,
|
|
269
|
+
Gem,
|
|
270
|
+
} from "secs4js";
|
|
271
|
+
|
|
272
|
+
// 1. Set up Equipment side (Passive)
|
|
273
|
+
const equipComm = new HsmsPassiveCommunicator({
|
|
274
|
+
ip: "127.0.0.1",
|
|
275
|
+
port: 5000,
|
|
276
|
+
deviceId: 1,
|
|
277
|
+
isEquip: true,
|
|
278
|
+
name: "Equipment",
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Use the GEM helper class (optional)
|
|
282
|
+
const equipGem = new Gem(equipComm);
|
|
283
|
+
equipGem.mdln = "MyEquip";
|
|
284
|
+
equipGem.softrev = "1.0.0";
|
|
285
|
+
|
|
286
|
+
// Handle received messages
|
|
287
|
+
equipComm.on("message", (msg: SecsMessage) => {
|
|
288
|
+
void (async () => {
|
|
289
|
+
try {
|
|
290
|
+
// S1F13: Establish Communications Request
|
|
291
|
+
if (msg.stream === 1 && msg.func === 13) {
|
|
292
|
+
console.log("[Equip] Received S1F13, replying S1F14...");
|
|
293
|
+
await equipGem.s1f14(msg, CommAck.OK);
|
|
294
|
+
}
|
|
295
|
+
// S1F17: Request ON-LINE
|
|
296
|
+
else if (msg.stream === 1 && msg.func === 17) {
|
|
297
|
+
console.log("[Equip] Received S1F17, replying S1F18...");
|
|
298
|
+
await equipGem.s1f18(msg, OnlAck.OK);
|
|
299
|
+
}
|
|
300
|
+
// S2F17: Date and Time Request
|
|
301
|
+
else if (msg.stream === 2 && msg.func === 17) {
|
|
302
|
+
console.log("[Equip] Received S2F17, replying S2F18...");
|
|
303
|
+
await equipGem.s2f18Now(msg);
|
|
304
|
+
} else {
|
|
305
|
+
console.log(
|
|
306
|
+
`[Equip] Received unhandled message S${msg.stream}F${msg.func}`,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.error("[Equip] Error handling message:", err);
|
|
311
|
+
}
|
|
312
|
+
})();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
await equipComm.open();
|
|
316
|
+
console.log("Passive opened and listening");
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## SECS-I Serial
|
|
320
|
+
|
|
321
|
+
Supports SECS-I communication via serial port.
|
|
322
|
+
|
|
323
|
+
**Note**:
|
|
324
|
+
|
|
325
|
+
- Serial port communication needs to be tested on devices that support the SECS-I protocol.
|
|
326
|
+
- Ensure the serial port path and baud rate match your device configuration.
|
|
327
|
+
- If you want to test locally first, we recommend using a **virtual serial port tool** to simulate serial port communication.
|
|
328
|
+
|
|
329
|
+
### Active
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
import { A, L, Secs1SerialCommunicator, SecsMessage } from "secs4js";
|
|
333
|
+
|
|
334
|
+
async function SerialActive() {
|
|
335
|
+
const active = new Secs1SerialCommunicator({
|
|
336
|
+
path: "COM5", // Serial port path
|
|
337
|
+
baudRate: 9600, // Baud rate
|
|
338
|
+
deviceId: 10,
|
|
339
|
+
isEquip: false, // Whether it is equipment
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
active.on("message", (msg: SecsMessage) => {
|
|
343
|
+
void (async () => {
|
|
344
|
+
console.log(`Active received: ${msg.toSml()}`);
|
|
345
|
+
if (msg.stream === 1 && msg.func === 1) {
|
|
346
|
+
await active.reply(msg, 1, 2, L(A("MDLN-A"), A("SOFTREV-1")));
|
|
347
|
+
}
|
|
348
|
+
})();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
active.on("connected", () => {
|
|
352
|
+
console.log("Active connected");
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
await active.open();
|
|
356
|
+
console.log("Active opened");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
SerialActive().catch((err) => console.error(err));
|
|
360
|
+
|
|
361
|
+
// Communication results with the simulator
|
|
362
|
+
// Our reply message:
|
|
363
|
+
// 2025-12-30 01:35:40.187:onReceivedEvent[SERIAL_EQP] DeviceID=[10] SB=[5985]
|
|
364
|
+
// S1F2
|
|
365
|
+
// <L[2/1]
|
|
366
|
+
// <A[6/1] "MDLN-A">
|
|
367
|
+
// <A[9/1] "SOFTREV-1">
|
|
368
|
+
// >.
|
|
369
|
+
|
|
370
|
+
// Message actively sent by the simulator:
|
|
371
|
+
// 2025-12-30 01:35:40.155:OnSent[SERIAL_EQP] DeviceID=[1] SB=[5985]
|
|
372
|
+
|
|
373
|
+
// S1F1 W.
|
|
374
|
+
// 2025-12-30 01:35:40.095:Send the Message successfully.
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Passive
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
import { Secs1SerialCommunicator, SecsMessage, L, A } from "secs4js";
|
|
381
|
+
|
|
382
|
+
async function SerialPassive() {
|
|
383
|
+
const passive = new Secs1SerialCommunicator({
|
|
384
|
+
path: "COM5",
|
|
385
|
+
baudRate: 9600,
|
|
386
|
+
deviceId: 10,
|
|
387
|
+
isEquip: true,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
passive.on("message", (msg: SecsMessage) => {
|
|
391
|
+
void (async () => {
|
|
392
|
+
if (msg.stream === 1 && msg.func === 1) {
|
|
393
|
+
await passive.reply(msg, 1, 2, L(A("MDLN-A"), A("SOFTREV-1")));
|
|
394
|
+
}
|
|
395
|
+
console.log(`Passive received: ${msg.toSml()}`);
|
|
396
|
+
})();
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
await passive.open();
|
|
400
|
+
console.log("Passive opened");
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
SerialPassive().catch((err) => console.error(err));
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## SECS-I On TCP/IP
|
|
407
|
+
|
|
408
|
+
Supports SECS-I serial communication via TCP/IP (usually used for testing or connecting through a terminal server).
|
|
409
|
+
|
|
410
|
+
### Active
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import { Secs1OnTcpIpActiveCommunicator, SecsMessage, L, A } from "secs4js";
|
|
414
|
+
|
|
415
|
+
async function TcpActive() {
|
|
416
|
+
const active = new Secs1OnTcpIpActiveCommunicator({
|
|
417
|
+
ip: "127.0.0.1",
|
|
418
|
+
port: 5000,
|
|
419
|
+
deviceId: 10,
|
|
420
|
+
isEquip: false,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
active.on("message", (msg: SecsMessage) => {
|
|
424
|
+
void (async () => {
|
|
425
|
+
console.log(`Active received: ${msg.toSml()}`);
|
|
426
|
+
// Handle message...
|
|
427
|
+
})();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
active.on("connected", () => {
|
|
431
|
+
console.log("Active connected");
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
await active.open();
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Passive
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
import { Secs1OnTcpIpPassiveCommunicator, SecsMessage, L, A } from "secs4js";
|
|
442
|
+
|
|
443
|
+
async function TcpPassive() {
|
|
444
|
+
const passive = new Secs1OnTcpIpPassiveCommunicator({
|
|
445
|
+
ip: "0.0.0.0",
|
|
446
|
+
port: 5000,
|
|
447
|
+
deviceId: 10,
|
|
448
|
+
isEquip: true,
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
passive.on("message", (msg: SecsMessage) => {
|
|
452
|
+
void (async () => {
|
|
453
|
+
console.log(`Passive received: ${msg.toSml()}`);
|
|
454
|
+
// Process message and reply...
|
|
455
|
+
})();
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
await passive.open();
|
|
459
|
+
console.log("Passive server started");
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## GEM
|
|
464
|
+
|
|
465
|
+
This library provides partial `GEM` (Generic Equipment Model) support. You can access commonly used GEM methods through the `Gem` object.
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
// 1. Set up equipment side (Passive)
|
|
469
|
+
const equipComm = new HsmsPassiveCommunicator({
|
|
470
|
+
ip: "127.0.0.1",
|
|
471
|
+
port: 5000,
|
|
472
|
+
deviceId: 1,
|
|
473
|
+
isEquip: true,
|
|
474
|
+
name: "Equipment",
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// Use the GEM helper class (optional)
|
|
478
|
+
const equipGem = new Gem(equipComm);
|
|
479
|
+
equipGem.mdln = "MyEquip";
|
|
480
|
+
equipGem.softrev = "1.0.0";
|
|
481
|
+
|
|
482
|
+
equipComm.on("message", (msg: SecsMessage) => {
|
|
483
|
+
void (async () => {
|
|
484
|
+
console.log(`Passive received: ${msg.toSml()}`);
|
|
485
|
+
|
|
486
|
+
// Reply to Host using messages defined in the Generic Equipment Model
|
|
487
|
+
if (msg.stream === 1 && msg.func === 1) {
|
|
488
|
+
await equipGem.s1f2(msg);
|
|
489
|
+
}
|
|
490
|
+
})();
|
|
491
|
+
});
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
## Logging
|
|
495
|
+
|
|
496
|
+
Logging is implemented using the `Pino` library.
|
|
497
|
+
|
|
498
|
+
There are two types of logs: `DETAIL` logs that record all detailed information, and SECS-II `SML` logs that only record bidirectional communication. The default level for DETAIL logs is `DEBUG`, and the default level for SECS-II logs is `INFO`.
|
|
499
|
+
|
|
500
|
+
You can configure logging properties by passing the `log` configuration parameter when initializing the communicator.
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
const active = new HsmsActiveCommunicator({
|
|
504
|
+
ip: "127.0.0.1",
|
|
505
|
+
port: 5000,
|
|
506
|
+
deviceId: 10,
|
|
507
|
+
isEquip: false,
|
|
508
|
+
log: {
|
|
509
|
+
enabled: true, // Whether to enable logging
|
|
510
|
+
console: true, // Whether to output logs to console
|
|
511
|
+
baseDir: "./secs4js-logs", // Path for log storage
|
|
512
|
+
retentionDays: 30, // Number of days to retain logs
|
|
513
|
+
detailLevel: "trace", // Level for DETAIL logs
|
|
514
|
+
secs2Level: "info", // Level for SECS-II logs
|
|
515
|
+
maxHexBytes: 65536, // Maximum number of hex bytes to record
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
## Development
|
|
521
|
+
|
|
522
|
+
If you are interested in this project, welcome to contribute your code!
|
|
523
|
+
|
|
524
|
+
Thank you for your contribution! 💖
|
|
525
|
+
|
|
526
|
+
> 💝 This project was generated using [`create-typescript-app`](https://github.com/JoshuaKGoldberg/create-typescript-app) and the [Bingo framework](https://create.bingo).
|