sportident.js 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dependency-cruiser.js +233 -0
- package/.editorconfig +12 -0
- package/.eslintignore +6 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/.github/workflows/npm.yml +17 -0
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/babel.config.js +21 -0
- package/build-docs.sh +25 -0
- package/docs/index.md +9 -0
- package/docs/typedoc/index.md +11 -0
- package/eslint.base.js +232 -0
- package/install.sh +6 -0
- package/jest.config.ts +49 -0
- package/nx.json +39 -0
- package/package.json +51 -0
- package/src/SiCard/BaseSiCard.test.ts +187 -0
- package/src/SiCard/BaseSiCard.ts +101 -0
- package/src/SiCard/IRaceResultData.ts +16 -0
- package/src/SiCard/ISiCard.ts +23 -0
- package/src/SiCard/ISiCardExamples.ts +4 -0
- package/src/SiCard/index.ts +2 -0
- package/src/SiCard/raceResultTools.test.ts +260 -0
- package/src/SiCard/raceResultTools.ts +150 -0
- package/src/SiCard/types/FCard.test.ts +19 -0
- package/src/SiCard/types/FCard.ts +14 -0
- package/src/SiCard/types/ModernSiCard.test.ts +186 -0
- package/src/SiCard/types/ModernSiCard.ts +241 -0
- package/src/SiCard/types/PCard.test.ts +19 -0
- package/src/SiCard/types/PCard.ts +14 -0
- package/src/SiCard/types/SIAC.test.ts +84 -0
- package/src/SiCard/types/SIAC.ts +19 -0
- package/src/SiCard/types/SiCard10.test.ts +85 -0
- package/src/SiCard/types/SiCard10.ts +17 -0
- package/src/SiCard/types/SiCard11.test.ts +84 -0
- package/src/SiCard/types/SiCard11.ts +19 -0
- package/src/SiCard/types/SiCard5.test.ts +149 -0
- package/src/SiCard/types/SiCard5.ts +129 -0
- package/src/SiCard/types/SiCard6.test.ts +179 -0
- package/src/SiCard/types/SiCard6.ts +222 -0
- package/src/SiCard/types/SiCard8.test.ts +137 -0
- package/src/SiCard/types/SiCard8.ts +129 -0
- package/src/SiCard/types/SiCard9.test.ts +132 -0
- package/src/SiCard/types/SiCard9.ts +128 -0
- package/src/SiCard/types/TCard.test.ts +19 -0
- package/src/SiCard/types/TCard.ts +14 -0
- package/src/SiCard/types/index.test.ts +26 -0
- package/src/SiCard/types/index.ts +15 -0
- package/src/SiCard/types/modernSiCardExamples.ts +364 -0
- package/src/SiCard/types/siCard5Examples.ts +73 -0
- package/src/SiCard/types/siCard6Examples.ts +262 -0
- package/src/SiCard/types/siCard8Examples.ts +152 -0
- package/src/SiCard/types/siCard9Examples.ts +143 -0
- package/src/SiDevice/INavigatorWebSerial.ts +78 -0
- package/src/SiDevice/INavigatorWebUsb.ts +62 -0
- package/src/SiDevice/ISiDevice.ts +48 -0
- package/src/SiDevice/ISiDeviceDriver.ts +35 -0
- package/src/SiDevice/README.md +13 -0
- package/src/SiDevice/SiDevice.test.ts +354 -0
- package/src/SiDevice/SiDevice.ts +132 -0
- package/src/SiDevice/WebSerialSiDeviceDriver.ts +146 -0
- package/src/SiDevice/WebUsbSiDeviceDriver.ts +343 -0
- package/src/SiDevice/index.ts +3 -0
- package/src/SiDevice/testUtils/index.ts +2 -0
- package/src/SiDevice/testUtils/testISiDeviceDriver.ts +63 -0
- package/src/SiDevice/testUtils/testISiDeviceDriverWithAutodetection.ts +72 -0
- package/src/SiStation/BaseSiStation.test.ts +221 -0
- package/src/SiStation/BaseSiStation.ts +253 -0
- package/src/SiStation/CoupledSiStation.test.ts +41 -0
- package/src/SiStation/CoupledSiStation.ts +130 -0
- package/src/SiStation/ISiMainStation.ts +29 -0
- package/src/SiStation/ISiSendTask.ts +9 -0
- package/src/SiStation/ISiStation.ts +88 -0
- package/src/SiStation/ISiTargetMultiplexer.ts +51 -0
- package/src/SiStation/SiMainStation.test.ts +222 -0
- package/src/SiStation/SiMainStation.ts +133 -0
- package/src/SiStation/SiSendTask.ts +50 -0
- package/src/SiStation/SiTargetMultiplexer.targeting.test.ts +112 -0
- package/src/SiStation/SiTargetMultiplexer.test.ts +605 -0
- package/src/SiStation/SiTargetMultiplexer.ts +241 -0
- package/src/SiStation/index.ts +5 -0
- package/src/SiStation/siStationExamples.ts +103 -0
- package/src/constants.test.ts +17 -0
- package/src/constants.ts +92 -0
- package/src/fakes/FakeSiCard/BaseFakeSiCard.test.ts +11 -0
- package/src/fakes/FakeSiCard/BaseFakeSiCard.ts +10 -0
- package/src/fakes/FakeSiCard/IFakeSiCard.ts +6 -0
- package/src/fakes/FakeSiCard/index.ts +2 -0
- package/src/fakes/FakeSiCard/types/FakeModernSiCard.test.ts +62 -0
- package/src/fakes/FakeSiCard/types/FakeModernSiCard.ts +43 -0
- package/src/fakes/FakeSiCard/types/FakeSIAC.ts +17 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard10.ts +17 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard11.ts +17 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard5.test.ts +42 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard5.ts +40 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard6.test.ts +62 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard6.ts +44 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard8.ts +16 -0
- package/src/fakes/FakeSiCard/types/FakeSiCard9.ts +16 -0
- package/src/fakes/FakeSiCard/types/index.ts +7 -0
- package/src/fakes/FakeSiDeviceDriver.ts +148 -0
- package/src/fakes/FakeSiMainStation.test.ts +141 -0
- package/src/fakes/FakeSiMainStation.ts +118 -0
- package/src/fakes/IFakeSiMainStation.ts +15 -0
- package/src/fakes/index.ts +2 -0
- package/src/index.ts +24 -0
- package/src/siProtocol.test.ts +509 -0
- package/src/siProtocol.ts +417 -0
- package/src/storage/SiArray.test.ts +103 -0
- package/src/storage/SiArray.ts +56 -0
- package/src/storage/SiBool.test.ts +81 -0
- package/src/storage/SiBool.ts +47 -0
- package/src/storage/SiDataType.test.ts +81 -0
- package/src/storage/SiDataType.ts +60 -0
- package/src/storage/SiDict.test.ts +115 -0
- package/src/storage/SiDict.ts +60 -0
- package/src/storage/SiEnum.test.ts +77 -0
- package/src/storage/SiEnum.ts +48 -0
- package/src/storage/SiFieldValue.test.ts +58 -0
- package/src/storage/SiFieldValue.ts +23 -0
- package/src/storage/SiInt.test.ts +80 -0
- package/src/storage/SiInt.ts +84 -0
- package/src/storage/SiModified.test.ts +135 -0
- package/src/storage/SiModified.ts +59 -0
- package/src/storage/SiStorage.test.ts +51 -0
- package/src/storage/SiStorage.ts +44 -0
- package/src/storage/index.test.ts +222 -0
- package/src/storage/index.ts +12 -0
- package/src/storage/interfaces.ts +41 -0
- package/src/storage/siStringEncoding.ts +1361 -0
- package/src/testUtils.test.ts +266 -0
- package/src/testUtils.ts +75 -0
- package/src/utils/NumberRange.test.ts +66 -0
- package/src/utils/NumberRange.ts +46 -0
- package/src/utils/NumberRangeRegistry.test.ts +49 -0
- package/src/utils/NumberRangeRegistry.ts +43 -0
- package/src/utils/bytes.test.ts +126 -0
- package/src/utils/bytes.ts +69 -0
- package/src/utils/errors.test.ts +29 -0
- package/src/utils/errors.ts +20 -0
- package/src/utils/events.test.ts +112 -0
- package/src/utils/events.ts +68 -0
- package/src/utils/general.test.ts +139 -0
- package/src/utils/general.ts +69 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/mixins.test.ts +40 -0
- package/src/utils/mixins.ts +13 -0
- package/src/utils/typed.ts +3 -0
- package/tsconfig.base.json +22 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { SiTargetMultiplexerTarget } from './ISiTargetMultiplexer';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
4
|
+
export interface ISiStation<T extends SiTargetMultiplexerTarget> {
|
|
5
|
+
multiplexerTarget: T;
|
|
6
|
+
ident: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const SiStationMode = {
|
|
10
|
+
SIACSpecialFunction1: 0x01, // Source: SI Config+
|
|
11
|
+
// 7B=battery test, 7C=on, 7D=off, 7F=radio readout
|
|
12
|
+
Control: 0x02, // Source: SI Config+
|
|
13
|
+
Start: 0x03, // Source: SI Config+
|
|
14
|
+
Finish: 0x04, // Source: SI Config+
|
|
15
|
+
Readout: 0x05, // Source: SI Config+
|
|
16
|
+
Clear: 0x07, // Source: SI Config+
|
|
17
|
+
Check: 0x0a, // Source: SI Config+
|
|
18
|
+
Print: 0x0b, // Source: old SI Config
|
|
19
|
+
StartWithTimeTrigger: 0x0c, // Source: old SI Config
|
|
20
|
+
FinishWithTimeTrigger: 0x0d, // Source: old SI Config
|
|
21
|
+
SIACSpecialFunction2: 0x11, // Source: SI Config+
|
|
22
|
+
// 7C=test
|
|
23
|
+
BCControl: 0x12, // Source: old SI Config
|
|
24
|
+
BCStart: 0x13, // Source: old SI Config
|
|
25
|
+
BCFinish: 0x14, // Source: old SI Config
|
|
26
|
+
BCSlave: 0x1f, // Source: old SI Config
|
|
27
|
+
BeaconControl: 0x32, // Source: SI Config+
|
|
28
|
+
BeaconStart: 0x33, // Source: SI Config+
|
|
29
|
+
BeaconFinish: 0x34 // Source: SI Config+
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/* eslint-disable no-unused-vars,no-shadow */
|
|
33
|
+
export enum SiStationType {
|
|
34
|
+
Main = 0x00,
|
|
35
|
+
Sprint = 0x01,
|
|
36
|
+
Print = 0x02,
|
|
37
|
+
Field = 0x03,
|
|
38
|
+
Master = 0x04
|
|
39
|
+
}
|
|
40
|
+
/* eslint-enable no-unused-vars,no-shadow */
|
|
41
|
+
|
|
42
|
+
export const SiStationModel = {
|
|
43
|
+
BSF3: 0x8003,
|
|
44
|
+
BSF4: 0x8004,
|
|
45
|
+
BSF5: 0x8115,
|
|
46
|
+
BSF6: 0x8146,
|
|
47
|
+
BSF7A: 0x8117,
|
|
48
|
+
BSF7B: 0x8197,
|
|
49
|
+
BSF8A: 0x8118,
|
|
50
|
+
BSF8B: 0x8198,
|
|
51
|
+
BS7Master: 0x8187,
|
|
52
|
+
BS8Master: 0x8188,
|
|
53
|
+
BSM4: 0x8084,
|
|
54
|
+
BSM6: 0x8086,
|
|
55
|
+
BSM7: 0x9197,
|
|
56
|
+
BSM8: 0x9198,
|
|
57
|
+
BS7S: 0x9597,
|
|
58
|
+
BS7P: 0xb197,
|
|
59
|
+
BS7GSM: 0xb897,
|
|
60
|
+
BS8P: 0xb198
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
interface SiStationModelInfo {
|
|
64
|
+
description: string;
|
|
65
|
+
type: SiStationType;
|
|
66
|
+
series: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const SI_STATION_MODEL_INFO: { [model in keyof typeof SiStationModel]: SiStationModelInfo } = {
|
|
70
|
+
BSF3: { description: 'BSF3', type: SiStationType.Field, series: 3 },
|
|
71
|
+
BSF4: { description: 'BSF4', type: SiStationType.Field, series: 4 },
|
|
72
|
+
BSF5: { description: 'BSF5', type: SiStationType.Field, series: 5 },
|
|
73
|
+
BSF6: { description: 'BSF6', type: SiStationType.Field, series: 6 },
|
|
74
|
+
BSF7A: { description: 'BSF7', type: SiStationType.Field, series: 7 },
|
|
75
|
+
BSF7B: { description: 'BSF7', type: SiStationType.Field, series: 7 },
|
|
76
|
+
BSF8A: { description: 'BSF8', type: SiStationType.Field, series: 8 },
|
|
77
|
+
BSF8B: { description: 'BSF8', type: SiStationType.Field, series: 8 },
|
|
78
|
+
BS7Master: { description: 'BS7-Master', type: SiStationType.Master, series: 7 },
|
|
79
|
+
BS8Master: { description: 'BS8-Master', type: SiStationType.Master, series: 8 },
|
|
80
|
+
BSM4: { description: 'BSM4', type: SiStationType.Main, series: 4 },
|
|
81
|
+
BSM6: { description: 'BSM6', type: SiStationType.Main, series: 6 },
|
|
82
|
+
BSM7: { description: 'BSM7', type: SiStationType.Main, series: 7 },
|
|
83
|
+
BSM8: { description: 'BSM8', type: SiStationType.Main, series: 8 },
|
|
84
|
+
BS7S: { description: 'BS7-S', type: SiStationType.Sprint, series: 7 },
|
|
85
|
+
BS7P: { description: 'BS7-P', type: SiStationType.Print, series: 7 },
|
|
86
|
+
BS7GSM: { description: 'BS7-GSM', type: SiStationType.Field, series: 7 },
|
|
87
|
+
BS8P: { description: 'BS8-P', type: SiStationType.Print, series: 8 }
|
|
88
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as utils from '../utils';
|
|
2
|
+
import type * as siProtocol from '../siProtocol';
|
|
3
|
+
import type { ISiDevice, ISiDeviceDriverData } from '../SiDevice/ISiDevice';
|
|
4
|
+
import type { ISiStation } from './ISiStation';
|
|
5
|
+
import type { SiSendTask } from './SiSendTask';
|
|
6
|
+
|
|
7
|
+
export interface ISiTargetMultiplexer extends utils.IEventTarget<SiTargetMultiplexerEvents> {
|
|
8
|
+
_test: _ISiTargetMultiplexerTestData;
|
|
9
|
+
stations: { [Target in SiTargetMultiplexerTarget]?: ISiStation<Target> };
|
|
10
|
+
target: SiTargetMultiplexerTarget;
|
|
11
|
+
latestTarget: SiTargetMultiplexerTarget;
|
|
12
|
+
siDevice: ISiDevice<ISiDeviceDriverData<unknown>>;
|
|
13
|
+
sendMessage: (target: SiTargetMultiplexerTarget, message: siProtocol.SiMessage, numResponses?: number, timeoutInMiliseconds?: number) => Promise<number[][]>;
|
|
14
|
+
sendMessageToLatestTarget: (message: siProtocol.SiMessage, numResponses: number | undefined, timeoutInMiliseconds: number | undefined) => Promise<number[][]>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface _ISiTargetMultiplexerTestData {
|
|
18
|
+
latestTarget: SiTargetMultiplexerTarget;
|
|
19
|
+
sendQueue: SiSendTask[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* eslint-disable no-unused-vars,no-shadow */
|
|
23
|
+
export enum SiTargetMultiplexerTarget {
|
|
24
|
+
Unknown = 0,
|
|
25
|
+
Switching = 1,
|
|
26
|
+
Direct = 2,
|
|
27
|
+
Remote = 3
|
|
28
|
+
}
|
|
29
|
+
/* eslint-enable no-unused-vars,no-shadow */
|
|
30
|
+
|
|
31
|
+
export class SiTargetMultiplexerMessageEvent extends utils.Event<'message'> {
|
|
32
|
+
constructor(public siTargetMultiplexer: ISiTargetMultiplexer, public message: siProtocol.SiMessage) {
|
|
33
|
+
super();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class SiTargetMultiplexerDirectMessageEvent extends utils.Event<'directMessage'> {
|
|
37
|
+
constructor(public siTargetMultiplexer: ISiTargetMultiplexer, public message: siProtocol.SiMessage) {
|
|
38
|
+
super();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class SiTargetMultiplexerRemoteMessageEvent extends utils.Event<'remoteMessage'> {
|
|
42
|
+
constructor(public siTargetMultiplexer: ISiTargetMultiplexer, public message: siProtocol.SiMessage) {
|
|
43
|
+
super();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type SiTargetMultiplexerEvents = {
|
|
48
|
+
message: SiTargetMultiplexerMessageEvent;
|
|
49
|
+
directMessage: SiTargetMultiplexerDirectMessageEvent;
|
|
50
|
+
remoteMessage: SiTargetMultiplexerRemoteMessageEvent;
|
|
51
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, expect, test } from '@jest/globals';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import { proto } from '../constants';
|
|
4
|
+
import type * as siProtocol from '../siProtocol';
|
|
5
|
+
import * as testUtils from '../testUtils';
|
|
6
|
+
import type { ISiCard } from '../SiCard/ISiCard';
|
|
7
|
+
import type { ISiDevice, ISiDeviceDriverData } from '../SiDevice/ISiDevice';
|
|
8
|
+
import type { ISiDeviceDriver } from '../SiDevice/ISiDeviceDriver';
|
|
9
|
+
import { SiDevice } from '../SiDevice/SiDevice';
|
|
10
|
+
import { SiMainStationSiCardInsertedEvent, SiMainStationSiCardObservedEvent, SiMainStationSiCardRemovedEvent } from './ISiMainStation';
|
|
11
|
+
import { type ISiTargetMultiplexer, SiTargetMultiplexerMessageEvent, SiTargetMultiplexerTarget } from './ISiTargetMultiplexer';
|
|
12
|
+
import { SiTargetMultiplexer } from './SiTargetMultiplexer';
|
|
13
|
+
import { siStationStorageDefinition } from './BaseSiStation';
|
|
14
|
+
import { getBSM8Station } from './siStationExamples';
|
|
15
|
+
import { SiMainStation } from './SiMainStation';
|
|
16
|
+
import { getSiCard5Examples } from '../SiCard/types/siCard5Examples';
|
|
17
|
+
import { getSiCard6Examples } from '../SiCard/types/siCard6Examples';
|
|
18
|
+
import { FakeSiCard5 } from '../fakes/FakeSiCard/types/FakeSiCard5';
|
|
19
|
+
import { FakeSiCard6 } from '../fakes/FakeSiCard/types/FakeSiCard6';
|
|
20
|
+
|
|
21
|
+
testUtils.useFakeTimers();
|
|
22
|
+
|
|
23
|
+
function mockDriver(driver: Partial<ISiDeviceDriver<ISiDeviceDriverData<unknown>>>) {
|
|
24
|
+
return driver as unknown as ISiDeviceDriver<ISiDeviceDriverData<unknown>>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe('SiMainStation', () => {
|
|
28
|
+
test('fromSiDevice', () => {
|
|
29
|
+
const fakeSiDevice = new SiDevice('fromSiDevice', {
|
|
30
|
+
driver: mockDriver({ name: 'FakeSiDevice' })
|
|
31
|
+
});
|
|
32
|
+
const myMainStation1 = SiMainStation.fromSiDevice(fakeSiDevice);
|
|
33
|
+
expect(myMainStation1 instanceof SiMainStation).toBe(true);
|
|
34
|
+
expect(myMainStation1.ident).toBe('Direct-FakeSiDevice-fromSiDevice');
|
|
35
|
+
expect(myMainStation1.multiplexerTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
36
|
+
const myMainStation2 = SiMainStation.fromSiDevice(fakeSiDevice);
|
|
37
|
+
expect(myMainStation2).toBe(myMainStation1);
|
|
38
|
+
expect(myMainStation2.ident).toBe('Direct-FakeSiDevice-fromSiDevice');
|
|
39
|
+
expect(myMainStation2.multiplexerTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
40
|
+
});
|
|
41
|
+
test('fromSiTargetMultiplexer', () => {
|
|
42
|
+
const myTargetMultiplexer = new SiTargetMultiplexer({ ident: 'fake-ident' } as ISiDevice<ISiDeviceDriverData<unknown>>);
|
|
43
|
+
const myMainStation1 = SiMainStation.fromSiTargetMultiplexer(myTargetMultiplexer);
|
|
44
|
+
expect(myMainStation1 instanceof SiMainStation).toBe(true);
|
|
45
|
+
expect(myMainStation1.ident).toBe('Direct-fake-ident');
|
|
46
|
+
expect(myMainStation1.multiplexerTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
47
|
+
const myMainStation2 = SiMainStation.fromSiTargetMultiplexer(myTargetMultiplexer);
|
|
48
|
+
expect(myMainStation2).toBe(myMainStation1);
|
|
49
|
+
expect(myMainStation2.ident).toBe('Direct-fake-ident');
|
|
50
|
+
expect(myMainStation2.multiplexerTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('can readCards', async () => {
|
|
54
|
+
const storage = siStationStorageDefinition(getBSM8Station().storageData);
|
|
55
|
+
storage.set('mode', 'Control');
|
|
56
|
+
storage.set('code', 31);
|
|
57
|
+
storage.set('autoSend', true);
|
|
58
|
+
storage.set('handshake', false);
|
|
59
|
+
storage.set('beeps', false);
|
|
60
|
+
storage.set('flashes', false);
|
|
61
|
+
const fakeSiTargetMultiplexer = {
|
|
62
|
+
addEventListener: () => undefined,
|
|
63
|
+
sendMessage: (_target: SiTargetMultiplexerTarget, message: siProtocol.SiMessage, _numResponses: number) => {
|
|
64
|
+
if (message.mode !== undefined) {
|
|
65
|
+
throw new Error();
|
|
66
|
+
}
|
|
67
|
+
if (message.command === proto.cmd.GET_SYS_VAL) {
|
|
68
|
+
return Promise.resolve([[0x00, 0x00, 0x00, ...storage.data]]);
|
|
69
|
+
}
|
|
70
|
+
if (message.command === proto.cmd.SET_SYS_VAL) {
|
|
71
|
+
storage.splice(message.parameters[0], message.parameters.length - 1, ...message.parameters.slice(1));
|
|
72
|
+
return Promise.resolve([[0x00, 0x00, message.parameters[0]]]);
|
|
73
|
+
}
|
|
74
|
+
throw new Error();
|
|
75
|
+
}
|
|
76
|
+
} as unknown as ISiTargetMultiplexer;
|
|
77
|
+
const mySiStation = new SiMainStation(fakeSiTargetMultiplexer);
|
|
78
|
+
const cardsRead: ISiCard[] = [];
|
|
79
|
+
const cleanUpFunction = await mySiStation.readCards((card) => {
|
|
80
|
+
cardsRead.push(card);
|
|
81
|
+
});
|
|
82
|
+
await testUtils.nTimesAsync(3, () => testUtils.advanceTimersByTime(0));
|
|
83
|
+
if (cleanUpFunction === undefined) {
|
|
84
|
+
throw new Error('expect cleanUp function');
|
|
85
|
+
}
|
|
86
|
+
expect(storage.get('mode')!.value).toBe('Readout');
|
|
87
|
+
expect(storage.get('code')!.value).toBe(10);
|
|
88
|
+
expect(storage.get('autoSend')!.value).toBe(false);
|
|
89
|
+
expect(storage.get('handshake')!.value).toBe(true);
|
|
90
|
+
expect(storage.get('beeps')!.value).toBe(true);
|
|
91
|
+
expect(storage.get('flashes')!.value).toBe(true);
|
|
92
|
+
|
|
93
|
+
const fakeSiCard = {
|
|
94
|
+
cardNumber: 1234
|
|
95
|
+
} as ISiCard;
|
|
96
|
+
mySiStation.dispatchEvent('siCardInserted', new SiMainStationSiCardInsertedEvent(mySiStation, fakeSiCard));
|
|
97
|
+
await testUtils.nTimesAsync(1, () => testUtils.advanceTimersByTime(0));
|
|
98
|
+
expect(cardsRead).toEqual([{ cardNumber: 1234 } as ISiCard]);
|
|
99
|
+
|
|
100
|
+
const actualCleanUpFunction: () => Promise<void> = cleanUpFunction;
|
|
101
|
+
await actualCleanUpFunction();
|
|
102
|
+
expect(storage.get('mode')!.value).toBe('Control');
|
|
103
|
+
expect(storage.get('code')!.value).toBe(31);
|
|
104
|
+
expect(storage.get('autoSend')!.value).toBe(true);
|
|
105
|
+
expect(storage.get('handshake')!.value).toBe(false);
|
|
106
|
+
expect(storage.get('beeps')!.value).toBe(false);
|
|
107
|
+
expect(storage.get('flashes')!.value).toBe(false);
|
|
108
|
+
|
|
109
|
+
mySiStation.dispatchEvent('siCardInserted', new SiMainStationSiCardInsertedEvent(mySiStation, fakeSiCard));
|
|
110
|
+
await testUtils.nTimesAsync(1, () => testUtils.advanceTimersByTime(0));
|
|
111
|
+
// No additional entry
|
|
112
|
+
expect(cardsRead).toEqual([{ cardNumber: 1234 } as ISiCard]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('card detection & removal', async () => {
|
|
116
|
+
const myTargetMultiplexer = new SiTargetMultiplexer({} as ISiDevice<ISiDeviceDriverData<unknown>>);
|
|
117
|
+
const myMainStation = SiMainStation.fromSiTargetMultiplexer(myTargetMultiplexer);
|
|
118
|
+
const testData = getSiCard5Examples().fullCard;
|
|
119
|
+
const myFakeSiCard5 = new FakeSiCard5(testData.storageData);
|
|
120
|
+
|
|
121
|
+
const insertedCardNumbers: number[] = [];
|
|
122
|
+
const handleCardInserted = (e: SiMainStationSiCardInsertedEvent) => {
|
|
123
|
+
insertedCardNumbers.push(e.siCard.cardNumber);
|
|
124
|
+
};
|
|
125
|
+
myMainStation.addEventListener('siCardInserted', handleCardInserted);
|
|
126
|
+
const message = myFakeSiCard5.handleDetect() as siProtocol.SiMessageWithoutMode;
|
|
127
|
+
myTargetMultiplexer.dispatchEvent(
|
|
128
|
+
'message',
|
|
129
|
+
new SiTargetMultiplexerMessageEvent(myTargetMultiplexer, {
|
|
130
|
+
command: message.command,
|
|
131
|
+
parameters: [...[0x00, 0x00], ...message.parameters] as number[]
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
|
|
135
|
+
expect(insertedCardNumbers).toEqual([406402]);
|
|
136
|
+
|
|
137
|
+
const removedCardNumbers: number[] = [];
|
|
138
|
+
const handleCardRemoved = (e: SiMainStationSiCardRemovedEvent) => {
|
|
139
|
+
removedCardNumbers.push(e.siCard.cardNumber);
|
|
140
|
+
};
|
|
141
|
+
myMainStation.addEventListener('siCardRemoved', handleCardRemoved);
|
|
142
|
+
myTargetMultiplexer.dispatchEvent(
|
|
143
|
+
'message',
|
|
144
|
+
new SiTargetMultiplexerMessageEvent(myTargetMultiplexer, {
|
|
145
|
+
command: proto.cmd.SI_REM,
|
|
146
|
+
parameters: [...[0x00, 0x00], ...message.parameters] as number[]
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
|
|
150
|
+
expect(removedCardNumbers).toEqual([406402]);
|
|
151
|
+
|
|
152
|
+
myTargetMultiplexer.dispatchEvent(
|
|
153
|
+
'message',
|
|
154
|
+
new SiTargetMultiplexerMessageEvent(myTargetMultiplexer, {
|
|
155
|
+
command: proto.cmd.SI_REM,
|
|
156
|
+
parameters: [0x00, 0x00, 0x01, 0x23, 0x45, 0x67]
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
|
|
160
|
+
expect(removedCardNumbers).toEqual([406402]);
|
|
161
|
+
|
|
162
|
+
myMainStation.removeEventListener('siCardInserted', handleCardInserted);
|
|
163
|
+
myMainStation.removeEventListener('siCardRemoved', handleCardRemoved);
|
|
164
|
+
});
|
|
165
|
+
test('card observation', async () => {
|
|
166
|
+
const myTargetMultiplexer = new SiTargetMultiplexer({} as ISiDevice<ISiDeviceDriverData<unknown>>);
|
|
167
|
+
const myMainStation = SiMainStation.fromSiTargetMultiplexer(myTargetMultiplexer);
|
|
168
|
+
const testData = getSiCard6Examples().fullCard;
|
|
169
|
+
const myFakeSiCard6 = new FakeSiCard6(testData.storageData);
|
|
170
|
+
const observedCardNumbers: number[] = [];
|
|
171
|
+
const handleCardObserved = (e: SiMainStationSiCardObservedEvent) => {
|
|
172
|
+
observedCardNumbers.push(e.siCard.cardNumber);
|
|
173
|
+
};
|
|
174
|
+
myMainStation.addEventListener('siCardObserved', handleCardObserved);
|
|
175
|
+
const message = myFakeSiCard6.handleDetect() as siProtocol.SiMessageWithoutMode;
|
|
176
|
+
myTargetMultiplexer.dispatchEvent(
|
|
177
|
+
'message',
|
|
178
|
+
new SiTargetMultiplexerMessageEvent(myTargetMultiplexer, {
|
|
179
|
+
command: proto.cmd.TRANS_REC,
|
|
180
|
+
parameters: [...[0x00, 0x00], ...message.parameters] as number[]
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
|
|
185
|
+
expect(observedCardNumbers).toEqual([testData.cardData.cardNumber]);
|
|
186
|
+
});
|
|
187
|
+
test('card observation with mode', async () => {
|
|
188
|
+
const myTargetMultiplexer = new SiTargetMultiplexer({} as ISiDevice<ISiDeviceDriverData<unknown>>);
|
|
189
|
+
const myMainStation = SiMainStation.fromSiTargetMultiplexer(myTargetMultiplexer);
|
|
190
|
+
const observedCardNumbers: number[] = [];
|
|
191
|
+
const handleCardObserved = (e: SiMainStationSiCardObservedEvent) => {
|
|
192
|
+
observedCardNumbers.push(e.siCard.cardNumber);
|
|
193
|
+
};
|
|
194
|
+
myMainStation.addEventListener('siCardObserved', handleCardObserved);
|
|
195
|
+
myTargetMultiplexer.dispatchEvent('message', new SiTargetMultiplexerMessageEvent(myTargetMultiplexer, { mode: proto.NAK }));
|
|
196
|
+
|
|
197
|
+
await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
|
|
198
|
+
expect(observedCardNumbers).toEqual([]);
|
|
199
|
+
});
|
|
200
|
+
test('other message', () => {
|
|
201
|
+
const fakeSiTargetMultiplexer = {
|
|
202
|
+
addEventListener: () => undefined,
|
|
203
|
+
sendMessage: () => Promise.resolve([])
|
|
204
|
+
} as unknown as ISiTargetMultiplexer;
|
|
205
|
+
const mySiStation = new SiMainStation(fakeSiTargetMultiplexer);
|
|
206
|
+
mySiStation.handleMessage({ command: proto.cmd.SIGNAL, parameters: [0x01] });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('sendMessage', async () => {
|
|
210
|
+
const fakeSiTargetMultiplexer = {
|
|
211
|
+
addEventListener: () => undefined,
|
|
212
|
+
sendMessage: () => Promise.resolve([])
|
|
213
|
+
} as unknown as ISiTargetMultiplexer;
|
|
214
|
+
const mySiStation = new SiMainStation(fakeSiTargetMultiplexer);
|
|
215
|
+
let sendMessageSucceeded:boolean|undefined = undefined;
|
|
216
|
+
mySiStation.sendMessage({} as siProtocol.SiMessage).then(() => {
|
|
217
|
+
sendMessageSucceeded = true;
|
|
218
|
+
});
|
|
219
|
+
await testUtils.nTimesAsync(1, () => testUtils.advanceTimersByTime(0));
|
|
220
|
+
expect(sendMessageSucceeded).toBe(true);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as utils from '../utils';
|
|
2
|
+
import * as siProtocol from '../siProtocol';
|
|
3
|
+
import { proto } from '../constants';
|
|
4
|
+
import { BaseSiCard } from '../SiCard';
|
|
5
|
+
import type { ISiCard } from '../SiCard/ISiCard';
|
|
6
|
+
import type { ISiDevice, ISiDeviceDriverData } from '../SiDevice/ISiDevice';
|
|
7
|
+
import type { ISiStation } from './ISiStation';
|
|
8
|
+
import { type SiMainStationEvents, SiMainStationSiCardInsertedEvent, SiMainStationSiCardObservedEvent, SiMainStationSiCardRemovedEvent } from './ISiMainStation';
|
|
9
|
+
import { type ISiTargetMultiplexer, SiTargetMultiplexerMessageEvent, SiTargetMultiplexerTarget } from './ISiTargetMultiplexer';
|
|
10
|
+
import { BaseSiStation, type ISiStationStorageFields } from './BaseSiStation';
|
|
11
|
+
import { SiTargetMultiplexer } from './SiTargetMultiplexer';
|
|
12
|
+
|
|
13
|
+
type SiStationSetup = {
|
|
14
|
+
[key in keyof ISiStationStorageFields]?: ISiStationStorageFields[key];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type CleanUpFunction = () => Promise<void>;
|
|
18
|
+
|
|
19
|
+
export class SiMainStation extends BaseSiStation<SiTargetMultiplexerTarget.Direct> implements ISiStation<SiTargetMultiplexerTarget.Direct> {
|
|
20
|
+
static fromSiDevice(siDevice: ISiDevice<ISiDeviceDriverData<unknown>>): SiMainStation {
|
|
21
|
+
const multiplexer = SiTargetMultiplexer.fromSiDevice(siDevice);
|
|
22
|
+
return this.fromSiTargetMultiplexer(multiplexer);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static fromSiTargetMultiplexer(multiplexer: ISiTargetMultiplexer): SiMainStation {
|
|
26
|
+
return this.fromSiTargetMultiplexerWithGivenTarget(multiplexer, SiTargetMultiplexerTarget.Direct, () => new this(multiplexer, SiTargetMultiplexerTarget.Direct)) as SiMainStation;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public siCard: ISiCard | null = null;
|
|
30
|
+
|
|
31
|
+
constructor(siTargetMultiplexer: ISiTargetMultiplexer, multiplexerTarget: SiTargetMultiplexerTarget.Direct = SiTargetMultiplexerTarget.Direct) {
|
|
32
|
+
super(siTargetMultiplexer, multiplexerTarget);
|
|
33
|
+
siTargetMultiplexer.addEventListener(
|
|
34
|
+
'message', // not directMessage, as the target might still be unknown, but we still need the message
|
|
35
|
+
(e: SiTargetMultiplexerMessageEvent) => {
|
|
36
|
+
const message = e.message;
|
|
37
|
+
this.handleMessage(message);
|
|
38
|
+
console.log(`There's a SiMainStation listening to this ${message}`);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
readCards(onCardInserted: (card: ISiCard) => void, siStationSetupModification: SiStationSetup = {}): Promise<CleanUpFunction> {
|
|
44
|
+
const siStationSetup: SiStationSetup = {
|
|
45
|
+
code: 10,
|
|
46
|
+
mode: 'Readout',
|
|
47
|
+
autoSend: false,
|
|
48
|
+
handshake: true,
|
|
49
|
+
beeps: true,
|
|
50
|
+
flashes: true,
|
|
51
|
+
...siStationSetupModification
|
|
52
|
+
};
|
|
53
|
+
const siStationSetupKeys = Object.keys(siStationSetup) as (keyof ISiStationStorageFields)[];
|
|
54
|
+
const oldState: SiStationSetup = {};
|
|
55
|
+
|
|
56
|
+
const handleCardInserted = (e: SiMainStationSiCardInsertedEvent) => {
|
|
57
|
+
onCardInserted(e.siCard);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const cleanUp: CleanUpFunction = () => {
|
|
61
|
+
this.removeEventListener('siCardInserted', handleCardInserted);
|
|
62
|
+
return this.atomically(() => {
|
|
63
|
+
siStationSetupKeys.forEach((infoName) => {
|
|
64
|
+
const oldInfoValue = oldState[infoName];
|
|
65
|
+
if (oldInfoValue !== undefined) {
|
|
66
|
+
this.setInfo(infoName, oldInfoValue);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return this.atomically(() => {
|
|
73
|
+
siStationSetupKeys.forEach((infoName: keyof ISiStationStorageFields) => {
|
|
74
|
+
const oldFieldValue = this.getInfo(infoName);
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
oldState[infoName] = oldFieldValue ? oldFieldValue.value : undefined;
|
|
77
|
+
const newValue = siStationSetup[infoName];
|
|
78
|
+
if (newValue !== undefined) {
|
|
79
|
+
this.setInfo(infoName, newValue);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}).then(() => {
|
|
83
|
+
this.addEventListener('siCardInserted', handleCardInserted);
|
|
84
|
+
return cleanUp;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
handleMessage(message: siProtocol.SiMessage): void {
|
|
89
|
+
if (message.mode !== undefined) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const { command, parameters } = message;
|
|
93
|
+
const detectedSiCard = BaseSiCard.detectFromMessage(message);
|
|
94
|
+
if (detectedSiCard !== undefined) {
|
|
95
|
+
detectedSiCard.mainStation = this;
|
|
96
|
+
this.siCard = detectedSiCard as ISiCard;
|
|
97
|
+
this.dispatchEvent('siCardInserted', new SiMainStationSiCardInsertedEvent(this, detectedSiCard as ISiCard));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const handleSiCardRemoved = () => {
|
|
101
|
+
const removedCardNumber = siProtocol.arr2cardNumber([parameters[5], parameters[4], parameters[3]]); // TODO: also [2]?
|
|
102
|
+
if (this.siCard !== null && this.siCard.cardNumber === removedCardNumber) {
|
|
103
|
+
this.dispatchEvent('siCardRemoved', new SiMainStationSiCardRemovedEvent(this, this.siCard));
|
|
104
|
+
} else {
|
|
105
|
+
console.warn(`Card ${removedCardNumber} was removed, but never inserted`);
|
|
106
|
+
}
|
|
107
|
+
this.siCard = null;
|
|
108
|
+
};
|
|
109
|
+
const handleSiCardObserved = () => {
|
|
110
|
+
const observedCardNumber = siProtocol.arr2cardNumber([parameters[5], parameters[4], parameters[3]]); // TODO: also [2]?
|
|
111
|
+
if (observedCardNumber === undefined) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const transRecordCard = BaseSiCard.fromCardNumber(observedCardNumber);
|
|
115
|
+
if (transRecordCard !== undefined) {
|
|
116
|
+
transRecordCard.mainStation = this;
|
|
117
|
+
this.dispatchEvent('siCardObserved', new SiMainStationSiCardObservedEvent(this, transRecordCard as ISiCard));
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const handlerByCommand: { [command: number]: () => void } = {
|
|
121
|
+
[proto.cmd.SI_REM]: handleSiCardRemoved,
|
|
122
|
+
[proto.cmd.TRANS_REC]: handleSiCardObserved
|
|
123
|
+
};
|
|
124
|
+
const handler = handlerByCommand[command];
|
|
125
|
+
if (handler === undefined) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
handler();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
132
|
+
export interface SiMainStation extends utils.EventTarget<SiMainStationEvents> {}
|
|
133
|
+
utils.applyMixins(SiMainStation, [utils.EventTarget]);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as siProtocol from '../siProtocol';
|
|
2
|
+
import { SiSendTaskState } from './ISiSendTask';
|
|
3
|
+
|
|
4
|
+
export class SiSendTask {
|
|
5
|
+
public state: SiSendTaskState = SiSendTaskState.Queued;
|
|
6
|
+
public responses: number[][] = [];
|
|
7
|
+
private timeoutTimer: unknown;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
public message: siProtocol.SiMessage,
|
|
11
|
+
public numResponses: number,
|
|
12
|
+
public timeoutInMiliseconds: number,
|
|
13
|
+
public onResolve: (task: SiSendTask) => void,
|
|
14
|
+
public onReject: (task: SiSendTask) => void
|
|
15
|
+
) {
|
|
16
|
+
this.timeoutTimer = setTimeout(() => {
|
|
17
|
+
const shouldAbortInState: { [state in SiSendTaskState]: boolean } = {
|
|
18
|
+
[SiSendTaskState.Queued]: true,
|
|
19
|
+
[SiSendTaskState.Sending]: true,
|
|
20
|
+
[SiSendTaskState.Sent]: true,
|
|
21
|
+
[SiSendTaskState.Succeeded]: false,
|
|
22
|
+
[SiSendTaskState.Failed]: false
|
|
23
|
+
};
|
|
24
|
+
if (!shouldAbortInState[this.state]) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.debug(`Timeout: ${siProtocol.prettyMessage(this.message)} (expected ${this.numResponses} responses)`, this.responses);
|
|
28
|
+
this.fail();
|
|
29
|
+
}, timeoutInMiliseconds);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
addResponse(response: number[]): void {
|
|
33
|
+
this.responses.push(response);
|
|
34
|
+
if (this.responses.length === this.numResponses) {
|
|
35
|
+
this.succeed();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
succeed(): void {
|
|
40
|
+
this.state = SiSendTaskState.Succeeded;
|
|
41
|
+
clearTimeout(this.timeoutTimer as Parameters<typeof clearTimeout>[0]);
|
|
42
|
+
this.onResolve(this);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fail(): void {
|
|
46
|
+
this.state = SiSendTaskState.Failed;
|
|
47
|
+
clearTimeout(this.timeoutTimer as Parameters<typeof clearTimeout>[0]);
|
|
48
|
+
this.onReject(this);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, expect, test } from '@jest/globals';
|
|
2
|
+
import { proto } from '../constants';
|
|
3
|
+
import * as siProtocol from '../siProtocol';
|
|
4
|
+
import * as testUtils from '../testUtils';
|
|
5
|
+
import { SiDevice } from '../SiDevice/SiDevice';
|
|
6
|
+
import { SiDeviceState, SiDeviceReceiveEvent, type ISiDeviceDriverData } from '../SiDevice/ISiDevice';
|
|
7
|
+
import type { ISiDeviceDriver } from '../SiDevice/ISiDeviceDriver';
|
|
8
|
+
import { SiTargetMultiplexerTarget } from './ISiTargetMultiplexer';
|
|
9
|
+
import { SiTargetMultiplexer } from './SiTargetMultiplexer';
|
|
10
|
+
|
|
11
|
+
testUtils.useFakeTimers();
|
|
12
|
+
|
|
13
|
+
function mockDriver(driver: Partial<ISiDeviceDriver<ISiDeviceDriverData<unknown>>>) {
|
|
14
|
+
return driver as unknown as ISiDeviceDriver<ISiDeviceDriverData<unknown>>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('SiTargetMultiplexer', () => {
|
|
18
|
+
test('handles targeting', async () => {
|
|
19
|
+
const siDevice = new SiDevice('handlesTargeting0', {
|
|
20
|
+
driver: mockDriver({
|
|
21
|
+
send: () => Promise.resolve()
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
siDevice.setState(SiDeviceState.Opened);
|
|
25
|
+
const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
|
|
26
|
+
expect(muxer instanceof SiTargetMultiplexer).toBe(true);
|
|
27
|
+
|
|
28
|
+
const randomMessage = testUtils.getRandomMessage({});
|
|
29
|
+
const timeState = {
|
|
30
|
+
sendingFinished: false,
|
|
31
|
+
resendingFinished: false,
|
|
32
|
+
remoteSendingFinished: false
|
|
33
|
+
};
|
|
34
|
+
muxer.sendMessage(SiTargetMultiplexerTarget.Direct, randomMessage, 0, 1).then((responses) => {
|
|
35
|
+
expect(responses.length).toBe(0);
|
|
36
|
+
expect(muxer._test.sendQueue.length).toBe(0);
|
|
37
|
+
timeState.sendingFinished = true;
|
|
38
|
+
});
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
siDevice.dispatchEvent(
|
|
41
|
+
'receive',
|
|
42
|
+
new SiDeviceReceiveEvent(
|
|
43
|
+
siDevice,
|
|
44
|
+
siProtocol.render({
|
|
45
|
+
command: proto.cmd.SET_MS,
|
|
46
|
+
parameters: [0x00, 0x00, proto.P_MS_DIRECT]
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
}, 1);
|
|
51
|
+
expect(muxer.target).toBe(SiTargetMultiplexerTarget.Unknown);
|
|
52
|
+
expect(muxer._test.latestTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
53
|
+
await testUtils.advanceTimersByTime(0); // resolve setTarget send promise
|
|
54
|
+
await testUtils.advanceTimersByTime(1); // trigger setTarget receive
|
|
55
|
+
await testUtils.nTimesAsync(10, () => testUtils.advanceTimersByTime(1));
|
|
56
|
+
expect(muxer.target).toBe(SiTargetMultiplexerTarget.Direct);
|
|
57
|
+
expect(muxer._test.latestTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
58
|
+
await testUtils.advanceTimersByTime(0);
|
|
59
|
+
await testUtils.advanceTimersByTime(0);
|
|
60
|
+
expect(timeState).toEqual({
|
|
61
|
+
sendingFinished: true,
|
|
62
|
+
resendingFinished: false,
|
|
63
|
+
remoteSendingFinished: false
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
muxer.sendMessage(SiTargetMultiplexerTarget.Direct, randomMessage, 0, 1).then((responses) => {
|
|
67
|
+
expect(responses.length).toBe(0);
|
|
68
|
+
expect(muxer._test.sendQueue.length).toBe(0);
|
|
69
|
+
timeState.resendingFinished = true;
|
|
70
|
+
});
|
|
71
|
+
await testUtils.advanceTimersByTime(0);
|
|
72
|
+
await testUtils.advanceTimersByTime(0);
|
|
73
|
+
expect(muxer.target).toBe(SiTargetMultiplexerTarget.Direct);
|
|
74
|
+
expect(muxer._test.latestTarget).toBe(SiTargetMultiplexerTarget.Direct);
|
|
75
|
+
expect(timeState).toEqual({
|
|
76
|
+
sendingFinished: true,
|
|
77
|
+
resendingFinished: true,
|
|
78
|
+
remoteSendingFinished: false
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
muxer.sendMessage(SiTargetMultiplexerTarget.Remote, randomMessage, 0, 1).then((responses) => {
|
|
82
|
+
expect(responses.length).toBe(0);
|
|
83
|
+
expect(muxer._test.sendQueue.length).toBe(0);
|
|
84
|
+
timeState.remoteSendingFinished = true;
|
|
85
|
+
});
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
siDevice.dispatchEvent(
|
|
88
|
+
'receive',
|
|
89
|
+
new SiDeviceReceiveEvent(
|
|
90
|
+
siDevice,
|
|
91
|
+
siProtocol.render({
|
|
92
|
+
command: proto.cmd.SET_MS,
|
|
93
|
+
parameters: [0x00, 0x00, proto.P_MS_REMOTE]
|
|
94
|
+
})
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
}, 1);
|
|
98
|
+
expect(muxer.target).toBe(SiTargetMultiplexerTarget.Direct);
|
|
99
|
+
expect(muxer._test.latestTarget).toBe(SiTargetMultiplexerTarget.Remote);
|
|
100
|
+
await testUtils.advanceTimersByTime(0); // resolve setTarget send promise
|
|
101
|
+
await testUtils.advanceTimersByTime(1); // trigger setTarget receive
|
|
102
|
+
expect(muxer.target).toBe(SiTargetMultiplexerTarget.Remote);
|
|
103
|
+
expect(muxer._test.latestTarget).toBe(SiTargetMultiplexerTarget.Remote);
|
|
104
|
+
await testUtils.advanceTimersByTime(0);
|
|
105
|
+
await testUtils.advanceTimersByTime(0);
|
|
106
|
+
expect(timeState).toEqual({
|
|
107
|
+
sendingFinished: true,
|
|
108
|
+
resendingFinished: true,
|
|
109
|
+
remoteSendingFinished: true
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|