@robdobsn/raftjs 1.1.1

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 (149) hide show
  1. package/.editorconfig +14 -0
  2. package/.gitattributes +11 -0
  3. package/.nvmrc +1 -0
  4. package/LICENSE +22 -0
  5. package/README.md +11 -0
  6. package/TODO.md +1 -0
  7. package/dist/RaftAttributeHandler.d.ts +12 -0
  8. package/dist/RaftAttributeHandler.js +241 -0
  9. package/dist/RaftAttributeHandler.js.map +1 -0
  10. package/dist/RaftChannel.d.ts +18 -0
  11. package/dist/RaftChannel.js +12 -0
  12. package/dist/RaftChannel.js.map +1 -0
  13. package/dist/RaftChannelWebBLE.d.ts +38 -0
  14. package/dist/RaftChannelWebBLE.js +274 -0
  15. package/dist/RaftChannelWebBLE.js.map +1 -0
  16. package/dist/RaftChannelWebSerial.d.ts +37 -0
  17. package/dist/RaftChannelWebSerial.js +319 -0
  18. package/dist/RaftChannelWebSerial.js.map +1 -0
  19. package/dist/RaftChannelWebSocket.d.ts +28 -0
  20. package/dist/RaftChannelWebSocket.js +197 -0
  21. package/dist/RaftChannelWebSocket.js.map +1 -0
  22. package/dist/RaftCommsStats.d.ts +39 -0
  23. package/dist/RaftCommsStats.js +128 -0
  24. package/dist/RaftCommsStats.js.map +1 -0
  25. package/dist/RaftConnEvents.d.ts +31 -0
  26. package/dist/RaftConnEvents.js +44 -0
  27. package/dist/RaftConnEvents.js.map +1 -0
  28. package/dist/RaftConnector.d.ts +242 -0
  29. package/dist/RaftConnector.js +613 -0
  30. package/dist/RaftConnector.js.map +1 -0
  31. package/dist/RaftCustomAttrHandler.d.ts +4 -0
  32. package/dist/RaftCustomAttrHandler.js +50 -0
  33. package/dist/RaftCustomAttrHandler.js.map +1 -0
  34. package/dist/RaftDeviceInfo.d.ts +64 -0
  35. package/dist/RaftDeviceInfo.js +36 -0
  36. package/dist/RaftDeviceInfo.js.map +1 -0
  37. package/dist/RaftDeviceManager.d.ts +37 -0
  38. package/dist/RaftDeviceManager.js +450 -0
  39. package/dist/RaftDeviceManager.js.map +1 -0
  40. package/dist/RaftDeviceMsg.d.ts +9 -0
  41. package/dist/RaftDeviceMsg.js +11 -0
  42. package/dist/RaftDeviceMsg.js.map +1 -0
  43. package/dist/RaftDeviceStates.d.ts +33 -0
  44. package/dist/RaftDeviceStates.js +60 -0
  45. package/dist/RaftDeviceStates.js.map +1 -0
  46. package/dist/RaftFileHandler.d.ts +52 -0
  47. package/dist/RaftFileHandler.js +502 -0
  48. package/dist/RaftFileHandler.js.map +1 -0
  49. package/dist/RaftLog.d.ts +22 -0
  50. package/dist/RaftLog.js +63 -0
  51. package/dist/RaftLog.js.map +1 -0
  52. package/dist/RaftMiniHDLC.d.ts +18 -0
  53. package/dist/RaftMiniHDLC.js +383 -0
  54. package/dist/RaftMiniHDLC.js.map +1 -0
  55. package/dist/RaftMsgHandler.d.ts +57 -0
  56. package/dist/RaftMsgHandler.js +480 -0
  57. package/dist/RaftMsgHandler.js.map +1 -0
  58. package/dist/RaftMsgTrackInfo.d.ts +17 -0
  59. package/dist/RaftMsgTrackInfo.js +42 -0
  60. package/dist/RaftMsgTrackInfo.js.map +1 -0
  61. package/dist/RaftProtocolDefs.d.ts +30 -0
  62. package/dist/RaftProtocolDefs.js +48 -0
  63. package/dist/RaftProtocolDefs.js.map +1 -0
  64. package/dist/RaftStreamHandler.d.ts +38 -0
  65. package/dist/RaftStreamHandler.js +257 -0
  66. package/dist/RaftStreamHandler.js.map +1 -0
  67. package/dist/RaftSystemType.d.ts +21 -0
  68. package/dist/RaftSystemType.js +3 -0
  69. package/dist/RaftSystemType.js.map +1 -0
  70. package/dist/RaftSystemUtils.d.ts +136 -0
  71. package/dist/RaftSystemUtils.js +410 -0
  72. package/dist/RaftSystemUtils.js.map +1 -0
  73. package/dist/RaftTypes.d.ts +184 -0
  74. package/dist/RaftTypes.js +157 -0
  75. package/dist/RaftTypes.js.map +1 -0
  76. package/dist/RaftUpdateEvents.d.ts +33 -0
  77. package/dist/RaftUpdateEvents.js +46 -0
  78. package/dist/RaftUpdateEvents.js.map +1 -0
  79. package/dist/RaftUpdateManager.d.ts +61 -0
  80. package/dist/RaftUpdateManager.js +618 -0
  81. package/dist/RaftUpdateManager.js.map +1 -0
  82. package/dist/RaftUtils.d.ts +125 -0
  83. package/dist/RaftUtils.js +454 -0
  84. package/dist/RaftUtils.js.map +1 -0
  85. package/dist/RaftWifiTypes.d.ts +23 -0
  86. package/dist/RaftWifiTypes.js +43 -0
  87. package/dist/RaftWifiTypes.js.map +1 -0
  88. package/dist/TestDataGen.d.ts +7 -0
  89. package/dist/TestDataGen.js +133 -0
  90. package/dist/TestDataGen.js.map +1 -0
  91. package/dist/main.d.ts +18 -0
  92. package/dist/main.js +42 -0
  93. package/dist/main.js.map +1 -0
  94. package/eslint.config.mjs +33 -0
  95. package/examples/dashboard/package.json +39 -0
  96. package/examples/dashboard/src/ConnManager.ts +86 -0
  97. package/examples/dashboard/src/Main.tsx +100 -0
  98. package/examples/dashboard/src/StatusScreen.tsx +72 -0
  99. package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +144 -0
  100. package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +77 -0
  101. package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
  102. package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
  103. package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
  104. package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
  105. package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
  106. package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
  107. package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
  108. package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
  109. package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +32 -0
  110. package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
  111. package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
  112. package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +113 -0
  113. package/examples/dashboard/src/index.html +15 -0
  114. package/examples/dashboard/src/index.tsx +15 -0
  115. package/examples/dashboard/src/styles.css +122 -0
  116. package/examples/dashboard/tsconfig.json +18 -0
  117. package/jest.config.js +11 -0
  118. package/package.json +50 -0
  119. package/src/RaftAttributeHandler.ts +289 -0
  120. package/src/RaftChannel.ts +30 -0
  121. package/src/RaftChannelWebBLE.ts +342 -0
  122. package/src/RaftChannelWebSerial.ts +408 -0
  123. package/src/RaftChannelWebSocket.ts +245 -0
  124. package/src/RaftCommsStats.ts +142 -0
  125. package/src/RaftConnEvents.ts +46 -0
  126. package/src/RaftConnector.ts +745 -0
  127. package/src/RaftCustomAttrHandler.ts +54 -0
  128. package/src/RaftDeviceInfo.ts +104 -0
  129. package/src/RaftDeviceManager.ts +542 -0
  130. package/src/RaftDeviceMsg.ts +20 -0
  131. package/src/RaftDeviceStates.ts +89 -0
  132. package/src/RaftFileHandler.ts +668 -0
  133. package/src/RaftLog.ts +70 -0
  134. package/src/RaftMiniHDLC.ts +396 -0
  135. package/src/RaftMsgHandler.ts +778 -0
  136. package/src/RaftMsgTrackInfo.ts +51 -0
  137. package/src/RaftProtocolDefs.ts +46 -0
  138. package/src/RaftStreamHandler.ts +328 -0
  139. package/src/RaftSystemType.ts +25 -0
  140. package/src/RaftSystemUtils.ts +487 -0
  141. package/src/RaftTypes.ts +250 -0
  142. package/src/RaftUpdateEvents.ts +48 -0
  143. package/src/RaftUpdateManager.ts +778 -0
  144. package/src/RaftUtils.ts +484 -0
  145. package/src/RaftWifiTypes.ts +36 -0
  146. package/src/TestDataGen.ts +157 -0
  147. package/src/main.ts +28 -0
  148. package/testdata/TestDeviceTypeRecs.json +492 -0
  149. package/tsconfig.json +27 -0
@@ -0,0 +1,144 @@
1
+ import { time } from "console";
2
+ import RaftLog from "../../../../src/RaftLog";
3
+
4
+ export interface IMUStateInfo {
5
+ gx: number;
6
+ gy: number;
7
+ gz: number;
8
+ ax: number;
9
+ ay: number;
10
+ az: number;
11
+ tsMs: number;
12
+ }
13
+
14
+ export interface DeviceLastTsState {
15
+ lastMs: number;
16
+ offsetMs: number;
17
+ }
18
+
19
+ export interface DeviceMsgJsonElem {
20
+ _t: string; // Device type
21
+ _o: string; // Device name
22
+ x: string; // Hex encoded message values
23
+ }
24
+
25
+ export interface DeviceMsgJsonBus {
26
+ [devAddr: string]: DeviceMsgJsonElem;
27
+ }
28
+
29
+ export interface DeviceMsgJson {
30
+ [busName: string]: DeviceMsgJsonBus;
31
+ }
32
+
33
+ export class CogStateInfo {
34
+
35
+ LSM6DS: IMUStateInfo = {gx: 0, gy: 0, gz: 0, ax: 0, ay: 0, az: 0, tsMs: 0};
36
+
37
+ // Last timestamp for each device
38
+ private _deviceLastTs: {[devName: string]: DeviceLastTsState} = {};
39
+
40
+ updateFromMsg(rxMsg: Uint8Array, frameTimeMs: number): Array<string> {
41
+
42
+ // RaftLog.info(`CogStateInfo: updateFromMsg: rxMsg: ${rxMsg} frameTimeMs: ${frameTimeMs}`);
43
+
44
+ // Convert Uint8Array to string
45
+ const decoder = new TextDecoder('utf-8');
46
+ const jsonString = decoder.decode(rxMsg.slice(2));
47
+
48
+ // Debug
49
+ // RaftLog.info(`CogStateInfo: updateFromMsg: jsonString: ${jsonString}`);
50
+
51
+ // Parse JSON string to TypeScript object
52
+ const deviceMsg: DeviceMsgJson = JSON.parse(jsonString);
53
+
54
+ // Debug
55
+ // for (const busName in deviceMsg) {
56
+ // for (const devAddr in deviceMsg[busName]) {
57
+ // for (const attrGroupName in deviceMsg[busName][devAddr]) {
58
+ // RaftLog.info(`CogStateInfo: updateFromMsg: busName ${busName} devAddr ${devAddr} attrGroupName: ${attrGroupName}`);
59
+ // RaftLog.info(`CogStateInfo: updateFromMsg: attrValue: ${deviceMsg[busName][devAddr][attrGroupName]}`);
60
+ // }
61
+ // }
62
+ // }
63
+
64
+ // Iterate over values and extract
65
+ for (const busName in deviceMsg) {
66
+ for (const devAddr in deviceMsg[busName]) {
67
+
68
+ // Validate
69
+ if ((deviceMsg[busName][devAddr].x === undefined) || (deviceMsg[busName][devAddr]._t === undefined)) {
70
+ RaftLog.warn(`CogStateInfo: updateFromMsg: Invalid message`);
71
+ continue;
72
+ }
73
+
74
+ // Extract message and device type
75
+ const msgHex = deviceMsg[busName][devAddr].x;
76
+ const devType = deviceMsg[busName][devAddr]._t;
77
+
78
+ // Check if message is empty
79
+ if (msgHex === '') {
80
+ RaftLog.warn(`CogStateInfo: updateFromMsg: Empty message`);
81
+ continue;
82
+ }
83
+
84
+ // Convert the hex string to an arraybuffer by converting each pair of hex chars to a byte
85
+ const msgBytes = this.hexToBytes(msgHex);
86
+
87
+ // Convert to a Buffer
88
+ const msgBuffer = Buffer.from(msgBytes);
89
+
90
+ // Extract timestamp
91
+ let timestamp = msgBuffer.readUInt16BE(0);
92
+ if (this._deviceLastTs[devType] === undefined) {
93
+ this._deviceLastTs[devType] = {lastMs: 0, offsetMs: 0};
94
+ }
95
+ const devTsState = this._deviceLastTs[devType];
96
+ if (timestamp < devTsState.lastMs) {
97
+ devTsState.offsetMs += 0x10000;
98
+ }
99
+ devTsState.lastMs = timestamp;
100
+ timestamp += devTsState.offsetMs;
101
+ let msgBufferOffset = 2;
102
+ // RaftLog.info(`CogStateInfo: updateFromMsg: timestamp: ${timestamp}`);
103
+
104
+ // Handle device types
105
+ switch (devType) {
106
+ case 'LSM6DS':
107
+ // RaftLog.info(`CogStateInfo: updateFromMsg: IMU`);
108
+
109
+ // LSD6DS IMU data is coded as 16-bit signed integers little-endian
110
+ // gx, gy, gz, ax, ay, az
111
+ this.LSM6DS = {
112
+ gx: msgBuffer.readInt16LE(msgBufferOffset) / 16.384,
113
+ gy: msgBuffer.readInt16LE(msgBufferOffset + 2) / 16.384,
114
+ gz: msgBuffer.readInt16LE(msgBufferOffset + 4) / 16.384,
115
+ ax: msgBuffer.readInt16LE(msgBufferOffset + 6) / 8192,
116
+ ay: msgBuffer.readInt16LE(msgBufferOffset + 8) / 8192,
117
+ az: msgBuffer.readInt16LE(msgBufferOffset + 10) / 8192,
118
+ tsMs: timestamp
119
+ };
120
+
121
+ // Debug
122
+ // RaftLog.info(`CogStateInfo: updateFromMsg: LSM6DS: gx: ${this.LSM6DS.gx.toFixed(2)} gy: ${this.LSM6DS.gy.toFixed(2)} gz: ${this.LSM6DS.gz.toFixed(2)} ax: ${this.LSM6DS.ax.toFixed(2)} ay: ${this.LSM6DS.ay.toFixed(2)} az: ${this.LSM6DS.az.toFixed(2)} tsMs: ${this.LSM6DS.tsMs}`);
123
+
124
+
125
+
126
+ // const imu = deviceMsg[busName][devAddr] as DeviceMsgJsonElem;
127
+ // this.imu = {x: imu.x as number, y: imu.y as number, z: imu.z as number, lastMs: frameTimeMs};
128
+ break;
129
+ }
130
+ }
131
+ }
132
+
133
+ return [];
134
+
135
+ }
136
+
137
+ private hexToBytes(hex: string): Uint8Array {
138
+ const bytes = new Uint8Array(hex.length / 2);
139
+ for (let i = 0; i < bytes.length; i++) {
140
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
141
+ }
142
+ return bytes;
143
+ }
144
+ }
@@ -0,0 +1,77 @@
1
+ import { RaftSubscribeForUpdatesCBType, RaftSystemType } from "../../../../src/RaftSystemType";
2
+ import { RaftEventFn, RaftLog, RaftOKFail, RaftPublishEvent, RaftPublishEventNames, RaftSystemUtils } from "../../../../src/main";
3
+ import { CogStateInfo } from "./CogStateInfo";
4
+
5
+ export default class SystemTypeCog implements RaftSystemType {
6
+ nameForDialogs = "Robotical Cog";
7
+ defaultWiFiHostname = "Cog";
8
+ firmwareDestName = "ricfw";
9
+ normalFileDestName = "fs";
10
+ connectorOptions = {wsSuffix: "wsjson"};
11
+
12
+ // Latest data from servos, IMU, etc
13
+ private _stateInfo: CogStateInfo = new CogStateInfo();
14
+ getStateInfo(): CogStateInfo {
15
+ return this._stateInfo;
16
+ }
17
+
18
+ // Event handler
19
+ private _onEvent: RaftEventFn | null = null;
20
+
21
+ // Raft system utils
22
+ private _systemUtils: RaftSystemUtils | null = null;
23
+
24
+ // Setup
25
+ setup(systemUtils: RaftSystemUtils, onEvent: RaftEventFn | null): void {
26
+ this._systemUtils = systemUtils;
27
+ this._onEvent = onEvent;
28
+ }
29
+
30
+ // Subscribe for updates
31
+ subscribeForUpdates: RaftSubscribeForUpdatesCBType | null = async (systemUtils: RaftSystemUtils, enable: boolean) => {
32
+ // Subscription rate
33
+ const subscribeRateHz = 0.1;
34
+ try {
35
+ const subscribeDisable = '{"cmdName":"subscription","action":"update",' +
36
+ '"pubRecs":[' +
37
+ `{"name":"devjson","rateHz":0,}` +
38
+ ']}';
39
+ const subscribeEnable = '{"cmdName":"subscription","action":"update",' +
40
+ '"pubRecs":[' +
41
+ `{"name":"devjson","trigger":"timeorchange","rateHz":${subscribeRateHz.toString()}}` +
42
+ ']}';
43
+
44
+ const msgHandler = systemUtils.getMsgHandler();
45
+ const ricResp = await msgHandler.sendRICRESTCmdFrame<RaftOKFail>(
46
+ enable ? subscribeEnable : subscribeDisable
47
+ );
48
+
49
+ // Debug
50
+ RaftLog.debug(`subscribe enable/disable returned ${JSON.stringify(ricResp)}`);
51
+ } catch (error: unknown) {
52
+ RaftLog.warn(`getRICCalibInfo Failed subscribe for updates ${error}`);
53
+ }
54
+ };
55
+
56
+ // Invalidate state
57
+ stateIsInvalid(): void {};
58
+
59
+ // Other message type
60
+ rxOtherMsgType(payload: Uint8Array, frameTimeMs: number) {
61
+
62
+ // RICLog.debug(`rxOtherMsgType payload ${RICUtils.bufferToHex(payload)}`);
63
+ RaftLog.verbose(`rxOtherMsgType payloadLen ${payload.length}`);
64
+ const topicIDs = this._stateInfo.updateFromMsg(payload, frameTimeMs);
65
+
66
+ // Call event handler if registered
67
+ if (this._onEvent) {
68
+ this._onEvent("pub", RaftPublishEvent.PUBLISH_EVENT_DATA, RaftPublishEventNames[RaftPublishEvent.PUBLISH_EVENT_DATA],
69
+ {
70
+ topicIDs: topicIDs,
71
+ payload: payload,
72
+ frameTimeMs: frameTimeMs
73
+ });
74
+ }
75
+
76
+ };
77
+ }
@@ -0,0 +1,70 @@
1
+ import { RICHWElem } from "./RICHWElem";
2
+
3
+ /**
4
+ * RICAddOn
5
+ *
6
+ * @description
7
+ * Information about an add-on
8
+ *
9
+ * @field name: string - Name of add-on
10
+ * @field SN: string - Serial number
11
+ * @field poll: string - polling type ("status")
12
+ * @field pollRd: string - hex data most recently read
13
+ * @field pollHz: number - rate of polling
14
+ */
15
+ export type RICAddOn = {
16
+ name: string;
17
+ SN: string;
18
+ poll: string;
19
+ pollRd: number;
20
+ pollHz: number;
21
+ };
22
+
23
+ export class RICConfiguredAddOns {
24
+ req = '';
25
+ rslt = 'ok';
26
+ addons: Array<RICAddOn> = [];
27
+ }
28
+
29
+ /**
30
+ * AddOnElemAndConfig
31
+ *
32
+ * @description
33
+ * Carrier of information about an add-on combining
34
+ * the add-on element and the add-on configuration
35
+ *
36
+ * @field addOnConfig: RICAddOn - Add-on configuration
37
+ * @field hwElemRec: RICHWElem - Add-on element
38
+ * @field elemIdx: number - Index of the add-on element
39
+ */
40
+ export class AddOnElemAndConfig {
41
+ constructor(
42
+ addOnConfig: RICAddOn | null,
43
+ hwElemRec: RICHWElem | null,
44
+ elemIdx: number,
45
+ ) {
46
+ this.isConfigured = addOnConfig !== null;
47
+ this.isConnected = hwElemRec !== null;
48
+ if (addOnConfig != null) {
49
+ this.SN = addOnConfig.SN;
50
+ this.name = addOnConfig.name;
51
+ } else if (hwElemRec != null) {
52
+ this.SN = hwElemRec.SN;
53
+ this.name = hwElemRec.name;
54
+ }
55
+ this.addOnConfig = addOnConfig;
56
+ this.hwElemRec = hwElemRec;
57
+ this.id = elemIdx.toString();
58
+ }
59
+
60
+ // Fields from config (stored in RIC NVS using addon REST API)
61
+ addOnConfig: RICAddOn | null = null;
62
+ // Fields from HWElem (from hwstatus command)
63
+ hwElemRec: RICHWElem | null = null;
64
+ // Fields allocated when combining records
65
+ name = '';
66
+ SN = '';
67
+ id = '0';
68
+ isConnected = false;
69
+ isConfigured = false;
70
+ }
@@ -0,0 +1,33 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RICJS
4
+ // Communications Library
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2022
7
+ // (C) 2020-2022
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ import { RaftReportMsg } from '../../../../src/RaftTypes';
12
+ import { ROSSerialAddOnStatus } from './RICROSSerial';
13
+
14
+ export default abstract class RICAddOnBase {
15
+ _name = '';
16
+ _typeName = '';
17
+ _whoAmI = "";
18
+ _whoAmITypeCode = "";
19
+ _isStatic = false;
20
+ _initCmd: string | null = null;
21
+ constructor(name: string, typeName: string, whoAmI: string, whoAmITypeCode: string) {
22
+ this._name = name;
23
+ this._typeName = typeName;
24
+ this._whoAmI = whoAmI;
25
+ this._whoAmITypeCode = whoAmITypeCode;
26
+ }
27
+ abstract processInit(_dataReceived: RaftReportMsg): void;
28
+ abstract processPublishedData(
29
+ addOnID: number,
30
+ statusByte: number,
31
+ rawData: Uint8Array,
32
+ ): ROSSerialAddOnStatus;
33
+ }
@@ -0,0 +1,342 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RICJS
4
+ // Communications Library
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2022
7
+ // (C) 2020-2022
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ import RaftLog from "../../../../src/RaftLog";
12
+ import RaftMsgHandler from "../../../../src/RaftMsgHandler";
13
+ import { Dictionary, RaftOKFail, RaftReportMsg } from "../../../../src/RaftTypes";
14
+ import RICAddOnBase from "./RICAddOnBase";
15
+ import { RICHWElem } from "./RICHWElem";
16
+ import { ROSSerialAddOnStatus } from "./RICROSSerial";
17
+
18
+ export type RICAddOnCreator = (
19
+ name: string,
20
+ addOnFamily: string,
21
+ whoAmI: string,
22
+ whoAmITypeCode: string
23
+ ) => RICAddOnBase;
24
+
25
+ class AddOnFactoryElem {
26
+ typeName: string;
27
+ addOnFamily: string;
28
+ whoAmI: string;
29
+ factoryFn: RICAddOnCreator;
30
+ constructor(
31
+ typeName: string,
32
+ addOnFamily: string,
33
+ whoAmI: string,
34
+ factoryFn: RICAddOnCreator
35
+ ) {
36
+ this.addOnFamily = addOnFamily;
37
+ this.typeName = typeName;
38
+ this.whoAmI = whoAmI;
39
+ this.factoryFn = factoryFn;
40
+ }
41
+ }
42
+
43
+ export interface RICAddOnRegistry {
44
+ registerHWElemType(
45
+ typeName: string,
46
+ addOnFamily: string,
47
+ whoAmI: string,
48
+ factoryFn: RICAddOnCreator
49
+ ): void;
50
+ }
51
+
52
+ /**
53
+ * RICAddOnManager
54
+ *
55
+ * @description
56
+ * Handles the creation and management of RIC Add-Ons
57
+ *
58
+ */
59
+ export default class RICAddOnManager implements RICAddOnRegistry {
60
+
61
+ // Message handler, etc
62
+ private _msgHandler: RaftMsgHandler | null = null;
63
+
64
+ // Add-on factory map
65
+ private _addOnFactoryMap: Dictionary<AddOnFactoryElem> = {};
66
+
67
+ // Configured add-ons
68
+ private _configuredAddOns: Dictionary<RICAddOnBase> = {};
69
+
70
+ /**
71
+ * Setup the RIC Add-On Manager
72
+ */
73
+ setup(msgHandler: RaftMsgHandler): void {
74
+ this._msgHandler = msgHandler;
75
+ }
76
+
77
+ /**
78
+ *
79
+ * @param typeName Register HWElem type
80
+ * @param addOnFamily
81
+ * @param whoAmI
82
+ * @param factoryFn
83
+ */
84
+ registerHWElemType(
85
+ typeName: string,
86
+ addOnFamily: string,
87
+ whoAmI: string,
88
+ factoryFn: RICAddOnCreator
89
+ ): void {
90
+ RaftLog.debug(`registerHWElemType ${whoAmI} ${typeName}`);
91
+ const lookupStr = addOnFamily + "_" + whoAmI;
92
+ this._addOnFactoryMap[lookupStr] = new AddOnFactoryElem(
93
+ typeName,
94
+ addOnFamily,
95
+ whoAmI,
96
+ factoryFn
97
+ );
98
+ }
99
+
100
+ // Mark: Set AddOn config -----------------------------------------------------------
101
+
102
+ /**
103
+ *
104
+ * setAddOnConfig - set a specified add-on's configuration
105
+ * @param serialNo used to identify the add-on
106
+ * @param newName name to refer to add-on by
107
+ * @returns Promise<RaftOKFail>
108
+ *
109
+ */
110
+ async setAddOnConfig(serialNo: string, newName: string): Promise<RaftOKFail> {
111
+ try {
112
+ if (this._msgHandler) {
113
+ const msgRslt = await this._msgHandler.sendRICRESTURL<RaftOKFail>(
114
+ `addon/set?SN=${serialNo}&name=${newName}`,
115
+ );
116
+ return msgRslt;
117
+ }
118
+ } catch (error) {
119
+ }
120
+ return new RaftOKFail();
121
+ }
122
+
123
+ /**
124
+ * deleteAddOn - remove an addon from the addonlist on RIC
125
+ * @param serialNo used to identify the add-on
126
+ * @returns Promise<RaftOKFail>
127
+ */
128
+ async deleteAddOn(serialNo: string): Promise<RaftOKFail> {
129
+ try {
130
+ if (this._msgHandler) {
131
+ const msgRslt = await this._msgHandler.sendRICRESTURL<RaftOKFail>(
132
+ `addon/del?SN=${serialNo}`,
133
+ );
134
+ return msgRslt;
135
+ }
136
+ } catch (error) {
137
+ }
138
+ return new RaftOKFail();
139
+ }
140
+
141
+ // Mark: Identify AddOn -----------------------------------------------------------
142
+
143
+ /**
144
+ *
145
+ * identifyAddOn - send the 'identify' command to a specified add-on
146
+ * @param name used to identify the add-on
147
+ * @returns Promise<RaftOKFail>
148
+ *
149
+ */
150
+ async identifyAddOn(name: string): Promise<RaftOKFail> {
151
+ try {
152
+ if (this._msgHandler) {
153
+ const msgRslt = await this._msgHandler.sendRICRESTURL<RaftOKFail>(
154
+ `elem/${name}/json?cmd=raw&hexWr=F8`,
155
+ );
156
+ return msgRslt;
157
+ }
158
+ } catch (error) {
159
+ }
160
+ return new RaftOKFail();
161
+ }
162
+
163
+ /**
164
+ * @function getStaticAddonIds
165
+ * Get the ids of the add-ons that are static
166
+ * (their data do not get published from ricjs, eg buspixel ledeyes)
167
+ * @returns {Array<number>} the ids of the static add-ons
168
+ */
169
+ getStaticAddonIds(): Array<number> {
170
+ // at this point we will create the buspixel addon for the batch 4 ledeye,
171
+ // as their data is not published the same way the RSAddOn do
172
+ // to do so, however, we need to know if the batch 4 ledeye is connected
173
+ const staticAddonIds = [];
174
+ for (const addOnId in this._configuredAddOns) {
175
+ const addon = this._configuredAddOns[addOnId];
176
+ if (addon._isStatic) {
177
+ staticAddonIds.push(+addOnId);
178
+ }
179
+ }
180
+ return staticAddonIds;
181
+ }
182
+
183
+ /**
184
+ * @function getStaticAddons
185
+ * Get the add-ons that are static
186
+ * (their data do not get published from ricjs, eg buspixel ledeyes)
187
+ * @returns {Array<RICAddOnBase>} the static add-ons unprocessed
188
+ */
189
+ getStaticAddons(): Array<RICAddOnBase> {
190
+ const staticAddons = [];
191
+ for (const addOnId in this._configuredAddOns) {
192
+ const addon = this._configuredAddOns[addOnId];
193
+ if (addon._isStatic) {
194
+ staticAddons.push(addon);
195
+ }
196
+ }
197
+ return staticAddons;
198
+ }
199
+
200
+ /**
201
+ * @function getProcessedStaticAddons
202
+ * Get the add-ons that are static
203
+ * (their data do not get published from ricjs, eg buspixel ledeyes)
204
+ * @returns {Array<ROSSerialAddOnStatus>} the static add-ons processed
205
+ */
206
+ getProcessedStaticAddons(): Array<ROSSerialAddOnStatus> {
207
+ const ids = this.getStaticAddonIds();
208
+ const staticAddons: ROSSerialAddOnStatus[] = [];
209
+ ids.forEach((id) => {
210
+ const processedAddon = this.processPublishedData(
211
+ id,
212
+ 0,
213
+ new Uint8Array(0)
214
+ );
215
+ if (processedAddon) {
216
+ staticAddons.push(processedAddon);
217
+ }
218
+ });
219
+ return staticAddons;
220
+ }
221
+
222
+ /**
223
+ * @function setHWElems
224
+ * Set the hardware elements from a list of RICHWElem
225
+ * @param hwElems
226
+ *
227
+ */
228
+ setHWElems(hwElems: Array<RICHWElem>): void {
229
+ this._configuredAddOns = this.configureAddOns(hwElems);
230
+ }
231
+
232
+ clear(): void {
233
+ this._configuredAddOns = {};
234
+ }
235
+
236
+ configureAddOns(hwElems: Array<RICHWElem>): Dictionary<RICAddOnBase> {
237
+ const addOnMap: Dictionary<RICAddOnBase> = {};
238
+ // Iterate HWElems to find addons
239
+ for (const hwElem of hwElems) {
240
+ RaftLog.debug(`configureAddOns whoAmITypeCode ${hwElem.whoAmI}`);
241
+
242
+ // Lookup the add-on
243
+ const lookupStr = hwElem.type + "_" + hwElem.whoAmI;
244
+ if (lookupStr in this._addOnFactoryMap) {
245
+ const addOnFactoryElem = this._addOnFactoryMap[lookupStr];
246
+ const whoAmILen = hwElem.whoAmITypeCode.length;
247
+ hwElem.whoAmITypeCode = hwElem.whoAmITypeCode.slice(
248
+ whoAmILen - 2,
249
+ whoAmILen
250
+ );
251
+ const addOn = addOnFactoryElem.factoryFn(
252
+ hwElem.name,
253
+ hwElem.type,
254
+ hwElem.whoAmI,
255
+ hwElem.whoAmITypeCode
256
+ );
257
+ if (addOn !== null) {
258
+ addOnMap[hwElem.IDNo.toString()] = addOn;
259
+ }
260
+ }
261
+ }
262
+ return addOnMap;
263
+ }
264
+
265
+ getHWElemTypeStr(
266
+ whoAmITypeCode: string | undefined,
267
+ whoAmI: string | undefined
268
+ ) {
269
+ RaftLog.debug(`getting type code for ${whoAmITypeCode}`);
270
+ if (whoAmITypeCode === undefined) {
271
+ return `Undefined whoamiTypeCode`;
272
+ }
273
+ if (whoAmITypeCode in this._addOnFactoryMap) {
274
+ return this._addOnFactoryMap[whoAmITypeCode].typeName;
275
+ }
276
+ return `Unknown (${whoAmI} - ${whoAmITypeCode})`;
277
+ }
278
+
279
+ processPublishedData(
280
+ addOnID: number,
281
+ statusByte: number,
282
+ rawData: Uint8Array
283
+ ): ROSSerialAddOnStatus | null {
284
+ // Lookup in map
285
+ const addOnIdStr = addOnID.toString();
286
+ if (addOnIdStr in this._configuredAddOns) {
287
+ const addOnHandler = this._configuredAddOns[addOnIdStr];
288
+ const data = addOnHandler.processPublishedData(
289
+ addOnID,
290
+ statusByte,
291
+ rawData
292
+ );
293
+ return data;
294
+ }
295
+ return null;
296
+ }
297
+ getIDNoFromName(name: string): string | null {
298
+ for (const key in this._configuredAddOns) {
299
+ if (key in this._configuredAddOns) {
300
+ if (this._configuredAddOns[key]._name == name) return key;
301
+ }
302
+ }
303
+ return null;
304
+ }
305
+
306
+ getInitCmds(): Array<string> {
307
+ const cmds: Array<string> = [];
308
+ for (const key in this._configuredAddOns) {
309
+ if (key in this._configuredAddOns) {
310
+ const initCmd = this._configuredAddOns[key]._initCmd;
311
+ if (initCmd) {
312
+ cmds.push(initCmd);
313
+ }
314
+ }
315
+ }
316
+ return cmds;
317
+ }
318
+
319
+ processReportMsg(reportMsgs: Array<RaftReportMsg>, timeInitStart: number) {
320
+ for (const reportID in reportMsgs) {
321
+ const report = reportMsgs[reportID];
322
+ //RaftLog.debug(`Report message: ${JSON.stringify(report)}`);
323
+ if (report.timeReceived && report.timeReceived < timeInitStart) {
324
+ continue;
325
+ }
326
+ if (report.elemName) {
327
+ let hwElemIDNoStr = "";
328
+ if (report.IDNo) {
329
+ hwElemIDNoStr = report.IDNo.toString();
330
+ } else if (report.elemName) {
331
+ const maybeIdno = this.getIDNoFromName(report.elemName);
332
+ if (maybeIdno) {
333
+ hwElemIDNoStr = maybeIdno;
334
+ }
335
+ }
336
+ if (hwElemIDNoStr.length > 0) {
337
+ this._configuredAddOns[hwElemIDNoStr].processInit(report);
338
+ }
339
+ }
340
+ }
341
+ }
342
+ }