@hangtime/grip-connect 0.3.4 → 0.3.6

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 (107) hide show
  1. package/README.md +12 -8
  2. package/dist/battery.d.ts +7 -0
  3. package/dist/battery.js +25 -0
  4. package/dist/calibration.d.ts +7 -0
  5. package/dist/calibration.js +19 -0
  6. package/dist/characteristic.d.ts +9 -0
  7. package/dist/characteristic.js +20 -0
  8. package/dist/commands/climbro.d.ts +6 -0
  9. package/dist/commands/climbro.js +5 -0
  10. package/dist/commands/entralpi.d.ts +6 -0
  11. package/dist/commands/entralpi.js +5 -0
  12. package/dist/commands/index.d.ts +6 -0
  13. package/dist/commands/index.js +6 -0
  14. package/dist/commands/kilterboard.d.ts +23 -0
  15. package/dist/commands/kilterboard.js +24 -0
  16. package/dist/commands/motherboard.d.ts +6 -0
  17. package/dist/commands/motherboard.js +13 -0
  18. package/dist/commands/mysmartboard.d.ts +6 -0
  19. package/dist/commands/mysmartboard.js +5 -0
  20. package/dist/commands/progressor.d.ts +17 -0
  21. package/dist/commands/progressor.js +30 -0
  22. package/dist/commands/wh-c06.d.ts +6 -0
  23. package/dist/commands/wh-c06.js +5 -0
  24. package/dist/connect.d.ts +7 -0
  25. package/dist/connect.js +159 -0
  26. package/dist/data/entralpi.d.ts +5 -0
  27. package/dist/data/entralpi.js +30 -0
  28. package/dist/data/index.d.ts +4 -0
  29. package/dist/data/index.js +4 -0
  30. package/dist/data/motherboard.d.ts +6 -0
  31. package/dist/data/motherboard.js +133 -0
  32. package/dist/data/progressor.d.ts +5 -0
  33. package/dist/data/progressor.js +72 -0
  34. package/dist/data/wh-c06.d.ts +5 -0
  35. package/dist/data/wh-c06.js +35 -0
  36. package/dist/devices/climbro.d.ts +6 -0
  37. package/dist/devices/climbro.js +8 -0
  38. package/dist/devices/entralpi.d.ts +5 -0
  39. package/dist/devices/entralpi.js +59 -0
  40. package/dist/devices/index.d.ts +7 -0
  41. package/dist/devices/index.js +7 -0
  42. package/dist/devices/kilterboard.d.ts +6 -0
  43. package/dist/devices/kilterboard.js +30 -0
  44. package/dist/devices/motherboard.d.ts +5 -0
  45. package/dist/devices/motherboard.js +81 -0
  46. package/dist/devices/mysmartboard.d.ts +6 -0
  47. package/dist/devices/mysmartboard.js +8 -0
  48. package/dist/devices/progressor.d.ts +5 -0
  49. package/dist/devices/progressor.js +37 -0
  50. package/dist/devices/wh-c06.d.ts +6 -0
  51. package/dist/devices/wh-c06.js +17 -0
  52. package/dist/disconnect.d.ts +6 -0
  53. package/dist/disconnect.js +12 -0
  54. package/dist/download.d.ts +10 -0
  55. package/dist/download.js +50 -0
  56. package/dist/index.d.ts +13 -0
  57. package/dist/index.js +22 -0
  58. package/dist/info.d.ts +7 -0
  59. package/dist/info.js +30 -0
  60. package/dist/is-connected.d.ts +7 -0
  61. package/dist/is-connected.js +13 -0
  62. package/dist/led.d.ts +19 -0
  63. package/dist/led.js +183 -0
  64. package/dist/notify.d.ts +16 -0
  65. package/dist/notify.js +14 -0
  66. package/dist/read.d.ts +10 -0
  67. package/dist/read.js +49 -0
  68. package/dist/stop.d.ts +7 -0
  69. package/dist/stop.js +21 -0
  70. package/dist/stream.d.ts +8 -0
  71. package/dist/stream.js +41 -0
  72. package/dist/struct/index.d.ts +9 -0
  73. package/dist/struct/index.js +203 -0
  74. package/dist/tare.d.ts +12 -0
  75. package/dist/tare.js +70 -0
  76. package/dist/types/commands.d.ts +18 -0
  77. package/dist/types/commands.js +1 -0
  78. package/dist/types/devices.d.ts +38 -0
  79. package/dist/types/devices.js +1 -0
  80. package/dist/types/download.d.ts +15 -0
  81. package/dist/types/download.js +1 -0
  82. package/dist/types/notify.d.ts +14 -0
  83. package/dist/types/notify.js +1 -0
  84. package/dist/write.d.ts +16 -0
  85. package/dist/write.js +57 -0
  86. package/package.json +3 -2
  87. package/src/commands/index.ts +1 -1
  88. package/src/commands/kilterboard.ts +23 -0
  89. package/src/commands/{musclemeter.ts → wh-c06.ts} +1 -1
  90. package/src/connect.ts +33 -8
  91. package/src/data/entralpi.ts +37 -0
  92. package/src/data/index.ts +7 -0
  93. package/src/{data.ts → data/motherboard.ts} +14 -105
  94. package/src/data/progressor.ts +72 -0
  95. package/src/data/wh-c06.ts +43 -0
  96. package/src/devices/index.ts +1 -1
  97. package/src/devices/wh-c06.ts +19 -0
  98. package/src/index.ts +4 -1
  99. package/src/led.ts +196 -0
  100. package/src/notify.ts +1 -1
  101. package/src/read.ts +1 -6
  102. package/src/stream.ts +2 -2
  103. package/src/struct/index.ts +45 -21
  104. package/src/tare.ts +9 -9
  105. package/src/write.ts +16 -12
  106. package/tsconfig.json +3 -1
  107. package/src/devices/musclemeter.ts +0 -10
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ // Export device types
2
+ export { Climbro, Entralpi, KilterBoard, Motherboard, mySmartBoard, WHC06, Progressor } from "./devices/index";
3
+ // Export battery related functions
4
+ export { battery } from "./battery";
5
+ // Export calibration function
6
+ export { calibration } from "./calibration";
7
+ // Export download function
8
+ export { download } from "./download";
9
+ // Export connection related functions
10
+ export { connect } from "./connect";
11
+ export { disconnect } from "./disconnect";
12
+ export { isConnected } from "./is-connected";
13
+ // Export information retrieval function
14
+ export { info } from "./info";
15
+ // Export led retrieval function
16
+ export { led } from "./led";
17
+ // Export notification related function
18
+ export { notify } from "./notify";
19
+ // Export stream related functions
20
+ export { stop } from "./stop";
21
+ export { stream } from "./stream";
22
+ export { tare } from "./tare";
package/dist/info.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Retrieves device information.
4
+ * @param {Device} board - The device to retrieve information from.
5
+ * @returns {Promise<void>} A promise that resolves when the information retrieval is completed.
6
+ */
7
+ export declare const info: (board: Device) => Promise<void>;
package/dist/info.js ADDED
@@ -0,0 +1,30 @@
1
+ import { write } from "./write";
2
+ import { read } from "./read";
3
+ import { isConnected } from "./is-connected";
4
+ import { Motherboard, Progressor } from "./devices";
5
+ import { MotherboardCommands, ProgressorCommands } from "./commands";
6
+ /**
7
+ * Retrieves device information.
8
+ * @param {Device} board - The device to retrieve information from.
9
+ * @returns {Promise<void>} A promise that resolves when the information retrieval is completed.
10
+ */
11
+ export const info = async (board) => {
12
+ if (isConnected(board)) {
13
+ if (board.filters.some((filter) => filter.name === "Motherboard")) {
14
+ // Read manufacturer information
15
+ await read(Motherboard, "device", "manufacturer", 250);
16
+ // Read hardware version
17
+ await read(Motherboard, "device", "hardware", 250);
18
+ // Read firmware version
19
+ await read(Motherboard, "device", "firmware", 250);
20
+ // Get text from Motherboard
21
+ await write(Motherboard, "uart", "tx", MotherboardCommands.GET_TEXT, 250);
22
+ // Get serial number from Motherboard
23
+ await write(Motherboard, "uart", "tx", MotherboardCommands.GET_SERIAL, 250);
24
+ }
25
+ if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
26
+ // Get firmware version from Progressor
27
+ await write(Progressor, "progressor", "tx", ProgressorCommands.GET_FW_VERSION, 250);
28
+ }
29
+ }
30
+ };
@@ -0,0 +1,7 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Checks if a Bluetooth device is connected.
4
+ * @param {Device} board - The device to check for connection.
5
+ * @returns {boolean} A boolean indicating whether the device is connected.
6
+ */
7
+ export declare const isConnected: (board?: Device) => boolean;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Checks if a Bluetooth device is connected.
3
+ * @param {Device} board - The device to check for connection.
4
+ * @returns {boolean} A boolean indicating whether the device is connected.
5
+ */
6
+ export const isConnected = (board) => {
7
+ // Check if the device is defined and available
8
+ if (!board?.device) {
9
+ return false;
10
+ }
11
+ // Check if the device is connected using optional chaining
12
+ return !!board.device.gatt?.connected;
13
+ };
package/dist/led.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { Device } from "./types/devices";
2
+ declare class ClimbPlacement {
3
+ position: number;
4
+ role_id: string;
5
+ constructor(position: number, role_id: string);
6
+ }
7
+ /**
8
+ * Prepares byte arrays for transmission based on a list of climb placements.
9
+ * @param climbPlacementList - The list of climb placements containing position and role ID.
10
+ * @returns The final byte array ready for transmission.
11
+ */
12
+ export declare function prepBytesV3(climbPlacementList: ClimbPlacement[]): number[];
13
+ /**
14
+ * Set device leds.
15
+ * @param {Device} board - The device to retrieve information from.
16
+ * @returns {Promise<void>} A promise that resolves when the information retrieval is completed.
17
+ */
18
+ export declare const led: (board: Device, placement?: ClimbPlacement[]) => Promise<number[] | undefined>;
19
+ export {};
package/dist/led.js ADDED
@@ -0,0 +1,183 @@
1
+ import { write } from "./write";
2
+ import { isConnected } from "./is-connected";
3
+ import { KilterBoard, Motherboard } from "./devices";
4
+ import { KilterBoardPacket } from "./commands/kilterboard";
5
+ /**
6
+ * Maximum length of the message body for byte wrapping.
7
+ */
8
+ const MESSAGE_BODY_MAX_LENGTH = 255;
9
+ /**
10
+ * Maximum length of the the bluetooth chunk.
11
+ */
12
+ const MAX_BLUETOOTH_MESSAGE_SIZE = 20;
13
+ /**
14
+ * Calculates the checksum for a byte array by summing up all bytes ot hre packet in a single-byte variable.
15
+ * @param data - The array of bytes to calculate the checksum for.
16
+ * @returns The calculated checksum value.
17
+ */
18
+ function checksum(data) {
19
+ let i = 0;
20
+ for (const value of data) {
21
+ i = (i + value) & 255;
22
+ }
23
+ return ~i & 255;
24
+ }
25
+ /**
26
+ * Wraps a byte array with header and footer bytes for transmission.
27
+ * @param data - The array of bytes to wrap.
28
+ * @returns The wrapped byte array.
29
+ */
30
+ function wrapBytes(data) {
31
+ if (data.length > MESSAGE_BODY_MAX_LENGTH) {
32
+ return [];
33
+ }
34
+ /**
35
+ - 0x1
36
+ - len(packets)
37
+ - checksum(packets)
38
+ - 0x2
39
+ - *packets
40
+ - 0x3
41
+
42
+ First byte is always 1, the second is a number of packets, then checksum, then 2, packets themselves, and finally 3.
43
+ */
44
+ return [1, data.length, checksum(data), 2, ...data, 3];
45
+ }
46
+ class ClimbPlacement {
47
+ position;
48
+ role_id;
49
+ constructor(position, role_id) {
50
+ this.position = position;
51
+ this.role_id = role_id;
52
+ }
53
+ }
54
+ /**
55
+ * Encodes a position into a byte array.
56
+ * The lowest 8 bits of the position get put in the first byte of the group.
57
+ * The highest 8 bits of the position get put in the second byte of the group.
58
+ * @param position - The position to encode.
59
+ * @returns The encoded byte array representing the position.
60
+ */
61
+ function encodePosition(position) {
62
+ const position1 = position & 255;
63
+ const position2 = (position & 65280) >> 8;
64
+ return [position1, position2];
65
+ }
66
+ /**
67
+ * Encodes a color string into a numeric representation.
68
+ * The rgb color, 3 bits for the R and G components, 2 bits for the B component, with the 3 R bits occupying the high end of the byte and the 2 B bits in the low end (hence 3 G bits in the middle).
69
+ * @param color - The color string in hexadecimal format (e.g., 'FFFFFF').
70
+ * @returns The encoded /compressed color value.
71
+ */
72
+ function encodeColor(color) {
73
+ const substring = color.substring(0, 2);
74
+ const substring2 = color.substring(2, 4);
75
+ const parsedSubstring = parseInt(substring, 16) / 32;
76
+ const parsedSubstring2 = parseInt(substring2, 16) / 32;
77
+ const parsedResult = (parsedSubstring << 5) | (parsedSubstring2 << 2);
78
+ const substring3 = color.substring(4, 6);
79
+ const parsedSubstring3 = parseInt(substring3, 16) / 64;
80
+ const finalParsedResult = parsedResult | parsedSubstring3;
81
+ return finalParsedResult;
82
+ }
83
+ /**
84
+ * Encodes a placement (requires a 16-bit position and a 24-bit rgb color. ) into a byte array.
85
+ * @param position - The position to encode.
86
+ * @param ledColor - The color of the LED in hexadecimal format (e.g., 'FFFFFF').
87
+ * @returns The encoded byte array representing the placement.
88
+ */
89
+ function encodePlacement(position, ledColor) {
90
+ return [...encodePosition(position), encodeColor(ledColor)];
91
+ }
92
+ /**
93
+ * Prepares byte arrays for transmission based on a list of climb placements.
94
+ * @param climbPlacementList - The list of climb placements containing position and role ID.
95
+ * @returns The final byte array ready for transmission.
96
+ */
97
+ export function prepBytesV3(climbPlacementList) {
98
+ const resultArray = [];
99
+ let tempArray = [KilterBoardPacket.V3_MIDDLE];
100
+ for (const climbPlacement of climbPlacementList) {
101
+ if (tempArray.length + 3 > MESSAGE_BODY_MAX_LENGTH) {
102
+ resultArray.push(tempArray);
103
+ tempArray = [KilterBoardPacket.V3_MIDDLE];
104
+ }
105
+ const ledColor = climbPlacement.role_id;
106
+ const encodedPlacement = encodePlacement(climbPlacement.position, ledColor);
107
+ tempArray.push(...encodedPlacement);
108
+ }
109
+ resultArray.push(tempArray);
110
+ if (resultArray.length === 1) {
111
+ resultArray[0][0] = KilterBoardPacket.V3_ONLY;
112
+ }
113
+ else if (resultArray.length > 1) {
114
+ resultArray[0][0] = KilterBoardPacket.V3_FIRST;
115
+ resultArray[resultArray.length - 1][0] = KilterBoardPacket.V3_LAST;
116
+ }
117
+ const finalResultArray = [];
118
+ for (const currentArray of resultArray) {
119
+ finalResultArray.push(...wrapBytes(currentArray));
120
+ }
121
+ return finalResultArray;
122
+ }
123
+ /**
124
+ * Splits a collection into slices of the specified length.
125
+ * https://github.com/ramda/ramda/blob/master/source/splitEvery.js
126
+ * @param {Number} n
127
+ * @param {Array} list
128
+ * @return {Array}
129
+ */
130
+ function splitEvery(n, list) {
131
+ if (n <= 0) {
132
+ throw new Error("First argument to splitEvery must be a positive integer");
133
+ }
134
+ const result = [];
135
+ let idx = 0;
136
+ while (idx < list.length) {
137
+ result.push(list.slice(idx, (idx += n)));
138
+ }
139
+ return result;
140
+ }
141
+ /**
142
+ * The kilter board only supports messages of 20 bytes
143
+ * at a time. This method splits a full message into parts
144
+ * of 20 bytes
145
+ *
146
+ * @param buffer
147
+ */
148
+ const splitMessages = (buffer) => splitEvery(MAX_BLUETOOTH_MESSAGE_SIZE, buffer).map((arr) => new Uint8Array(arr));
149
+ /**
150
+ * Sends a series of messages to a device.
151
+ */
152
+ async function writeMessageSeries(messages) {
153
+ for (const message of messages) {
154
+ await write(KilterBoard, "uart", "tx", message);
155
+ }
156
+ }
157
+ /**
158
+ * Set device leds.
159
+ * @param {Device} board - The device to retrieve information from.
160
+ * @returns {Promise<void>} A promise that resolves when the information retrieval is completed.
161
+ */
162
+ export const led = async (board, placement) => {
163
+ // Check if the filter contains the Aurora Climbing Advertising service
164
+ const AuroraUUID = "4488b571-7806-4df6-bcff-a2897e4953ff";
165
+ if (board.filters.some((filter) => filter.services?.includes(AuroraUUID))) {
166
+ // The Aurora Boards needs a LED / Postion Placememnet Array
167
+ if (placement) {
168
+ // Prepares byte arrays for transmission based on a list of climb placements.
169
+ const payload = prepBytesV3(placement);
170
+ // Sends the payload to the device by splitting it into messages and writing each message.
171
+ if (isConnected(board)) {
172
+ writeMessageSeries(splitMessages(payload));
173
+ }
174
+ return payload;
175
+ }
176
+ }
177
+ if (board.filters.some((filter) => filter.name === "Motherboard")) {
178
+ // Orange
179
+ await write(Motherboard, "led", "01", "0", 1000);
180
+ // Yellow
181
+ await write(Motherboard, "led", "02", "0", 1000);
182
+ }
183
+ };
@@ -0,0 +1,16 @@
1
+ import type { massObject } from "./types/notify";
2
+ /** Define the type for the callback function */
3
+ type NotifyCallback = (data: massObject) => void;
4
+ /**
5
+ * Defines the type for the callback function.
6
+ * @callback NotifyCallback
7
+ * @param {massObject} data - The data passed to the callback.
8
+ */
9
+ export declare let notifyCallback: NotifyCallback;
10
+ /**
11
+ * Sets the callback function to be called when notifications are received.
12
+ * @param {NotifyCallback} callback - The callback function to be set.
13
+ * @returns {void}
14
+ */
15
+ export declare const notify: (callback: NotifyCallback) => void;
16
+ export {};
package/dist/notify.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Defines the type for the callback function.
3
+ * @callback NotifyCallback
4
+ * @param {massObject} data - The data passed to the callback.
5
+ */
6
+ export let notifyCallback;
7
+ /**
8
+ * Sets the callback function to be called when notifications are received.
9
+ * @param {NotifyCallback} callback - The callback function to be set.
10
+ * @returns {void}
11
+ */
12
+ export const notify = (callback) => {
13
+ notifyCallback = callback;
14
+ };
package/dist/read.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Reads the value of the specified characteristic from the device.
4
+ * @param {Device} board - The device to read from.
5
+ * @param {string} serviceId - The service ID where the characteristic belongs.
6
+ * @param {string} characteristicId - The characteristic ID to read from.
7
+ * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
8
+ * @returns {Promise<void>} A promise that resolves when the read operation is completed.
9
+ */
10
+ export declare const read: (board: Device, serviceId: string, characteristicId: string, duration?: number) => Promise<void>;
package/dist/read.js ADDED
@@ -0,0 +1,49 @@
1
+ import { getCharacteristic } from "./characteristic";
2
+ import { isConnected } from "./is-connected";
3
+ /**
4
+ * Reads the value of the specified characteristic from the device.
5
+ * @param {Device} board - The device to read from.
6
+ * @param {string} serviceId - The service ID where the characteristic belongs.
7
+ * @param {string} characteristicId - The characteristic ID to read from.
8
+ * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
9
+ * @returns {Promise<void>} A promise that resolves when the read operation is completed.
10
+ */
11
+ export const read = (board, serviceId, characteristicId, duration = 0) => {
12
+ return new Promise((resolve, reject) => {
13
+ if (isConnected(board)) {
14
+ const characteristic = getCharacteristic(board, serviceId, characteristicId);
15
+ if (characteristic) {
16
+ characteristic
17
+ .readValue()
18
+ .then((value) => {
19
+ let decodedValue;
20
+ const decoder = new TextDecoder("utf-8");
21
+ switch (characteristicId) {
22
+ case "level":
23
+ // TODO: This is Motherboard specific.
24
+ decodedValue = value.getUint8(0);
25
+ break;
26
+ default:
27
+ decodedValue = decoder.decode(value);
28
+ break;
29
+ }
30
+ // TODO: Create Read callback
31
+ console.log(decodedValue);
32
+ // Resolve after specified duration
33
+ setTimeout(() => {
34
+ resolve();
35
+ }, duration);
36
+ })
37
+ .catch((error) => {
38
+ reject(error);
39
+ });
40
+ }
41
+ else {
42
+ reject(new Error("Characteristic is undefined"));
43
+ }
44
+ }
45
+ else {
46
+ reject(new Error("Device is not connected"));
47
+ }
48
+ });
49
+ };
package/dist/stop.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Stops the data stream on the specified device.
4
+ * @param {Device} board - The device to stop the stream on.
5
+ * @returns {Promise<void>} A promise that resolves when the stream is stopped.
6
+ */
7
+ export declare const stop: (board: Device) => Promise<void>;
package/dist/stop.js ADDED
@@ -0,0 +1,21 @@
1
+ import { write } from "./write";
2
+ import { isConnected } from "./is-connected";
3
+ import { Motherboard, Progressor } from "./devices";
4
+ import { MotherboardCommands, ProgressorCommands } from "./commands";
5
+ /**
6
+ * Stops the data stream on the specified device.
7
+ * @param {Device} board - The device to stop the stream on.
8
+ * @returns {Promise<void>} A promise that resolves when the stream is stopped.
9
+ */
10
+ export const stop = async (board) => {
11
+ if (isConnected(board)) {
12
+ if (board.filters.some((filter) => filter.name === "Motherboard")) {
13
+ // Stop stream on Motherboard
14
+ await write(Motherboard, "uart", "tx", MotherboardCommands.STOP_WEIGHT_MEAS, 0);
15
+ }
16
+ if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
17
+ // Stop stream on Progressor
18
+ await write(Progressor, "progressor", "tx", ProgressorCommands.STOP_WEIGHT_MEAS, 0);
19
+ }
20
+ }
21
+ };
@@ -0,0 +1,8 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Starts streaming data from the specified device.
4
+ * @param {Device} board - The device to stream data from.
5
+ * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
6
+ * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
7
+ */
8
+ export declare const stream: (board: Device, duration?: number) => Promise<void>;
package/dist/stream.js ADDED
@@ -0,0 +1,41 @@
1
+ import { isConnected } from "./is-connected";
2
+ import { write } from "./write";
3
+ import { stop } from "./stop";
4
+ import { Motherboard, Progressor } from "./devices";
5
+ import { MotherboardCommands, ProgressorCommands } from "./commands";
6
+ import { emptyDownloadPackets } from "./download";
7
+ import { CALIBRATION } from "./data/motherboard";
8
+ import { calibration } from "./calibration";
9
+ /**
10
+ * Starts streaming data from the specified device.
11
+ * @param {Device} board - The device to stream data from.
12
+ * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
13
+ * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
14
+ */
15
+ export const stream = async (board, duration = 0) => {
16
+ if (isConnected(board)) {
17
+ // Reset download packets
18
+ emptyDownloadPackets();
19
+ // Device specific logic
20
+ if (board.filters.some((filter) => filter.name === "Motherboard")) {
21
+ // Read calibration data if not already available
22
+ if (!CALIBRATION[0].length) {
23
+ await calibration(Motherboard);
24
+ }
25
+ // Start streaming data
26
+ await write(Motherboard, "uart", "tx", MotherboardCommands.START_WEIGHT_MEAS, duration);
27
+ // Stop streaming if duration is set
28
+ if (duration !== 0) {
29
+ await stop(Motherboard);
30
+ }
31
+ }
32
+ if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
33
+ // Start streaming data
34
+ await write(Progressor, "progressor", "tx", ProgressorCommands.START_WEIGHT_MEAS, duration);
35
+ // Stop streaming if duration is set
36
+ if (duration !== 0) {
37
+ await stop(Progressor);
38
+ }
39
+ }
40
+ }
41
+ };
@@ -0,0 +1,9 @@
1
+ export default function struct(format: string): Readonly<{
2
+ unpack: (arrb: ArrayBuffer) => unknown[];
3
+ pack: (...values: unknown[]) => ArrayBuffer;
4
+ unpack_from: (arrb: ArrayBuffer, offs: number) => unknown[];
5
+ pack_into: (arrb: ArrayBuffer, offs: number, ...values: unknown[]) => void;
6
+ iter_unpack: (arrb: ArrayBuffer) => IterableIterator<unknown[]>;
7
+ format: string;
8
+ size: number;
9
+ }>;
@@ -0,0 +1,203 @@
1
+ const rechk = /^([<>])?(([1-9]\d*)?([xcbB?hHiIfdsp]))*$/;
2
+ const refmt = /([1-9]\d*)?([xcbB?hHiIfdsp])/g;
3
+ const str = (v, o, c) => String.fromCharCode(...Array.from(new Uint8Array(v.buffer, v.byteOffset + o, c)));
4
+ const rts = (v, o, c, s) => {
5
+ new Uint8Array(v.buffer, v.byteOffset + o, c).set(s.split("").map((str) => str.charCodeAt(0)));
6
+ };
7
+ const pst = (v, o, c) => str(v, o + 1, Math.min(v.getUint8(o), c - 1));
8
+ const tsp = (v, o, c, s) => {
9
+ v.setUint8(o, s.length);
10
+ rts(v, o + 1, c - 1, s);
11
+ };
12
+ const lut = (le) => ({
13
+ x: (c) => [
14
+ 1,
15
+ c,
16
+ () => ({
17
+ u: () => undefined,
18
+ p: () => undefined,
19
+ }),
20
+ ],
21
+ c: (c) => [
22
+ c,
23
+ 1,
24
+ (o) => ({
25
+ u: (v) => str(v, o, 1),
26
+ p: (v, s) => {
27
+ rts(v, o, 1, s);
28
+ },
29
+ }),
30
+ ],
31
+ "?": (c) => [
32
+ c,
33
+ 1,
34
+ (o) => ({
35
+ u: (v) => Boolean(v.getUint8(o)),
36
+ p: (v, B) => {
37
+ v.setUint8(o, B ? 1 : 0);
38
+ },
39
+ }),
40
+ ],
41
+ b: (c) => [
42
+ c,
43
+ 1,
44
+ (o) => ({
45
+ u: (v) => v.getInt8(o),
46
+ p: (v, b) => {
47
+ v.setInt8(o, b);
48
+ },
49
+ }),
50
+ ],
51
+ B: (c) => [
52
+ c,
53
+ 1,
54
+ (o) => ({
55
+ u: (v) => v.getUint8(o),
56
+ p: (v, B) => {
57
+ v.setUint8(o, B);
58
+ },
59
+ }),
60
+ ],
61
+ h: (c) => [
62
+ c,
63
+ 2,
64
+ (o) => ({
65
+ u: (v) => v.getInt16(o, le),
66
+ p: (v, h) => {
67
+ v.setInt16(o, h, le);
68
+ },
69
+ }),
70
+ ],
71
+ H: (c) => [
72
+ c,
73
+ 2,
74
+ (o) => ({
75
+ u: (v) => v.getUint16(o, le),
76
+ p: (v, H) => {
77
+ v.setUint16(o, H, le);
78
+ },
79
+ }),
80
+ ],
81
+ i: (c) => [
82
+ c,
83
+ 4,
84
+ (o) => ({
85
+ u: (v) => v.getInt32(o, le),
86
+ p: (v, i) => {
87
+ v.setInt32(o, i, le);
88
+ },
89
+ }),
90
+ ],
91
+ I: (c) => [
92
+ c,
93
+ 4,
94
+ (o) => ({
95
+ u: (v) => v.getUint32(o, le),
96
+ p: (v, I) => {
97
+ v.setUint32(o, I, le);
98
+ },
99
+ }),
100
+ ],
101
+ f: (c) => [
102
+ c,
103
+ 4,
104
+ (o) => ({
105
+ u: (v) => v.getFloat32(o, le),
106
+ p: (v, f) => {
107
+ v.setFloat32(o, f, le);
108
+ },
109
+ }),
110
+ ],
111
+ d: (c) => [
112
+ c,
113
+ 8,
114
+ (o) => ({
115
+ u: (v) => v.getFloat64(o, le),
116
+ p: (v, d) => {
117
+ v.setFloat64(o, d, le);
118
+ },
119
+ }),
120
+ ],
121
+ s: (c) => [
122
+ 1,
123
+ c,
124
+ (o) => ({
125
+ u: (v) => str(v, o, c),
126
+ p: (v, s) => {
127
+ rts(v, o, c, s.slice(0, c));
128
+ },
129
+ }),
130
+ ],
131
+ p: (c) => [
132
+ 1,
133
+ c,
134
+ (o) => ({
135
+ u: (v) => pst(v, o, c),
136
+ p: (v, s) => {
137
+ tsp(v, o, c, s.slice(0, c - 1));
138
+ },
139
+ }),
140
+ ],
141
+ });
142
+ const errbuf = new RangeError("Structure larger than remaining buffer");
143
+ const errval = new RangeError("Not enough values for structure");
144
+ export default function struct(format) {
145
+ const fns = [];
146
+ let size = 0;
147
+ let m = rechk.exec(format);
148
+ if (!m) {
149
+ throw new RangeError("Invalid format string");
150
+ }
151
+ const t = lut("<" === m[1]);
152
+ const lu = (n, c) => t[c](n ? parseInt(n, 10) : 1);
153
+ while ((m = refmt.exec(format))) {
154
+ ;
155
+ ((r, s, f) => {
156
+ for (let i = 0; i < r; ++i, size += s) {
157
+ if (f) {
158
+ fns.push(f(size));
159
+ }
160
+ }
161
+ })(...lu(...m.slice(1)));
162
+ }
163
+ const unpack_from = (arrb, offs) => {
164
+ if (arrb.byteLength < (offs | 0) + size) {
165
+ throw errbuf;
166
+ }
167
+ const v = new DataView(arrb, offs | 0);
168
+ return fns.map((f) => f.u(v));
169
+ };
170
+ const pack_into = (arrb, offs, ...values) => {
171
+ if (values.length < fns.length) {
172
+ throw errval;
173
+ }
174
+ if (arrb.byteLength < offs + size) {
175
+ throw errbuf;
176
+ }
177
+ const v = new DataView(arrb, offs);
178
+ new Uint8Array(arrb, offs, size).fill(0);
179
+ fns.forEach((f, i) => {
180
+ f.p(v, values[i]);
181
+ });
182
+ };
183
+ const pack = (...values) => {
184
+ const b = new ArrayBuffer(size);
185
+ pack_into(b, 0, ...values);
186
+ return b;
187
+ };
188
+ const unpack = (arrb) => unpack_from(arrb, 0);
189
+ function* iter_unpack(arrb) {
190
+ for (let offs = 0; offs + size <= arrb.byteLength; offs += size) {
191
+ yield unpack_from(arrb, offs);
192
+ }
193
+ }
194
+ return Object.freeze({
195
+ unpack,
196
+ pack,
197
+ unpack_from,
198
+ pack_into,
199
+ iter_unpack,
200
+ format,
201
+ size,
202
+ });
203
+ }