@microbit/microbit-connection 0.0.0-alpha.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 (68) hide show
  1. package/README.md +36 -0
  2. package/build/accelerometer-service.d.ts +17 -0
  3. package/build/accelerometer-service.js +84 -0
  4. package/build/accelerometer-service.js.map +1 -0
  5. package/build/accelerometer.d.ts +9 -0
  6. package/build/accelerometer.js +12 -0
  7. package/build/accelerometer.js.map +1 -0
  8. package/build/async-util.d.ts +13 -0
  9. package/build/async-util.js +22 -0
  10. package/build/async-util.js.map +1 -0
  11. package/build/bluetooth-device-wrapper.d.ts +39 -0
  12. package/build/bluetooth-device-wrapper.js +316 -0
  13. package/build/bluetooth-device-wrapper.js.map +1 -0
  14. package/build/bluetooth-profile.d.ts +139 -0
  15. package/build/bluetooth-profile.js +83 -0
  16. package/build/bluetooth-profile.js.map +1 -0
  17. package/build/bluetooth.d.ts +50 -0
  18. package/build/bluetooth.js +247 -0
  19. package/build/bluetooth.js.map +1 -0
  20. package/build/board-id.d.ts +35 -0
  21. package/build/board-id.js +69 -0
  22. package/build/board-id.js.map +1 -0
  23. package/build/board-serial-info.d.ts +14 -0
  24. package/build/board-serial-info.js +47 -0
  25. package/build/board-serial-info.js.map +1 -0
  26. package/build/constants.d.ts +47 -0
  27. package/build/constants.js +69 -0
  28. package/build/constants.js.map +1 -0
  29. package/build/device.d.ts +202 -0
  30. package/build/device.js +153 -0
  31. package/build/device.js.map +1 -0
  32. package/build/events.d.ts +101 -0
  33. package/build/events.js +19 -0
  34. package/build/events.js.map +1 -0
  35. package/build/hex-flash-data-source.d.ts +9 -0
  36. package/build/hex-flash-data-source.js +50 -0
  37. package/build/hex-flash-data-source.js.map +1 -0
  38. package/build/index.d.ts +7 -0
  39. package/build/index.js +7 -0
  40. package/build/index.js.map +1 -0
  41. package/build/logging.d.ts +21 -0
  42. package/build/logging.js +10 -0
  43. package/build/logging.js.map +1 -0
  44. package/build/service-events.d.ts +9 -0
  45. package/build/service-events.js +11 -0
  46. package/build/service-events.js.map +1 -0
  47. package/build/setupTests.d.ts +6 -0
  48. package/build/setupTests.js.map +1 -0
  49. package/build/usb-device-wrapper.d.ts +46 -0
  50. package/build/usb-device-wrapper.js +347 -0
  51. package/build/usb-device-wrapper.js.map +1 -0
  52. package/build/usb-partial-flashing-utils.d.ts +17 -0
  53. package/build/usb-partial-flashing-utils.js +122 -0
  54. package/build/usb-partial-flashing-utils.js.map +1 -0
  55. package/build/usb-partial-flashing.d.ts +63 -0
  56. package/build/usb-partial-flashing.js +270 -0
  57. package/build/usb-partial-flashing.js.map +1 -0
  58. package/build/usb-radio-bridge.d.ts +28 -0
  59. package/build/usb-radio-bridge.js +318 -0
  60. package/build/usb-radio-bridge.js.map +1 -0
  61. package/build/usb-serial-protocol.d.ts +66 -0
  62. package/build/usb-serial-protocol.js +171 -0
  63. package/build/usb-serial-protocol.js.map +1 -0
  64. package/build/usb.d.ts +61 -0
  65. package/build/usb.js +451 -0
  66. package/build/usb.js.map +1 -0
  67. package/package.json +32 -0
  68. package/vite.config.ts +32 -0
@@ -0,0 +1,318 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * (c) 2023, Center for Computational Thinking and Design at Aarhus University and contributors
4
+ *
5
+ * SPDX-License-Identifier: MIT
6
+ */
7
+ import * as protocol from "./usb-serial-protocol";
8
+ const connectTimeoutDuration = 10000;
9
+ class BridgeError extends Error {
10
+ }
11
+ class RemoteError extends Error {
12
+ }
13
+ export class MicrobitRadioBridgeConnection {
14
+ constructor(usb, logging, remoteDeviceId) {
15
+ Object.defineProperty(this, "usb", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: usb
20
+ });
21
+ Object.defineProperty(this, "logging", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: logging
26
+ });
27
+ Object.defineProperty(this, "remoteDeviceId", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: remoteDeviceId
32
+ });
33
+ Object.defineProperty(this, "responseMap", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: new Map()
38
+ });
39
+ // To avoid concurrent connect attempts
40
+ Object.defineProperty(this, "isConnecting", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: false
45
+ });
46
+ Object.defineProperty(this, "connectionCheckIntervalId", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: void 0
51
+ });
52
+ Object.defineProperty(this, "lastReceivedMessageTimestamp", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ Object.defineProperty(this, "isReconnect", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: false
63
+ });
64
+ // Whether this is the final reconnection attempt.
65
+ Object.defineProperty(this, "finalAttempt", {
66
+ enumerable: true,
67
+ configurable: true,
68
+ writable: true,
69
+ value: false
70
+ });
71
+ }
72
+ async connect() {
73
+ this.logging.event({
74
+ type: this.isReconnect ? "Reconnect" : "Connect",
75
+ message: "Serial connect start",
76
+ });
77
+ if (this.isConnecting) {
78
+ this.logging.log("Skipping connect attempt when one is already in progress");
79
+ return;
80
+ }
81
+ this.isConnecting = true;
82
+ let unprocessedData = "";
83
+ let previousButtonState = { A: 0, B: 0 };
84
+ let onPeriodicMessageRecieved;
85
+ const handleError = (e) => {
86
+ this.logging.error("Serial error", e);
87
+ void this.disconnectInternal(false, "bridge");
88
+ };
89
+ const processMessage = (data) => {
90
+ const messages = protocol.splitMessages(unprocessedData + data);
91
+ unprocessedData = messages.remainingInput;
92
+ messages.messages.forEach(async (msg) => {
93
+ this.lastReceivedMessageTimestamp = Date.now();
94
+ // Messages are either periodic sensor data or command/response
95
+ const sensorData = protocol.processPeriodicMessage(msg);
96
+ if (sensorData) {
97
+ // stateOnReconnected();
98
+ // if (onPeriodicMessageRecieved) {
99
+ // onPeriodicMessageRecieved();
100
+ // onPeriodicMessageRecieved = undefined;
101
+ // }
102
+ // onAccelerometerChange(
103
+ // sensorData.accelerometerX,
104
+ // sensorData.accelerometerY,
105
+ // sensorData.accelerometerZ
106
+ // );
107
+ // if (sensorData.buttonA !== previousButtonState.A) {
108
+ // previousButtonState.A = sensorData.buttonA;
109
+ // onButtonChange(sensorData.buttonA, "A");
110
+ // }
111
+ // if (sensorData.buttonB !== previousButtonState.B) {
112
+ // previousButtonState.B = sensorData.buttonB;
113
+ // onButtonChange(sensorData.buttonB, "B");
114
+ // }
115
+ }
116
+ else {
117
+ const messageResponse = protocol.processResponseMessage(msg);
118
+ if (!messageResponse) {
119
+ return;
120
+ }
121
+ const responseResolve = this.responseMap.get(messageResponse.messageId);
122
+ if (responseResolve) {
123
+ this.responseMap.delete(messageResponse.messageId);
124
+ responseResolve(messageResponse);
125
+ }
126
+ }
127
+ });
128
+ };
129
+ try {
130
+ await this.usb.startSerial(processMessage, handleError);
131
+ await this.handshake();
132
+ // stateOnConnected(DeviceRequestStates.INPUT);
133
+ // Check for connection lost
134
+ if (this.connectionCheckIntervalId === undefined) {
135
+ this.connectionCheckIntervalId = setInterval(async () => {
136
+ if (this.lastReceivedMessageTimestamp &&
137
+ Date.now() - this.lastReceivedMessageTimestamp > 1_000) {
138
+ // stateOnReconnectionAttempt();
139
+ }
140
+ if (this.lastReceivedMessageTimestamp &&
141
+ Date.now() - this.lastReceivedMessageTimestamp >
142
+ connectTimeoutDuration) {
143
+ await this.handleReconnect();
144
+ }
145
+ }, 1000);
146
+ }
147
+ this.logging.log(`Serial: using remote device id ${this.remoteDeviceId}`);
148
+ const remoteMbIdCommand = protocol.generateCmdRemoteMbId(this.remoteDeviceId);
149
+ const remoteMbIdResponse = await this.sendCmdWaitResponse(remoteMbIdCommand);
150
+ if (remoteMbIdResponse.type === protocol.ResponseTypes.Error ||
151
+ remoteMbIdResponse.value !== this.remoteDeviceId) {
152
+ throw new BridgeError(`Failed to set remote micro:bit ID. Expected ${this.remoteDeviceId}, got ${remoteMbIdResponse.value}`);
153
+ }
154
+ // For now we only support input state.
155
+ // TODO: when do we do this?
156
+ if (false) {
157
+ // Request the micro:bit to start sending the periodic messages
158
+ const startCmd = protocol.generateCmdStart({
159
+ accelerometer: true,
160
+ buttons: true,
161
+ });
162
+ const periodicMessagePromise = new Promise((resolve, reject) => {
163
+ onPeriodicMessageRecieved = resolve;
164
+ setTimeout(() => {
165
+ onPeriodicMessageRecieved = undefined;
166
+ reject(new Error("Failed to receive data from remote micro:bit"));
167
+ }, 500);
168
+ });
169
+ const startCmdResponse = await this.sendCmdWaitResponse(startCmd);
170
+ if (startCmdResponse.type === protocol.ResponseTypes.Error) {
171
+ throw new RemoteError(`Failed to start streaming sensors data. Error response received: ${startCmdResponse.message}`);
172
+ }
173
+ if (this.isReconnect) {
174
+ await periodicMessagePromise;
175
+ }
176
+ else {
177
+ periodicMessagePromise.catch(async (e) => {
178
+ this.logging.error("Failed to initialise serial protocol", e);
179
+ await this.disconnectInternal(false, "remote");
180
+ this.isConnecting = false;
181
+ });
182
+ }
183
+ }
184
+ // stateOnAssigned(DeviceRequestStates.INPUT, this.usb.getModelNumber());
185
+ // stateOnReady(DeviceRequestStates.INPUT);
186
+ this.logging.event({
187
+ type: this.isReconnect ? "Reconnect" : "Connect",
188
+ message: "Serial connect success",
189
+ });
190
+ }
191
+ catch (e) {
192
+ this.logging.error("Failed to initialise serial protocol", e);
193
+ this.logging.event({
194
+ type: this.isReconnect ? "Reconnect" : "Connect",
195
+ message: "Serial connect failed",
196
+ });
197
+ const reconnectHelp = e instanceof BridgeError ? "bridge" : "remote";
198
+ await this.disconnectInternal(false, reconnectHelp);
199
+ throw e;
200
+ }
201
+ finally {
202
+ this.finalAttempt = false;
203
+ this.isConnecting = false;
204
+ }
205
+ }
206
+ async disconnect() {
207
+ return this.disconnectInternal(true, "bridge");
208
+ }
209
+ stopConnectionCheck() {
210
+ clearInterval(this.connectionCheckIntervalId);
211
+ this.connectionCheckIntervalId = undefined;
212
+ this.lastReceivedMessageTimestamp = undefined;
213
+ }
214
+ async disconnectInternal(userDisconnect) {
215
+ this.stopConnectionCheck();
216
+ try {
217
+ await this.sendCmdWaitResponse(protocol.generateCmdStop());
218
+ }
219
+ catch (e) {
220
+ // If this fails the remote micro:bit has already gone away.
221
+ }
222
+ this.responseMap.clear();
223
+ await this.usb.stopSerial();
224
+ // stateOnDisconnected(
225
+ // DeviceRequestStates.INPUT,
226
+ // userDisconnect || this.finalAttempt
227
+ // ? false
228
+ // : this.isReconnect
229
+ // ? "autoReconnect"
230
+ // : "connect",
231
+ // reconnectHelp
232
+ // );
233
+ }
234
+ async handleReconnect() {
235
+ if (this.isConnecting) {
236
+ this.logging.log("Serial disconnect ignored... reconnect already in progress");
237
+ return;
238
+ }
239
+ try {
240
+ this.stopConnectionCheck();
241
+ this.logging.log("Serial disconnected... automatically trying to reconnect");
242
+ this.responseMap.clear();
243
+ await this.usb.stopSerial();
244
+ await this.usb.softwareReset();
245
+ await this.reconnect();
246
+ }
247
+ catch (e) {
248
+ this.logging.error("Serial connect triggered by disconnect listener failed", e);
249
+ }
250
+ finally {
251
+ this.isConnecting = false;
252
+ }
253
+ }
254
+ async reconnect(finalAttempt = false) {
255
+ this.finalAttempt = finalAttempt;
256
+ this.logging.log("Serial reconnect");
257
+ this.isReconnect = true;
258
+ await this.connect();
259
+ }
260
+ async sendCmdWaitResponse(cmd) {
261
+ const responsePromise = new Promise((resolve, reject) => {
262
+ this.responseMap.set(cmd.messageId, resolve);
263
+ setTimeout(() => {
264
+ this.responseMap.delete(cmd.messageId);
265
+ reject(new Error(`Timeout waiting for response ${cmd.messageId}`));
266
+ }, 1_000);
267
+ });
268
+ await this.usb.serialWrite(cmd.message);
269
+ return responsePromise;
270
+ }
271
+ async handshake() {
272
+ // There is an issue where we cannot read data out from the micro:bit serial
273
+ // buffer until the buffer has been filled.
274
+ // As a workaround we can spam the micro:bit with handshake messages until
275
+ // enough responses have been queued in the buffer to fill it and the data
276
+ // starts to flow.
277
+ this.logging.log("Serial handshake");
278
+ const handshakeResult = await new Promise(async (resolve, reject) => {
279
+ const attempts = 20;
280
+ let attemptCounter = 0;
281
+ let failureCounter = 0;
282
+ let resolved = false;
283
+ while (attemptCounter < 20 && !resolved) {
284
+ attemptCounter++;
285
+ this.sendCmdWaitResponse(protocol.generateCmdHandshake())
286
+ .then((value) => {
287
+ if (!resolved) {
288
+ resolved = true;
289
+ resolve(value);
290
+ }
291
+ })
292
+ .catch(() => {
293
+ // We expect some to time out, likely well after the handshake is completed.
294
+ if (!resolved) {
295
+ if (++failureCounter === attempts) {
296
+ reject(new BridgeError("Handshake not completed"));
297
+ }
298
+ }
299
+ });
300
+ await new Promise((resolve) => setTimeout(resolve, 100));
301
+ }
302
+ });
303
+ if (handshakeResult.value !== protocol.version) {
304
+ throw new BridgeError(`Handshake failed. Unexpected protocol version ${protocol.version}`);
305
+ }
306
+ }
307
+ }
308
+ export const startSerialConnection = async (logging, usb, remoteDeviceId) => {
309
+ try {
310
+ const serial = new MicrobitRadioBridgeConnection(usb, logging, remoteDeviceId);
311
+ await serial.connect();
312
+ return serial;
313
+ }
314
+ catch (e) {
315
+ return undefined;
316
+ }
317
+ };
318
+ //# sourceMappingURL=usb-radio-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usb-radio-bridge.js","sourceRoot":"","sources":["../lib/usb-radio-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * (c) 2024, Micro:bit Educational Foundation and contributors
3
+ *
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export type SplittedMessages = {
7
+ messages: string[];
8
+ remainingInput: string;
9
+ };
10
+ export declare enum CommandTypes {
11
+ Handshake = "HS",
12
+ RadioFrequency = "RF",
13
+ RemoteMbId = "RMBID",
14
+ SoftwareVersion = "SWVER",
15
+ HardwareVersion = "HWVER",
16
+ Zstart = "ZSTART",
17
+ Stop = "STOP"
18
+ }
19
+ declare enum ResponseExtraTypes {
20
+ Error = "ERROR"
21
+ }
22
+ export type ResponseTypes = CommandTypes | ResponseExtraTypes;
23
+ export declare const ResponseTypes: {
24
+ Error: ResponseExtraTypes.Error;
25
+ Handshake: CommandTypes.Handshake;
26
+ RadioFrequency: CommandTypes.RadioFrequency;
27
+ RemoteMbId: CommandTypes.RemoteMbId;
28
+ SoftwareVersion: CommandTypes.SoftwareVersion;
29
+ HardwareVersion: CommandTypes.HardwareVersion;
30
+ Zstart: CommandTypes.Zstart;
31
+ Stop: CommandTypes.Stop;
32
+ };
33
+ export type MessageCmd = {
34
+ message: string;
35
+ messageId: number;
36
+ type: CommandTypes;
37
+ value: number | string;
38
+ };
39
+ export type MessageResponse = {
40
+ message: string;
41
+ messageId: number;
42
+ type: ResponseTypes;
43
+ value: number | string;
44
+ };
45
+ export type MicrobitSensors = {
46
+ accelerometer: boolean;
47
+ buttons: boolean;
48
+ };
49
+ export type MicrobitSensorState = {
50
+ accelerometerX: number;
51
+ accelerometerY: number;
52
+ accelerometerZ: number;
53
+ buttonA: number;
54
+ buttonB: number;
55
+ };
56
+ export declare const version = 1;
57
+ export declare const splitMessages: (message: string) => SplittedMessages;
58
+ export declare const processResponseMessage: (message: string) => MessageResponse | undefined;
59
+ export declare const processPeriodicMessage: (message: string) => MicrobitSensorState | undefined;
60
+ export declare const generateCmdHandshake: () => MessageCmd;
61
+ export declare const generateCmdStart: (sensors: MicrobitSensors) => MessageCmd;
62
+ export declare const generateCmdStop: () => MessageCmd;
63
+ export declare const generateCmdRadioFrequency: (frequency: number) => MessageCmd;
64
+ export declare const generateCmdRemoteMbId: (remoteMicrobitId: number) => MessageCmd;
65
+ export declare const generateRandomRadioFrequency: () => number;
66
+ export {};
@@ -0,0 +1,171 @@
1
+ /**
2
+ * (c) 2024, Micro:bit Educational Foundation and contributors
3
+ *
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ var MessageTypes;
7
+ (function (MessageTypes) {
8
+ MessageTypes["Command"] = "C";
9
+ MessageTypes["Response"] = "R";
10
+ MessageTypes["Periodic"] = "P";
11
+ })(MessageTypes || (MessageTypes = {}));
12
+ export var CommandTypes;
13
+ (function (CommandTypes) {
14
+ CommandTypes["Handshake"] = "HS";
15
+ CommandTypes["RadioFrequency"] = "RF";
16
+ CommandTypes["RemoteMbId"] = "RMBID";
17
+ CommandTypes["SoftwareVersion"] = "SWVER";
18
+ CommandTypes["HardwareVersion"] = "HWVER";
19
+ CommandTypes["Zstart"] = "ZSTART";
20
+ CommandTypes["Stop"] = "STOP";
21
+ })(CommandTypes || (CommandTypes = {}));
22
+ var ResponseExtraTypes;
23
+ (function (ResponseExtraTypes) {
24
+ ResponseExtraTypes["Error"] = "ERROR";
25
+ })(ResponseExtraTypes || (ResponseExtraTypes = {}));
26
+ export const ResponseTypes = { ...CommandTypes, ...ResponseExtraTypes };
27
+ // Currently implemented protocol version
28
+ export const version = 1;
29
+ export const splitMessages = (message) => {
30
+ if (!message) {
31
+ return {
32
+ messages: [],
33
+ remainingInput: "",
34
+ };
35
+ }
36
+ let messages = message.split("\n");
37
+ let remainingInput = messages.pop() || "";
38
+ // Throw away any empty messages and messages that don't start with a valid type
39
+ messages = messages.filter((msg) => msg.length > 0 &&
40
+ Object.values(MessageTypes).includes(msg[0]));
41
+ // Any remaining input will be the start of the next message, so if it doesn't start
42
+ // with a valid type throw it away as it'll be prepended to the next serial string
43
+ if (remainingInput.length > 0 &&
44
+ !Object.values(MessageTypes).includes(remainingInput[0])) {
45
+ remainingInput = "";
46
+ }
47
+ return {
48
+ messages,
49
+ remainingInput,
50
+ };
51
+ };
52
+ export const processResponseMessage = (message) => {
53
+ // Regex for a message response with 3 groups:
54
+ // id -> The message ID, 1-8 hex characters
55
+ // cmd -> The command type, a string, only capital letters, matching CommandTypes
56
+ // value -> The response value, empty string or a word, number,
57
+ // or version (e.g 1.2.3) depending on the command type
58
+ const responseMatch = /^R\[(?<id>[0-9A-Fa-f]{1,8})\](?<cmd>[A-Z]+)\[(?<value>-?[\w.]*)\]$/.exec(message);
59
+ if (!responseMatch || !responseMatch.groups) {
60
+ return undefined;
61
+ }
62
+ const messageId = parseInt(responseMatch.groups["id"], 16);
63
+ if (isNaN(messageId)) {
64
+ return undefined;
65
+ }
66
+ const responseType = responseMatch.groups["cmd"];
67
+ if (!Object.values(ResponseTypes).includes(responseType)) {
68
+ return undefined;
69
+ }
70
+ let value = responseMatch.groups["value"];
71
+ switch (responseType) {
72
+ // Commands with numeric values
73
+ case ResponseTypes.Handshake:
74
+ case ResponseTypes.RadioFrequency:
75
+ case ResponseTypes.RemoteMbId:
76
+ case ResponseTypes.HardwareVersion:
77
+ case ResponseTypes.Error:
78
+ value = Number(value);
79
+ if (isNaN(value) || value < 0 || value > 0xffffffff) {
80
+ return undefined;
81
+ }
82
+ break;
83
+ // Commands without values
84
+ case ResponseTypes.Zstart:
85
+ case ResponseTypes.Stop:
86
+ if (value !== "") {
87
+ return undefined;
88
+ }
89
+ break;
90
+ // Semver-ish values (valid range 00.00.00 to 99.99.99)
91
+ case ResponseTypes.SoftwareVersion:
92
+ if (!/^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}$/.test(value)) {
93
+ return undefined;
94
+ }
95
+ break;
96
+ }
97
+ return {
98
+ message,
99
+ messageId,
100
+ type: responseType,
101
+ value,
102
+ };
103
+ };
104
+ export const processPeriodicMessage = (message) => {
105
+ // Basic checks to match the message being a compact periodic message
106
+ if (message.length !== 13 || message[0] !== MessageTypes.Periodic) {
107
+ return undefined;
108
+ }
109
+ // All characters except the first one should be hex
110
+ if (!/^[0-9A-Fa-f]+$/.test(message.substring(1))) {
111
+ return undefined;
112
+ }
113
+ // Only the two Least Significant Bits from the buttons are used
114
+ const buttons = parseInt(message[12], 16);
115
+ if (buttons > 3) {
116
+ return undefined;
117
+ }
118
+ return {
119
+ // The accelerometer data has been clamped to -2048 to 2047, and an offset
120
+ // added to make the values positive, so that needs to be reversed
121
+ accelerometerX: parseInt(message.substring(3, 6), 16) - 2048,
122
+ accelerometerY: parseInt(message.substring(6, 9), 16) - 2048,
123
+ accelerometerZ: parseInt(message.substring(9, 12), 16) - 2048,
124
+ // Button A is the LSB, button B is the next bit
125
+ buttonA: buttons & 1,
126
+ buttonB: (buttons >> 1) & 1,
127
+ };
128
+ };
129
+ const generateCommand = (cmdType, cmdData = "") => {
130
+ // Generate an random (enough) ID with max value of 8 hex digits
131
+ const msgID = Math.floor(Math.random() * 0xffffffff);
132
+ return {
133
+ message: `C[${msgID.toString(16).toUpperCase()}]${cmdType}[${cmdData}]\n`,
134
+ messageId: msgID,
135
+ type: cmdType,
136
+ value: cmdData,
137
+ };
138
+ };
139
+ export const generateCmdHandshake = () => {
140
+ return generateCommand(CommandTypes.Handshake);
141
+ };
142
+ export const generateCmdStart = (sensors) => {
143
+ let cmdData = "";
144
+ if (sensors.accelerometer) {
145
+ cmdData += "A";
146
+ }
147
+ if (sensors.buttons) {
148
+ cmdData += "B";
149
+ }
150
+ return generateCommand(CommandTypes.Zstart, cmdData);
151
+ };
152
+ export const generateCmdStop = () => {
153
+ return generateCommand(CommandTypes.Stop);
154
+ };
155
+ export const generateCmdRadioFrequency = (frequency) => {
156
+ if (frequency < 0 || frequency > 83) {
157
+ throw new Error("Radio frequency out of range");
158
+ }
159
+ return generateCommand(CommandTypes.RadioFrequency, frequency.toString());
160
+ };
161
+ export const generateCmdRemoteMbId = (remoteMicrobitId) => {
162
+ if (remoteMicrobitId < 0 || remoteMicrobitId > 0xffffffff) {
163
+ throw new Error("Remote micro:bit ID out of range");
164
+ }
165
+ return generateCommand(CommandTypes.RemoteMbId, remoteMicrobitId.toString());
166
+ };
167
+ export const generateRandomRadioFrequency = () => {
168
+ // The value range for radio frequencies is 0 to 83
169
+ return Math.floor(Math.random() * 84);
170
+ };
171
+ //# sourceMappingURL=usb-serial-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usb-serial-protocol.js","sourceRoot":"","sources":["../lib/usb-serial-protocol.ts"],"names":[],"mappings":"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"}
package/build/usb.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * (c) 2021, Micro:bit Educational Foundation and contributors
3
+ *
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Logging } from "./logging";
7
+ import { BoardVersion, ConnectionStatus, ConnectOptions, DeviceConnection, DeviceConnectionEventMap, FlashDataSource } from "./device";
8
+ import { TypedEventTarget } from "./events";
9
+ export declare const isChromeOS105: () => boolean;
10
+ export interface MicrobitWebUSBConnectionOptions {
11
+ logging: Logging;
12
+ }
13
+ /**
14
+ * A WebUSB connection to a micro:bit device.
15
+ */
16
+ export declare class MicrobitWebUSBConnection extends TypedEventTarget<DeviceConnectionEventMap> implements DeviceConnection {
17
+ status: ConnectionStatus;
18
+ /**
19
+ * The USB device we last connected to.
20
+ * Cleared if it is disconnected.
21
+ */
22
+ private device;
23
+ /**
24
+ * The connection to the device.
25
+ */
26
+ private connection;
27
+ /**
28
+ * DAPLink gives us a promise that lasts as long as we're serial reading.
29
+ * When stopping serial we await it to be sure we're done.
30
+ */
31
+ private serialReadInProgress;
32
+ private serialListener;
33
+ private flashing;
34
+ private disconnectAfterFlash;
35
+ private visibilityReconnect;
36
+ private visibilityChangeListener;
37
+ private unloading;
38
+ private beforeUnloadListener;
39
+ private logging;
40
+ constructor(options?: MicrobitWebUSBConnectionOptions);
41
+ private log;
42
+ initialize(): Promise<void>;
43
+ dispose(): void;
44
+ connect(options?: ConnectOptions): Promise<ConnectionStatus>;
45
+ getBoardVersion(): BoardVersion | undefined;
46
+ flash(dataSource: FlashDataSource, options: {
47
+ partial: boolean;
48
+ progress: (percentage: number | undefined) => void;
49
+ }): Promise<void>;
50
+ private flashInternal;
51
+ private startSerialInternal;
52
+ private stopSerialInternal;
53
+ disconnect(): Promise<void>;
54
+ private setStatus;
55
+ private withEnrichedErrors;
56
+ serialWrite(data: string): Promise<void>;
57
+ private handleDisconnect;
58
+ clearDevice(): Promise<void>;
59
+ private connectInternal;
60
+ private chooseDevice;
61
+ }