@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,371 @@
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 { RaftOKFail, RaftReportMsg } from "../../../../src/RaftTypes";
14
+ import { RICConfiguredAddOns } from "./RICAddOn";
15
+ import RICAddOnManager from "./RICAddOnManager";
16
+ import { RICHWElem, RICHWElemList, RICHWElemList_Str } from "./RICHWElem";
17
+ import { RICCalibInfo } from "./RICTypes";
18
+
19
+ export default class RICSystemUtils {
20
+
21
+ // Message handler
22
+ private _msgHandler: RaftMsgHandler;
23
+
24
+ // Add-on manager
25
+ private _addOnManager: RICAddOnManager;
26
+
27
+ // HWElems (connected to RIC) - excluding AddOns
28
+ private _hwElemsExcludingAddOns: Array<RICHWElem> = new Array<RICHWElem>();
29
+ private _connectedAddOns: Array<RICHWElem> = new Array<RICHWElem>();
30
+
31
+ // Calibration info
32
+ private _calibInfo: RICCalibInfo | null = null;
33
+
34
+ /**
35
+ * constructor
36
+ * @param raftMsgHandler
37
+ * @param addOnManager
38
+ */
39
+ constructor(msgHandler: RaftMsgHandler, addOnManager: RICAddOnManager) {
40
+ this._msgHandler = msgHandler;
41
+ this._addOnManager = addOnManager;
42
+ }
43
+
44
+ /**
45
+ * invalidate
46
+ */
47
+ invalidate() {
48
+ // Invalidate system info
49
+ this._hwElemsExcludingAddOns = new Array<RICHWElem>();
50
+ this._connectedAddOns = new Array<RICHWElem>();
51
+ this._addOnManager.clear();
52
+ this._calibInfo = null;
53
+ RaftLog.debug("RICSystem information invalidated");
54
+ }
55
+
56
+ /**
57
+ * getSystemInfo - get system info
58
+ * @returns Promise<RICSystemInfo>
59
+ *
60
+ */
61
+ async retrieveInfo(): Promise<boolean> {
62
+ // Get HWElems (connected to RIC)
63
+ try {
64
+ await this.getHWElemList();
65
+ } catch (error) {
66
+ RaftLog.warn("retrieveInfo - failed to get HWElems " + error);
67
+ return false;
68
+ }
69
+
70
+ // Get calibration info
71
+ try {
72
+ await this.getRICCalibInfo(true);
73
+ } catch (error) {
74
+ RaftLog.warn("retrieveInfo - failed to get calib info " + error);
75
+ return false;
76
+ }
77
+
78
+ // Get HWElems (connected to RIC)
79
+ try {
80
+ await this.getHWElemList();
81
+ } catch (error) {
82
+ RaftLog.warn("retrieveInfo - failed to get HWElems " + error);
83
+ return false;
84
+ }
85
+ return true;
86
+ }
87
+
88
+ /**
89
+ * Get information Marty system
90
+ *
91
+ * @return void
92
+ *
93
+ */
94
+ async retrieveMartySystemInfo(): Promise<boolean> {
95
+
96
+ // Retrieve system info
97
+ try {
98
+ const retrieveResult = await this.retrieveInfo();
99
+ return retrieveResult;
100
+ } catch (err) {
101
+ RaftLog.error(`retrieveMartySystemInfo: error ${err}`);
102
+ }
103
+ return false;
104
+ }
105
+
106
+ // Mark: Calibration -----------------------------------------------------------------------------------------
107
+
108
+ async calibrate(
109
+ cmd: string,
110
+ jointList: Array<string>,
111
+ jointNames: { [key: string]: string }
112
+ ) {
113
+ let overallResult = true;
114
+ if (cmd === "set") {
115
+ // Set calibration
116
+ for (const jnt of jointList) {
117
+ try {
118
+ // Set calibration on joint
119
+ const cmdUrl = "calibrate/set/" + jnt;
120
+ const rsl = await this._msgHandler.sendRICRESTURL<RaftOKFail>(
121
+ cmdUrl
122
+ );
123
+ // saving the calibration... (For the new servo boards it is necessary
124
+ // to send a "save" command after the calibration ones or any servo
125
+ // parameter changes in order to save any changes made into nonvolatile storage)
126
+ const saveCalibCmd = `elem/${jnt}/saveparams`;
127
+ await this._msgHandler.sendRICRESTURL<RaftOKFail>(saveCalibCmd);
128
+ if (rsl.rslt != "ok") overallResult = false;
129
+ } catch (error) {
130
+ console.log(`calibrate failed on joint ${jnt}`, error);
131
+ }
132
+
133
+ // Wait as writing to flash blocks servo access
134
+ // as of v0.0.113 of firmware, the pause is no longer required
135
+ //await new Promise(resolve => setTimeout(resolve, 3000));
136
+ }
137
+
138
+ // ensure all joints are enabled
139
+ for (const jnt in jointNames) {
140
+ try {
141
+ // enable joint
142
+ const cmdUrl = "servo/" + jnt + "/enable/1";
143
+ const rsl = await this._msgHandler.sendRICRESTURL<RaftOKFail>(
144
+ cmdUrl
145
+ );
146
+ if (rsl.rslt != "ok") overallResult = false;
147
+ } catch (error) {
148
+ console.log(`enable failed on joint ${jnt}`, error);
149
+ }
150
+ }
151
+
152
+ // Result
153
+ console.log("Set calibration flag to true");
154
+ const rslt = new RaftOKFail();
155
+ rslt.set(overallResult);
156
+ return rslt;
157
+ }
158
+ return false;
159
+ }
160
+
161
+ /**
162
+ *
163
+ * getRICCalibInfo
164
+ * @returns Promise<RICCalibInfo>
165
+ *
166
+ */
167
+ async getRICCalibInfo(forceGetFromRIC = false): Promise<RICCalibInfo> {
168
+ if (!forceGetFromRIC && this._calibInfo) {
169
+ return this._calibInfo;
170
+ }
171
+ try {
172
+ this._calibInfo = await this._msgHandler.sendRICRESTURL<RICCalibInfo>(
173
+ "calibrate"
174
+ );
175
+ RaftLog.debug("getRICCalibInfo returned " + this._calibInfo);
176
+ this._calibInfo.validMs = Date.now();
177
+ return this._calibInfo;
178
+ } catch (error) {
179
+ RaftLog.debug(`getRICCalibInfo Failed to get version ${error}`);
180
+ return new RICCalibInfo();
181
+ }
182
+ }
183
+
184
+ /**
185
+ *
186
+ * getHWElemList - get the list of hardware elements connected to the robot
187
+ * - the result (if successful) is processed as follows:
188
+ * = if no filter is applied then all non-add-ons found are stored in
189
+ * this._hwElemsExcludingAddOns and all addons are stored in this._connectedAddOns
190
+ * = if a filter is applied and this filter is RSAddOns then this._connectedAddOns is
191
+ * updated with the new list of addons
192
+ * = in all cases the discovered list is returned
193
+ *
194
+ * @returns Promise<RICHWElemList>
195
+ *
196
+ */
197
+
198
+ async getHWElemList(filterByType?: string): Promise<Array<RICHWElem>> {
199
+ // Form a list of the requests to make
200
+ const reqList: Array<string> = [];
201
+ let addToNonAddOnsList = false;
202
+ if (!filterByType) {
203
+ reqList.push("SmartServo");
204
+ reqList.push("RSAddOn");
205
+ reqList.push("BusPixels");
206
+ reqList.push("!SmartServo,RSAddOn,BusPixels"); // not SmartServo or RSAddOn or BusPixels
207
+ this._hwElemsExcludingAddOns = new Array<RICHWElem>();
208
+ addToNonAddOnsList = true;
209
+ } else if (filterByType === "RSAddOn") {
210
+ // we treat BusPixels as an RSAddOn
211
+ // (batch 4 led eye add-ons have type BusPixels)
212
+ reqList.push("RSAddOn");
213
+ reqList.push("BusPixels");
214
+ this._connectedAddOns = new Array<RICHWElem>();
215
+ } else {
216
+ reqList.push(filterByType);
217
+ }
218
+
219
+ // Make the requests
220
+ const fullListOfElems = new Array<RICHWElem>();
221
+ this._connectedAddOns = [];
222
+ for (const reqType of reqList) {
223
+ try {
224
+ const hwElemList_Str = await this._msgHandler.sendRICRESTURL<
225
+ RICHWElemList_Str
226
+ >(`hwstatus/strstat?filterByType=${reqType}`);
227
+ // if the results of hwElem indicates that we are on an older fw version
228
+ // send the old hwstatus command and don't expand()
229
+ // the logic behind deciding if we are on a fw version that
230
+ // supports strstat is: given that hwElemList_Str.hw === object[]
231
+ // if we get back string[], then we know we are on an older version
232
+ // if hw === empty array, then we don't have any hw elems in which
233
+ // case we can stop at that point
234
+ const hwElems = hwElemList_Str.hw;
235
+ let hwElemList;
236
+ if (hwElems.length) {
237
+ if (typeof hwElems[0] !== "object") {
238
+ // we are on an older version
239
+ hwElemList = await this._msgHandler.sendRICRESTURL<
240
+ RICHWElemList
241
+ >(`hwstatus?filterByType=${reqType}`);
242
+ } else {
243
+ // we are on the fw version that supports strstat
244
+ hwElemList = RICHWElemList_Str.expand(hwElemList_Str);
245
+ }
246
+ }
247
+ if (hwElemList && hwElemList.rslt && hwElemList.rslt === "ok") {
248
+ fullListOfElems.push(...hwElemList.hw);
249
+ if (reqType === "RSAddOn") {
250
+ this._connectedAddOns = hwElemList.hw;
251
+ this._addOnManager.setHWElems(this._connectedAddOns);
252
+ // Debug
253
+ RaftLog.debug(
254
+ `getHWElemList: found ${hwElemList.hw.length} addons/buspixels`
255
+ );
256
+ } else if (reqType === "BusPixels") {
257
+ // BusPixels are treated as an RSAddOn
258
+ this._connectedAddOns.push(...hwElemList.hw);
259
+ this._addOnManager.setHWElems(this._connectedAddOns);
260
+ // Debug
261
+ RaftLog.debug(
262
+ `getHWElemList: found ${hwElemList.hw.length} addons/buspixels`
263
+
264
+ } else if (addToNonAddOnsList) {
265
+ this._hwElemsExcludingAddOns.push(...hwElemList.hw);
266
+ // Debug
267
+ RaftLog.debug(
268
+ `getHWElemList: found ${hwElemList.hw.length} elems matching ${reqType}`
269
+ );
270
+ }
271
+ }
272
+ } catch (error) {
273
+ RaftLog.debug(`getHWElemList failed to get ${reqType} ${error}`);
274
+ return new Array<RICHWElem>();
275
+ }
276
+ }
277
+
278
+ // Handle any callbacks
279
+ try {
280
+ const reports: Array<RaftReportMsg> = [];
281
+ // add callback to subscribe to report messages
282
+ this._msgHandler.reportMsgCallbacksSet("getHWElemCB", function (
283
+ report: RaftReportMsg
284
+ ) {
285
+ reports.push(report);
286
+ RaftLog.debug(`getHWElemCB Report callback ${JSON.stringify(report)}`);
287
+ });
288
+
289
+ // run any required initialisation for the addons
290
+ const initCmds = this._addOnManager.getInitCmds();
291
+ // send init commands to the robot
292
+ const timeInitStart = Date.now();
293
+ for (let i = 0; i < initCmds.length; i++) {
294
+ this.runCommand(initCmds[i], {});
295
+ }
296
+ // wait a couple of seconds for any report messages to be received
297
+ await new Promise((resolve) => setTimeout(resolve, 2000));
298
+ // pass report messages to add on manager for processing
299
+ this._addOnManager.processReportMsg(reports, timeInitStart);
300
+
301
+ // clean up callback
302
+ this._msgHandler.reportMsgCallbacksDelete("getHWElemCB");
303
+ } catch (error) {
304
+ RaftLog.debug(`getHWElemList failed processing callback reports ${error}`);
305
+ return new Array<RICHWElem>();
306
+ }
307
+
308
+ // return the full list of elements
309
+ return fullListOfElems;
310
+ }
311
+
312
+ /**
313
+ *
314
+ * getAddOnConfigs - get list of add-ons configured on the robot
315
+ * @returns Promise<RICConfiguredAddOns>
316
+ *
317
+ */
318
+ async getAddOnConfigs(): Promise<RICConfiguredAddOns> {
319
+ try {
320
+ const addOnList = await this._msgHandler.sendRICRESTURL<
321
+ RICConfiguredAddOns
322
+ >("addon/list");
323
+ RaftLog.debug("getAddOnConfigs returned " + addOnList);
324
+ return addOnList;
325
+ } catch (error) {
326
+ RaftLog.debug(`getAddOnConfigs Failed to get list of add-ons ${error}`);
327
+ return new RICConfiguredAddOns();
328
+ }
329
+ }
330
+
331
+ /**
332
+ *
333
+ * runCommand
334
+ * @param commandName command API string
335
+ * @param params parameters (simple name value pairs only) to parameterize trajectory
336
+ * @returns Promise<RaftOKFail>
337
+ *
338
+ */
339
+ async runCommand(commandName: string, params: object): Promise<RaftOKFail> {
340
+ try {
341
+ // Format the paramList as query string
342
+ const paramEntries = Object.entries(params);
343
+ let paramQueryStr = "";
344
+ for (const param of paramEntries) {
345
+ if (paramQueryStr.length > 0) paramQueryStr += "&";
346
+ paramQueryStr += param[0] + "=" + param[1];
347
+ }
348
+ // Format the url to send
349
+ if (paramQueryStr.length > 0) commandName += "?" + paramQueryStr;
350
+ return await this._msgHandler.sendRICRESTURL<RaftOKFail>(commandName);
351
+ } catch (error) {
352
+ RaftLog.debug(`RaftSystemUtils runCommand failed ${error}`);
353
+ return new RaftOKFail();
354
+ }
355
+ }
356
+
357
+ getCachedAddOnList(): Array<RICHWElem> {
358
+ return this._connectedAddOns;
359
+ }
360
+
361
+ getCachedAllHWElems(): Array<RICHWElem> {
362
+ const allHWElems = new Array<RICHWElem>();
363
+ allHWElems.push(...this._connectedAddOns);
364
+ allHWElems.push(...this._hwElemsExcludingAddOns);
365
+ return allHWElems;
366
+ }
367
+
368
+ getCachedCalibInfo(): RICCalibInfo | null {
369
+ return this._calibInfo;
370
+ }
371
+ }
@@ -0,0 +1,20 @@
1
+ export type RICLEDPatternCheckerColour = {
2
+ led: string;
3
+ lcd: string;
4
+ }
5
+
6
+ export type RICLedLcdColours = Array<RICLEDPatternCheckerColour>;
7
+
8
+ export type RICServoFaultFlags = {
9
+ intermittentConnection: boolean,
10
+ noConnection: boolean,
11
+ faultyConnection: boolean,
12
+ servoHornPositionError: boolean
13
+ };
14
+
15
+ export class RICCalibInfo {
16
+ rslt = '';
17
+ calDone = 0;
18
+ validMs?= 0;
19
+ }
20
+
@@ -0,0 +1,113 @@
1
+ import { RaftSystemType } from "../../../../src/RaftSystemType";
2
+ import { RaftLog, RaftSystemUtils, RaftOKFail, RaftConnEventFn, RaftEventFn, RaftPublishEvent, RaftPublishEventNames } from "../../../../src/main";
3
+ import RICAddOnManager from "./RICAddOnManager";
4
+ import RICCommsStats from "./RICCommsStats";
5
+ import RICLEDPatternChecker from "./RICLEDPatternChecker";
6
+ import RICServoFaultDetector from "./RICServoFaultDetector";
7
+ import { RICStateInfo } from "./RICStateInfo";
8
+
9
+ export default class SystemTypeMarty implements RaftSystemType {
10
+ nameForDialogs = "Robotical Marty";
11
+ defaultWiFiHostname = "Marty";
12
+ firmwareDestName = "ricfw";
13
+ normalFileDestName = "fs";
14
+ connectorOptions = {wsSuffix: "ws"};
15
+
16
+ // LED Pattern checker
17
+ private _ledPatternChecker: RICLEDPatternChecker = new RICLEDPatternChecker();
18
+ getLEDPatternChecker(): RICLEDPatternChecker {
19
+ return this._ledPatternChecker;
20
+ }
21
+
22
+ // Latest data from servos, IMU, etc
23
+ private _ricStateInfo: RICStateInfo = new RICStateInfo();
24
+ getRICStateInfo(): RICStateInfo {
25
+ return this._ricStateInfo;
26
+ }
27
+
28
+ // Add-on Manager
29
+ private _addOnManager = new RICAddOnManager();
30
+ getAddOnManager(): RICAddOnManager {
31
+ return this._addOnManager;
32
+ }
33
+
34
+ // Properties for Marty
35
+ private _ricServoFaultDetector: RICServoFaultDetector | null = null;
36
+ getRICServoFaultDetector(): RICServoFaultDetector {
37
+ return this._ricServoFaultDetector!;
38
+ }
39
+
40
+ // RIC comms stats
41
+ private _commsStats = new RICCommsStats();
42
+ getCommsStats(): RICCommsStats {
43
+ return this._commsStats;
44
+ }
45
+
46
+ // Event handler
47
+ private _onEvent: RaftEventFn | null = null;
48
+
49
+ // Raft system utils
50
+ private _systemUtils: RaftSystemUtils | null = null;
51
+
52
+ // Setup
53
+ setup(systemUtils: RaftSystemUtils, onEvent: RaftEventFn | null): void {
54
+ this._systemUtils = systemUtils;
55
+ this._onEvent = onEvent;
56
+ this._ricServoFaultDetector = new RICServoFaultDetector(this._systemUtils!.getMsgHandler(), this._ricStateInfo);
57
+ }
58
+
59
+ // Subscribe for updates
60
+ async subscribeForUpdates(systemUtils: RaftSystemUtils, enable: boolean): Promise<void> {
61
+ // Subscription rate
62
+ const subscribeRateHz = 10;
63
+ try {
64
+ const subscribeDisable = '{"cmdName":"subscription","action":"update",' +
65
+ '"pubRecs":[' +
66
+ `{"name":"MultiStatus","rateHz":0,}` +
67
+ '{"name":"PowerStatus","rateHz":0},' +
68
+ `{"name":"AddOnStatus","rateHz":0}` +
69
+ ']}';
70
+ const subscribeEnable = '{"cmdName":"subscription","action":"update",' +
71
+ '"pubRecs":[' +
72
+ `{"name":"MultiStatus","rateHz":${subscribeRateHz.toString()}}` +
73
+ `{"name":"PowerStatus","rateHz":1.0},` +
74
+ `{"name":"AddOnStatus","rateHz":${subscribeRateHz.toString()}}` +
75
+ ']}';
76
+
77
+ const msgHandler = systemUtils.getMsgHandler();
78
+ const ricResp = await msgHandler.sendRICRESTCmdFrame<RaftOKFail>(
79
+ enable ? subscribeEnable : subscribeDisable
80
+ );
81
+
82
+ // Debug
83
+ RaftLog.debug(`subscribe enable/disable returned ${JSON.stringify(ricResp)}`);
84
+ } catch (error: unknown) {
85
+ RaftLog.warn(`getRICCalibInfo Failed subscribe for updates ${error}`);
86
+ }
87
+ }
88
+
89
+ // Invalidate state
90
+ stateIsInvalid(): void {
91
+ if (this._systemUtils) {
92
+ this._systemUtils.invalidate();
93
+ }
94
+ }
95
+
96
+ // Other message type
97
+ rxOtherMsgType(payload: Uint8Array, frameTimeMs: number) {
98
+ // RICLog.debug(`onRxROSSerialMsg payload ${RICUtils.bufferToHex(payload)}`);
99
+ RaftLog.verbose(`onRxROSSerialMsg payloadLen ${payload.length}`);
100
+ const topicIDs = this._ricStateInfo.updateFromROSSerialMsg(payload, this._commsStats, this._addOnManager, frameTimeMs);
101
+
102
+ // Call event handler if registered
103
+ if (this._onEvent) {
104
+ this._onEvent("pub", RaftPublishEvent.PUBLISH_EVENT_DATA, RaftPublishEventNames[RaftPublishEvent.PUBLISH_EVENT_DATA],
105
+ {
106
+ topicIDs: topicIDs,
107
+ payload: payload,
108
+ frameTimeMs: frameTimeMs
109
+ });
110
+ }
111
+ }
112
+ }
113
+
@@ -0,0 +1,15 @@
1
+ <!-- index.html -->
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width,initial-scale=1">
7
+ <meta name="description" content="BusI2CWebTest">
8
+ <title>BusI2CWebTest</title>
9
+ <link rel="icon" href="data:image/svg+xml;base64, PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iNTExIgogICBoZWlnaHQ9IjUxMSIKICAgdmlld0JveD0iMCAwIDEzNS4yMDIwOSAxMzUuMjAyMDkiCiAgIHZlcnNpb249IjEuMSIKICAgaWQ9InN2ZzE3OCIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4zLjIgKDA5MWUyMGUsIDIwMjMtMTEtMjUsIGN1c3RvbSkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlNjYWRlclVpTG9nby5zdmciCiAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0ibG9nbzUxMi5wbmciCiAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI5Ni4xODc4NjYiCiAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI5Ni4xODc4NjYiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0ibmFtZWR2aWV3MTgwIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIKICAgICBpbmtzY2FwZTpkZXNrY29sb3I9IiNkMWQxZDEiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9Im1tIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBzaG93Z3VpZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOnpvb209IjEiCiAgICAgaW5rc2NhcGU6Y3g9IjU3OCIKICAgICBpbmtzY2FwZTpjeT0iNTM2LjUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIzODQwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjE1MjkiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjI1NTIiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIj4KICAgIDxzb2RpcG9kaTpndWlkZQogICAgICAgcG9zaXRpb249IjM4Ljc1MTcwNSw1NS4yMDIwODIiCiAgICAgICBvcmllbnRhdGlvbj0iMCwxIgogICAgICAgaWQ9Imd1aWRlMzg4IgogICAgICAgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSIiCiAgICAgICBpbmtzY2FwZTpjb2xvcj0icmdiKDAsMTM0LDIyOSkiIC8+CiAgICA8c29kaXBvZGk6Z3VpZGUKICAgICAgIHBvc2l0aW9uPSI2Ny43NTAwMDMsMTQzLjQwNDE3IgogICAgICAgb3JpZW50YXRpb249Ii0xLDAiCiAgICAgICBpZD0iZ3VpZGUzOTAiCiAgICAgICBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IiIKICAgICAgIGlua3NjYXBlOmNvbG9yPSJyZ2IoMCwxMzQsMjI5KSIgLz4KICAgIDxzb2RpcG9kaTpndWlkZQogICAgICAgcG9zaXRpb249IjEzNSw2Ni4wODUyNDUiCiAgICAgICBvcmllbnRhdGlvbj0iLTEsMCIKICAgICAgIGlkPSJndWlkZTM5MiIKICAgICAgIGlua3NjYXBlOmxvY2tlZD0iZmFsc2UiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iIgogICAgICAgaW5rc2NhcGU6Y29sb3I9InJnYigwLDEzNCwyMjkpIiAvPgogICAgPHNvZGlwb2RpOmd1aWRlCiAgICAgICBwb3NpdGlvbj0iMzUuMDAwMDAyLDkyLjY5MDg5MyIKICAgICAgIG9yaWVudGF0aW9uPSItMSwwIgogICAgICAgaWQ9Imd1aWRlMzk0IgogICAgICAgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSIiCiAgICAgICBpbmtzY2FwZTpjb2xvcj0icmdiKDAsMTM0LDIyOSkiIC8+CiAgICA8c29kaXBvZGk6Z3VpZGUKICAgICAgIHBvc2l0aW9uPSIxNDkuMjc3MzQsLTE0Ljc5NzkyIgogICAgICAgb3JpZW50YXRpb249IjAsMSIKICAgICAgIGlkPSJndWlkZTM5NiIKICAgICAgIGlua3NjYXBlOmxvY2tlZD0iZmFsc2UiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iIgogICAgICAgaW5rc2NhcGU6Y29sb3I9InJnYigwLDEzNCwyMjkpIiAvPgogICAgPHNvZGlwb2RpOmd1aWRlCiAgICAgICBwb3NpdGlvbj0iNDUuMDAwMDAzLDk4LjQxMzY5MyIKICAgICAgIG9yaWVudGF0aW9uPSItMSwwIgogICAgICAgaWQ9Imd1aWRlNDMxIgogICAgICAgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSIiCiAgICAgICBpbmtzY2FwZTpjb2xvcj0icmdiKDAsMTM0LDIyOSkiIC8+CiAgICA8c29kaXBvZGk6Z3VpZGUKICAgICAgIHBvc2l0aW9uPSItNDEuMTAyMzkyLC00Ljc5NzkyMTEiCiAgICAgICBvcmllbnRhdGlvbj0iMCwxIgogICAgICAgaWQ9Imd1aWRlNDMzIgogICAgICAgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSIiCiAgICAgICBpbmtzY2FwZTpjb2xvcj0icmdiKDAsMTM0LDIyOSkiIC8+CiAgICA8c29kaXBvZGk6Z3VpZGUKICAgICAgIHBvc2l0aW9uPSIxMjUsODQuMDc5NzE3IgogICAgICAgb3JpZW50YXRpb249Ii0xLDAiCiAgICAgICBpZD0iZ3VpZGU0MzUiCiAgICAgICBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IiIKICAgICAgIGlua3NjYXBlOmNvbG9yPSJyZ2IoMCwxMzQsMjI5KSIgLz4KICAgIDxzb2RpcG9kaTpndWlkZQogICAgICAgcG9zaXRpb249IjE0LjMxNDI2Niw1MS4yMDIwODUiCiAgICAgICBvcmllbnRhdGlvbj0iMCwxIgogICAgICAgaWQ9Imd1aWRlNDM3IgogICAgICAgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSIiCiAgICAgICBpbmtzY2FwZTpjb2xvcj0icmdiKDAsMTM0LDIyOSkiIC8+CiAgICA8c29kaXBvZGk6Z3VpZGUKICAgICAgIHBvc2l0aW9uPSI1NS4wMDAwMDMsNzMuODg3ODUzIgogICAgICAgb3JpZW50YXRpb249Ii0xLDAiCiAgICAgICBpZD0iZ3VpZGU0MzkiCiAgICAgICBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IiIKICAgICAgIGlua3NjYXBlOmNvbG9yPSJyZ2IoMCwxMzQsMjI5KSIgLz4KICAgIDxzb2RpcG9kaTpndWlkZQogICAgICAgcG9zaXRpb249Ijk3Ljc1MDAwNSwxNTUuODM5NTkiCiAgICAgICBvcmllbnRhdGlvbj0iLTEsMCIKICAgICAgIGlkPSJndWlkZTQ0MSIKICAgICAgIGlua3NjYXBlOmxvY2tlZD0iZmFsc2UiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iIgogICAgICAgaW5rc2NhcGU6Y29sb3I9InJnYigwLDEzNCwyMjkpIiAvPgogICAgPHNvZGlwb2RpOmd1aWRlCiAgICAgICBwb3NpdGlvbj0iLTM2LjYwMzYyMSw1LjIwMjA3OTQiCiAgICAgICBvcmllbnRhdGlvbj0iMCwxIgogICAgICAgaWQ9Imd1aWRlNDQzIgogICAgICAgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSIiCiAgICAgICBpbmtzY2FwZTpjb2xvcj0icmdiKDAsMTM0LDIyOSkiIC8+CiAgICA8c29kaXBvZGk6Z3VpZGUKICAgICAgIHBvc2l0aW9uPSItMjAuNjUzNDQsNDcuMjAyMDg1IgogICAgICAgb3JpZW50YXRpb249IjAsMSIKICAgICAgIGlkPSJndWlkZTQ0NSIKICAgICAgIGlua3NjYXBlOmxvY2tlZD0iZmFsc2UiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iIgogICAgICAgaW5rc2NhcGU6Y29sb3I9InJnYigwLDEzNCwyMjkpIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxkZWZzCiAgICAgaWQ9ImRlZnMxNzUiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0ODEzIgogICAgICAgaW5rc2NhcGU6c3dhdGNoPSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDgxMSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQ4MTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0ODE1IgogICAgICAgeDE9IjY0LjY0NDQzNyIKICAgICAgIHkxPSI2NS44Njc1ODUiCiAgICAgICB4Mj0iOTcuNDU5NTYxIgogICAgICAgeTI9IjY1Ljg2NzU4NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGZpbHRlcgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCIgogICAgICAgaWQ9ImZpbHRlcjEwIgogICAgICAgeD0iLTAuMDMyNzgxOTciCiAgICAgICB5PSItMC4wMjQ3MTkxNSIKICAgICAgIHdpZHRoPSIxLjA2NTU2MzkiCiAgICAgICBoZWlnaHQ9IjEuMDUzNzIxMyI+CiAgICAgIDxmZUdhdXNzaWFuQmx1cgogICAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMC41MzI1ODIwNCIKICAgICAgICAgaWQ9ImZlR2F1c3NpYW5CbHVyMTAiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQiIKICAgICAgIGlkPSJmaWx0ZXIxMSIKICAgICAgIHg9Ii0wLjAzNzc2MjYyMiIKICAgICAgIHk9Ii0wLjAyODE4ODY5OCIKICAgICAgIHdpZHRoPSIxLjA3NTUyNTIiCiAgICAgICBoZWlnaHQ9IjEuMDYxNjkyOCI+CiAgICAgIDxmZUdhdXNzaWFuQmx1cgogICAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMC40MjU0MjA3MSIKICAgICAgICAgaWQ9ImZlR2F1c3NpYW5CbHVyMTEiIC8+CiAgICA8L2ZpbHRlcj4KICAgIDxmaWx0ZXIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQiIKICAgICAgIGlkPSJmaWx0ZXIxMiIKICAgICAgIHg9Ii0wLjAyOTI5NjUwOSIKICAgICAgIHk9Ii0wLjAxNzUwNzUyNCIKICAgICAgIHdpZHRoPSIxLjA1ODU5MyIKICAgICAgIGhlaWdodD0iMS4wMzUwMTUiPgogICAgICA8ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgICBzdGREZXZpYXRpb249IjAuMzU1NDU5NiIKICAgICAgICAgaWQ9ImZlR2F1c3NpYW5CbHVyMTIiIC8+CiAgICA8L2ZpbHRlcj4KICA8L2RlZnM+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDojZTY3MTFlO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxO2ZpbHRlcjp1cmwoI2ZpbHRlcjEwKSIKICAgICAgIGQ9Ik0gMTcuODAyMDgzLDEyMy4wMTI1IFYgNTMuMDEyNTAxIGwgNTAsLTQzLjAzMjgyMSA0OS45OTk5OTcsNDMuMDMyODIxIFYgMTIzLjAxMjUgWiIKICAgICAgIGlkPSJwYXRoNDA3IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjE2NzE5ODQsMCwwLDEuMTE0OTM2MiwtMTAuOTM5NTI4LC04LjE5OTc5MjkpIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiNlNjcxMWU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7ZmlsdGVyOnVybCgjZmlsdGVyMTEpIgogICAgICAgZD0iTSAyNy44MDIwODMsMTEzLjAxMjUgViA1Ny4wMTI1MDEgbCA0MCwtMzQuMTY4Mjg3IDM5Ljk5OTk5NywzNC4xNjgyODcgViAxMTMuMDEyNSBaIgogICAgICAgaWQ9InBhdGg0MDctOSIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4xMDQ3NjAzLDAsMCwxLjA5MzkzODYsLTUuNTE1NDYxNywtNS44NzQ0NDU0KSIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjI2NDU4MztzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjA7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpZD0icmVjdDI3NzciCiAgICAgICB3aWR0aD0iMTM1LjIwMjA5IgogICAgICAgaGVpZ2h0PSIxMzUuMjAyMDkiCiAgICAgICB4PSIwIgogICAgICAgeT0iMCIgLz4KICAgIDx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjk3LjEwNDhweDtsaW5lLWhlaWdodDoxLjI1O2ZvbnQtZmFtaWx5OkNhbGlicmk7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQ2FsaWJyaSwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDowLjUwNTIwNjtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtmaWx0ZXI6dXJsKCNmaWx0ZXIxMikiCiAgICAgICB4PSIzOS4zOTM2NjEiCiAgICAgICB5PSIxMTYuMTE2OCIKICAgICAgIGlkPSJ0ZXh0Mjg1NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjIwMTU3OCwwLDAsMC45NDYxNTE3NSwtNS43NTQ3Mzk5LC0yLjU0ODUyODQpIj48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgaWQ9InRzcGFuMjg1MiIKICAgICAgICAgeD0iMzkuMzkzNjYxIgogICAgICAgICB5PSIxMTYuMTE2OCIKICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjk3LjEwNDhweDtmb250LWZhbWlseTpDYWxpYnJpOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0NhbGlicmksIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7ZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDowLjUwNTIwNjtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSI+UzwvdHNwYW4+PC90ZXh0PgogIDwvZz4KPC9zdmc+Cg==" type="image/svg+xml" />
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ <script type="module" src="./index.tsx"></script>
14
+ </body>
15
+ </html>
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import Main from './Main';
4
+ import './styles.css';
5
+ import 'process';
6
+ import 'buffer';
7
+
8
+ // Find the root element
9
+ const rootElement = document.getElementById('root');
10
+
11
+ // Create a root
12
+ const root = createRoot(rootElement!);
13
+
14
+ // Render the Main component into the root
15
+ root.render(<Main />);
@@ -0,0 +1,122 @@
1
+ /* Main.css */
2
+
3
+ /* General styling for the dark theme */
4
+ body,
5
+ .device-screen,
6
+ .device-block-heading,
7
+ .device-attrs-and-actions,
8
+ .device-attrs-form,
9
+ .device-actions-form,
10
+ .device-line-chart {
11
+ /* Dark background for all components */
12
+ color: #fff;
13
+ /* Light text for better readability */
14
+ font-family: 'Segoe UI', 'Roboto', 'Oxygen',
15
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
16
+ sans-serif;
17
+ -webkit-font-smoothing: antialiased;
18
+ -moz-osx-font-smoothing: grayscale;
19
+ background-color: #282c34;
20
+ color: #ffffff;
21
+ }
22
+
23
+ code {
24
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
25
+ monospace;
26
+ }
27
+
28
+ .header {
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ padding: 10px 20px;
33
+ border: 1px solid #666;
34
+ /* Adjusting border color for dark theme */
35
+ border-radius: 8px;
36
+ margin-bottom: 10px;
37
+ }
38
+
39
+ h1 {
40
+ margin: 0;
41
+ }
42
+
43
+ .always-enabled {
44
+ pointer-events: auto !important; /* Ensures interactions are always enabled */
45
+ }
46
+
47
+ .content-body {
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: 10px;
51
+ }
52
+
53
+ .content-row {
54
+ display: flex;
55
+ justify-content: space-between;
56
+ margin-bottom: 10px;
57
+ flex-direction: col;
58
+ }
59
+
60
+ .conn-indication {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ padding: 10px;
65
+ border-radius: 8px;
66
+ margin-bottom: 10px;
67
+ }
68
+
69
+ .action-button {
70
+ margin-left: 10px;
71
+ }
72
+
73
+ .info-boxes {
74
+ display: flex;
75
+ justify-content: flex-start;
76
+ margin-bottom: 10px;
77
+ gap: 10px;
78
+ }
79
+
80
+ .info-box {
81
+ display: flex;
82
+ flex-direction: column;
83
+ align-items: center;
84
+ border-radius: 10px;
85
+ padding: 10px 20px;
86
+ border: 1px solid #666;
87
+ }
88
+
89
+ .ip-addr-input {
90
+ width: 100%;
91
+ margin-bottom: 10px;
92
+ }
93
+
94
+ .status-screen {
95
+ display: flex;
96
+ flex-direction: column;
97
+ gap: 10px;
98
+ border-radius: 10px;
99
+ padding: 10px 20px;
100
+ border: 1px solid #666;
101
+ }
102
+
103
+ .info {
104
+ display: flex;
105
+ flex-direction: column;
106
+ justify-content: space-between;
107
+ }
108
+
109
+ .info-line {
110
+ display: flex;
111
+ justify-content: space-between;
112
+ margin-bottom: 10px;
113
+ }
114
+
115
+ .info-label {
116
+ font-weight: bold;
117
+ margin-right: 10px;
118
+ }
119
+
120
+ .info-value {
121
+ font-weight: normal;
122
+ }