@robdobsn/raftjs 1.8.5 → 1.10.7

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 (224) hide show
  1. package/.editorconfig +14 -0
  2. package/.gitattributes +11 -0
  3. package/.nvmrc +1 -0
  4. package/TODO.md +1 -0
  5. package/dist/react-native/RaftAttributeHandler.d.ts +14 -0
  6. package/dist/react-native/RaftAttributeHandler.js +375 -0
  7. package/dist/react-native/RaftAttributeHandler.js.map +1 -0
  8. package/dist/react-native/RaftChannel.d.ts +20 -0
  9. package/dist/react-native/RaftChannel.js +12 -0
  10. package/dist/react-native/RaftChannel.js.map +1 -0
  11. package/dist/react-native/RaftChannelBLE.native.d.ts +95 -0
  12. package/dist/react-native/RaftChannelBLE.native.js +483 -0
  13. package/dist/react-native/RaftChannelBLE.native.js.map +1 -0
  14. package/dist/react-native/RaftChannelBLE.web.d.ts +40 -0
  15. package/dist/react-native/RaftChannelBLE.web.js +302 -0
  16. package/dist/react-native/RaftChannelBLE.web.js.map +1 -0
  17. package/dist/react-native/RaftChannelBLEFactory.d.ts +10 -0
  18. package/dist/react-native/RaftChannelBLEFactory.js +17 -0
  19. package/dist/react-native/RaftChannelBLEFactory.js.map +1 -0
  20. package/dist/react-native/RaftChannelBLEScanner.native.d.ts +18 -0
  21. package/dist/react-native/RaftChannelBLEScanner.native.js +138 -0
  22. package/dist/react-native/RaftChannelBLEScanner.native.js.map +1 -0
  23. package/dist/react-native/RaftChannelSimulated.d.ts +42 -0
  24. package/dist/react-native/RaftChannelSimulated.js +1000 -0
  25. package/dist/react-native/RaftChannelSimulated.js.map +1 -0
  26. package/dist/react-native/RaftChannelWebSerial.d.ts +39 -0
  27. package/dist/react-native/RaftChannelWebSerial.js +329 -0
  28. package/dist/react-native/RaftChannelWebSerial.js.map +1 -0
  29. package/dist/react-native/RaftChannelWebSocket.d.ts +30 -0
  30. package/dist/react-native/RaftChannelWebSocket.js +222 -0
  31. package/dist/react-native/RaftChannelWebSocket.js.map +1 -0
  32. package/dist/react-native/RaftCommsStats.d.ts +39 -0
  33. package/dist/react-native/RaftCommsStats.js +128 -0
  34. package/dist/react-native/RaftCommsStats.js.map +1 -0
  35. package/dist/react-native/RaftConnEvents.d.ts +39 -0
  36. package/dist/react-native/RaftConnEvents.js +54 -0
  37. package/dist/react-native/RaftConnEvents.js.map +1 -0
  38. package/dist/react-native/RaftConnector.d.ts +248 -0
  39. package/dist/react-native/RaftConnector.js +658 -0
  40. package/dist/react-native/RaftConnector.js.map +1 -0
  41. package/dist/react-native/RaftCustomAttrHandler.d.ts +6 -0
  42. package/dist/react-native/RaftCustomAttrHandler.js +93 -0
  43. package/dist/react-native/RaftCustomAttrHandler.js.map +1 -0
  44. package/dist/react-native/RaftDeviceInfo.d.ts +71 -0
  45. package/dist/react-native/RaftDeviceInfo.js +50 -0
  46. package/dist/react-native/RaftDeviceInfo.js.map +1 -0
  47. package/dist/react-native/RaftDeviceManager.d.ts +61 -0
  48. package/dist/react-native/RaftDeviceManager.js +665 -0
  49. package/dist/react-native/RaftDeviceManager.js.map +1 -0
  50. package/dist/react-native/RaftDeviceMgrIF.d.ts +15 -0
  51. package/dist/react-native/RaftDeviceMgrIF.js +11 -0
  52. package/dist/react-native/RaftDeviceMgrIF.js.map +1 -0
  53. package/dist/react-native/RaftDeviceMsg.d.ts +9 -0
  54. package/dist/react-native/RaftDeviceMsg.js +11 -0
  55. package/dist/react-native/RaftDeviceMsg.js.map +1 -0
  56. package/dist/react-native/RaftDeviceStates.d.ts +37 -0
  57. package/dist/react-native/RaftDeviceStates.js +60 -0
  58. package/dist/react-native/RaftDeviceStates.js.map +1 -0
  59. package/dist/react-native/RaftFileHandler.d.ts +52 -0
  60. package/dist/react-native/RaftFileHandler.js +502 -0
  61. package/dist/react-native/RaftFileHandler.js.map +1 -0
  62. package/dist/react-native/RaftLog.d.ts +22 -0
  63. package/dist/react-native/RaftLog.js +63 -0
  64. package/dist/react-native/RaftLog.js.map +1 -0
  65. package/dist/react-native/RaftMiniHDLC.d.ts +18 -0
  66. package/dist/react-native/RaftMiniHDLC.js +383 -0
  67. package/dist/react-native/RaftMiniHDLC.js.map +1 -0
  68. package/dist/react-native/RaftMsgHandler.d.ts +62 -0
  69. package/dist/react-native/RaftMsgHandler.js +511 -0
  70. package/dist/react-native/RaftMsgHandler.js.map +1 -0
  71. package/dist/react-native/RaftMsgTrackInfo.d.ts +17 -0
  72. package/dist/react-native/RaftMsgTrackInfo.js +42 -0
  73. package/dist/react-native/RaftMsgTrackInfo.js.map +1 -0
  74. package/dist/react-native/RaftProtocolDefs.d.ts +30 -0
  75. package/dist/react-native/RaftProtocolDefs.js +48 -0
  76. package/dist/react-native/RaftProtocolDefs.js.map +1 -0
  77. package/dist/react-native/RaftStreamHandler.d.ts +38 -0
  78. package/dist/react-native/RaftStreamHandler.js +258 -0
  79. package/dist/react-native/RaftStreamHandler.js.map +1 -0
  80. package/dist/react-native/RaftStruct.d.ts +3 -0
  81. package/dist/react-native/RaftStruct.js +258 -0
  82. package/dist/react-native/RaftStruct.js.map +1 -0
  83. package/dist/react-native/RaftSysTypeManager.d.ts +16 -0
  84. package/dist/react-native/RaftSysTypeManager.js +78 -0
  85. package/dist/react-native/RaftSysTypeManager.js.map +1 -0
  86. package/dist/react-native/RaftSystemType.d.ts +30 -0
  87. package/dist/react-native/RaftSystemType.js +3 -0
  88. package/dist/react-native/RaftSystemType.js.map +1 -0
  89. package/dist/react-native/RaftSystemUtils.d.ts +136 -0
  90. package/dist/react-native/RaftSystemUtils.js +412 -0
  91. package/dist/react-native/RaftSystemUtils.js.map +1 -0
  92. package/dist/react-native/RaftTypes.d.ts +195 -0
  93. package/dist/react-native/RaftTypes.js +153 -0
  94. package/dist/react-native/RaftTypes.js.map +1 -0
  95. package/dist/react-native/RaftUpdateEvents.d.ts +33 -0
  96. package/dist/react-native/RaftUpdateEvents.js +46 -0
  97. package/dist/react-native/RaftUpdateEvents.js.map +1 -0
  98. package/dist/react-native/RaftUpdateManager.d.ts +61 -0
  99. package/dist/react-native/RaftUpdateManager.js +621 -0
  100. package/dist/react-native/RaftUpdateManager.js.map +1 -0
  101. package/dist/react-native/RaftUtils.d.ts +128 -0
  102. package/dist/react-native/RaftUtils.js +487 -0
  103. package/dist/react-native/RaftUtils.js.map +1 -0
  104. package/dist/react-native/RaftWifiTypes.d.ts +23 -0
  105. package/dist/react-native/RaftWifiTypes.js +43 -0
  106. package/dist/react-native/RaftWifiTypes.js.map +1 -0
  107. package/dist/react-native/main.d.ts +26 -0
  108. package/dist/react-native/main.js +51 -0
  109. package/dist/react-native/main.js.map +1 -0
  110. package/dist/web/RaftAttributeHandler.js +1 -1
  111. package/dist/web/RaftAttributeHandler.js.map +1 -1
  112. package/dist/web/RaftChannelBLE.web.js +8 -6
  113. package/dist/web/RaftChannelBLE.web.js.map +1 -1
  114. package/dist/web/RaftChannelSimulated.d.ts +10 -0
  115. package/dist/web/RaftChannelSimulated.js +662 -80
  116. package/dist/web/RaftChannelSimulated.js.map +1 -1
  117. package/dist/web/RaftChannelWebSerial.js +2 -2
  118. package/dist/web/RaftChannelWebSerial.js.map +1 -1
  119. package/dist/web/RaftChannelWebSocket.js +16 -1
  120. package/dist/web/RaftChannelWebSocket.js.map +1 -1
  121. package/dist/web/RaftConnector.d.ts +2 -0
  122. package/dist/web/RaftConnector.js +38 -15
  123. package/dist/web/RaftConnector.js.map +1 -1
  124. package/dist/web/RaftCustomAttrHandler.d.ts +2 -0
  125. package/dist/web/RaftCustomAttrHandler.js +54 -26
  126. package/dist/web/RaftCustomAttrHandler.js.map +1 -1
  127. package/dist/web/RaftDeviceInfo.d.ts +3 -1
  128. package/dist/web/RaftDeviceInfo.js +17 -3
  129. package/dist/web/RaftDeviceInfo.js.map +1 -1
  130. package/dist/web/RaftDeviceManager.d.ts +19 -1
  131. package/dist/web/RaftDeviceManager.js +89 -3
  132. package/dist/web/RaftDeviceManager.js.map +1 -1
  133. package/dist/web/RaftDeviceStates.d.ts +1 -1
  134. package/dist/web/RaftDeviceStates.js +2 -2
  135. package/dist/web/RaftDeviceStates.js.map +1 -1
  136. package/dist/web/RaftMsgHandler.js.map +1 -1
  137. package/dist/web/RaftStreamHandler.js +2 -1
  138. package/dist/web/RaftStreamHandler.js.map +1 -1
  139. package/dist/web/RaftStruct.js +197 -147
  140. package/dist/web/RaftStruct.js.map +1 -1
  141. package/dist/web/RaftUpdateManager.js +1 -1
  142. package/dist/web/RaftUpdateManager.js.map +1 -1
  143. package/dist/web/RaftUtils.d.ts +2 -0
  144. package/dist/web/RaftUtils.js +20 -0
  145. package/dist/web/RaftUtils.js.map +1 -1
  146. package/dist/web/main.d.ts +1 -0
  147. package/dist/web/main.js.map +1 -1
  148. package/eslint.config.mjs +33 -0
  149. package/examples/dashboard/package.json +36 -0
  150. package/examples/dashboard/src/CommandPanel.tsx +147 -0
  151. package/examples/dashboard/src/ConnManager.ts +166 -0
  152. package/examples/dashboard/src/DeviceActionsForm.tsx +133 -0
  153. package/examples/dashboard/src/DeviceAttrsForm.tsx +49 -0
  154. package/examples/dashboard/src/DeviceLineChart.tsx +163 -0
  155. package/examples/dashboard/src/DevicePanel.tsx +171 -0
  156. package/examples/dashboard/src/DevicesPanel.tsx +58 -0
  157. package/examples/dashboard/src/DispLedGrid.tsx +110 -0
  158. package/examples/dashboard/src/DispOneLed.tsx +20 -0
  159. package/examples/dashboard/src/LatencyTest.ts +130 -0
  160. package/examples/dashboard/src/LatencyTestPanel.tsx +92 -0
  161. package/examples/dashboard/src/Main.tsx +234 -0
  162. package/examples/dashboard/src/SettingsManager.ts +67 -0
  163. package/examples/dashboard/src/SettingsScreen.tsx +174 -0
  164. package/examples/dashboard/src/StatusPanel.tsx +71 -0
  165. package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +162 -0
  166. package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +91 -0
  167. package/examples/dashboard/src/SystemTypeGeneric/StateInfoGeneric.ts +30 -0
  168. package/examples/dashboard/src/SystemTypeGeneric/SystemTypeGeneric.ts +91 -0
  169. package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
  170. package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
  171. package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
  172. package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
  173. package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
  174. package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
  175. package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
  176. package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
  177. package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +97 -0
  178. package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
  179. package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
  180. package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +119 -0
  181. package/examples/dashboard/src/index.html +15 -0
  182. package/examples/dashboard/src/index.tsx +13 -0
  183. package/examples/dashboard/src/styles.css +408 -0
  184. package/examples/dashboard/tsconfig.json +18 -0
  185. package/jest.config.js +11 -0
  186. package/package.json +4 -7
  187. package/src/RaftAttributeHandler.ts +450 -0
  188. package/src/RaftChannel.ts +32 -0
  189. package/src/RaftChannelBLE.native.ts +617 -0
  190. package/src/RaftChannelBLE.web.ts +374 -0
  191. package/src/RaftChannelBLEFactory.ts +13 -0
  192. package/src/RaftChannelBLEScanner.native.ts +184 -0
  193. package/src/RaftChannelSimulated.ts +1176 -0
  194. package/src/RaftChannelWebSerial.ts +420 -0
  195. package/src/RaftChannelWebSocket.ts +272 -0
  196. package/src/RaftCommsStats.ts +142 -0
  197. package/src/RaftConnEvents.ts +58 -0
  198. package/src/RaftConnector.ts +785 -0
  199. package/src/RaftCustomAttrHandler.ts +117 -0
  200. package/src/RaftDeviceInfo.ts +125 -0
  201. package/src/RaftDeviceManager.ts +844 -0
  202. package/src/RaftDeviceMgrIF.ts +33 -0
  203. package/src/RaftDeviceMsg.ts +20 -0
  204. package/src/RaftDeviceStates.ts +92 -0
  205. package/src/RaftFileHandler.ts +668 -0
  206. package/src/RaftLog.ts +70 -0
  207. package/src/RaftMiniHDLC.ts +396 -0
  208. package/src/RaftMsgHandler.ts +812 -0
  209. package/src/RaftMsgTrackInfo.ts +51 -0
  210. package/src/RaftProtocolDefs.ts +46 -0
  211. package/src/RaftStreamHandler.ts +329 -0
  212. package/src/RaftStruct.ts +282 -0
  213. package/src/RaftSysTypeManager.ts +87 -0
  214. package/src/RaftSystemType.ts +34 -0
  215. package/src/RaftSystemUtils.ts +489 -0
  216. package/src/RaftTypes.ts +279 -0
  217. package/src/RaftUpdateEvents.ts +48 -0
  218. package/src/RaftUpdateManager.ts +781 -0
  219. package/src/RaftUtils.ts +514 -0
  220. package/src/RaftWifiTypes.ts +36 -0
  221. package/src/main.ts +39 -0
  222. package/testdata/TestDeviceTypeRecs.json +492 -0
  223. package/tsconfig.json +30 -0
  224. package/tsconfig.react-native.json +29 -0
@@ -0,0 +1,207 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RICJS
4
+ // Communications Library
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2022
7
+ // (C) 2020-2022
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ import { RaftConnEvent, RaftConnEventFn } from '../../../../src/RaftConnEvents';
12
+ import RaftLog from '../../../../src/RaftLog';
13
+ import RaftMsgHandler from '../../../../src/RaftMsgHandler';
14
+ import { RaftOKFail } from '../../../../src/RaftTypes';
15
+ import { RICLEDPatternCheckerColour, RICLedLcdColours } from './RICTypes';
16
+
17
+ export default class RICLEDPatternChecker {
18
+
19
+ // LED pattern refresh
20
+ private _ledPatternTimeoutMs = 10000;
21
+ private _ledPatternRefreshTimer: ReturnType<typeof setTimeout> | null = null;
22
+
23
+ // Verification of correct device
24
+ private _ledColours: Array<string> = new Array<string>();
25
+ private _lcdColours: Array<string> = new Array<string>();
26
+ private _bleVerifActive = false;
27
+
28
+ // Message handler, etc
29
+ private _msgHandler: RaftMsgHandler | null = null;
30
+ private _onConnEvent: RaftConnEventFn | null = null;
31
+ private _isConnectedFn: () => boolean = () => false;
32
+
33
+ /**
34
+ * Start checking correct RIC using LED pattern
35
+ *
36
+ * @param {RICLedLcdColours} ricLedLcdColours - available colours
37
+ * @param {RaftMsgHandler} msgHandler - message handler
38
+ * @param {RaftConnEventFn} onConnEvent - connection event handler
39
+ * @param {() => boolean} isConnectedFn - function to check if connected
40
+ * @return boolean - true if started ok
41
+ *
42
+ */
43
+ async checkCorrectRICStart(ricLedLcdColours: RICLedLcdColours,
44
+ msgHandler: RaftMsgHandler,
45
+ onConnEvent: RaftConnEventFn,
46
+ isConnectedFn: () => boolean): Promise<boolean> {
47
+
48
+ // Store the onConnEvent, etc
49
+ this._msgHandler = msgHandler;
50
+ this._onConnEvent = onConnEvent;
51
+ this._isConnectedFn = isConnectedFn;
52
+
53
+ // Set colour pattern checker colours
54
+ const randomColours = this.setupColours(ricLedLcdColours);
55
+
56
+ // Start timer to repeat checking LED pattern
57
+ RaftLog.debug(`checkCorrectRICStart: starting LED pattern checker`);
58
+ if (!await this._checkCorrectRICRefreshLEDs()) {
59
+ return false;
60
+ }
61
+
62
+ // Event
63
+ onConnEvent(RaftConnEvent.CONN_VERIFYING_CORRECT, randomColours);
64
+
65
+ // Start timer to repeat sending of LED pattern
66
+ // This is because RIC's LED pattern override times out after a while
67
+ // so has to be refreshed periodically
68
+ this._ledPatternRefreshTimer = setInterval(async () => {
69
+ RaftLog.verbose(`checkCorrectRICStart: loop`);
70
+ if (!this._checkCorrectRICRefreshLEDs()) {
71
+ RaftLog.debug('checkCorrectRICStart no longer active - clearing timer');
72
+ this._clearLedPatternRefreshTimer();
73
+ }
74
+ }, this._ledPatternTimeoutMs / 2.1);
75
+ return true;
76
+ }
77
+
78
+ /**
79
+ * Stop checking correct RIC
80
+ * @param {boolean} confirmCorrectRIC - true if user confirmed correct RIC
81
+ * @return void
82
+ *
83
+ */
84
+ async checkCorrectRICStop(confirmCorrectRIC: boolean): Promise<boolean> {
85
+
86
+ // Stop refreshing LED pattern on RIC
87
+ this._clearLedPatternRefreshTimer();
88
+
89
+ // Stop the LED pattern checker if connected
90
+ if (this._isConnectedFn()) {
91
+ await this.clearRICColors();
92
+ }
93
+
94
+ // Check correct
95
+ if (!confirmCorrectRIC) {
96
+ // Event
97
+ if (this._onConnEvent)
98
+ this._onConnEvent(RaftConnEvent.CONN_REJECTED);
99
+ // Indicate as rejected if we're not connected or if user didn't confirm
100
+ return false;
101
+ }
102
+ // Event
103
+ if (this._onConnEvent)
104
+ this._onConnEvent(RaftConnEvent.CONN_VERIFIED_CORRECT);
105
+ return true;
106
+ }
107
+
108
+ /**
109
+ * Refresh LED pattern on RIC
110
+ *
111
+ * @return boolean - true if checking still active
112
+ *
113
+ */
114
+ async _checkCorrectRICRefreshLEDs(): Promise<boolean> {
115
+ // Check LED pattern is active
116
+ if (!this.isActive()) {
117
+ return false;
118
+ }
119
+
120
+ // Check connected
121
+ RaftLog.debug(`_verificationRepeat getting isConnected`);
122
+ if (!this._isConnectedFn()) {
123
+ console.warn('_verificationRepeat not connected');
124
+ return false;
125
+ }
126
+
127
+ // Repeat the LED pattern (RIC times out the LED override after ~10 seconds)
128
+ RaftLog.debug(`_verificationRepeat setting pattern`);
129
+ return await this.setRICColors();
130
+ }
131
+
132
+ _clearLedPatternRefreshTimer(): void {
133
+ if (this._ledPatternRefreshTimer) {
134
+ clearInterval(this._ledPatternRefreshTimer);
135
+ this._ledPatternRefreshTimer = null;
136
+ }
137
+ }
138
+
139
+ isActive(): boolean {
140
+ return this._bleVerifActive;
141
+ }
142
+
143
+ clear(): void {
144
+ this._bleVerifActive = false;
145
+ }
146
+
147
+ setupColours(availableColors: RICLEDPatternCheckerColour[]): string[] {
148
+
149
+ // Check length of available colours
150
+ if (availableColors.length == 0) {
151
+ RaftLog.warn('start no available colours');
152
+ }
153
+
154
+ // Random colour selection
155
+ const LED_1 =
156
+ availableColors[Math.floor(Math.random() * availableColors.length)];
157
+ const LED_2 =
158
+ availableColors[Math.floor(Math.random() * availableColors.length)];
159
+ const LED_3 =
160
+ availableColors[Math.floor(Math.random() * availableColors.length)];
161
+
162
+ // LED and LCD colours are different to attempt to be visually similar
163
+ this._ledColours = [LED_1.led, LED_2.led, LED_3.led];
164
+ this._lcdColours = [LED_1.lcd, LED_2.lcd, LED_3.lcd];
165
+
166
+ // Set the colours to display on LEDs
167
+ this._bleVerifActive = true;
168
+
169
+ // Return LCD colours to display
170
+ return this._lcdColours;
171
+ }
172
+
173
+ async setRICColors(): Promise<boolean> {
174
+ // Set bonding colours
175
+ let colourSetStr = '';
176
+ for (let i = 0; i < this._ledColours.length; i++) {
177
+ if (i != 0) {
178
+ colourSetStr += '&';
179
+ }
180
+ let colr = this._ledColours[i];
181
+ if (colr.startsWith('#')) colr = colr.slice(1);
182
+ colourSetStr += `c${i}=${colr}`;
183
+ }
184
+ try {
185
+ RaftLog.debug('setRICColors setting colours');
186
+ if (this._msgHandler) {
187
+ await this._msgHandler.sendRICRESTURL<RaftOKFail>(`indicator/set?${colourSetStr}&ms=${this._ledPatternTimeoutMs}`);
188
+ }
189
+ } catch (error) {
190
+ RaftLog.debug(`setRICColors failed to send ${error}`);
191
+ return false;
192
+ }
193
+ return true;
194
+ }
195
+
196
+ async clearRICColors(): Promise<void> {
197
+ // Clear the LED colours
198
+ RaftLog.debug('clearRICColors');
199
+ try {
200
+ if (this._msgHandler) {
201
+ await this._msgHandler.sendRICRESTURL<RaftOKFail>(`indicator/resume`);
202
+ }
203
+ } catch (error) {
204
+ RaftLog.debug(`clearRICColors failed to send ${error}`);
205
+ }
206
+ }
207
+ }
@@ -0,0 +1,464 @@
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 RaftUtils from "../../../../src/RaftUtils";
13
+ import RICAddOnManager from "./RICAddOnManager";
14
+ import RICCommsStats from "./RICCommsStats";
15
+ import { RICStateInfo } from "./RICStateInfo";
16
+
17
+ export class ROSSerialSmartServos {
18
+ smartServos: {
19
+ id: number;
20
+ pos: number;
21
+ current: number;
22
+ status: number;
23
+ }[] = [];
24
+ }
25
+
26
+ export class ROSSerialIMU {
27
+ accel: {
28
+ x: number;
29
+ y: number;
30
+ z: number;
31
+ } = { x: 0, y: 0, z: 0 };
32
+ }
33
+
34
+ export class ROSSerialPowerStatus {
35
+ powerStatus: {
36
+ battRemainCapacityPercent: number;
37
+ battTempDegC: number;
38
+ battRemainCapacityMAH: number;
39
+ battFullCapacityMAH: number;
40
+ battCurrentMA: number;
41
+ power5VOnTimeSecs: number;
42
+ power5VIsOn: boolean;
43
+ powerUSBIsConnected: boolean;
44
+ battInfoValid: boolean;
45
+ powerUSBIsValid: boolean;
46
+ powerFlags: number;
47
+ } = {
48
+ battRemainCapacityPercent: 0,
49
+ battTempDegC: 0,
50
+ battRemainCapacityMAH: 0,
51
+ battFullCapacityMAH: 0,
52
+ battCurrentMA: 0,
53
+ power5VOnTimeSecs: 0,
54
+ power5VIsOn: false,
55
+ powerUSBIsConnected: false,
56
+ battInfoValid: false,
57
+ powerUSBIsValid: false,
58
+ powerFlags: 0,
59
+ };
60
+ }
61
+
62
+ export class ROSSerialAddOnStatus {
63
+ id = 0;
64
+ deviceTypeID = 0;
65
+ whoAmI = "";
66
+ name = "";
67
+ status = 0;
68
+ vals: { [key: string]: number | boolean | string} = {};
69
+ }
70
+
71
+ export class ROSSerialAddOnStatusList {
72
+ addons: Array<ROSSerialAddOnStatus> = new Array<ROSSerialAddOnStatus>();
73
+ }
74
+
75
+ export class ROSSerialRGBT {
76
+ r = 0;
77
+ g = 0;
78
+ b = 0;
79
+ t = 0;
80
+ constructor(r: number, g: number, b: number, t: number) {
81
+ this.r = r;
82
+ this.g = g;
83
+ this.b = b;
84
+ this.t = t;
85
+ }
86
+ toString() {
87
+ return `R:${this.r} G:${this.g} B:${this.b} T:${this.t}`;
88
+ }
89
+ }
90
+
91
+ export class ROSSerialRobotStatus {
92
+ robotStatus: {
93
+ flags: number;
94
+ isMoving: boolean;
95
+ isPaused: boolean;
96
+ isFwUpdating: boolean;
97
+ workQCount: number;
98
+ heapFree: number;
99
+ heapMin: number;
100
+ pixRGBT: ROSSerialRGBT[];
101
+ loopMsAvg: number;
102
+ loopMsMax: number;
103
+ wifiRSSI: number;
104
+ bleRSSI: number;
105
+ } = {
106
+ flags: 0,
107
+ isMoving: false,
108
+ isPaused: false,
109
+ isFwUpdating: false,
110
+ workQCount: 0,
111
+ heapFree: 0,
112
+ heapMin: 0,
113
+ pixRGBT: [],
114
+ loopMsAvg: 0,
115
+ loopMsMax: 0,
116
+ wifiRSSI: 0,
117
+ bleRSSI: 0,
118
+ };
119
+ }
120
+
121
+ export class ROSCameraData {
122
+ cameraData: {
123
+ unixTimeMs: number;
124
+ sinceStartMs: number;
125
+ imageData: Uint8Array;
126
+ imageWidth: number,
127
+ imageHeight: number,
128
+ imageFormat: number,
129
+ imageQuality: number,
130
+ frameTimeMs: number,
131
+ imageCount: number
132
+ } = {
133
+ unixTimeMs: 0,
134
+ sinceStartMs: 0,
135
+ imageData: new Uint8Array(0),
136
+ imageWidth: 0,
137
+ imageHeight: 0,
138
+ imageFormat: 0,
139
+ imageQuality: 0,
140
+ frameTimeMs: 0,
141
+ imageCount: 0
142
+ };
143
+ }
144
+
145
+ export type ROSSerialMsg =
146
+ | ROSSerialSmartServos
147
+ | ROSSerialIMU
148
+ | ROSSerialPowerStatus
149
+ | ROSSerialAddOnStatusList
150
+ | ROSSerialRobotStatus;
151
+
152
+ // ROSSerial ROSTopics
153
+ export const ROSTOPIC_V2_SMART_SERVOS = 120;
154
+ export const ROSTOPIC_V2_ACCEL = 121;
155
+ export const ROSTOPIC_V2_POWER_STATUS = 122;
156
+ export const ROSTOPIC_V2_ADDONS = 123;
157
+ export const ROSTOPIC_V2_ROBOT_STATUS = 124;
158
+ export const ROSTOPIC_V2_CAMERA = 200;
159
+
160
+ export class RICROSSerial {
161
+
162
+ static decode(
163
+ rosSerialMsg: Uint8Array,
164
+ startPos: number,
165
+ commsStats: RICCommsStats,
166
+ addOnManager: RICAddOnManager,
167
+ ricStateInfo: RICStateInfo,
168
+ frameTimeMs: number
169
+ ): Array<number> {
170
+
171
+ // ROSSerial message format
172
+ const RS_MSG_MIN_LENGTH = 8;
173
+ const RS_MSG_LEN_LOW_POS = 2;
174
+ const RS_MSG_LEN_HIGH_POS = 3;
175
+ const RS_MSG_TOPIC_ID_LOW_POS = 5;
176
+ const RS_MSG_TOPIC_ID_HIGH_POS = 6;
177
+ const RS_MSG_PAYLOAD_POS = 7;
178
+
179
+ // Max payload length
180
+ const MAX_VALID_PAYLOAD_LEN = 200000;
181
+
182
+ // Update stats
183
+ commsStats.updateROSSerialRxRate(rosSerialMsg.length, frameTimeMs);
184
+
185
+ // Payload may contain multiple ROSSerial messages
186
+ let msgPos = startPos;
187
+ const topicIDs = new Array<number>();
188
+ for (;;) {
189
+ const remainingMsgLen = rosSerialMsg.length - msgPos;
190
+
191
+ // RaftLog.debug('ROSSerial Decode ' + remainingMsgLen);
192
+
193
+ if (remainingMsgLen < RS_MSG_MIN_LENGTH) break;
194
+
195
+ // Extract header
196
+ const payloadLength =
197
+ rosSerialMsg[msgPos + RS_MSG_LEN_LOW_POS] +
198
+ rosSerialMsg[msgPos + RS_MSG_LEN_HIGH_POS] * 256;
199
+ const topicID =
200
+ rosSerialMsg[msgPos + RS_MSG_TOPIC_ID_LOW_POS] +
201
+ rosSerialMsg[msgPos + RS_MSG_TOPIC_ID_HIGH_POS] * 256;
202
+
203
+ // RaftLog.debug('ROSSerial ' + payloadLength + ' topic ' + topicID);
204
+
205
+ // Check max length
206
+ if (payloadLength < 0 || payloadLength > MAX_VALID_PAYLOAD_LEN) break;
207
+
208
+ // Check min length
209
+ if (rosSerialMsg.length < payloadLength + RS_MSG_MIN_LENGTH) break;
210
+
211
+ // Extract payload
212
+ const payload = rosSerialMsg.slice(
213
+ msgPos + RS_MSG_PAYLOAD_POS,
214
+ msgPos + RS_MSG_PAYLOAD_POS + payloadLength
215
+ );
216
+ // RaftLog.debug('ROSSerial ' + RaftUtils.bufferToHex(payload));
217
+
218
+ // we need to register the static addons here in case
219
+ // marty only has static addons (and so the rostopic_v2_addons case
220
+ // never runs)
221
+ let allAdons: ROSSerialAddOnStatusList = {addons: []};
222
+ const staticAddons = addOnManager.getProcessedStaticAddons();
223
+ for (const staticAddon of staticAddons) {
224
+ allAdons.addons.push(staticAddon);
225
+ }
226
+ if (commsStats._msgAddOnPub === 0) {
227
+ // we set the static addons only if we don't have any other addons
228
+ // the _msgAddOnPub is incremented in the rostopic_v2_addons case
229
+ // (when we get addons from marty)
230
+ // otherwise, the static addons will be set along with the regular addons (below)
231
+ ricStateInfo.addOnInfo = allAdons;
232
+ ricStateInfo.addOnInfoValidMs = Date.now();
233
+ }
234
+
235
+ // Record topic ID
236
+ topicIDs.push(topicID);
237
+
238
+ // Update state info
239
+ switch (topicID) {
240
+ case ROSTOPIC_V2_SMART_SERVOS:
241
+ // Smart Servos
242
+ ricStateInfo.smartServos = this.extractSmartServos(payload);
243
+ ricStateInfo.smartServosValidMs = Date.now();
244
+ commsStats.recordSmartServos();
245
+ break;
246
+ case ROSTOPIC_V2_ACCEL:
247
+ // Accelerometer
248
+ ricStateInfo.imuData = this.extractAccel(payload);
249
+ ricStateInfo.imuDataValidMs = Date.now();
250
+ commsStats.recordIMU();
251
+ break;
252
+ case ROSTOPIC_V2_POWER_STATUS:
253
+ // Power Status
254
+ ricStateInfo.power = this.extractPowerStatus(payload);
255
+ ricStateInfo.powerValidMs = Date.now();
256
+ commsStats.recordPowerStatus();
257
+ break;
258
+ case ROSTOPIC_V2_ADDONS:
259
+ // Addons
260
+ ricStateInfo.addOnInfo = this.extractAddOnStatus(payload, addOnManager);
261
+ ricStateInfo.addOnInfoValidMs = Date.now();
262
+ for (const staticAddon of staticAddons) {
263
+ allAdons.addons.push(staticAddon);
264
+ }
265
+ commsStats.recordAddOnPub();
266
+ break;
267
+ case ROSTOPIC_V2_ROBOT_STATUS:
268
+ // Robot Status
269
+ ricStateInfo.robotStatus = this.extractRobotStatus(payload);
270
+ ricStateInfo.robotStatusValidMs = Date.now();
271
+ commsStats.recordRobotStatus();
272
+ break;
273
+ case ROSTOPIC_V2_CAMERA:
274
+ // Camera
275
+ // RaftLog.debug('Camera ' + payloadLength);
276
+ ricStateInfo.cameraData = this.extractCameraData(payload, frameTimeMs);
277
+ ricStateInfo.cameraDataValidMs = Date.now();
278
+ commsStats.recordOtherTopic();
279
+ break;
280
+ default:
281
+ // Unknown topic
282
+ commsStats.recordOtherTopic();
283
+ break;
284
+ }
285
+
286
+ // Move msgPos on
287
+ msgPos += RS_MSG_PAYLOAD_POS + payloadLength + 1;
288
+
289
+ // RaftLog.debug('MsgPos ' + msgPos);
290
+ }
291
+
292
+ return topicIDs;
293
+ }
294
+
295
+ static extractSmartServos(buf: Uint8Array): ROSSerialSmartServos {
296
+ // Each group of attributes for a servo is a fixed size
297
+ const ROS_SMART_SERVOS_ATTR_GROUP_BYTES = 6;
298
+ const numGroups = Math.floor(
299
+ buf.length / ROS_SMART_SERVOS_ATTR_GROUP_BYTES
300
+ );
301
+ const msg: ROSSerialSmartServos = { smartServos: [] };
302
+ let bufPos = 0;
303
+ for (let i = 0; i < numGroups; i++) {
304
+ const servoId = buf[bufPos];
305
+ const servoPos = RaftUtils.getBEInt16FromBuf(buf, bufPos + 1);
306
+ const servoCurrent = RaftUtils.getBEUint16FromBuf(buf, bufPos + 3);
307
+ const servoStatus = buf[bufPos + 5];
308
+ bufPos += ROS_SMART_SERVOS_ATTR_GROUP_BYTES;
309
+ msg.smartServos.push({
310
+ id: servoId,
311
+ pos: servoPos,
312
+ current: servoCurrent,
313
+ status: servoStatus,
314
+ });
315
+ }
316
+ return msg;
317
+ }
318
+
319
+ static extractAccel(buf: Uint8Array): ROSSerialIMU {
320
+ // Three accelerometer floats
321
+ const x = RaftUtils.getBEFloatFromBuf(buf);
322
+ const y = RaftUtils.getBEFloatFromBuf(buf.slice(4));
323
+ const z = RaftUtils.getBEFloatFromBuf(buf.slice(8));
324
+ return { accel: { x: x / 1024, y: y / 1024, z: z / 1024 } };
325
+ }
326
+
327
+ static extractPowerStatus(buf: Uint8Array): ROSSerialPowerStatus {
328
+ // Power indicator values
329
+ // RaftLog.debug(`PowerStatus ${RaftUtils.bufferToHex(buf)}`);
330
+ const remCapPC = RaftUtils.getBEUint8FromBuf(buf, 0);
331
+ const tempDegC = RaftUtils.getBEUint8FromBuf(buf, 1);
332
+ const remCapMAH = RaftUtils.getBEUint16FromBuf(buf, 2);
333
+ const fullCapMAH = RaftUtils.getBEUint16FromBuf(buf, 4);
334
+ const currentMA = RaftUtils.getBEInt16FromBuf(buf, 6);
335
+ const power5VOnTimeSecs = RaftUtils.getBEUint16FromBuf(buf, 8);
336
+ const powerFlags = RaftUtils.getBEUint16FromBuf(buf, 10);
337
+ const isOnUSBPower = (powerFlags & 0x0001) != 0;
338
+ const is5VOn = (powerFlags & 0x0002) != 0;
339
+ const isBattInfoValid = (powerFlags & 0x0004) == 0;
340
+ const isUSBPowerInfoValid = (powerFlags & 0x0008) == 0;
341
+ return {
342
+ powerStatus: {
343
+ battRemainCapacityPercent: remCapPC,
344
+ battTempDegC: tempDegC,
345
+ battRemainCapacityMAH: remCapMAH,
346
+ battFullCapacityMAH: fullCapMAH,
347
+ battCurrentMA: currentMA,
348
+ power5VOnTimeSecs: power5VOnTimeSecs,
349
+ power5VIsOn: is5VOn,
350
+ powerUSBIsConnected: isOnUSBPower && isUSBPowerInfoValid,
351
+ battInfoValid: isBattInfoValid,
352
+ powerUSBIsValid: isUSBPowerInfoValid,
353
+ powerFlags: powerFlags,
354
+ },
355
+ };
356
+ }
357
+
358
+ static extractAddOnStatus(
359
+ buf: Uint8Array,
360
+ addOnManager: RICAddOnManager
361
+ ): ROSSerialAddOnStatusList {
362
+ // RaftLog.debug(`AddOnRawData ${RaftUtils.bufferToHex(buf)}`);
363
+ // Each group of attributes for a add-on is a fixed size
364
+ const ROS_ADDON_ATTR_GROUP_BYTES = 12;
365
+ const numGroups = Math.floor(buf.length / ROS_ADDON_ATTR_GROUP_BYTES);
366
+ const msg: ROSSerialAddOnStatusList = { addons: [] };
367
+ let bufPos = 0;
368
+ for (let i = 0; i < numGroups; i++) {
369
+ const addOnId = buf[bufPos];
370
+ const status = buf[bufPos + 1];
371
+ const addOnData = buf.slice(bufPos + 2, bufPos + 12);
372
+ bufPos += ROS_ADDON_ATTR_GROUP_BYTES;
373
+ const addOnRec = addOnManager.processPublishedData(
374
+ addOnId,
375
+ status,
376
+ addOnData
377
+ );
378
+ if (addOnRec !== null) {
379
+ msg.addons.push(addOnRec);
380
+ }
381
+ }
382
+ return msg;
383
+ }
384
+
385
+ static extractRGBT(buf: Uint8Array, offset: number): ROSSerialRGBT {
386
+ return new ROSSerialRGBT(
387
+ buf[offset],
388
+ buf[offset + 1],
389
+ buf[offset + 2],
390
+ buf[offset + 3]
391
+ );
392
+ }
393
+
394
+ static extractRobotStatus(buf: Uint8Array): ROSSerialRobotStatus {
395
+ const flags = RaftUtils.getBEUint8FromBuf(buf, 0);
396
+ const workQCount = RaftUtils.getBEUint8FromBuf(buf, 1);
397
+ let heapFree = 0;
398
+ let heapMin = 0;
399
+ let pixRGBT1 = new ROSSerialRGBT(0, 0, 0, 0);
400
+ let pixRGBT2 = new ROSSerialRGBT(0, 0, 0, 0);
401
+ let pixRGBT3 = new ROSSerialRGBT(0, 0, 0, 0);
402
+ let loopMsAvg = 0;
403
+ let loopMsMax = 0;
404
+ // RaftLog.debug(`RobotStatus ${buf.length} ${RaftUtils.bufferToHex(buf)} ${flags} ${workQCount} ${heapFree} ${heapMin} ${pixRGBT1.toString()} ${pixRGBT2.toString()} ${pixRGBT3.toString()} ${loopMsAvg} ${loopMsMax}`);
405
+ let wifiRSSI = 0;
406
+ let bleRSSI = 0;
407
+
408
+ if (buf.length >= 24) {
409
+ heapFree = RaftUtils.getBEUint32FromBuf(buf, 2);
410
+ heapMin = RaftUtils.getBEUint32FromBuf(buf, 6);
411
+ pixRGBT1 = RICROSSerial.extractRGBT(buf, 10);
412
+ pixRGBT2 = RICROSSerial.extractRGBT(buf, 14);
413
+ pixRGBT3 = RICROSSerial.extractRGBT(buf, 18);
414
+ loopMsAvg = RaftUtils.getBEUint8FromBuf(buf, 22);
415
+ loopMsMax = RaftUtils.getBEUint8FromBuf(buf, 23);
416
+ // RaftLog.debug(`RobotStatus ${buf.length} ${RaftUtils.bufferToHex(buf)} ${flags} ${workQCount} ${heapFree} ${heapMin} ${pixRGBT1.toString()} ${pixRGBT2.toString()} ${pixRGBT3.toString()} ${loopMsAvg} ${loopMsMax}`);
417
+ if (buf.length >= 26) {
418
+ wifiRSSI = RaftUtils.getBEInt8FromBuf(buf, 24);
419
+ bleRSSI = RaftUtils.getBEInt8FromBuf(buf, 25);
420
+ }
421
+ }
422
+ return {
423
+ robotStatus: {
424
+ flags: flags,
425
+ isMoving: (flags & 0x01) != 0,
426
+ isPaused: (flags & 0x02) != 0,
427
+ isFwUpdating: (flags & 0x04) != 0,
428
+ workQCount: workQCount,
429
+ heapFree: heapFree,
430
+ heapMin: heapMin,
431
+ pixRGBT: [pixRGBT1, pixRGBT2, pixRGBT3],
432
+ loopMsAvg: loopMsAvg,
433
+ loopMsMax: loopMsMax,
434
+ wifiRSSI: wifiRSSI,
435
+ bleRSSI: bleRSSI,
436
+ },
437
+ };
438
+ }
439
+
440
+ static extractCameraData(buf: Uint8Array, frameTimeMs: number): ROSCameraData {
441
+ RaftLog.verbose(`CameraData ${buf.length} ${RaftUtils.bufferToHex(buf.slice(0,30))}`);
442
+ const unixTime = RaftUtils.getBEUint64FromBuf(buf, 0);
443
+ const sinceStartMs = RaftUtils.getBEUint32FromBuf(buf, 8);
444
+ const imageWidth = RaftUtils.getBEUint16FromBuf(buf, 12);
445
+ const imageHeight = RaftUtils.getBEUint16FromBuf(buf, 14);
446
+ const imageFormat = RaftUtils.getBEUint8FromBuf(buf, 16);
447
+ const imageQuality = RaftUtils.getBEUint8FromBuf(buf, 17);
448
+ const imageCount = RaftUtils.getBEUint32FromBuf(buf, 18);
449
+ const imageData = buf.slice(22);
450
+ return { cameraData:
451
+ {
452
+ unixTimeMs: unixTime,
453
+ sinceStartMs: sinceStartMs,
454
+ imageWidth: imageWidth,
455
+ imageHeight: imageHeight,
456
+ imageFormat: imageFormat,
457
+ imageQuality: imageQuality,
458
+ imageData: imageData,
459
+ frameTimeMs: frameTimeMs,
460
+ imageCount: imageCount
461
+ }
462
+ };
463
+ }
464
+ }