@robdobsn/raftjs 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/.editorconfig +14 -0
  2. package/.gitattributes +11 -0
  3. package/.nvmrc +1 -0
  4. package/LICENSE +22 -0
  5. package/README.md +11 -0
  6. package/TODO.md +1 -0
  7. package/dist/RaftAttributeHandler.d.ts +12 -0
  8. package/dist/RaftAttributeHandler.js +241 -0
  9. package/dist/RaftAttributeHandler.js.map +1 -0
  10. package/dist/RaftChannel.d.ts +18 -0
  11. package/dist/RaftChannel.js +12 -0
  12. package/dist/RaftChannel.js.map +1 -0
  13. package/dist/RaftChannelWebBLE.d.ts +38 -0
  14. package/dist/RaftChannelWebBLE.js +274 -0
  15. package/dist/RaftChannelWebBLE.js.map +1 -0
  16. package/dist/RaftChannelWebSerial.d.ts +37 -0
  17. package/dist/RaftChannelWebSerial.js +319 -0
  18. package/dist/RaftChannelWebSerial.js.map +1 -0
  19. package/dist/RaftChannelWebSocket.d.ts +28 -0
  20. package/dist/RaftChannelWebSocket.js +197 -0
  21. package/dist/RaftChannelWebSocket.js.map +1 -0
  22. package/dist/RaftCommsStats.d.ts +39 -0
  23. package/dist/RaftCommsStats.js +128 -0
  24. package/dist/RaftCommsStats.js.map +1 -0
  25. package/dist/RaftConnEvents.d.ts +31 -0
  26. package/dist/RaftConnEvents.js +44 -0
  27. package/dist/RaftConnEvents.js.map +1 -0
  28. package/dist/RaftConnector.d.ts +242 -0
  29. package/dist/RaftConnector.js +613 -0
  30. package/dist/RaftConnector.js.map +1 -0
  31. package/dist/RaftCustomAttrHandler.d.ts +4 -0
  32. package/dist/RaftCustomAttrHandler.js +50 -0
  33. package/dist/RaftCustomAttrHandler.js.map +1 -0
  34. package/dist/RaftDeviceInfo.d.ts +64 -0
  35. package/dist/RaftDeviceInfo.js +36 -0
  36. package/dist/RaftDeviceInfo.js.map +1 -0
  37. package/dist/RaftDeviceManager.d.ts +37 -0
  38. package/dist/RaftDeviceManager.js +450 -0
  39. package/dist/RaftDeviceManager.js.map +1 -0
  40. package/dist/RaftDeviceMsg.d.ts +9 -0
  41. package/dist/RaftDeviceMsg.js +11 -0
  42. package/dist/RaftDeviceMsg.js.map +1 -0
  43. package/dist/RaftDeviceStates.d.ts +33 -0
  44. package/dist/RaftDeviceStates.js +60 -0
  45. package/dist/RaftDeviceStates.js.map +1 -0
  46. package/dist/RaftFileHandler.d.ts +52 -0
  47. package/dist/RaftFileHandler.js +502 -0
  48. package/dist/RaftFileHandler.js.map +1 -0
  49. package/dist/RaftLog.d.ts +22 -0
  50. package/dist/RaftLog.js +63 -0
  51. package/dist/RaftLog.js.map +1 -0
  52. package/dist/RaftMiniHDLC.d.ts +18 -0
  53. package/dist/RaftMiniHDLC.js +383 -0
  54. package/dist/RaftMiniHDLC.js.map +1 -0
  55. package/dist/RaftMsgHandler.d.ts +57 -0
  56. package/dist/RaftMsgHandler.js +480 -0
  57. package/dist/RaftMsgHandler.js.map +1 -0
  58. package/dist/RaftMsgTrackInfo.d.ts +17 -0
  59. package/dist/RaftMsgTrackInfo.js +42 -0
  60. package/dist/RaftMsgTrackInfo.js.map +1 -0
  61. package/dist/RaftProtocolDefs.d.ts +30 -0
  62. package/dist/RaftProtocolDefs.js +48 -0
  63. package/dist/RaftProtocolDefs.js.map +1 -0
  64. package/dist/RaftStreamHandler.d.ts +38 -0
  65. package/dist/RaftStreamHandler.js +257 -0
  66. package/dist/RaftStreamHandler.js.map +1 -0
  67. package/dist/RaftSystemType.d.ts +21 -0
  68. package/dist/RaftSystemType.js +3 -0
  69. package/dist/RaftSystemType.js.map +1 -0
  70. package/dist/RaftSystemUtils.d.ts +136 -0
  71. package/dist/RaftSystemUtils.js +410 -0
  72. package/dist/RaftSystemUtils.js.map +1 -0
  73. package/dist/RaftTypes.d.ts +184 -0
  74. package/dist/RaftTypes.js +157 -0
  75. package/dist/RaftTypes.js.map +1 -0
  76. package/dist/RaftUpdateEvents.d.ts +33 -0
  77. package/dist/RaftUpdateEvents.js +46 -0
  78. package/dist/RaftUpdateEvents.js.map +1 -0
  79. package/dist/RaftUpdateManager.d.ts +61 -0
  80. package/dist/RaftUpdateManager.js +618 -0
  81. package/dist/RaftUpdateManager.js.map +1 -0
  82. package/dist/RaftUtils.d.ts +125 -0
  83. package/dist/RaftUtils.js +454 -0
  84. package/dist/RaftUtils.js.map +1 -0
  85. package/dist/RaftWifiTypes.d.ts +23 -0
  86. package/dist/RaftWifiTypes.js +43 -0
  87. package/dist/RaftWifiTypes.js.map +1 -0
  88. package/dist/TestDataGen.d.ts +7 -0
  89. package/dist/TestDataGen.js +133 -0
  90. package/dist/TestDataGen.js.map +1 -0
  91. package/dist/main.d.ts +18 -0
  92. package/dist/main.js +42 -0
  93. package/dist/main.js.map +1 -0
  94. package/eslint.config.mjs +33 -0
  95. package/examples/dashboard/package.json +39 -0
  96. package/examples/dashboard/src/ConnManager.ts +86 -0
  97. package/examples/dashboard/src/Main.tsx +100 -0
  98. package/examples/dashboard/src/StatusScreen.tsx +72 -0
  99. package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +144 -0
  100. package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +77 -0
  101. package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
  102. package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
  103. package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
  104. package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
  105. package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
  106. package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
  107. package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
  108. package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
  109. package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +32 -0
  110. package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
  111. package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
  112. package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +113 -0
  113. package/examples/dashboard/src/index.html +15 -0
  114. package/examples/dashboard/src/index.tsx +15 -0
  115. package/examples/dashboard/src/styles.css +122 -0
  116. package/examples/dashboard/tsconfig.json +18 -0
  117. package/jest.config.js +11 -0
  118. package/package.json +50 -0
  119. package/src/RaftAttributeHandler.ts +289 -0
  120. package/src/RaftChannel.ts +30 -0
  121. package/src/RaftChannelWebBLE.ts +342 -0
  122. package/src/RaftChannelWebSerial.ts +408 -0
  123. package/src/RaftChannelWebSocket.ts +245 -0
  124. package/src/RaftCommsStats.ts +142 -0
  125. package/src/RaftConnEvents.ts +46 -0
  126. package/src/RaftConnector.ts +745 -0
  127. package/src/RaftCustomAttrHandler.ts +54 -0
  128. package/src/RaftDeviceInfo.ts +104 -0
  129. package/src/RaftDeviceManager.ts +542 -0
  130. package/src/RaftDeviceMsg.ts +20 -0
  131. package/src/RaftDeviceStates.ts +89 -0
  132. package/src/RaftFileHandler.ts +668 -0
  133. package/src/RaftLog.ts +70 -0
  134. package/src/RaftMiniHDLC.ts +396 -0
  135. package/src/RaftMsgHandler.ts +778 -0
  136. package/src/RaftMsgTrackInfo.ts +51 -0
  137. package/src/RaftProtocolDefs.ts +46 -0
  138. package/src/RaftStreamHandler.ts +328 -0
  139. package/src/RaftSystemType.ts +25 -0
  140. package/src/RaftSystemUtils.ts +487 -0
  141. package/src/RaftTypes.ts +250 -0
  142. package/src/RaftUpdateEvents.ts +48 -0
  143. package/src/RaftUpdateManager.ts +778 -0
  144. package/src/RaftUtils.ts +484 -0
  145. package/src/RaftWifiTypes.ts +36 -0
  146. package/src/TestDataGen.ts +157 -0
  147. package/src/main.ts +28 -0
  148. package/testdata/TestDeviceTypeRecs.json +492 -0
  149. package/tsconfig.json +27 -0
@@ -0,0 +1,484 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RaftUtils
4
+ // Part of RaftJS
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2024
7
+ // (C) 2020-2024 All rights reserved
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ import RaftLog from "./RaftLog";
12
+ import semverGt from "semver/functions/gt";
13
+ import semverEq from "semver/functions/eq";
14
+
15
+ export default class RaftUtils {
16
+ static _isEndianSet = false;
17
+ static _isLittleEndian = false;
18
+
19
+ /**
20
+ *
21
+ * Add a string to a Uint8Array buffer
22
+ *
23
+ * @param buffer - buffer to add to
24
+ * @param strToAdd - string to be added
25
+ * @param startPos - start position in buffer (i.e. offset to place string at)
26
+ */
27
+ static addStringToBuffer(
28
+ buffer: Uint8Array,
29
+ strToAdd: string,
30
+ startPos: number
31
+ ): void {
32
+ // Check valid
33
+ if (buffer.length < startPos + strToAdd.length + 1) {
34
+ RaftLog.error("addStringToBuffer buffer too short");
35
+ return;
36
+ }
37
+ let curPos = startPos;
38
+ for (let i = 0; i < strToAdd.length; i++) {
39
+ let charAt = strToAdd.charCodeAt(i);
40
+ if (charAt > 255) charAt = 255;
41
+ buffer.set([charAt], curPos++);
42
+ }
43
+ buffer.set([0], buffer.length - 1);
44
+ }
45
+
46
+ /**
47
+ *
48
+ * Get a string from a Uint8Array buffer
49
+ *
50
+ * @param buffer - buffer to get from
51
+ * @param startPos - start position in buffer (i.e. offset to start of string at)
52
+ * @param strLen - length of string to get
53
+ * @returns strGot - string got from buffer
54
+ */
55
+ static getStringFromBuffer(
56
+ buffer: Uint8Array,
57
+ startPos: number,
58
+ strLen: number
59
+ ): string {
60
+ // Check valid
61
+ if (buffer.length < startPos + strLen) {
62
+ strLen = buffer.length - startPos;
63
+ if (strLen <= 0) return "";
64
+ }
65
+ let curPos = startPos;
66
+ let outStr = "";
67
+ for (let i = 0; i < strLen; i++) {
68
+ outStr += String.fromCharCode(buffer[curPos++]);
69
+ }
70
+ return outStr;
71
+ }
72
+
73
+ /**
74
+ *
75
+ * Debug code to format a Uint8Array to string for logging
76
+ *
77
+ * @param buffer - Uint8Array to be converted to hex string
78
+ */
79
+ static bufferToHex(buffer: Uint8Array | null): string {
80
+ if (buffer == null) return "null";
81
+ return Array.from(new Uint8Array(buffer))
82
+ .map((b) => RaftUtils.padStartFn(b.toString(16), 2, "0"))
83
+ .join("");
84
+ }
85
+
86
+ /**
87
+ *
88
+ * Extract a big-endian float from a uint8array
89
+ *
90
+ * @param buf - Uint8Array containing float
91
+ * @returns float
92
+ */
93
+ static getBEFloatFromBuf(buf: Uint8Array): number {
94
+ const revBuf = new Uint8Array(4);
95
+ if (RaftUtils.isLittleEndian()) {
96
+ for (let i = 0; i < 4; i++) revBuf[3 - i] = buf[i];
97
+ } else {
98
+ for (let i = 0; i < 4; i++) revBuf[i] = buf[i];
99
+ }
100
+
101
+ const floatVal = new Float32Array(revBuf.buffer);
102
+ // RaftUtils.debug('revFloat ' + RaftUtils.bufferToHex(revBuf) + floatVal[0]);
103
+ return floatVal[0];
104
+ }
105
+
106
+ /**
107
+ * Extract a big-endian uint64 from a uint8array
108
+ *
109
+ * @param buf - Uint8Array containing uint64
110
+ * @param pos - position (offset in buf) to get from
111
+ * @returns uint64
112
+ */
113
+
114
+ static getBEUint64FromBuf(buf: Uint8Array, bufPos: number): number {
115
+ if (RaftUtils.isLittleEndian())
116
+ return (
117
+ (buf[bufPos] << 56) +
118
+ (buf[bufPos + 1] << 48) +
119
+ (buf[bufPos + 2] << 40) +
120
+ (buf[bufPos + 3] << 32) +
121
+ (buf[bufPos + 4] << 24) +
122
+ (buf[bufPos + 5] << 16) +
123
+ (buf[bufPos + 6] << 8) +
124
+ buf[bufPos + 7]
125
+ );
126
+ return (
127
+ (buf[bufPos + 7] << 56) +
128
+ (buf[bufPos + 6] << 48) +
129
+ (buf[bufPos + 5] << 40) +
130
+ (buf[bufPos + 4] << 32) +
131
+ (buf[bufPos + 3] << 24) +
132
+ (buf[bufPos + 2] << 16) +
133
+ (buf[bufPos + 1] << 8) +
134
+ buf[bufPos]
135
+ );
136
+ }
137
+
138
+ /**
139
+ *
140
+ * Extract a big-endian uint32 from a uint8array
141
+ *
142
+ * @param buf - Uint8Array containing uint32
143
+ * @param pos - position (offset in buf) to get from
144
+ * @returns uint32
145
+ */
146
+ static getBEUint32FromBuf(buf: Uint8Array, bufPos: number): number {
147
+ if (RaftUtils.isLittleEndian())
148
+ return (
149
+ (buf[bufPos] << 24) +
150
+ (buf[bufPos + 1] << 16) +
151
+ (buf[bufPos + 2] << 8) +
152
+ buf[bufPos + 3]
153
+ );
154
+ return (
155
+ (buf[bufPos + 3] << 24) +
156
+ (buf[bufPos + 2] << 16) +
157
+ (buf[bufPos + 1] << 8) +
158
+ buf[bufPos]
159
+ );
160
+ }
161
+
162
+ /**
163
+ *
164
+ * Extract a big-endian int16 from a uint8array
165
+ *
166
+ * @param buf - Uint8Array containing int16
167
+ * @param pos - position (offset in buf) to get from
168
+ * @returns int16
169
+ */
170
+ static getBEInt16FromBuf(buf: Uint8Array, bufPos: number): number {
171
+ if (RaftUtils.isLittleEndian()) {
172
+ const val = buf[bufPos] * 256 + buf[bufPos + 1];
173
+ return val > 32767 ? val - 65536 : val;
174
+ }
175
+ const val = buf[bufPos + 1] * 256 + buf[bufPos];
176
+ return val > 32767 ? val - 65536 : val;
177
+ }
178
+
179
+ /**
180
+ *
181
+ * Extract a big-endian uint16 from a uint8array
182
+ *
183
+ * @param buf - Uint8Array containing uint16
184
+ * @param pos - position (offset in buf) to get from
185
+ * @returns int16
186
+ */
187
+ static getBEUint16FromBuf(buf: Uint8Array, bufPos: number): number {
188
+ if (RaftUtils.isLittleEndian()) return buf[bufPos] * 256 + buf[bufPos + 1];
189
+ return buf[bufPos + 1] * 256 + buf[bufPos];
190
+ }
191
+
192
+ /**
193
+ *
194
+ * Extract a big-endian uint8 from a uint8array
195
+ *
196
+ * @param buf - Uint8Array containing uint8
197
+ * @param pos - position (offset in buf) to get from
198
+ * @returns int16
199
+ */
200
+ static getBEUint8FromBuf(buf: Uint8Array, pos: number): number {
201
+ return buf[pos];
202
+ }
203
+
204
+ /**
205
+ *
206
+ * Extract a big-endian int8 from a uint8array
207
+ *
208
+ * @param buf - Uint8Array containing int8
209
+ * @param pos - position (offset in buf) to get from
210
+ * @returns int16
211
+ */
212
+ static getBEInt8FromBuf(buf: Uint8Array, pos: number): number {
213
+ return buf[pos] > 127 ? buf[pos] - 256 : buf[pos];
214
+ }
215
+
216
+ static isLittleEndian(): boolean {
217
+ // If already known just return
218
+ if (this._isEndianSet) return this._isLittleEndian;
219
+
220
+ // Figure out endian-ness
221
+ const a = new Uint32Array([0x12345678]);
222
+ const b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
223
+ this._isEndianSet = true;
224
+ this._isLittleEndian = b[0] != 0x12;
225
+ return this._isLittleEndian;
226
+ // RaftUtils.debug("bigendian " + BigEndian);
227
+
228
+ // let buf = new ArrayBuffer(2);
229
+ // let shView = new Uint16Array(buf);
230
+ // buf[0] = 1;
231
+ // buf[1] = 0;
232
+ // RaftUtils.debug("Resulting short " + shView[0]);
233
+ // return shView[0] == 1;
234
+ }
235
+
236
+ // The following code from https://github.com/jsdom/abab
237
+ /**
238
+ * Implementation of atob() according to the HTML and Infra specs, except that
239
+ * instead of throwing INVALID_CHARACTER_ERR we return null.
240
+ *
241
+ * @param data - string containing base64 representation
242
+ * @returns Uint8Array
243
+ *
244
+ */
245
+ static atob(data: string): Uint8Array | null {
246
+ // Web IDL requires DOMStrings to just be converted using ECMAScript
247
+ // ToString, which in our case amounts to using a template literal.
248
+ data = `${data}`;
249
+ // "Remove all ASCII whitespace from data."
250
+ data = data.replace(/[ \t\n\f\r]/g, "");
251
+ // "If data's length divides by 4 leaving no remainder, then: if data ends
252
+ // with one or two U+003D (=) code points, then remove them from data."
253
+ if (data.length % 4 === 0) {
254
+ data = data.replace(/==?$/, "");
255
+ }
256
+ // "If data's length divides by 4 leaving a remainder of 1, then return
257
+ // failure."
258
+ //
259
+ // "If data contains a code point that is not one of
260
+ //
261
+ // U+002B (+)
262
+ // U+002F (/)
263
+ // ASCII alphanumeric
264
+ //
265
+ // then return failure."
266
+ if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) {
267
+ return null;
268
+ }
269
+ // "Let output be an empty byte sequence."
270
+ const output = new Uint8Array((data.length * 3) / 4 + 1);
271
+ // "Let buffer be an empty buffer that can have bits appended to it."
272
+ //
273
+ // We append bits via left-shift and or. accumulatedBits is used to track
274
+ // when we've gotten to 24 bits.
275
+ let buffer = 0;
276
+ let accumulatedBits = 0;
277
+ // "Let position be a position variable for data, initially pointing at the
278
+ // start of data."
279
+ //
280
+ // "While position does not point past the end of data:"
281
+ let bytePos = 0;
282
+ for (let i = 0; i < data.length; i++) {
283
+ // "Find the code point pointed to by position in the second column of
284
+ // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in
285
+ // the first cell of the same row.
286
+ //
287
+ // "Append to buffer the six bits corresponding to n, most significant bit
288
+ // first."
289
+ //
290
+ // atobLookup() implements the table from RFC 4648.
291
+ buffer <<= 6;
292
+ const atobVal = RaftUtils.atobLookup(data[i]);
293
+ if (atobVal !== undefined) {
294
+ buffer |= atobVal;
295
+ }
296
+ accumulatedBits += 6;
297
+ // "If buffer has accumulated 24 bits, interpret them as three 8-bit
298
+ // big-endian numbers. Append three bytes with values equal to those
299
+ // numbers to output, in the same order, and then empty buffer."
300
+ if (accumulatedBits === 24) {
301
+ output[bytePos++] = (buffer & 0xff0000) >> 16;
302
+ output[bytePos++] = (buffer & 0xff00) >> 8;
303
+ output[bytePos++] = buffer & 0xff;
304
+ buffer = accumulatedBits = 0;
305
+ }
306
+ // "Advance position by 1."
307
+ }
308
+ // "If buffer is not empty, it contains either 12 or 18 bits. If it contains
309
+ // 12 bits, then discard the last four and interpret the remaining eight as
310
+ // an 8-bit big-endian number. If it contains 18 bits, then discard the last
311
+ // two and interpret the remaining 16 as two 8-bit big-endian numbers. Append
312
+ // the one or two bytes with values equal to those one or two numbers to
313
+ // output, in the same order."
314
+ if (accumulatedBits === 12) {
315
+ buffer >>= 4;
316
+ output[bytePos++] = buffer & 0xff;
317
+ } else if (accumulatedBits === 18) {
318
+ buffer >>= 2;
319
+ output[bytePos++] = (buffer & 0xff00) >> 8;
320
+ output[bytePos++] = buffer & 0xff;
321
+ }
322
+ // "Return output."
323
+ return output.slice(0, bytePos);
324
+ }
325
+
326
+ /**
327
+ * A lookup table for atob(), which converts an ASCII character to the
328
+ * corresponding six-bit number.
329
+ */
330
+ static atobLookup(chr: string): number | undefined {
331
+ if (/[A-Z]/.test(chr)) {
332
+ return chr.charCodeAt(0) - "A".charCodeAt(0);
333
+ }
334
+ if (/[a-z]/.test(chr)) {
335
+ return chr.charCodeAt(0) - "a".charCodeAt(0) + 26;
336
+ }
337
+ if (/[0-9]/.test(chr)) {
338
+ return chr.charCodeAt(0) - "0".charCodeAt(0) + 52;
339
+ }
340
+ if (chr === "+") {
341
+ return 62;
342
+ }
343
+ if (chr === "/") {
344
+ return 63;
345
+ }
346
+ // Throw exception; should not be hit in tests
347
+ return undefined;
348
+ }
349
+
350
+ /**
351
+ * btoa() as defined by the HTML and Infra specs, which mostly just references
352
+ * RFC 4648.
353
+ *
354
+ * @param data - Uint8Array
355
+ * @returns string containing base64 representation
356
+ *
357
+ */
358
+ static btoa(inBuf: Uint8Array): string {
359
+ let i;
360
+ // String conversion as required by Web IDL.
361
+ // s = `${s}`;
362
+ // "The btoa() method must throw an "InvalidCharacterError" DOMException if
363
+ // data contains any character whose code point is greater than U+00FF."
364
+ // for (i = 0; i < s.length; i++) {
365
+ // if (s.charCodeAt(i) > 255) {
366
+ // return null;
367
+ // }
368
+ // }
369
+ let out = "";
370
+ for (i = 0; i < inBuf.length; i += 3) {
371
+ const groupsOfSix: Array<number | undefined> = [
372
+ undefined,
373
+ undefined,
374
+ undefined,
375
+ undefined,
376
+ ];
377
+ groupsOfSix[0] = inBuf[i] >> 2;
378
+ groupsOfSix[1] = (inBuf[i] & 0x03) << 4;
379
+ if (inBuf.length > i + 1) {
380
+ groupsOfSix[1] |= inBuf[i + 1] >> 4;
381
+ groupsOfSix[2] = (inBuf[i + 1] & 0x0f) << 2;
382
+ if (inBuf.length > i + 2) {
383
+ groupsOfSix[2] |= inBuf[i + 2] >> 6;
384
+ groupsOfSix[3] = inBuf[i + 2] & 0x3f;
385
+ }
386
+ }
387
+ for (let j = 0; j < groupsOfSix.length; j++) {
388
+ if (typeof groupsOfSix[j] === "undefined") {
389
+ out += "=";
390
+ } else {
391
+ out += this.btoaLookup(groupsOfSix[j]);
392
+ }
393
+ }
394
+ }
395
+ return out;
396
+ }
397
+
398
+ /**
399
+ * Lookup table for btoa(), which converts a six-bit number into the
400
+ * corresponding ASCII character.
401
+ */
402
+ static btoaLookup(idx: number | undefined): string | undefined {
403
+ if (idx === undefined) {
404
+ return undefined;
405
+ }
406
+ if (idx < 26) {
407
+ return String.fromCharCode(idx + "A".charCodeAt(0));
408
+ }
409
+ if (idx < 52) {
410
+ return String.fromCharCode(idx - 26 + "a".charCodeAt(0));
411
+ }
412
+ if (idx < 62) {
413
+ return String.fromCharCode(idx - 52 + "0".charCodeAt(0));
414
+ }
415
+ if (idx === 62) {
416
+ return "+";
417
+ }
418
+ if (idx === 63) {
419
+ return "/";
420
+ }
421
+ // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
422
+ return undefined;
423
+ }
424
+
425
+ static buf2hex(buffer: Uint8Array) {
426
+ return Array.prototype.map
427
+ .call(buffer, (x: number) => ("00" + x.toString(16)).slice(-2))
428
+ .join("");
429
+ }
430
+
431
+ static padStartFn(
432
+ inStr: string,
433
+ targetLength: number,
434
+ padString: string
435
+ ): string {
436
+ targetLength = targetLength >> 0; //truncate if number or convert non-number to 0;
437
+ padString = String(typeof padString !== "undefined" ? padString : " ");
438
+ if (inStr.length > targetLength) {
439
+ return String(inStr);
440
+ } else {
441
+ targetLength = targetLength - inStr.length;
442
+ if (targetLength > padString.length) {
443
+ padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed
444
+ }
445
+ return padString.slice(0, targetLength) + String(inStr);
446
+ }
447
+ }
448
+
449
+ static isVersionGreater(v1: string, v2: string) {
450
+ try {
451
+ return semverGt(v1, v2);
452
+ } catch (e) {
453
+ // one of the two versions is invalid, return true
454
+ RaftLog.error(`isVersionGreater - invalid version ${v1} or ${v2} ${e}`);
455
+ return true;
456
+ }
457
+ }
458
+
459
+ static isVersionEqual(v1: string, v2: string) {
460
+ try {
461
+ return semverEq(v1, v2);
462
+ } catch (e) {
463
+ // one of the two versions is invalid, return false
464
+ RaftLog.error(`isVersionEqual - invalid version ${v1} or ${v2} ${e}`);
465
+ return false;
466
+ }
467
+ }
468
+
469
+ static withTimeout(ms: number, promise: Promise<any>) {
470
+ let id: NodeJS.Timeout;
471
+ const timeout = new Promise((_, reject) => {
472
+ id = setTimeout(() => {
473
+ clearTimeout(id);
474
+ reject('Timed out in '+ ms + 'ms.')
475
+ }, ms)
476
+ })
477
+
478
+ return Promise.race([
479
+ promise,
480
+ timeout
481
+ ])
482
+ }
483
+
484
+ }
@@ -0,0 +1,36 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RaftWifiTypes
4
+ // Part of RaftJS
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2024
7
+ // (C) 2020-2024 All rights reserved
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ export enum RaftWifiConnState {
12
+ WIFI_CONN_NONE,
13
+ WIFI_CONN_CONNECTED,
14
+ }
15
+
16
+ export class RaftWifiConnStatus {
17
+ connState = RaftWifiConnState.WIFI_CONN_NONE;
18
+ isPaused = false;
19
+ ipAddress = '';
20
+ hostname = '';
21
+ ssid = '';
22
+ bssid = '';
23
+ validMs = 0;
24
+ }
25
+
26
+ export class RaftSysModInfoWiFi {
27
+ rslt = 'ok';
28
+ isConn = 0;
29
+ isPaused = 0;
30
+ connState = 'None';
31
+ SSID = '';
32
+ IP = '';
33
+ Hostname = '';
34
+ WiFiMAC = '';
35
+ }
36
+
@@ -0,0 +1,157 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // TestDataGen
4
+ // Test data generation for Raft device manager
5
+ //
6
+ // Rob Dobson (C) 2024
7
+ //
8
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9
+
10
+ class TestDataGen {
11
+
12
+ // Start generating test data and use the callback provided to handle the data JSON string
13
+ public start(handleDeviceMsgJson: (msg: string) => void) {
14
+ // Start timer for testing which sends randomized data
15
+ let psVals = [50, 150];
16
+ let iterCount = 0;
17
+ let psValAltCount = 0;
18
+ let alsVal = 1000;
19
+ let alsValInc = 1;
20
+ let whiteVal = 1000;
21
+ let whiteValInc = 10;
22
+ let x = 0;
23
+ let y = 0;
24
+ let z = 0;
25
+ setInterval(() => {
26
+ // Performance testing
27
+ // const debugPerfTimerStart = performance.now();
28
+
29
+ // Vars for VSNL4040
30
+ const psVar = psVals[psValAltCount] + Math.floor(Math.random() * 10) - 5;
31
+ const alsVar = alsVal;
32
+ const whiteVar = whiteVal;
33
+ iterCount++;
34
+ if (iterCount % 10 === 0) {
35
+ psValAltCount = (psValAltCount + 1) % 2;
36
+ }
37
+ alsVal += alsValInc + Math.floor(Math.random() * 10) - 5;
38
+ if (iterCount % 1000 === 0) {
39
+ alsValInc = -alsValInc;
40
+ }
41
+ whiteVal += whiteValInc + Math.floor(Math.random() * 10) - 5;
42
+ if (iterCount % 100 === 0) {
43
+ whiteValInc = -whiteValInc;
44
+ }
45
+ const tsHexHighLow = ((Date.now()) & 0xffff).toString(16).padStart(4, '0');
46
+ const tsHexNextHighLow = ((Date.now()+1) & 0xffff).toString(16).padStart(4, '0');
47
+ const psHexLowHigh = ((psVar & 0xff) << 8 | (psVar >> 8)).toString(16).padStart(4, '0');
48
+ const alsHexLowHigh = ((alsVar & 0xff) << 8 | (alsVar >> 8)).toString(16).padStart(4, '0');
49
+ const whiteHexLowHigh = ((whiteVar & 0xff) << 8 | (whiteVar >> 8)).toString(16).padStart(4, '0');
50
+
51
+ // Vars for ADXL313
52
+ x += Math.floor(Math.random() * 10) - 5;
53
+ y += Math.floor(Math.random() * 10) - 5;
54
+ z += Math.floor(Math.random() * 10) - 5;
55
+ // Ensure x,y,z in range -512 to 511
56
+ x = Math.floor(Math.min(511, Math.max(-512, x)));
57
+ y = Math.floor(Math.min(511, Math.max(-512, y)));
58
+ z = Math.floor(Math.min(511, Math.max(-512, z)));
59
+ // Convert x,y,z to 10-bit signed values
60
+ x = x & 0x3ff;
61
+ y = y & 0x3ff;
62
+ z = z & 0x3ff;
63
+ const xHexLowHigh = ((x & 0xff) << 8 | (x >> 8)).toString(16).padStart(4, '0');
64
+ const yHexLowHigh = ((y & 0xff) << 8 | (y >> 8)).toString(16).padStart(4, '0');
65
+ const zHexLowHigh = ((z & 0xff) << 8 | (z >> 8)).toString(16).padStart(4, '0');
66
+
67
+ interface DevMsg {
68
+ x: string;
69
+ _t: string;
70
+ _o: boolean;
71
+ }
72
+
73
+ interface DevMsgs {
74
+ [address: string]: DevMsg;
75
+ }
76
+
77
+ // Dev messages
78
+ let devMsgs: DevMsgs = {
79
+ "0x60@1": {
80
+ x: `${tsHexHighLow}${psHexLowHigh}${alsHexLowHigh}${whiteHexLowHigh}`,
81
+ _t: "VCNL4040",
82
+ _o: this.onlineFrom(iterCount, 0, 100)
83
+ },
84
+ "0x38@1": {
85
+ x: `${tsHexHighLow}${xHexLowHigh}${yHexLowHigh}${zHexLowHigh}`,
86
+ _t: "ADXL313",
87
+ _o: this.onlineFrom(iterCount, 0, 150)
88
+ },
89
+ "0x6f@41": {
90
+ x: `${tsHexHighLow}${this.toHex(this.randInt(0,1)*4,1)}`,
91
+ _t: "QwiicButton",
92
+ _o: this.onlineFrom(iterCount, 0, 120)
93
+ },
94
+ "0x6f@42": {
95
+ x: `${tsHexHighLow}${this.toHex(this.randInt(0,1)*4,1)}`,
96
+ _t: "QwiicButton",
97
+ _o: this.onlineFrom(iterCount, 0, 90)
98
+ },
99
+ "0x23@0": {
100
+ x: "",
101
+ _t: "QwiicLEDStick",
102
+ _o: this.onlineFrom(iterCount, 100, 180)
103
+ },
104
+ "0x28@0": {
105
+ x: `${tsHexHighLow}${this.toHex(this.randInt(0,7),2)}${tsHexNextHighLow}${this.toHex(this.randInt(0,7),2)}`,
106
+ _t: "CAP1203",
107
+ _o: true
108
+ },
109
+ "0x57@0": {
110
+ x: `${tsHexHighLow}${this.toHex(5,1)}${this.toHex(0x00,1)}${this.toHex(0x04,1)}${this.toHex(Math.floor(10000*Math.sin(iterCount/10.0))+100000,3)}${this.toHex(Math.floor(10000*Math.cos(iterCount/10.0))+100000,3)}${this.toHex(0,42)}`,
111
+ _t: "MAX30101",
112
+ _o: true
113
+ }
114
+ };
115
+
116
+ interface DevMsgsEnabled {
117
+ [key: string]: boolean;
118
+ }
119
+
120
+ // const devMsgsEnabled:DevMsgsEnabled = { "0x6f@42":true };
121
+ const devMsgsEnabled:DevMsgsEnabled = {};
122
+ const I2CA: DevMsgs = Object.keys(devMsgsEnabled).length === 0 ? devMsgs : {};
123
+ for (const key in devMsgs) {
124
+ if (devMsgsEnabled[key]) {
125
+ I2CA[key] = devMsgs[key];
126
+ }
127
+ }
128
+
129
+ const msg = JSON.stringify({I2CA: I2CA});
130
+
131
+ // Performance testing
132
+ // const debugPerfTimerEnd = performance.now();
133
+
134
+ // Call the callback to handle the data JSON string
135
+ // const debugHandleMsgStart = performance.now();
136
+ handleDeviceMsgJson(msg);
137
+ // const debugHandleMsgEnd = performance.now();
138
+
139
+ // console.log(`iterCount ${iterCount} genTestDataTime ${debugPerfTimerEnd - debugPerfTimerStart} handleTestDataTime ${debugHandleMsgEnd - debugHandleMsgStart}`);
140
+
141
+ // console.log(`iterCount ${iterCount} x ${x} Test message sent: ${JSON.stringify(JSON.parse(msg))}`);
142
+ }, 200);
143
+ }
144
+
145
+ private toHex(val: number, numBytes: number) {
146
+ return val.toString(16).padStart(numBytes * 2, '0');
147
+ }
148
+ private randInt(min: number, max: number) {
149
+ return Math.floor(Math.random() * (max - min + 1) + min);
150
+ }
151
+ private onlineFrom(iterCount: number, start: number, end: number) {
152
+ const ic = iterCount % 200;
153
+ return ic >= start && ic <= end;
154
+ }
155
+ }
156
+
157
+ export default TestDataGen;