@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.
- package/.editorconfig +14 -0
- package/.gitattributes +11 -0
- package/.nvmrc +1 -0
- package/LICENSE +22 -0
- package/README.md +11 -0
- package/TODO.md +1 -0
- package/dist/RaftAttributeHandler.d.ts +12 -0
- package/dist/RaftAttributeHandler.js +241 -0
- package/dist/RaftAttributeHandler.js.map +1 -0
- package/dist/RaftChannel.d.ts +18 -0
- package/dist/RaftChannel.js +12 -0
- package/dist/RaftChannel.js.map +1 -0
- package/dist/RaftChannelWebBLE.d.ts +38 -0
- package/dist/RaftChannelWebBLE.js +274 -0
- package/dist/RaftChannelWebBLE.js.map +1 -0
- package/dist/RaftChannelWebSerial.d.ts +37 -0
- package/dist/RaftChannelWebSerial.js +319 -0
- package/dist/RaftChannelWebSerial.js.map +1 -0
- package/dist/RaftChannelWebSocket.d.ts +28 -0
- package/dist/RaftChannelWebSocket.js +197 -0
- package/dist/RaftChannelWebSocket.js.map +1 -0
- package/dist/RaftCommsStats.d.ts +39 -0
- package/dist/RaftCommsStats.js +128 -0
- package/dist/RaftCommsStats.js.map +1 -0
- package/dist/RaftConnEvents.d.ts +31 -0
- package/dist/RaftConnEvents.js +44 -0
- package/dist/RaftConnEvents.js.map +1 -0
- package/dist/RaftConnector.d.ts +242 -0
- package/dist/RaftConnector.js +613 -0
- package/dist/RaftConnector.js.map +1 -0
- package/dist/RaftCustomAttrHandler.d.ts +4 -0
- package/dist/RaftCustomAttrHandler.js +50 -0
- package/dist/RaftCustomAttrHandler.js.map +1 -0
- package/dist/RaftDeviceInfo.d.ts +64 -0
- package/dist/RaftDeviceInfo.js +36 -0
- package/dist/RaftDeviceInfo.js.map +1 -0
- package/dist/RaftDeviceManager.d.ts +37 -0
- package/dist/RaftDeviceManager.js +450 -0
- package/dist/RaftDeviceManager.js.map +1 -0
- package/dist/RaftDeviceMsg.d.ts +9 -0
- package/dist/RaftDeviceMsg.js +11 -0
- package/dist/RaftDeviceMsg.js.map +1 -0
- package/dist/RaftDeviceStates.d.ts +33 -0
- package/dist/RaftDeviceStates.js +60 -0
- package/dist/RaftDeviceStates.js.map +1 -0
- package/dist/RaftFileHandler.d.ts +52 -0
- package/dist/RaftFileHandler.js +502 -0
- package/dist/RaftFileHandler.js.map +1 -0
- package/dist/RaftLog.d.ts +22 -0
- package/dist/RaftLog.js +63 -0
- package/dist/RaftLog.js.map +1 -0
- package/dist/RaftMiniHDLC.d.ts +18 -0
- package/dist/RaftMiniHDLC.js +383 -0
- package/dist/RaftMiniHDLC.js.map +1 -0
- package/dist/RaftMsgHandler.d.ts +57 -0
- package/dist/RaftMsgHandler.js +480 -0
- package/dist/RaftMsgHandler.js.map +1 -0
- package/dist/RaftMsgTrackInfo.d.ts +17 -0
- package/dist/RaftMsgTrackInfo.js +42 -0
- package/dist/RaftMsgTrackInfo.js.map +1 -0
- package/dist/RaftProtocolDefs.d.ts +30 -0
- package/dist/RaftProtocolDefs.js +48 -0
- package/dist/RaftProtocolDefs.js.map +1 -0
- package/dist/RaftStreamHandler.d.ts +38 -0
- package/dist/RaftStreamHandler.js +257 -0
- package/dist/RaftStreamHandler.js.map +1 -0
- package/dist/RaftSystemType.d.ts +21 -0
- package/dist/RaftSystemType.js +3 -0
- package/dist/RaftSystemType.js.map +1 -0
- package/dist/RaftSystemUtils.d.ts +136 -0
- package/dist/RaftSystemUtils.js +410 -0
- package/dist/RaftSystemUtils.js.map +1 -0
- package/dist/RaftTypes.d.ts +184 -0
- package/dist/RaftTypes.js +157 -0
- package/dist/RaftTypes.js.map +1 -0
- package/dist/RaftUpdateEvents.d.ts +33 -0
- package/dist/RaftUpdateEvents.js +46 -0
- package/dist/RaftUpdateEvents.js.map +1 -0
- package/dist/RaftUpdateManager.d.ts +61 -0
- package/dist/RaftUpdateManager.js +618 -0
- package/dist/RaftUpdateManager.js.map +1 -0
- package/dist/RaftUtils.d.ts +125 -0
- package/dist/RaftUtils.js +454 -0
- package/dist/RaftUtils.js.map +1 -0
- package/dist/RaftWifiTypes.d.ts +23 -0
- package/dist/RaftWifiTypes.js +43 -0
- package/dist/RaftWifiTypes.js.map +1 -0
- package/dist/TestDataGen.d.ts +7 -0
- package/dist/TestDataGen.js +133 -0
- package/dist/TestDataGen.js.map +1 -0
- package/dist/main.d.ts +18 -0
- package/dist/main.js +42 -0
- package/dist/main.js.map +1 -0
- package/eslint.config.mjs +33 -0
- package/examples/dashboard/package.json +39 -0
- package/examples/dashboard/src/ConnManager.ts +86 -0
- package/examples/dashboard/src/Main.tsx +100 -0
- package/examples/dashboard/src/StatusScreen.tsx +72 -0
- package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +144 -0
- package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +77 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
- package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
- package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
- package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
- package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
- package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
- package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +32 -0
- package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
- package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
- package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +113 -0
- package/examples/dashboard/src/index.html +15 -0
- package/examples/dashboard/src/index.tsx +15 -0
- package/examples/dashboard/src/styles.css +122 -0
- package/examples/dashboard/tsconfig.json +18 -0
- package/jest.config.js +11 -0
- package/package.json +50 -0
- package/src/RaftAttributeHandler.ts +289 -0
- package/src/RaftChannel.ts +30 -0
- package/src/RaftChannelWebBLE.ts +342 -0
- package/src/RaftChannelWebSerial.ts +408 -0
- package/src/RaftChannelWebSocket.ts +245 -0
- package/src/RaftCommsStats.ts +142 -0
- package/src/RaftConnEvents.ts +46 -0
- package/src/RaftConnector.ts +745 -0
- package/src/RaftCustomAttrHandler.ts +54 -0
- package/src/RaftDeviceInfo.ts +104 -0
- package/src/RaftDeviceManager.ts +542 -0
- package/src/RaftDeviceMsg.ts +20 -0
- package/src/RaftDeviceStates.ts +89 -0
- package/src/RaftFileHandler.ts +668 -0
- package/src/RaftLog.ts +70 -0
- package/src/RaftMiniHDLC.ts +396 -0
- package/src/RaftMsgHandler.ts +778 -0
- package/src/RaftMsgTrackInfo.ts +51 -0
- package/src/RaftProtocolDefs.ts +46 -0
- package/src/RaftStreamHandler.ts +328 -0
- package/src/RaftSystemType.ts +25 -0
- package/src/RaftSystemUtils.ts +487 -0
- package/src/RaftTypes.ts +250 -0
- package/src/RaftUpdateEvents.ts +48 -0
- package/src/RaftUpdateManager.ts +778 -0
- package/src/RaftUtils.ts +484 -0
- package/src/RaftWifiTypes.ts +36 -0
- package/src/TestDataGen.ts +157 -0
- package/src/main.ts +28 -0
- package/testdata/TestDeviceTypeRecs.json +492 -0
- 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
|
+
}
|