@robotical/webapp-types 3.25.5 → 3.25.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.
- package/dist-types/package.json +1 -1
- package/dist-types/src/application/RAFTs/Marty/PublishedDataAnalyser.d.ts +2 -2
- package/dist-types/src/application/RAFTs/Marty/PublishedDataAnalyser.js +7 -23
- package/dist-types/src/components/oneoffs/calibration-screens/ColourSensorCalibration/messages.d.ts +17 -13
- package/dist-types/src/components/oneoffs/calibration-screens/ColourSensorCalibration/messages.js +17 -13
- package/dist-types/src/screens/configuration/marty/Diagnostics/ColourSensorDiagnostics/messages.d.ts +2 -0
- package/dist-types/src/screens/configuration/marty/Diagnostics/ColourSensorDiagnostics/messages.js +3 -1
- package/dist-types/src/utils/colour-calibration-reconnect.d.ts +19 -0
- package/dist-types/src/utils/colour-calibration-reconnect.js +261 -0
- package/dist-types/src/utils/colour-calibration-records.d.ts +21 -0
- package/dist-types/src/utils/colour-calibration-records.js +253 -0
- package/dist-types/src/utils/colour-classifier.d.ts +32 -0
- package/dist-types/src/utils/colour-classifier.js +37 -0
- package/dist-types/src/utils/colour-sensor-diagnostics.d.ts +162 -0
- package/dist-types/src/utils/colour-sensor-diagnostics.js +364 -0
- package/dist-types/src/utils/colour-sensor-operation.d.ts +2 -0
- package/dist-types/src/utils/colour-sensor-operation.js +62 -0
- package/dist-types/src/utils/colour-sensor-profile.d.ts +32 -0
- package/dist-types/src/utils/colour-sensor-profile.js +229 -0
- package/dist-types/src/utils/colour-sensor-registers.d.ts +53 -0
- package/dist-types/src/utils/colour-sensor-registers.js +310 -0
- package/dist-types/src/utils/marty-colour-policy.json +5 -3
- package/package.json +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { COLOUR_DATABASE_URL, assertColourSensorActive, getColourSensors } from "./colour-sensor-diagnostics";
|
|
38
|
+
import { classifyColour, colourChannelsFromValues } from "./colour-classifier";
|
|
39
|
+
import { lockColourSensorOperation } from "./colour-sensor-operation";
|
|
40
|
+
import { readColourSensorHardware, readColourSensorReadiness, readColourSensorRegister } from "./colour-sensor-registers";
|
|
41
|
+
import { getPendingColourCalibration } from "./colour-calibration-reconnect";
|
|
42
|
+
var PREFIX = "marty-colour-signal-profile:";
|
|
43
|
+
var memory = new Map();
|
|
44
|
+
var active = new WeakMap();
|
|
45
|
+
var retries = new WeakMap();
|
|
46
|
+
var profileKey = function (profile) {
|
|
47
|
+
return "".concat(profile.serialNumber, "/").concat(profile.offsetsHex).concat(profile.whiteCalibrationHex);
|
|
48
|
+
};
|
|
49
|
+
export var validColourSensorProfile = function (value) {
|
|
50
|
+
var profile = value;
|
|
51
|
+
return !!profile && profile.schemaVersion === 1 && /^[a-zA-Z0-9_-]{1,128}$/.test(profile.serialNumber) &&
|
|
52
|
+
["97", "98"].includes(profile.typeCode) && typeof profile.firmwareVersion === "string" &&
|
|
53
|
+
/^[a-f0-9]{8}$/.test(profile.offsetsHex) && /^[a-f0-9]{16}$/.test(profile.whiteCalibrationHex) &&
|
|
54
|
+
Number.isFinite(profile.capturedAtMs) && profile.capturedAtMs > 0 && typeof profile.purpleIncluded === "boolean" &&
|
|
55
|
+
["clearThreshold", "rgbFallback", "purpleSkipped"].includes(profile.groundDetection) &&
|
|
56
|
+
["red", "green", "blue"].every(function (channel) {
|
|
57
|
+
var _a, _b, _c, _d, _e, _f;
|
|
58
|
+
var c = channel;
|
|
59
|
+
return [(_b = (_a = profile.signal) === null || _a === void 0 ? void 0 : _a.airMin) === null || _b === void 0 ? void 0 : _b[c], (_d = (_c = profile.signal) === null || _c === void 0 ? void 0 : _c.airMax) === null || _d === void 0 ? void 0 : _d[c], (_f = (_e = profile.signal) === null || _e === void 0 ? void 0 : _e.margin) === null || _f === void 0 ? void 0 : _f[c]]
|
|
60
|
+
.every(function (v) { return Number.isFinite(v) && v >= 0; }) && profile.signal.airMin[c] <= profile.signal.airMax[c] && profile.signal.margin[c] > 0;
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
export var cacheColourSensorProfile = function (profile) {
|
|
64
|
+
if (!validColourSensorProfile(profile))
|
|
65
|
+
return;
|
|
66
|
+
memory.set(profileKey(profile), profile);
|
|
67
|
+
try {
|
|
68
|
+
localStorage.setItem(PREFIX + profileKey(profile), JSON.stringify(profile));
|
|
69
|
+
}
|
|
70
|
+
catch ( /* Cloud records retain the profile too. */_a) { /* Cloud records retain the profile too. */ }
|
|
71
|
+
};
|
|
72
|
+
export var colourSensorProfilePath = function (profile) {
|
|
73
|
+
return "".concat(COLOUR_DATABASE_URL, "/colourSensorProfiles/").concat(profileKey(profile));
|
|
74
|
+
};
|
|
75
|
+
export var bindColourSensorProfile = function (sensor, profile) {
|
|
76
|
+
var profiles = active.get(sensor.raft);
|
|
77
|
+
if (!profiles) {
|
|
78
|
+
profiles = new Map();
|
|
79
|
+
active.set(sensor.raft, profiles);
|
|
80
|
+
}
|
|
81
|
+
profiles.set(sensor.key, profile);
|
|
82
|
+
};
|
|
83
|
+
export var getActiveColourSensorProfile = function (sensor) { var _a; return (_a = active.get(sensor.raft)) === null || _a === void 0 ? void 0 : _a.get(sensor.key); };
|
|
84
|
+
export var getAddonColourSensorProfile = function (raft, addon) { var _a; return (_a = active.get(raft)) === null || _a === void 0 ? void 0 : _a.get(JSON.stringify([addon.id, addon.name])); };
|
|
85
|
+
export var clearActiveColourSensorProfile = function (sensor) { var _a; return (_a = active.get(sensor.raft)) === null || _a === void 0 ? void 0 : _a.delete(sensor.key); };
|
|
86
|
+
export var classifyColourAddon = function (addon) {
|
|
87
|
+
var _a;
|
|
88
|
+
var raft = Object.values(window.applicationManager.connectedRafts).find(function (candidate) {
|
|
89
|
+
return candidate.raftStateInfo && "addOnInfo" in candidate.raftStateInfo &&
|
|
90
|
+
candidate.raftStateInfo.addOnInfo.addons.some(function (current) { return current === addon; });
|
|
91
|
+
});
|
|
92
|
+
return classifyColour(colourChannelsFromValues(addon.vals), raft ? (_a = getAddonColourSensorProfile(raft, addon)) === null || _a === void 0 ? void 0 : _a.signal : undefined).classifiedColour;
|
|
93
|
+
};
|
|
94
|
+
// Check physical identity and the complete saved coordinate system before using a persisted profile.
|
|
95
|
+
export var loadColourSensorProfile = function (sensor, signal) { return __awaiter(void 0, void 0, void 0, function () {
|
|
96
|
+
var release, check, readiness, hardware, white, offsets, identity, key_1, profile, stored, controller_1, abort, timeout, response, records, _a, state, current;
|
|
97
|
+
var _b;
|
|
98
|
+
return __generator(this, function (_c) {
|
|
99
|
+
switch (_c.label) {
|
|
100
|
+
case 0:
|
|
101
|
+
release = lockColourSensorOperation(sensor.raft, true);
|
|
102
|
+
if (!release)
|
|
103
|
+
return [2 /*return*/];
|
|
104
|
+
check = function () { return assertColourSensorActive(sensor, signal); };
|
|
105
|
+
_c.label = 1;
|
|
106
|
+
case 1:
|
|
107
|
+
_c.trys.push([1, , 13, 14]);
|
|
108
|
+
check();
|
|
109
|
+
clearActiveColourSensorProfile(sensor);
|
|
110
|
+
return [4 /*yield*/, readColourSensorReadiness(sensor, signal, check)];
|
|
111
|
+
case 2:
|
|
112
|
+
readiness = _c.sent();
|
|
113
|
+
if (readiness.status !== "ok" || !readiness.value)
|
|
114
|
+
return [2 /*return*/];
|
|
115
|
+
return [4 /*yield*/, readColourSensorHardware(sensor, signal, check)];
|
|
116
|
+
case 3:
|
|
117
|
+
hardware = _c.sent();
|
|
118
|
+
if (hardware.status !== "ok" || hardware.value.commsOk === 0 || !hardware.value.serialNumber ||
|
|
119
|
+
!/^[a-zA-Z0-9_-]{1,128}$/.test(hardware.value.serialNumber))
|
|
120
|
+
return [2 /*return*/];
|
|
121
|
+
return [4 /*yield*/, readColourSensorRegister(sensor, "4020", signal, check)];
|
|
122
|
+
case 4:
|
|
123
|
+
white = _c.sent();
|
|
124
|
+
if (white.status !== "ok")
|
|
125
|
+
return [2 /*return*/];
|
|
126
|
+
return [4 /*yield*/, readColourSensorRegister(sensor, "4018", signal, check)];
|
|
127
|
+
case 5:
|
|
128
|
+
offsets = _c.sent();
|
|
129
|
+
if (offsets.status !== "ok")
|
|
130
|
+
return [2 /*return*/];
|
|
131
|
+
identity = { serialNumber: hardware.value.serialNumber, offsetsHex: offsets.value, whiteCalibrationHex: white.value };
|
|
132
|
+
key_1 = profileKey(identity);
|
|
133
|
+
profile = memory.get(key_1);
|
|
134
|
+
try {
|
|
135
|
+
stored = JSON.parse(localStorage.getItem(PREFIX + key_1) || "null");
|
|
136
|
+
if (validColourSensorProfile(stored))
|
|
137
|
+
profile = stored;
|
|
138
|
+
}
|
|
139
|
+
catch ( /* Native WebViews may have temporary or unavailable storage. */_d) { /* Native WebViews may have temporary or unavailable storage. */ }
|
|
140
|
+
if (!!profile) return [3 /*break*/, 12];
|
|
141
|
+
controller_1 = new AbortController();
|
|
142
|
+
abort = function () { return controller_1.abort(); };
|
|
143
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
144
|
+
timeout = setTimeout(abort, 5000);
|
|
145
|
+
_c.label = 6;
|
|
146
|
+
case 6:
|
|
147
|
+
_c.trys.push([6, 10, 11, 12]);
|
|
148
|
+
return [4 /*yield*/, fetch("".concat(COLOUR_DATABASE_URL, "/colourSensorProfiles/").concat(key_1, ".json"), { signal: controller_1.signal })];
|
|
149
|
+
case 7:
|
|
150
|
+
response = _c.sent();
|
|
151
|
+
if (!response.ok) return [3 /*break*/, 9];
|
|
152
|
+
return [4 /*yield*/, response.json()];
|
|
153
|
+
case 8:
|
|
154
|
+
records = _c.sent();
|
|
155
|
+
if (records && typeof records === "object")
|
|
156
|
+
profile = Object.values(records).filter(validColourSensorProfile)
|
|
157
|
+
.filter(function (value) { return profileKey(value) === key_1; }).sort(function (a, b) { return b.capturedAtMs - a.capturedAtMs; })[0];
|
|
158
|
+
_c.label = 9;
|
|
159
|
+
case 9: return [3 /*break*/, 12];
|
|
160
|
+
case 10:
|
|
161
|
+
_a = _c.sent();
|
|
162
|
+
return [3 /*break*/, 12];
|
|
163
|
+
case 11:
|
|
164
|
+
clearTimeout(timeout);
|
|
165
|
+
signal.removeEventListener("abort", abort);
|
|
166
|
+
return [7 /*endfinally*/];
|
|
167
|
+
case 12:
|
|
168
|
+
check();
|
|
169
|
+
state = sensor.raft.raftStateInfo;
|
|
170
|
+
current = state.addOnInfo.addons.find(function (addon) { return addon.id === sensor.addon.id && addon.name === sensor.addon.name; });
|
|
171
|
+
if (!current || (current.status !== undefined && !(current.status & 128)) ||
|
|
172
|
+
Date.now() - state.addOnInfoValidMs > 1500 || state.addOnInfoValidMs > Date.now() || ((_b = state.power) === null || _b === void 0 ? void 0 : _b.powerStatus.power5VIsOn) === false)
|
|
173
|
+
return [2 /*return*/];
|
|
174
|
+
if (profile && profileKey(profile) === key_1 && profile.typeCode === hardware.value.typeCode &&
|
|
175
|
+
profile.firmwareVersion === hardware.value.firmwareVersion) {
|
|
176
|
+
cacheColourSensorProfile(profile);
|
|
177
|
+
bindColourSensorProfile(sensor, profile);
|
|
178
|
+
}
|
|
179
|
+
return [3 /*break*/, 14];
|
|
180
|
+
case 13:
|
|
181
|
+
release();
|
|
182
|
+
return [7 /*endfinally*/];
|
|
183
|
+
case 14: return [2 /*return*/];
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}); };
|
|
187
|
+
/** Read-only browser/WebView hydration. Never wakes sleeping sensors or modifies their registers. */
|
|
188
|
+
export var startColourSensorProfileSync = function () {
|
|
189
|
+
var controllers = new Set();
|
|
190
|
+
var busy = new Set();
|
|
191
|
+
var poll = function () {
|
|
192
|
+
var _a;
|
|
193
|
+
if (document.hidden || !window.applicationManager)
|
|
194
|
+
return;
|
|
195
|
+
for (var _i = 0, _b = Object.keys(window.applicationManager.connectedRafts); _i < _b.length; _i++) {
|
|
196
|
+
var raftId = _b[_i];
|
|
197
|
+
var _loop_1 = function (sensor) {
|
|
198
|
+
var state = sensor.raft.raftStateInfo;
|
|
199
|
+
if (sensor.addon.status !== undefined && !(sensor.addon.status & 128))
|
|
200
|
+
clearActiveColourSensorProfile(sensor);
|
|
201
|
+
if (busy.has(sensor.raft) || getPendingColourCalibration(sensor) || ((_a = state.power) === null || _a === void 0 ? void 0 : _a.powerStatus.power5VIsOn) === false ||
|
|
202
|
+
!(sensor.addon.status === undefined || sensor.addon.status & 128) || Date.now() - state.addOnInfoValidMs > 1500)
|
|
203
|
+
return "continue";
|
|
204
|
+
var times = retries.get(sensor.raft);
|
|
205
|
+
if (!times) {
|
|
206
|
+
times = new Map();
|
|
207
|
+
retries.set(sensor.raft, times);
|
|
208
|
+
}
|
|
209
|
+
if (Date.now() < (times.get(sensor.key) || 0))
|
|
210
|
+
return "continue";
|
|
211
|
+
// Refresh occasionally to notice a swapped sensor or settings changed by another app.
|
|
212
|
+
times.set(sensor.key, Date.now() + 60000);
|
|
213
|
+
var controller = new AbortController();
|
|
214
|
+
controllers.add(controller);
|
|
215
|
+
busy.add(sensor.raft);
|
|
216
|
+
void loadColourSensorProfile(sensor, controller.signal).catch(function () { }).finally(function () {
|
|
217
|
+
controllers.delete(controller);
|
|
218
|
+
busy.delete(sensor.raft);
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
for (var _c = 0, _d = getColourSensors(raftId); _c < _d.length; _c++) {
|
|
222
|
+
var sensor = _d[_c];
|
|
223
|
+
_loop_1(sensor);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var timer = setInterval(poll, 1000);
|
|
228
|
+
return function () { clearInterval(timer); controllers.forEach(function (controller) { return controller.abort(); }); };
|
|
229
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ColourSensor } from "./colour-sensor-diagnostics";
|
|
2
|
+
type ReadFailure = "unsupported" | "timeout" | "commandFailed" | "invalidResponse" | "initialising" | "offline";
|
|
3
|
+
export type SensorRead<T> = {
|
|
4
|
+
requestedAtMs: number;
|
|
5
|
+
receivedAtMs: number;
|
|
6
|
+
} & ({
|
|
7
|
+
status: "ok";
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
status: "unavailable";
|
|
11
|
+
reason: ReadFailure;
|
|
12
|
+
});
|
|
13
|
+
type Channels = {
|
|
14
|
+
clear: number;
|
|
15
|
+
red: number;
|
|
16
|
+
green: number;
|
|
17
|
+
blue: number;
|
|
18
|
+
hexRd: string;
|
|
19
|
+
};
|
|
20
|
+
export type RawColourFrame = Channels & {
|
|
21
|
+
sensorStatusByte: number;
|
|
22
|
+
detectionFlags: number;
|
|
23
|
+
isOnAir: boolean;
|
|
24
|
+
touch: boolean;
|
|
25
|
+
irVal: number;
|
|
26
|
+
irReading: number;
|
|
27
|
+
irAmbient: number;
|
|
28
|
+
};
|
|
29
|
+
type SensorHardware = {
|
|
30
|
+
firmwareVersion: string | null;
|
|
31
|
+
typeCode: string | null;
|
|
32
|
+
serialNumber: string | null;
|
|
33
|
+
commsOk: number | null;
|
|
34
|
+
};
|
|
35
|
+
export type ColourSensorSetup = {
|
|
36
|
+
readiness: SensorRead<boolean>;
|
|
37
|
+
power?: SensorRead<boolean>;
|
|
38
|
+
hardware: SensorRead<SensorHardware>;
|
|
39
|
+
groundThreshold: SensorRead<{
|
|
40
|
+
storedValue: number;
|
|
41
|
+
hexRd: string;
|
|
42
|
+
}>;
|
|
43
|
+
offsets: SensorRead<Channels>;
|
|
44
|
+
whiteCalibration: SensorRead<Channels>;
|
|
45
|
+
};
|
|
46
|
+
export type ColourSensorRegister = "4014" | "4018" | "4020";
|
|
47
|
+
export declare const readColourSensorRegister: (sensor: ColourSensor, address: ColourSensorRegister, signal: AbortSignal, checkActive: () => void) => Promise<SensorRead<string>>;
|
|
48
|
+
export declare const readColourSensorHardware: (sensor: ColourSensor, signal: AbortSignal, checkActive: () => void) => Promise<SensorRead<SensorHardware>>;
|
|
49
|
+
export declare const wakeColourSensor: (sensor: ColourSensor, signal: AbortSignal, checkActive: () => void) => Promise<SensorRead<boolean>>;
|
|
50
|
+
export declare const readColourSensorReadiness: (sensor: ColourSensor, signal: AbortSignal, checkActive: () => void) => Promise<SensorRead<boolean>>;
|
|
51
|
+
export declare const collectColourSensorSetup: (sensor: ColourSensor, signal: AbortSignal, checkActive: () => void) => Promise<ColourSensorSetup>;
|
|
52
|
+
export declare const readRawColourSensor: (sensor: ColourSensor, signal: AbortSignal, checkActive: () => void) => Promise<SensorRead<RawColourFrame>>;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
23
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
import { RICHWElemList_Str } from "@robotical/roboticaljs";
|
|
49
|
+
var READ_TIMEOUT_MS = 1500;
|
|
50
|
+
// The caller checks robot ownership, visibility and cancellation. Every exit removes the temporary observer.
|
|
51
|
+
var read = function (signal, checkActive, start, timeoutMs) {
|
|
52
|
+
if (timeoutMs === void 0) { timeoutMs = READ_TIMEOUT_MS; }
|
|
53
|
+
return new Promise(function (resolve, reject) {
|
|
54
|
+
checkActive();
|
|
55
|
+
var requestedAtMs = Date.now();
|
|
56
|
+
var finished = false;
|
|
57
|
+
var dispose = function () { };
|
|
58
|
+
var cleanup = function () {
|
|
59
|
+
clearTimeout(timeout);
|
|
60
|
+
clearInterval(watchdog);
|
|
61
|
+
signal.removeEventListener("abort", guard);
|
|
62
|
+
dispose();
|
|
63
|
+
};
|
|
64
|
+
var finish = function (result) {
|
|
65
|
+
if (finished)
|
|
66
|
+
return;
|
|
67
|
+
finished = true;
|
|
68
|
+
cleanup();
|
|
69
|
+
resolve(__assign({ requestedAtMs: requestedAtMs, receivedAtMs: Date.now() }, result));
|
|
70
|
+
};
|
|
71
|
+
var guard = function () {
|
|
72
|
+
if (finished)
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
checkActive();
|
|
76
|
+
}
|
|
77
|
+
catch (failure) {
|
|
78
|
+
finished = true;
|
|
79
|
+
cleanup();
|
|
80
|
+
reject(failure);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var timeout = setTimeout(function () {
|
|
84
|
+
guard();
|
|
85
|
+
finish({ status: "unavailable", reason: "timeout" });
|
|
86
|
+
}, timeoutMs);
|
|
87
|
+
var watchdog = setInterval(guard, 100);
|
|
88
|
+
signal.addEventListener("abort", guard, { once: true });
|
|
89
|
+
var ok = function (value) { guard(); finish({ status: "ok", value: value }); };
|
|
90
|
+
var unavailable = function (reason) { guard(); finish({ status: "unavailable", reason: reason }); };
|
|
91
|
+
try {
|
|
92
|
+
dispose = start(ok, unavailable) || (function () { });
|
|
93
|
+
}
|
|
94
|
+
catch (_a) {
|
|
95
|
+
unavailable("commandFailed");
|
|
96
|
+
}
|
|
97
|
+
if (finished)
|
|
98
|
+
dispose();
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
var readHex = function (sensor, hexWr, bytes, signal, checkActive) {
|
|
102
|
+
return read(signal, checkActive, function (ok, unavailable) {
|
|
103
|
+
var raft = sensor.raft;
|
|
104
|
+
if (!raft.sendRestMessage || !raft.subscribe || !raft.unsubscribe) {
|
|
105
|
+
unavailable("unsupported");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
var keyBytes = new Uint8Array(8);
|
|
109
|
+
window.crypto.getRandomValues(keyBytes);
|
|
110
|
+
var msgKey = "cd".concat(Array.from(keyBytes, function (byte) { return byte.toString(16).padStart(2, "0"); }).join(""));
|
|
111
|
+
var observer = {
|
|
112
|
+
notify: function (eventType, _eventEnum, _eventName, report) {
|
|
113
|
+
// Current RIC firmware labels raw-command replies "raw"; older add-on drivers use "addOnRx".
|
|
114
|
+
if (eventType !== "msg" || ((report === null || report === void 0 ? void 0 : report.msgType) !== "raw" && (report === null || report === void 0 ? void 0 : report.msgType) !== "addOnRx") || report.elemName !== sensor.addon.name ||
|
|
115
|
+
String(report.msgKey) !== msgKey || (report.IDNo !== undefined && Number(report.IDNo) !== sensor.addon.id))
|
|
116
|
+
return;
|
|
117
|
+
if (typeof report.hexRd !== "string" || !new RegExp("^[a-f0-9]{".concat(bytes * 2, "}$"), "i").test(report.hexRd)) {
|
|
118
|
+
unavailable("invalidResponse");
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
ok(report.hexRd.toLowerCase());
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
raft.subscribe(observer, ["msg"]);
|
|
126
|
+
// 0x10 selects an EEPROM read address; an empty write requests an atomic sample. No settings are written.
|
|
127
|
+
try {
|
|
128
|
+
raft.sendRestMessage("elem/".concat(encodeURIComponent(sensor.addon.name), "/json?cmd=raw&hexWr=").concat(hexWr, "&numToRd=").concat(bytes, "&msgKey=").concat(msgKey))
|
|
129
|
+
.then(function (result) {
|
|
130
|
+
if (!result || result.rslt !== "ok")
|
|
131
|
+
unavailable("commandFailed");
|
|
132
|
+
}, function () { return unavailable("commandFailed"); });
|
|
133
|
+
}
|
|
134
|
+
catch (_a) {
|
|
135
|
+
unavailable("commandFailed");
|
|
136
|
+
}
|
|
137
|
+
return function () { return raft.unsubscribe(observer); };
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
export var readColourSensorRegister = function (sensor, address, signal, checkActive) {
|
|
141
|
+
return readHex(sensor, "10".concat(address), { "4014": 2, "4018": 4, "4020": 8 }[address], signal, checkActive);
|
|
142
|
+
};
|
|
143
|
+
var mapRead = function (result, convert) {
|
|
144
|
+
return result.status === "ok" ? __assign(__assign({}, result), { value: convert(result.value) }) : result;
|
|
145
|
+
};
|
|
146
|
+
var byteAt = function (hex, byte) { return parseInt(hex.slice(byte * 2, byte * 2 + 2), 16); };
|
|
147
|
+
var wordAt = function (hex, byte) { return parseInt(hex.slice(byte * 2, byte * 2 + 4), 16); };
|
|
148
|
+
var channels = function (hexRd, word) {
|
|
149
|
+
var valueAt = word ? wordAt : byteAt;
|
|
150
|
+
var step = word ? 2 : 1;
|
|
151
|
+
return { hexRd: hexRd, clear: valueAt(hexRd, 0), red: valueAt(hexRd, step), green: valueAt(hexRd, step * 2), blue: valueAt(hexRd, step * 3) };
|
|
152
|
+
};
|
|
153
|
+
export var readColourSensorHardware = function (sensor, signal, checkActive) {
|
|
154
|
+
return read(signal, checkActive, function (ok, unavailable) {
|
|
155
|
+
if (!sensor.raft.sendRestMessage) {
|
|
156
|
+
unavailable("unsupported");
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
var stopped = false;
|
|
160
|
+
var request = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
161
|
+
var response, encoded, elements, element, stringOrNull;
|
|
162
|
+
return __generator(this, function (_a) {
|
|
163
|
+
switch (_a.label) {
|
|
164
|
+
case 0: return [4 /*yield*/, sensor.raft.sendRestMessage("hwstatus/strstat?filterByType=RSAddOn")];
|
|
165
|
+
case 1:
|
|
166
|
+
response = _a.sent();
|
|
167
|
+
if (stopped)
|
|
168
|
+
return [2 /*return*/];
|
|
169
|
+
checkActive();
|
|
170
|
+
if (!((response === null || response === void 0 ? void 0 : response.rslt) !== "ok" || !Array.isArray(response.hw) || response.hw.some(function (item) { return typeof item === "string"; }))) return [3 /*break*/, 3];
|
|
171
|
+
return [4 /*yield*/, sensor.raft.sendRestMessage("hwstatus?filterByType=RSAddOn")];
|
|
172
|
+
case 2:
|
|
173
|
+
response = (_a.sent());
|
|
174
|
+
if (stopped)
|
|
175
|
+
return [2 /*return*/];
|
|
176
|
+
checkActive();
|
|
177
|
+
_a.label = 3;
|
|
178
|
+
case 3:
|
|
179
|
+
if ((response === null || response === void 0 ? void 0 : response.rslt) !== "ok" || !Array.isArray(response.hw)) {
|
|
180
|
+
unavailable("invalidResponse");
|
|
181
|
+
return [2 /*return*/];
|
|
182
|
+
}
|
|
183
|
+
encoded = response.hw.some(function (item) { return typeof (item === null || item === void 0 ? void 0 : item.a) === "string"; });
|
|
184
|
+
if (encoded && response.hw.some(function (item) { return typeof (item === null || item === void 0 ? void 0 : item.a) !== "string" || item.a.split("|").length < 8; })) {
|
|
185
|
+
unavailable("invalidResponse");
|
|
186
|
+
return [2 /*return*/];
|
|
187
|
+
}
|
|
188
|
+
elements = encoded ? RICHWElemList_Str.expand(response).hw : response.hw;
|
|
189
|
+
element = elements.find(function (item) { return (item === null || item === void 0 ? void 0 : item.name) === sensor.addon.name && item.whoAmI === sensor.addon.whoAmI; });
|
|
190
|
+
if (!element) {
|
|
191
|
+
unavailable("invalidResponse");
|
|
192
|
+
return [2 /*return*/];
|
|
193
|
+
}
|
|
194
|
+
stringOrNull = function (value) { return typeof value === "string" && value.length ? value : null; };
|
|
195
|
+
ok({ firmwareVersion: stringOrNull(element.versionStr), typeCode: stringOrNull(element.whoAmITypeCode), serialNumber: stringOrNull(element.SN),
|
|
196
|
+
commsOk: typeof element.commsOk === "number" ? element.commsOk : null });
|
|
197
|
+
return [2 /*return*/];
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}); };
|
|
201
|
+
request().catch(function () { return unavailable("commandFailed"); });
|
|
202
|
+
return function () { stopped = true; };
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
// Marty can keep BLE alive after its idle timer turns off the 5V sensor/servo supply.
|
|
206
|
+
// This is the same temporary wake command used by colour calibration; it does not write settings or move joints.
|
|
207
|
+
export var wakeColourSensor = function (sensor, signal, checkActive) {
|
|
208
|
+
return read(signal, checkActive, function (ok, unavailable) {
|
|
209
|
+
if (!sensor.raft.sendRestMessage) {
|
|
210
|
+
unavailable("unsupported");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
var requestedAtMs = Date.now();
|
|
214
|
+
var acknowledged = false;
|
|
215
|
+
var inspect = function () {
|
|
216
|
+
var _a;
|
|
217
|
+
if (!acknowledged)
|
|
218
|
+
return;
|
|
219
|
+
var state = sensor.raft.raftStateInfo;
|
|
220
|
+
var addon = state === null || state === void 0 ? void 0 : state.addOnInfo.addons.find(function (item) { return item.id === sensor.addon.id && item.name === sensor.addon.name; });
|
|
221
|
+
// Wait for a new online frame, rather than accepting cached telemetry from before the wake command.
|
|
222
|
+
if (addon && state.addOnInfoValidMs >= requestedAtMs && ((_a = state === null || state === void 0 ? void 0 : state.power) === null || _a === void 0 ? void 0 : _a.powerStatus.power5VIsOn) !== false &&
|
|
223
|
+
(addon.status === undefined || Boolean(addon.status & 0x80)))
|
|
224
|
+
ok(true);
|
|
225
|
+
};
|
|
226
|
+
var timer = setInterval(inspect, 100);
|
|
227
|
+
try {
|
|
228
|
+
sensor.raft.sendRestMessage("pwrctrl/5von").then(function (response) {
|
|
229
|
+
if ((response === null || response === void 0 ? void 0 : response.rslt) !== "ok") {
|
|
230
|
+
unavailable("commandFailed");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
acknowledged = true;
|
|
234
|
+
inspect();
|
|
235
|
+
}, function () { return unavailable("commandFailed"); });
|
|
236
|
+
}
|
|
237
|
+
catch (_a) {
|
|
238
|
+
unavailable("commandFailed");
|
|
239
|
+
}
|
|
240
|
+
return function () { return clearInterval(timer); };
|
|
241
|
+
}, 5000);
|
|
242
|
+
};
|
|
243
|
+
export var readColourSensorReadiness = function (sensor, signal, checkActive) {
|
|
244
|
+
return read(signal, checkActive, function (ok, unavailable) {
|
|
245
|
+
if (!sensor.raft.sendRestMessage) {
|
|
246
|
+
unavailable("unsupported");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
sensor.raft.sendRestMessage("diagnostics/colourSensorReady").then(function (response) {
|
|
250
|
+
var result = response;
|
|
251
|
+
if ((result === null || result === void 0 ? void 0 : result.rslt) === "ok" && result.colourDiagnosticsProtocol === 1 && typeof result.ready === "boolean")
|
|
252
|
+
ok(result.ready);
|
|
253
|
+
else
|
|
254
|
+
unavailable("unsupported");
|
|
255
|
+
}, function () { return unavailable("unsupported"); });
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
export var collectColourSensorSetup = function (sensor, signal, checkActive) { return __awaiter(void 0, void 0, void 0, function () {
|
|
259
|
+
var readiness, missing, power, hardware, missing, groundThreshold, _a, offsets, _b, whiteCalibration, _c;
|
|
260
|
+
return __generator(this, function (_d) {
|
|
261
|
+
switch (_d.label) {
|
|
262
|
+
case 0: return [4 /*yield*/, readColourSensorReadiness(sensor, signal, checkActive)];
|
|
263
|
+
case 1:
|
|
264
|
+
readiness = _d.sent();
|
|
265
|
+
if (readiness.status !== "ok" || !readiness.value) {
|
|
266
|
+
missing = { requestedAtMs: readiness.requestedAtMs, receivedAtMs: readiness.receivedAtMs,
|
|
267
|
+
status: "unavailable", reason: readiness.status === "unavailable" ? readiness.reason : "initialising" };
|
|
268
|
+
return [2 /*return*/, { readiness: readiness, hardware: missing, groundThreshold: missing, offsets: missing, whiteCalibration: missing }];
|
|
269
|
+
}
|
|
270
|
+
return [4 /*yield*/, wakeColourSensor(sensor, signal, checkActive)];
|
|
271
|
+
case 2:
|
|
272
|
+
power = _d.sent();
|
|
273
|
+
if (power.status !== "ok") {
|
|
274
|
+
return [2 /*return*/, { readiness: readiness, power: power, hardware: power, groundThreshold: power, offsets: power, whiteCalibration: power }];
|
|
275
|
+
}
|
|
276
|
+
return [4 /*yield*/, readColourSensorHardware(sensor, signal, checkActive)];
|
|
277
|
+
case 3:
|
|
278
|
+
hardware = _d.sent();
|
|
279
|
+
if (hardware.status === "ok" && hardware.value.commsOk === 0) {
|
|
280
|
+
missing = { requestedAtMs: hardware.requestedAtMs, receivedAtMs: hardware.receivedAtMs,
|
|
281
|
+
status: "unavailable", reason: "offline" };
|
|
282
|
+
return [2 /*return*/, { readiness: readiness, power: power, hardware: hardware, groundThreshold: missing, offsets: missing, whiteCalibration: missing }];
|
|
283
|
+
}
|
|
284
|
+
_a = mapRead;
|
|
285
|
+
return [4 /*yield*/, readHex(sensor, "104014", 2, signal, checkActive)];
|
|
286
|
+
case 4:
|
|
287
|
+
groundThreshold = _a.apply(void 0, [_d.sent(), function (hexRd) { return ({ storedValue: wordAt(hexRd, 0), hexRd: hexRd }); }]);
|
|
288
|
+
_b = mapRead;
|
|
289
|
+
return [4 /*yield*/, readHex(sensor, "104018", 4, signal, checkActive)];
|
|
290
|
+
case 5:
|
|
291
|
+
offsets = _b.apply(void 0, [_d.sent(), function (hexRd) { return channels(hexRd, false); }]);
|
|
292
|
+
_c = mapRead;
|
|
293
|
+
return [4 /*yield*/, readHex(sensor, "104020", 8, signal, checkActive)];
|
|
294
|
+
case 6:
|
|
295
|
+
whiteCalibration = _c.apply(void 0, [_d.sent(), function (hexRd) { return channels(hexRd, true); }]);
|
|
296
|
+
return [2 /*return*/, { readiness: readiness, power: power, hardware: hardware, groundThreshold: groundThreshold, offsets: offsets, whiteCalibration: whiteCalibration }];
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}); };
|
|
300
|
+
export var readRawColourSensor = function (sensor, signal, checkActive) { return __awaiter(void 0, void 0, void 0, function () {
|
|
301
|
+
var _a;
|
|
302
|
+
return __generator(this, function (_b) {
|
|
303
|
+
switch (_b.label) {
|
|
304
|
+
case 0:
|
|
305
|
+
_a = mapRead;
|
|
306
|
+
return [4 /*yield*/, readHex(sensor, "", 13, signal, checkActive)];
|
|
307
|
+
case 1: return [2 /*return*/, _a.apply(void 0, [_b.sent(), function (hexRd) { return (__assign(__assign({}, channels(hexRd.slice(2, 10), false)), { hexRd: hexRd, sensorStatusByte: byteAt(hexRd, 0), detectionFlags: byteAt(hexRd, 6), isOnAir: Boolean(byteAt(hexRd, 6) & 2), touch: Boolean(byteAt(hexRd, 6) & 1), irVal: wordAt(hexRd, 7), irReading: wordAt(hexRd, 9), irAmbient: wordAt(hexRd, 11) })); }])];
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}); };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"source": "Marty web app
|
|
2
|
+
"source": "Marty web app RGB signal policy v4",
|
|
3
|
+
"clearBoundsUsedForClassification": false,
|
|
4
|
+
"signal": { "minimumChroma": 8, "minimumSaturation": 0.15, "airNoiseMarginRaw": 3 },
|
|
3
5
|
"boundaries": [
|
|
4
6
|
{ "hue": [0, 15], "chroma": [50, 200], "clear": [40, 150], "name": "red" },
|
|
5
7
|
{ "hue": [20, 65], "chroma": [40, 300], "clear": [100, 255], "name": "yellow" },
|
|
6
|
-
{ "hue": [
|
|
7
|
-
{ "hue": [180, 240], "chroma": [40,
|
|
8
|
+
{ "hue": [75, 160], "chroma": [5, 100], "clear": [25, 150], "name": "green" },
|
|
9
|
+
{ "hue": [180, 240], "chroma": [40, 260], "clear": [55, 255], "name": "blue" },
|
|
8
10
|
{ "hue": [240, 320], "chroma": [5, 100], "clear": [10, 150], "name": "purple" },
|
|
9
11
|
{ "hue": [345, 361], "chroma": [50, 200], "clear": [40, 150], "name": "red" }
|
|
10
12
|
]
|