@zimo-elektronik/zcan 1.0.51 → 1.0.53

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.
Files changed (42) hide show
  1. package/.prettierrc.json +3 -1
  2. package/__tests__/accessoriesGroup.test.ts +26 -26
  3. package/__tests__/connection.test.ts +52 -52
  4. package/__tests__/dataGroup.test.ts +82 -92
  5. package/__tests__/infoGroup.test.ts +18 -18
  6. package/__tests__/lanDataGroup.test.ts +54 -66
  7. package/__tests__/lanInfoGroup.test.ts +34 -34
  8. package/__tests__/lanLocoStateGroup.test.ts +17 -17
  9. package/__tests__/systemControlGroup.test.ts +36 -36
  10. package/__tests__/trackCfgGroup.test.ts +38 -38
  11. package/__tests__/vehicleGroup.test.ts +109 -110
  12. package/dist/common/enums.d.ts +4 -4
  13. package/dist/common/enums.js +12 -12
  14. package/dist/common/enums.js.map +1 -1
  15. package/dist/common/models.d.ts +2 -18
  16. package/dist/data/lanDataGroup.d.ts +0 -2
  17. package/dist/data/lanDataGroup.js +0 -30
  18. package/dist/data/lanDataGroup.js.map +1 -1
  19. package/dist/data/lanDataMsg.d.ts +1 -0
  20. package/dist/data/lanDataMsg.js +20 -0
  21. package/dist/data/lanDataMsg.js.map +1 -1
  22. package/dist/info/infoGroup.d.ts +0 -4
  23. package/dist/info/infoGroup.js +1 -28
  24. package/dist/info/infoGroup.js.map +1 -1
  25. package/dist/info/infoMsg.d.ts +4 -0
  26. package/dist/info/infoMsg.js +12 -0
  27. package/dist/info/infoMsg.js.map +1 -1
  28. package/dist/loco/vehicleGroup.d.ts +7 -5
  29. package/dist/loco/vehicleGroup.js +41 -18
  30. package/dist/loco/vehicleGroup.js.map +1 -1
  31. package/dist/loco/vehicleMsg.d.ts +14 -1
  32. package/dist/loco/vehicleMsg.js +20 -0
  33. package/dist/loco/vehicleMsg.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/common/enums.ts +4 -4
  36. package/src/common/models.ts +14 -18
  37. package/src/data/lanDataGroup.ts +3 -92
  38. package/src/data/lanDataMsg.ts +23 -79
  39. package/src/info/infoGroup.ts +21 -33
  40. package/src/info/infoMsg.ts +20 -0
  41. package/src/loco/vehicleGroup.ts +62 -24
  42. package/src/loco/vehicleMsg.ts +27 -1
@@ -1,8 +1,8 @@
1
1
  // 0x17
2
2
  import MX10 from '../MX10';
3
- import {FunctionMode, FxConfigType, getOperatingMode, MsgMode, OperatingMode} from '../common/enums';
4
- import {DataNameExtendedData, DataValueExtendedData, LocoGuiMXExtended, LocoSpeedTabExtended, SpeedTabData,
5
- Train, TrainFlags, TrainFunction} from '../common/models';
3
+ import {FxConfigType, getOperatingMode, MsgMode} from '../common/enums';
4
+ import {DataNameExtendedData, DataValueExtendedData, LocoSpeedTabExtended, SpeedTabData,
5
+ Train, TrainFlags} from '../common/models';
6
6
  import {Subject} from 'rxjs';
7
7
  import {parseSpeed} from '../common/speedUtils';
8
8
  import ExtendedASCII from '../common/extendedAscii';
@@ -17,13 +17,11 @@ import { MsgLocoGuiReq, MsgLocoGuiRsp } from './lanDataMsg';
17
17
  export default class LanDataGroup
18
18
  {
19
19
  public readonly onLocoGuiExtended = new Subject<MsgLocoGuiRsp>();
20
- // public readonly onOldLocoGuiExtended = new Subject<MsgOldLocoGuiRsp>();
21
20
  public readonly onDataValueExtended = new Subject<DataValueExtendedData>();
22
21
  public readonly onDataNameExtended = new Subject<DataNameExtendedData>();
23
22
  public readonly onLocoSpeedTabExtended = new Subject<LocoSpeedTabExtended>();
24
23
 
25
24
  private locoGuiQ: Query<MsgLocoGuiRsp> | undefined = undefined;
26
- // private oldLocoGuiQ: Query<MsgOldLocoGuiRsp> | undefined = undefined;
27
25
 
28
26
  private mx10: MX10;
29
27
 
@@ -140,50 +138,6 @@ export default class LanDataGroup
140
138
  return rv;
141
139
  }
142
140
 
143
- // async oldLocoGuiExtended(nid: number): Promise<MsgOldLocoGuiRsp | undefined>
144
- // {
145
- // if(this.oldLocoGuiQ !== undefined && !await this.oldLocoGuiQ.lock()) {
146
- // this.mx10.logInfo.next("mx10.locoGuiExtended: failed to acquire lock");
147
- // return undefined;
148
- // }
149
- // this.oldLocoGuiQ = new Query(MsgOldLocoGuiReq.header(MsgMode.REQ, this.mx10.mx10NID), this.onOldLocoGuiExtended);
150
- // this.oldLocoGuiQ.log = ((msg) => {
151
- // this.mx10.logInfo.next(msg);
152
- // });
153
- // this.oldLocoGuiQ.tx = ((header) => {
154
- // const msg = new MsgOldLocoGuiReq(header, nid, 0);
155
- // this.mx10.logInfo.next('locoGuiExtended query tx: ' + JSON.stringify(msg));
156
- // this.mx10.sendMsg(msg);
157
- // });
158
- // this.oldLocoGuiQ.match = ((msg) => {
159
- // this.mx10.logInfo.next('locoGuiExtended query rx: ' + JSON.stringify(msg));
160
- // return (msg.locoNid() === nid);
161
- // })
162
- // const rv = await this.oldLocoGuiQ.run();
163
- // this.mx10.logInfo.next("mx10.locoGuiExtended.rv: " + JSON.stringify(rv));
164
- // this.oldLocoGuiQ.unlock();
165
- // this.oldLocoGuiQ = undefined;
166
- // return rv;
167
- // }
168
-
169
- // locoGuiExtended(NID: number)
170
- // {
171
- // this.mx10.sendData(0x17, 0x27, [
172
- // {value: this.mx10.mx10NID, length: 2},
173
- // {value: NID, length: 2},
174
- // {value: 0, length: 2},
175
- // ], 0b00);
176
- // }
177
-
178
- // locoGuiMXExtended(NID: number)
179
- // {
180
- // this.mx10.sendData(0x17,0x28, [
181
- // {value: this.mx10.mx10NID, length: 2},
182
- // {value: NID, length: 2},
183
- // {value: 0, length: 2},
184
- // ], 0b00);
185
- // }
186
-
187
141
  locoSpeedTapExtended(NID: number)
188
142
  {
189
143
  this.mx10.sendData(0x17, 0x19, [
@@ -194,11 +148,6 @@ export default class LanDataGroup
194
148
  ], 0b00);
195
149
  }
196
150
 
197
- // mxUpdateFnIcons(destructuredBuffer: ZcanDataArray)
198
- // {
199
- // this.mx10.sendData(0x17, 0x28, destructuredBuffer, 0b01);
200
- // }
201
-
202
151
  parse(size: number, command: number, mode: number, nid: number, buffer: Buffer)
203
152
  {
204
153
  switch (command)
@@ -209,9 +158,6 @@ export default class LanDataGroup
209
158
  case 0x10:
210
159
  this.parseDataNameExtended(size, mode, nid, buffer);
211
160
  break;
212
- // case 0x27:
213
- // this.parseOldLocoGuiExtended(size, mode, nid, buffer);
214
- // break;
215
161
  case 0x28:
216
162
  this.parseLocoGuiExtended(size, mode, nid, buffer);
217
163
  break;
@@ -360,29 +306,6 @@ export default class LanDataGroup
360
306
  this.onLocoSpeedTabExtended.next({srcid: SrcID, nid: NID, dbat6: DBat6, speedTab: locoSpeedTab});
361
307
  }
362
308
 
363
- private parseEra(eraString: number)
364
- {
365
- switch (eraString & 0xf0)
366
- {
367
- case 0x10:
368
- return 'I';
369
- case 0x20:
370
- return 'II';
371
- case 0x30:
372
- return 'III';
373
- case 0x40:
374
- return 'IV';
375
- case 0x50:
376
- return 'V';
377
- case 0x60:
378
- return 'VI';
379
- case 0x70:
380
- return 'VII';
381
- default:
382
- return '';
383
- }
384
- }
385
-
386
309
  private parseFlags(flagsNumber: number): TrainFlags
387
310
  {
388
311
  return {deleted: flagsNumber >> 31 === 1};
@@ -392,16 +315,4 @@ export default class LanDataGroup
392
315
  {
393
316
  return parseDeletedFlag === 1;
394
317
  }
395
-
396
- private destructureBuffer(buffer: Buffer): ZcanDataArray
397
- {
398
- const values = [];
399
- for (let i = 0; i < buffer.length; i += 2) {
400
- values.push({
401
- value: buffer.readUInt16LE(i),
402
- length: 2,
403
- });
404
- }
405
- return values;
406
- }
407
318
  }
@@ -3,73 +3,6 @@ import { Header, Message } from "../common/communication";
3
3
  import { TrainFunction } from "../docs_entrypoint";
4
4
 
5
5
 
6
- // export class MsgOldLocoGuiReq extends Message
7
- // {
8
- // public static header(mode: MsgMode, nid: number): Header
9
- // {return {group: 0x17, cmd: 0x27, mode: mode, nid: nid}}
10
-
11
- // constructor(header: Header, locoNid: number, subNid: number)
12
- // {
13
- // super(header);
14
- // super.push({value: locoNid, length: 2});
15
- // super.push({value: subNid, length: 2});
16
- // }
17
- // locoNid(): number {return (this.data[0].value as number)}
18
- // subNid(): number {return (this.data[1].value as number)}
19
- // }
20
-
21
- // export class MsgOldLocoGuiRsp extends Message
22
- // {
23
- // public static header(mode: MsgMode, nid: number): Header
24
- // {return {group: 0x17, cmd: 0x27, mode: mode, nid: nid}}
25
-
26
- // constructor(header: Header, locoNid: number, subNid: number, group: number, name: string, imageId: number,
27
- // tacho: number, speedFwd: number, speedRev: number, speedRange: number, driveType: number, era: number,
28
- // country: number, functions: number[])
29
- // {
30
- // super(header);
31
- // super.push({value: locoNid, length: 2});
32
- // super.push({value: subNid, length: 2});
33
- // super.push({value: group, length: 2});
34
- // super.push({value: name, length: 32});
35
- // super.push({value: imageId, length: 2});
36
- // super.push({value: tacho, length: 2});
37
- // super.push({value: speedFwd, length: 2});
38
- // super.push({value: speedRev, length: 2});
39
- // super.push({value: speedRange, length: 2});
40
- // super.push({value: driveType, length: 2});
41
- // super.push({value: era, length: 2});
42
- // super.push({value: country, length: 2});
43
- // functions.forEach(funk => {
44
- // super.push({value: funk, length: 2});
45
- // });
46
- // }
47
- // locoNid(): number {return (this.data[0].value as number)}
48
- // subNid(): number {return (this.data[1].value as number)}
49
- // group(): number {return (this.data[2].value as number)}
50
- // name(): string {return (this.data[3].value as string)}
51
- // imageId(): number {return (this.data[4].value as number)}
52
- // tacho(): number {return (this.data[5].value as number)}
53
- // speedFwd(): number {return (this.data[6].value as number)}
54
- // speedRev(): number {return (this.data[7].value as number)}
55
- // speedRange(): number {return (this.data[8].value as number)}
56
- // driveType(): number {return (this.data[9].value as number)}
57
- // era(): number {return (this.data[10].value as number)}
58
- // country(): number {return (this.data[11].value as number)}
59
- // functions(): Array<TrainFunction>
60
- // {
61
- // const rv = Array<TrainFunction>();
62
- // for (let i = 12; i < this.data.length; i++) {
63
- // const icon = (this.data[i].value as number);
64
- // const iconString = icon === 0 ? String(i).padStart(2, '0') : String(icon);
65
- // rv.push({mode: FunctionMode.switch, active: false,
66
- // icon: iconString.padStart(4, icon === 0 ? '07' : '0'),
67
- // });
68
- // }
69
- // return rv;
70
- // }
71
- // }
72
-
73
6
  export class MsgLocoGuiReq extends Message
74
7
  {
75
8
  public static header(mode: MsgMode, nid: number): Header
@@ -146,16 +79,27 @@ export class MsgLocoGuiRsp extends Message
146
79
  }
147
80
  return rv;
148
81
  }
149
- // funModes(): Array<TrainFunction>
150
- // {
151
- // const rv = Array<TrainFunction>();
152
- // for (let i = 12; i < this.data.length; i++) {
153
- // const icon = (this.data[i].value as number);
154
- // const iconString = icon === 0 ? String(i).padStart(2, '0') : String(icon);
155
- // rv.push({mode: FunctionMode.switch, active: false,
156
- // icon: iconString.padStart(4, icon === 0 ? '07' : '0'),
157
- // });
158
- // }
159
- // return rv;
160
- // }
82
+
83
+ public static parseEra(era: number)
84
+ {
85
+ switch (era & 0xf0)
86
+ {
87
+ case 0x10:
88
+ return 'I';
89
+ case 0x20:
90
+ return 'II';
91
+ case 0x30:
92
+ return 'III';
93
+ case 0x40:
94
+ return 'IV';
95
+ case 0x50:
96
+ return 'V';
97
+ case 0x60:
98
+ return 'VI';
99
+ case 0x70:
100
+ return 'VII';
101
+ default:
102
+ return '';
103
+ }
104
+ }
161
105
  }
@@ -2,8 +2,7 @@ import {Buffer} from 'buffer';
2
2
  import MX10 from '../MX10';
3
3
  import {Subject} from 'rxjs';
4
4
  import {Query} from '../common/communication';
5
- import {BidiInfoData, BidiDirectionData} from '../common/models';
6
- import {BidiType, Direction, ForwardOrReverse, ModInfoType, MsgMode} from '../common/enums';
5
+ import {ModInfoType, MsgMode} from '../common/enums';
7
6
  import {MsgBidiInfo, MsgModInfo} from './infoMsg';
8
7
 
9
8
  /**
@@ -111,41 +110,30 @@ export default class InfoGroup
111
110
  const type = buffer.readUInt16LE(2);
112
111
  const info = buffer.readUInt32LE(4);
113
112
 
114
- let data: BidiDirectionData | number = {};
115
- switch (type) {
116
- case BidiType.DIRECTION:
117
- data.direction = this.parseEastWest(info);
118
- data.directionChange = this.parseDirChange(info);
119
- data.directionConfirm = this.parseDirectionConfirm(info);
120
- data.forwardOrReverse = this.parseFwdRev(info);
121
- break;
122
- default:
123
- data = info;
124
- }
125
113
  const msg = new MsgBidiInfo(MsgBidiInfo.header(mode, NID), type, undefined, info);
126
114
  this.onBidiInfoChange.next(msg);
127
115
  }
128
116
 
129
- private parseEastWest(data: number)
130
- {
131
- if ((data & 0x02) == 0x02)
132
- return Direction.EAST;
133
- return Direction.WEST;
134
- }
117
+ // private parseEastWest(data: number)
118
+ // {
119
+ // if ((data & 0x02) == 0x02)
120
+ // return Direction.EAST;
121
+ // return Direction.WEST;
122
+ // }
135
123
 
136
- private parseDirChange(data: number)
137
- {
138
- return (data & 0x04) == 0x04;
139
- }
124
+ // private parseDirChange(data: number)
125
+ // {
126
+ // return (data & 0x04) == 0x04;
127
+ // }
140
128
 
141
- private parseFwdRev(data: number)
142
- {
143
- if ((data & 0x01) == 0)
144
- return ForwardOrReverse.REVERSE;
145
- return ForwardOrReverse.FORWARD;
146
- }
147
- private parseDirectionConfirm(data: number)
148
- {
149
- return (data & 0x08) == 0x08;
150
- }
129
+ // private parseFwdRev(data: number)
130
+ // {
131
+ // if ((data & 0x01) == 0)
132
+ // return ForwardOrReverse.REVERSE;
133
+ // return ForwardOrReverse.FORWARD;
134
+ // }
135
+ // private parseDirectionConfirm(data: number)
136
+ // {
137
+ // return (data & 0x08) == 0x08;
138
+ // }
151
139
  }
@@ -40,4 +40,24 @@ export class MsgBidiInfo extends Message
40
40
  nid(): number {return this.header.mode === MsgMode.REQ ? this.data[0].value as number : this.header.nid || 0}
41
41
  type(): number {return this.data[this.header.mode === MsgMode.REQ ? 1 : 0].value as number}
42
42
  info(): number | undefined {return this.data.length > 1 ? this.data[1].value as number : undefined}
43
+
44
+ public static dirEast(info: number)
45
+ {
46
+ return ((info & 0x02) == 0x02)
47
+ }
48
+
49
+ public static dirChanging(info: number)
50
+ {
51
+ return ((info & 0x04) == 0x04)
52
+ }
53
+
54
+ public static dirForward(info: number)
55
+ {
56
+ return ((info & 0x01) == 0x01)
57
+ }
58
+
59
+ public static dirConfirm(info: number)
60
+ {
61
+ return ((info & 0x08) == 0x08)
62
+ }
43
63
  }
@@ -1,12 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import MX10 from '../MX10';
3
3
  import {Subject} from 'rxjs';
4
- import {CallFunctionData, CallSpecialFunctionData, VehicleStateData} from '../common/models';
5
- import {Direction, Manual, MaxSpeedSteps, MsgMode, OperatingMode, ShuntingFunction, SpecialFunctionMode,
6
- } from '../common/enums';
4
+ import {CallFunctionData} from '../common/models';
5
+ import {Direction, Manual, MaxSpeedSteps, MsgMode, OperatingMode, SpecialFxNr} from '../common/enums';
7
6
  import {combineSpeedAndDirection} from '../common/speedUtils';
8
7
  import { Query } from '../common/communication';
9
- import { MsgVehicleLastCtl, MsgVehicleMode, MsgVehicleSpeed, MsgVehicleState } from './vehicleMsg';
8
+ import { MsgSpecialFx, MsgVehicleLastCtl, MsgVehicleMode, MsgVehicleSpeed, MsgVehicleState } from './vehicleMsg';
10
9
 
11
10
  /**
12
11
  *
@@ -17,14 +16,15 @@ export default class VehicleGroup
17
16
  public readonly onVehicleState = new Subject<MsgVehicleState>();
18
17
  public readonly onVehicleLastCtl = new Subject<MsgVehicleLastCtl>();
19
18
  public readonly onVehicleMode = new Subject<MsgVehicleMode>();
20
- public readonly onVehicleSpeed = new Subject<MsgVehicleSpeed>(); // VehicleSpeedData
19
+ public readonly onVehicleSpeed = new Subject<MsgVehicleSpeed>();
21
20
  public readonly onCallFunction = new Subject<CallFunctionData>();
22
- public readonly onCallSpecialFunction = new Subject<CallSpecialFunctionData>();
21
+ public readonly onCallSpecialFunction = new Subject<MsgSpecialFx>();
23
22
 
24
23
  private stateQ: Query<MsgVehicleState> | undefined = undefined;
25
24
  private lastCtlQ: Query<MsgVehicleLastCtl> | undefined = undefined;
26
25
  private modeQ: Query<MsgVehicleMode> | undefined = undefined;
27
26
  private speedQ: Query<MsgVehicleSpeed> | undefined = undefined;
27
+ private sfxQ: Query<MsgSpecialFx> | undefined = undefined;
28
28
 
29
29
  private mx10: MX10;
30
30
 
@@ -199,15 +199,61 @@ export default class VehicleGroup
199
199
  ]);
200
200
  }
201
201
 
202
- changeSpecialFunction(vehicleAddress: number, specialFunctionMode: SpecialFunctionMode,
203
- specialFunctionStatus: Manual | ShuntingFunction | Direction) {
204
- this.mx10.sendData(0x02, 0x05, [
205
- {value: vehicleAddress, length: 2},
206
- {value: specialFunctionMode, length: 2},
207
- {value: specialFunctionStatus, length: 2},
208
- ]);
202
+ async getSpecialFx(nid: number, sfxNr: SpecialFxNr)
203
+ {
204
+ if(this.sfxQ !== undefined && !await this.sfxQ.lock()) {
205
+ this.mx10.logInfo.next("mx10.getSpecialFx: failed to acquire lock");
206
+ return undefined;
207
+ }
208
+ this.sfxQ = new Query(MsgSpecialFx.header(MsgMode.REQ, nid), this.onCallSpecialFunction);
209
+ this.sfxQ.tx = ((header) => {
210
+ const msg = new MsgSpecialFx(header, sfxNr);
211
+ // this.mx10.logInfo.next('sfx query tx: ' + JSON.stringify(msg));
212
+ this.mx10.sendMsg(msg);
213
+ });
214
+ this.sfxQ.match = ((msg) => {
215
+ // this.mx10.logInfo.next('sfx query rx: ' + JSON.stringify(msg));
216
+ return (msg.nid() === nid);
217
+ })
218
+ const rv = await this.sfxQ.run();
219
+ // this.mx10.logInfo.next("mx10.getSpecialFx.rv: " + JSON.stringify(rv));
220
+ this.sfxQ.unlock();
221
+ this.sfxQ = undefined;
222
+ return rv;
209
223
  }
210
224
 
225
+ async setSpecialFx(nid: number, sfxNr: SpecialFxNr, state: number)
226
+ {
227
+ if(this.sfxQ !== undefined && !await this.sfxQ.lock()) {
228
+ this.mx10.logInfo.next("mx10.setSpecialFx: failed to acquire lock");
229
+ return undefined;
230
+ }
231
+ this.sfxQ = new Query(MsgSpecialFx.header(MsgMode.CMD, nid), this.onCallSpecialFunction);
232
+ this.sfxQ.tx = ((header) => {
233
+ const msg = new MsgSpecialFx(header, sfxNr, state);
234
+ // this.mx10.logInfo.next('sfx query tx: ' + JSON.stringify(msg));
235
+ this.mx10.sendMsg(msg);
236
+ });
237
+ this.sfxQ.match = ((msg) => {
238
+ // this.mx10.logInfo.next('sfx query rx: ' + JSON.stringify(msg));
239
+ return (msg.nid() === nid);
240
+ })
241
+ const rv = await this.sfxQ.run();
242
+ // this.mx10.logInfo.next("mx10.setSpecialFx.rv: " + JSON.stringify(rv));
243
+ this.sfxQ.unlock();
244
+ this.sfxQ = undefined;
245
+ return rv;
246
+ }
247
+
248
+ // changeSpecialFunction(vehicleAddress: number, specialFunctionMode: SpecialFunctionMode,
249
+ // specialFunctionStatus: Manual | ShuntingFunction | Direction) {
250
+ // this.mx10.sendData(0x02, 0x05, [
251
+ // {value: vehicleAddress, length: 2},
252
+ // {value: specialFunctionMode, length: 2},
253
+ // {value: specialFunctionStatus, length: 2},
254
+ // ]);
255
+ // }
256
+
211
257
  // 0x02.0x10
212
258
  activeModeTrain(vehicleAddress: number) {
213
259
  return this.mx10.sendData(0x02, 0x10, [
@@ -288,17 +334,9 @@ export default class VehicleGroup
288
334
  // 0x02.0x05
289
335
  private parseVehicleSpecialFunction(size: number, mode: number, nid: number, buffer: Buffer)
290
336
  {
291
- if (this.onCallSpecialFunction.observed) {
292
- const NID = buffer.readUInt16LE(0);
293
- const specialFunctionMode = buffer.readUInt16LE(2);
294
- const specialFunctionState = buffer.readUInt16LE(4);
295
-
296
- this.onCallSpecialFunction.next({
297
- nid: NID,
298
- specialFunctionMode,
299
- specialFunctionState,
300
- });
301
- }
337
+ if(!this.onCallSpecialFunction.observed)
338
+ return;
339
+ this.onCallSpecialFunction.next(MsgSpecialFx.fromBuffer(mode, buffer));
302
340
  }
303
341
 
304
342
  // 0x02.0x12
@@ -1,7 +1,7 @@
1
1
 
2
2
  import { Header, Message } from "../common/communication";
3
3
  import { Ranger } from "../common/utils";
4
- import { Direction, MaxSpeedSteps, MsgMode, OperatingMode } from "../common/enums";
4
+ import { Direction, MaxSpeedSteps, MsgMode, OperatingMode, SpecialFxNr } from "../common/enums";
5
5
  import { directACKBites, directionBites, eastWestBites_, emergencyStopB, speedBites____ } from "../common/bites";
6
6
 
7
7
 
@@ -162,4 +162,30 @@ export class MsgVehicleLastCtl extends Message
162
162
  const msg = new MsgVehicleLastCtl(MsgVehicleLastCtl.header(mode, nid), type, ctlNid, seconds);
163
163
  return msg;
164
164
  }
165
+ }
166
+
167
+ export class MsgSpecialFx extends Message
168
+ {
169
+ public static header = (mode: MsgMode, nid: number) => {return {group: 0x2, cmd: 0x5, mode, nid}}
170
+
171
+ constructor(header: Header, sfxNr: SpecialFxNr, state?: number)
172
+ {
173
+ super(header);
174
+ super.push({value: sfxNr || 0, length: 2});
175
+ if(header.mode === MsgMode.REQ)
176
+ return;
177
+ super.push({value: state || 0, length: 2});
178
+ }
179
+ nid(): number {return this.header.nid || 0}
180
+ sfxNr(): number {return this.data[0].value as number;}
181
+ state(): number | undefined {return this.data.length < 2 ? undefined : this.data[1].value as number;}
182
+
183
+ public static fromBuffer(mode: MsgMode, buffer: Buffer)
184
+ {
185
+ const nid = buffer.readUInt16LE(0);
186
+ const sfxNr = buffer.readUInt16LE(2);
187
+ const state = buffer.readUint16LE(4);
188
+ const msg = new MsgSpecialFx(MsgVehicleState.header(mode, nid), sfxNr, state);
189
+ return msg;
190
+ }
165
191
  }