@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,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react",
4
+ "esModuleInterop": true,
5
+ "resolveJsonModule": true,
6
+ "module": "esnext",
7
+ "target": "es5",
8
+ "strict": true,
9
+ "moduleResolution": "node",
10
+ "lib": [
11
+ "ES2017",
12
+ "DOM"
13
+ ]
14
+ },
15
+ "include": [
16
+ "src"
17
+ ]
18
+ }
package/jest.config.js ADDED
@@ -0,0 +1,11 @@
1
+ module.exports = {
2
+ roots: ['<rootDir>'],
3
+ testMatch: [
4
+ "**/__tests__/**/*.+(ts|tsx|js)",
5
+ "**/?(*.)+(spec|test).+(ts|tsx|js)"
6
+ ],
7
+ transform: {
8
+ "^.+\\.(ts|tsx)$": "ts-jest"
9
+ },
10
+ }
11
+
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@robdobsn/raftjs",
3
+ "version": "1.1.1",
4
+ "description": "Javascript/TS library for Raft library",
5
+ "main": "dist/main.js",
6
+ "types": "dist/main.d.ts",
7
+ "author": "Rob Dobson <rob@dobson.com>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/robdobsn/raftjs.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/robdobsn/raftjs/issues"
14
+ },
15
+ "license": "MIT",
16
+ "keywords": [
17
+ "Raft"
18
+ ],
19
+ "publishConfig": {
20
+ "registry": "https://registry.npmjs.org/",
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc -p tsconfig.json",
25
+ "build-all": "npm run clean && npm run build",
26
+ "test": "jest",
27
+ "lint": "eslint ./src",
28
+ "clean": "rm -rf dist build package",
29
+ "docs": "typedoc --entryPoints src/main.ts"
30
+ },
31
+ "devDependencies": {
32
+ "@types/jest": "^29.5.12",
33
+ "@types/node": "^20.14.0",
34
+ "@types/python-struct": "^1.0.4",
35
+ "@types/semver": "^7.5.8",
36
+ "@types/web-bluetooth": "^0.0.20",
37
+ "@typescript-eslint/eslint-plugin": "^8.6.0",
38
+ "eslint": "^9.4.0",
39
+ "jest": "^29.7.0",
40
+ "ts-jest": "^29.1.4",
41
+ "typescript": "^5.4.5"
42
+ },
43
+ "dependencies": {
44
+ "axios": "^1.7.2",
45
+ "isomorphic-ws": "^5.0.0",
46
+ "python-struct": "^1.1.3",
47
+ "semver": "^7.6.2",
48
+ "tslib": "^2.6.2"
49
+ }
50
+ }
@@ -0,0 +1,289 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RaftAttributeHandler
4
+ // Attribute handler for Raft devices
5
+ //
6
+ // Rob Dobson (C) 2024
7
+ //
8
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9
+
10
+ import CustomAttrHandler from "./RaftCustomAttrHandler";
11
+ import { DeviceTypeAttribute, DeviceTypePollRespMetadata, decodeAttrUnitsEncoding, isAttrTypeSigned } from "./RaftDeviceInfo";
12
+ import { DeviceAttributesState, DeviceTimeline } from "./RaftDeviceStates";
13
+ import struct from 'python-struct';
14
+
15
+ export default class AttributeHandler {
16
+
17
+ // Custom attribute handler
18
+ private _customAttrHandler = new CustomAttrHandler();
19
+
20
+ // Message timestamp size
21
+ private POLL_RESULT_TIMESTAMP_SIZE = 2;
22
+ private POLL_RESULT_WRAP_VALUE = this.POLL_RESULT_TIMESTAMP_SIZE === 2 ? 65536 : 4294967296;
23
+ private POLL_RESULT_RESOLUTION_US = 1000;
24
+
25
+ public processMsgAttrGroup(msgBuffer: Buffer, msgBufIdx: number, deviceTimeline: DeviceTimeline, pollRespMetadata: DeviceTypePollRespMetadata,
26
+ devAttrsState: DeviceAttributesState, maxDataPoints: number): number {
27
+
28
+ // console.log(`processMsgAttrGroup msg ${msgHexStr} timestamp ${timestamp} origTimestamp ${origTimestamp} msgBufIdx ${msgBufIdx}`)
29
+
30
+ // Extract msg timestamp
31
+ let { newBufIdx, timestampUs } = this.extractTimestampAndAdvanceIdx(msgBuffer, msgBufIdx, deviceTimeline);
32
+ if (newBufIdx < 0)
33
+ return -1;
34
+ msgBufIdx = newBufIdx;
35
+
36
+ // Start of message data
37
+ const msgDataStartIdx = msgBufIdx;
38
+
39
+ // New attribute values (in order as they appear in the attributes JSON)
40
+ let newAttrValues: number[][] = [];
41
+ if ("c" in pollRespMetadata) {
42
+
43
+ // Extract attribute values using custom handler
44
+ newAttrValues = this._customAttrHandler.handleAttr(pollRespMetadata, msgBuffer, msgBufIdx);
45
+
46
+ } else {
47
+
48
+ // Iterate over attributes
49
+ for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
50
+
51
+ // Get the attribute definition
52
+ const attrDef: DeviceTypeAttribute = pollRespMetadata.a[attrIdx];
53
+ if (!("t" in attrDef)) {
54
+ console.warn(`DeviceManager msg unknown msgBuffer ${msgBuffer} tsUs ${timestampUs} attrDef ${JSON.stringify(attrDef)}`);
55
+ newAttrValues.push([]);
56
+ continue;
57
+ }
58
+
59
+ // Process the attribute
60
+ const { values, newMsgBufIdx } = this.processMsgAttribute(attrDef, msgBuffer, msgBufIdx, msgDataStartIdx);
61
+ if (newMsgBufIdx < 0) {
62
+ newAttrValues.push([]);
63
+ continue;
64
+ }
65
+ msgBufIdx = newMsgBufIdx;
66
+ newAttrValues.push(values);
67
+ }
68
+
69
+ }
70
+
71
+ // Number of bytes in group
72
+ const pollRespSizeBytes = pollRespMetadata.b;
73
+
74
+ // Check if any attributes were added (in addition to timestamp)
75
+ if (newAttrValues.length === 0) {
76
+ console.warn(`DeviceManager msg attrGroup ${JSON.stringify(pollRespMetadata)} newAttrValues ${newAttrValues} is empty`);
77
+ return msgDataStartIdx+pollRespSizeBytes;
78
+ }
79
+
80
+ // All attributes must have the same number of new values
81
+ let numNewDataPoints = newAttrValues[0].length;
82
+ for (let i = 1; i < newAttrValues.length; i++) {
83
+ if (newAttrValues[i].length !== numNewDataPoints) {
84
+ console.warn(`DeviceManager msg attrGroup ${pollRespMetadata} attrName ${pollRespMetadata.a[i].n} newAttrValues ${newAttrValues} do not have the same length`);
85
+ return msgDataStartIdx+pollRespSizeBytes;
86
+ }
87
+ }
88
+
89
+ // All attributes in the schema should have values
90
+ if (newAttrValues.length !== pollRespMetadata.a.length) {
91
+ console.warn(`DeviceManager msg attrGroup ${pollRespMetadata} newAttrValues ${newAttrValues} length does not match attrGroup.a length`);
92
+ return msgDataStartIdx+pollRespSizeBytes;
93
+ }
94
+
95
+ // Add the new attribute values to the device state
96
+ for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
97
+ // Check if attribute already exists in the device state
98
+ const attrDef: DeviceTypeAttribute = pollRespMetadata.a[attrIdx];
99
+ if (!(attrDef.n in devAttrsState)) {
100
+ devAttrsState[attrDef.n] = {
101
+ name: attrDef.n,
102
+ newAttribute: true,
103
+ newData: true,
104
+ values: [],
105
+ units: decodeAttrUnitsEncoding(attrDef.u || ""),
106
+ range: attrDef.r || [0, 0],
107
+ format: ("f" in attrDef && typeof attrDef.f == "string") ? attrDef.f : "",
108
+ visibleSeries: "v" in attrDef ? attrDef.v === 0 || attrDef.v === false : ("vs" in attrDef ? (attrDef.vs === 0 || attrDef.vs === false ? false : !!attrDef.vs) : true),
109
+ visibleForm: "v" in attrDef ? attrDef.v === 0 || attrDef.v === false : ("vf" in attrDef ? (attrDef.vf === 0 || attrDef.vf === false ? false : !!attrDef.vf) : true),
110
+ };
111
+ }
112
+
113
+ // Check if any data points need to be discarded
114
+ const discardCount = Math.max(0, devAttrsState[attrDef.n].values.length + newAttrValues[attrIdx].length - maxDataPoints);
115
+ if (discardCount > 0) {
116
+ devAttrsState[attrDef.n].values.splice(0, discardCount);
117
+ }
118
+
119
+ // Add the new values
120
+ devAttrsState[attrDef.n].values.push(...newAttrValues[attrIdx]);
121
+ devAttrsState[attrDef.n].newData = newAttrValues[attrIdx].length > 0;
122
+ }
123
+
124
+ // Handle the timestamps with increments if specified
125
+ const timeIncUs: number = pollRespMetadata.us ? pollRespMetadata.us : 1000;
126
+ let timestampsUs = Array(numNewDataPoints).fill(0);
127
+ for (let i = 0; i < numNewDataPoints; i++) {
128
+ timestampsUs[i] = timestampUs + i * timeIncUs;
129
+ }
130
+
131
+ // Check if timeline points need to be discarded
132
+ const discardCount = Math.max(0, deviceTimeline.timestampsUs.length + timestampsUs.length - maxDataPoints);
133
+ if (discardCount > 0) {
134
+ deviceTimeline.timestampsUs.splice(0, discardCount);
135
+ }
136
+
137
+ // Add the new timestamps
138
+ deviceTimeline.timestampsUs.push(...timestampsUs);
139
+
140
+ // Return the next message buffer index
141
+ return msgDataStartIdx+pollRespSizeBytes;
142
+ }
143
+
144
+ private processMsgAttribute(attrDef: DeviceTypeAttribute, msgBuffer: Buffer, msgBufIdx: number, msgDataStartIdx: number): { values: number[], newMsgBufIdx: number} {
145
+
146
+ // Current field message string index
147
+ let curFieldBufIdx = msgBufIdx;
148
+ let attrUsesAbsPos = false;
149
+
150
+ // Check for "at": N which means start reading from byte N of the message (after the timestamp bytes)
151
+ if (attrDef.at !== undefined) {
152
+ curFieldBufIdx = msgDataStartIdx + attrDef.at;
153
+ attrUsesAbsPos = true;
154
+ }
155
+
156
+ // Check if outside bounds of message
157
+ if (curFieldBufIdx >= msgBuffer.length) {
158
+ console.warn(`DeviceManager msg outside bounds msgBuffer ${msgBuffer} attrName ${attrDef.n}`);
159
+ return { values: [], newMsgBufIdx: -1 };
160
+ }
161
+
162
+ // Attribute type
163
+ const attrTypesOnly = attrDef.t;
164
+
165
+ // Slice into buffer
166
+ const attrBuf = msgBuffer.slice(curFieldBufIdx);
167
+
168
+ // Check if a mask is used and the value is signed
169
+ const maskOnSignedValue = "m" in attrDef && isAttrTypeSigned(attrTypesOnly);
170
+
171
+ // Extract the value using python-struct
172
+ let unpackValues = struct.unpack(maskOnSignedValue ? attrTypesOnly.toUpperCase() : attrTypesOnly, attrBuf);
173
+ let attrValues = unpackValues as number[];
174
+
175
+ // Get number of bytes consumed
176
+ const numBytesConsumed = struct.sizeOf(attrTypesOnly);
177
+
178
+ // // Check if sign extendable mask specified on signed value
179
+ // if (mmSpecifiedOnSignedValue) {
180
+ // const signBitMask = 1 << (signExtendableMaskSignPos - 1);
181
+ // const valueOnlyMask = signBitMask - 1;
182
+ // if (value & signBitMask) {
183
+ // value = (value & valueOnlyMask) - signBitMask;
184
+ // } else {
185
+ // value = value & valueOnlyMask;
186
+ // }
187
+ // }
188
+
189
+ // Check for XOR mask
190
+ if ("x" in attrDef) {
191
+ const mask = typeof attrDef.x === "string" ? parseInt(attrDef.x, 16) : attrDef.x as number;
192
+ attrValues = attrValues.map((value) => value ^ mask);
193
+ }
194
+
195
+ // Check for AND mask
196
+ if ("m" in attrDef) {
197
+ const mask = typeof attrDef.m === "string" ? parseInt(attrDef.m, 16) : attrDef.m as number;
198
+ attrValues = attrValues.map((value) => (maskOnSignedValue ? this.signExtend(value, mask) : value & mask));
199
+ }
200
+
201
+ // Check for a sign-bit
202
+ if ("sb" in attrDef) {
203
+ const signBitPos = attrDef.sb as number;
204
+ const signBitMask = 1 << signBitPos;
205
+ if ("ss" in attrDef) {
206
+ const signBitSubtract = attrDef.ss as number;
207
+ attrValues = attrValues.map((value) => (value & signBitMask) ? signBitSubtract - value : value);
208
+ } else {
209
+ attrValues = attrValues.map((value) => (value & signBitMask) ? value - (signBitMask << 1) : value);
210
+ }
211
+ }
212
+
213
+ // Check for bit shift required
214
+ if ("s" in attrDef && attrDef.s) {
215
+ const bitshift = attrDef.s as number;
216
+ if (bitshift > 0) {
217
+ attrValues = attrValues.map((value) => (value) >> bitshift);
218
+ } else if (bitshift < 0) {
219
+ attrValues = attrValues.map((value) => (value) << -bitshift);
220
+ }
221
+ }
222
+
223
+ // Check for divisor
224
+ if ("d" in attrDef && attrDef.d) {
225
+ const divisor = attrDef.d as number;
226
+ attrValues = attrValues.map((value) => (value) / divisor);
227
+ }
228
+
229
+ // Check for value to add
230
+ if ("a" in attrDef && attrDef.a !== undefined) {
231
+ const addValue = attrDef.a as number;
232
+ attrValues = attrValues.map((value) => (value) + addValue);
233
+ }
234
+
235
+ // console.log(`DeviceManager msg attrGroup ${attrGroup} devkey ${deviceKey} valueHexChars ${valueHexChars} msgHexStr ${msgHexStr} ts ${timestamp} attrName ${attrDef.n} type ${attrDef.t} value ${value} signExtendableMaskSignPos ${signExtendableMaskSignPos} attrTypeDefForStruct ${attrTypeDefForStruct} attrDef ${attrDef}`);
236
+ // Move buffer position if using relative positioning
237
+ msgBufIdx += attrUsesAbsPos ? 0 : numBytesConsumed;
238
+
239
+ // Return the value
240
+ return { values: attrValues, newMsgBufIdx: msgBufIdx };
241
+ }
242
+
243
+ private signExtend(value: number, mask: number): number {
244
+ const signBitMask = (mask + 1) >> 1;
245
+ const signBit = value & signBitMask;
246
+
247
+ if (signBit !== 0) { // If sign bit is set
248
+ const highBitsMask = ~mask & ~((mask + 1) >> 1);
249
+ value |= highBitsMask; // Apply the sign extension
250
+ }
251
+
252
+ return value;
253
+ }
254
+
255
+ private extractTimestampAndAdvanceIdx(msgBuffer: Buffer, msgBufIdx: number, timestampWrapHandler: DeviceTimeline):
256
+ { newBufIdx: number, timestampUs: number } {
257
+
258
+ // Check there are enough characters for the timestamp
259
+ if (msgBufIdx + this.POLL_RESULT_TIMESTAMP_SIZE > msgBuffer.length) {
260
+ return { newBufIdx: -1, timestampUs: 0 };
261
+ }
262
+
263
+ // Use struct to extract the timestamp
264
+ const tsBuffer = msgBuffer.slice(msgBufIdx, msgBufIdx + this.POLL_RESULT_TIMESTAMP_SIZE);
265
+ let timestampUs: number;
266
+ if (this.POLL_RESULT_TIMESTAMP_SIZE === 2) {
267
+ timestampUs = struct.unpack(">H", tsBuffer)[0] as number * this.POLL_RESULT_RESOLUTION_US;
268
+ } else {
269
+ timestampUs = struct.unpack(">I", tsBuffer)[0] as number * this.POLL_RESULT_RESOLUTION_US;
270
+ }
271
+
272
+ // Check if time is before lastReportTimeMs - in which case a wrap around occurred to add on the max value
273
+ if (timestampUs < timestampWrapHandler.lastReportTimestampUs) {
274
+ timestampWrapHandler.reportTimestampOffsetUs += this.POLL_RESULT_WRAP_VALUE * this.POLL_RESULT_RESOLUTION_US;
275
+ }
276
+ timestampWrapHandler.lastReportTimestampUs = timestampUs;
277
+
278
+ // Offset timestamp
279
+ timestampUs += timestampWrapHandler.reportTimestampOffsetUs;
280
+
281
+ // Advance the index
282
+ msgBufIdx += this.POLL_RESULT_TIMESTAMP_SIZE;
283
+
284
+ // Return the timestamp
285
+ return { newBufIdx: msgBufIdx, timestampUs: timestampUs };
286
+ }
287
+
288
+
289
+ }
@@ -0,0 +1,30 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RaftChannel
4
+ // Part of RaftJS
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2024
7
+ // (C) 2020-2024 All rights reserved
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ import { RaftConnEventFn } from "./RaftConnEvents";
12
+ import RaftMsgHandler from "./RaftMsgHandler";
13
+ import { ConnectorOptions } from "./RaftSystemType";
14
+
15
+ export default interface RaftChannel
16
+ {
17
+ isConnected(): boolean;
18
+ connect(locator: string | object, connectorOptions: ConnectorOptions): Promise<boolean>;
19
+ disconnect(): Promise<void>;
20
+ getConnectedLocator(): string | object;
21
+ setOnConnEvent(connEventFn: RaftConnEventFn): void;
22
+ setMsgHandler(raftMsgHandler: RaftMsgHandler): void;
23
+ sendTxMsg(msg: Uint8Array, sendWithResponse: boolean): Promise<boolean>;
24
+ sendTxMsgNoAwait(msg: Uint8Array, sendWithResponse: boolean): Promise<boolean>;
25
+ requiresSubscription(): boolean;
26
+ ricRestCmdBeforeDisconnect(): string | null;
27
+ fhBatchAckSize(): number;
28
+ fhFileBlockSize(): number;
29
+ pauseConnection(pause: boolean): void;
30
+ }