@robotical/raftjs 1.4.6 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react-native/RaftAttributeHandler.d.ts +2 -0
- package/dist/react-native/RaftAttributeHandler.js +136 -10
- package/dist/react-native/RaftAttributeHandler.js.map +1 -1
- package/dist/react-native/RaftChannel.d.ts +2 -0
- package/dist/react-native/RaftChannelBLE.native.d.ts +2 -0
- package/dist/react-native/RaftChannelBLE.native.js +17 -9
- package/dist/react-native/RaftChannelBLE.native.js.map +1 -1
- package/dist/react-native/RaftChannelBLE.web.d.ts +2 -0
- package/dist/react-native/RaftChannelBLE.web.js +24 -15
- package/dist/react-native/RaftChannelBLE.web.js.map +1 -1
- package/dist/react-native/RaftChannelSimulated.d.ts +32 -0
- package/dist/react-native/RaftChannelSimulated.js +418 -0
- package/dist/react-native/RaftChannelSimulated.js.map +1 -0
- package/dist/react-native/RaftChannelWebSerial.d.ts +2 -0
- package/dist/react-native/RaftChannelWebSerial.js +18 -9
- package/dist/react-native/RaftChannelWebSerial.js.map +1 -1
- package/dist/react-native/RaftChannelWebSocket.d.ts +2 -0
- package/dist/react-native/RaftChannelWebSocket.js +10 -0
- package/dist/react-native/RaftChannelWebSocket.js.map +1 -1
- package/dist/react-native/RaftConnector.js +13 -6
- package/dist/react-native/RaftConnector.js.map +1 -1
- package/dist/react-native/RaftCustomAttrHandler.js +15 -0
- package/dist/react-native/RaftCustomAttrHandler.js.map +1 -1
- package/dist/react-native/RaftDeviceInfo.d.ts +8 -1
- package/dist/react-native/RaftDeviceManager.d.ts +3 -0
- package/dist/react-native/RaftDeviceManager.js +123 -43
- package/dist/react-native/RaftDeviceManager.js.map +1 -1
- package/dist/react-native/RaftFileHandler.js +8 -8
- package/dist/react-native/RaftFileHandler.js.map +1 -1
- package/dist/react-native/RaftLog.js +1 -1
- package/dist/react-native/RaftLog.js.map +1 -1
- package/dist/react-native/RaftMsgHandler.d.ts +5 -0
- package/dist/react-native/RaftMsgHandler.js +32 -0
- package/dist/react-native/RaftMsgHandler.js.map +1 -1
- package/dist/react-native/RaftStreamHandler.js +6 -5
- package/dist/react-native/RaftStreamHandler.js.map +1 -1
- package/dist/react-native/RaftStruct.js +1 -1
- package/dist/react-native/RaftStruct.js.map +1 -1
- package/dist/react-native/RaftSysTypeManager.d.ts +2 -0
- package/dist/react-native/RaftSysTypeManager.js +25 -0
- package/dist/react-native/RaftSysTypeManager.js.map +1 -1
- package/dist/react-native/RaftSystemType.d.ts +9 -7
- package/dist/react-native/RaftSystemUtils.js +3 -1
- package/dist/react-native/RaftSystemUtils.js.map +1 -1
- package/dist/react-native/RaftUpdateManager.js +2 -2
- package/dist/react-native/RaftUpdateManager.js.map +1 -1
- package/dist/react-native/RaftUtils.d.ts +2 -0
- package/dist/react-native/RaftUtils.js +22 -2
- package/dist/react-native/RaftUtils.js.map +1 -1
- package/dist/react-native/main.d.ts +2 -0
- package/dist/react-native/main.js +4 -1
- package/dist/react-native/main.js.map +1 -1
- package/dist/web/RaftAttributeHandler.d.ts +2 -0
- package/dist/web/RaftAttributeHandler.js +136 -10
- package/dist/web/RaftAttributeHandler.js.map +1 -1
- package/dist/web/RaftChannel.d.ts +2 -0
- package/dist/web/RaftChannelBLE.web.d.ts +2 -0
- package/dist/web/RaftChannelBLE.web.js +24 -15
- package/dist/web/RaftChannelBLE.web.js.map +1 -1
- package/dist/web/RaftChannelSimulated.d.ts +32 -0
- package/dist/web/RaftChannelSimulated.js +418 -0
- package/dist/web/RaftChannelSimulated.js.map +1 -0
- package/dist/web/RaftChannelWebSerial.d.ts +2 -0
- package/dist/web/RaftChannelWebSerial.js +18 -9
- package/dist/web/RaftChannelWebSerial.js.map +1 -1
- package/dist/web/RaftChannelWebSocket.d.ts +2 -0
- package/dist/web/RaftChannelWebSocket.js +10 -0
- package/dist/web/RaftChannelWebSocket.js.map +1 -1
- package/dist/web/RaftConnector.js +13 -6
- package/dist/web/RaftConnector.js.map +1 -1
- package/dist/web/RaftCustomAttrHandler.js +15 -0
- package/dist/web/RaftCustomAttrHandler.js.map +1 -1
- package/dist/web/RaftDeviceInfo.d.ts +8 -1
- package/dist/web/RaftDeviceManager.d.ts +3 -0
- package/dist/web/RaftDeviceManager.js +123 -43
- package/dist/web/RaftDeviceManager.js.map +1 -1
- package/dist/web/RaftFileHandler.js +8 -8
- package/dist/web/RaftFileHandler.js.map +1 -1
- package/dist/web/RaftLog.js +1 -1
- package/dist/web/RaftLog.js.map +1 -1
- package/dist/web/RaftMsgHandler.d.ts +5 -0
- package/dist/web/RaftMsgHandler.js +32 -0
- package/dist/web/RaftMsgHandler.js.map +1 -1
- package/dist/web/RaftStreamHandler.js +6 -5
- package/dist/web/RaftStreamHandler.js.map +1 -1
- package/dist/web/RaftStruct.js +1 -1
- package/dist/web/RaftStruct.js.map +1 -1
- package/dist/web/RaftSysTypeManager.d.ts +2 -0
- package/dist/web/RaftSysTypeManager.js +25 -0
- package/dist/web/RaftSysTypeManager.js.map +1 -1
- package/dist/web/RaftSystemType.d.ts +9 -7
- package/dist/web/RaftSystemUtils.js +3 -1
- package/dist/web/RaftSystemUtils.js.map +1 -1
- package/dist/web/RaftUpdateManager.js +2 -2
- package/dist/web/RaftUpdateManager.js.map +1 -1
- package/dist/web/RaftUtils.d.ts +2 -0
- package/dist/web/RaftUtils.js +22 -2
- package/dist/web/RaftUtils.js.map +1 -1
- package/dist/web/main.d.ts +2 -0
- package/dist/web/main.js +4 -1
- package/dist/web/main.js.map +1 -1
- package/examples/dashboard/package.json +1 -1
- package/examples/dashboard/src/CommandPanel.tsx +3 -3
- package/examples/dashboard/src/ConnManager.ts +83 -6
- package/examples/dashboard/src/DeviceActionsForm.tsx +2 -2
- package/examples/dashboard/src/DevicePanel.tsx +2 -2
- package/examples/dashboard/src/Main.tsx +14 -4
- package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +4 -4
- package/examples/dashboard/src/styles.css +8 -0
- package/examples/dashboard/tsconfig.json +1 -1
- package/package.json +10 -11
- package/src/RaftAttributeHandler.ts +163 -11
- package/src/RaftChannel.ts +2 -0
- package/src/RaftChannelBLE.native.ts +20 -10
- package/src/RaftChannelBLE.web.ts +28 -16
- package/src/RaftChannelSimulated.ts +482 -0
- package/src/RaftChannelWebSerial.ts +18 -7
- package/src/RaftChannelWebSocket.ts +13 -0
- package/src/RaftConnector.ts +13 -7
- package/src/RaftCustomAttrHandler.ts +17 -0
- package/src/RaftDeviceInfo.ts +8 -2
- package/src/RaftDeviceManager.ts +155 -47
- package/src/RaftFileHandler.ts +8 -8
- package/src/RaftLog.ts +1 -1
- package/src/RaftMsgHandler.ts +36 -0
- package/src/RaftStreamHandler.ts +48 -47
- package/src/RaftStruct.ts +1 -1
- package/src/RaftSysTypeManager.ts +27 -0
- package/src/RaftSystemType.ts +9 -7
- package/src/RaftSystemUtils.ts +3 -1
- package/src/RaftUpdateManager.ts +2 -2
- package/src/RaftUtils.ts +25 -5
- package/src/main.ts +2 -0
package/dist/web/main.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
//
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.RaftDeviceManager = exports.RaftSysTypeManager = exports.RaftUtils = exports.RaftSystemUtils = exports.RaftStreamHandler = exports.RaftMsgHandler = exports.RaftMiniHDLC = exports.RaftLog = exports.RaftFileHandler = exports.RaftChannelWebSocket = exports.RaftConnector = exports.RaftCommsStats = exports.RaftChannelBLE = void 0;
|
|
12
|
+
exports.RaftDeviceManager = exports.RaftSysTypeManager = exports.RaftUtils = exports.RaftSystemUtils = exports.RaftStreamHandler = exports.RaftMsgHandler = exports.RaftMiniHDLC = exports.RaftLog = exports.RaftFileHandler = exports.RaftChannelSimulated = exports.RaftChannelWebSocket = exports.RaftConnector = exports.RaftCommsStats = exports.RaftChannelBLE = void 0;
|
|
13
13
|
const tslib_1 = require("tslib");
|
|
14
14
|
const RaftChannelBLEFactory_1 = require("./RaftChannelBLEFactory");
|
|
15
15
|
const raftChannel = (0, RaftChannelBLEFactory_1.createBLEChannel)();
|
|
@@ -20,6 +20,8 @@ var RaftConnector_1 = require("./RaftConnector");
|
|
|
20
20
|
Object.defineProperty(exports, "RaftConnector", { enumerable: true, get: function () { return tslib_1.__importDefault(RaftConnector_1).default; } });
|
|
21
21
|
var RaftChannelWebSocket_1 = require("./RaftChannelWebSocket");
|
|
22
22
|
Object.defineProperty(exports, "RaftChannelWebSocket", { enumerable: true, get: function () { return tslib_1.__importDefault(RaftChannelWebSocket_1).default; } });
|
|
23
|
+
var RaftChannelSimulated_1 = require("./RaftChannelSimulated");
|
|
24
|
+
Object.defineProperty(exports, "RaftChannelSimulated", { enumerable: true, get: function () { return tslib_1.__importDefault(RaftChannelSimulated_1).default; } });
|
|
23
25
|
var RaftFileHandler_1 = require("./RaftFileHandler");
|
|
24
26
|
Object.defineProperty(exports, "RaftFileHandler", { enumerable: true, get: function () { return tslib_1.__importDefault(RaftFileHandler_1).default; } });
|
|
25
27
|
var RaftLog_1 = require("./RaftLog");
|
|
@@ -45,4 +47,5 @@ tslib_1.__exportStar(require("./RaftConnEvents"), exports);
|
|
|
45
47
|
tslib_1.__exportStar(require("./RaftUpdateEvents"), exports);
|
|
46
48
|
tslib_1.__exportStar(require("./RaftProtocolDefs"), exports);
|
|
47
49
|
tslib_1.__exportStar(require("./RaftDeviceStates"), exports);
|
|
50
|
+
tslib_1.__exportStar(require("./RaftDeviceInfo"), exports);
|
|
48
51
|
//# sourceMappingURL=main.js.map
|
package/dist/web/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":";AAAA,iHAAiH;AACjH,EAAE;AACF,SAAS;AACT,gGAAgG;AAChG,EAAE;AACF,wCAAwC;AACxC,oCAAoC;AACpC,EAAE;AACF,iHAAiH;;;;AAEjH,mEAA2D;AAC3D,MAAM,WAAW,GAAG,IAAA,wCAAgB,GAAE,CAAC;AACf,qCAAc;AAEtC,mDAA6D;AAApD,yIAAA,OAAO,OAAkB;AAClC,iDAA2D;AAAlD,uIAAA,OAAO,OAAiB;AAEjC,+DAAyE;AAAhE,qJAAA,OAAO,OAAwB;AACxC,qDAA+D;AAAtD,2IAAA,OAAO,OAAmB;AACnC,qCAA+C;AAAtC,2HAAA,OAAO,OAAW;AAC3B,+CAAyD;AAAhD,qIAAA,OAAO,OAAgB;AAChC,mDAA4D;AAAnD,yIAAA,OAAO,OAAkB;AAClC,yDAAmE;AAA1D,+IAAA,OAAO,OAAqB;AACrC,qDAA+D;AAAtD,2IAAA,OAAO,OAAmB;AACnC,yCAAmD;AAA1C,+HAAA,OAAO,OAAa;AAC7B,2DAAqE;AAA5D,iJAAA,OAAO,OAAsB;AAEtC,yDAAyE;AAAhE,sHAAA,aAAa,OAAqB;AAE3C,sDAA4B;AAC5B,2DAAiC;AACjC,0DAAgC;AAChC,2DAAiC;AACjC,6DAAmC;AACnC,6DAAmC;AACnC,6DAAmC"}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":";AAAA,iHAAiH;AACjH,EAAE;AACF,SAAS;AACT,gGAAgG;AAChG,EAAE;AACF,wCAAwC;AACxC,oCAAoC;AACpC,EAAE;AACF,iHAAiH;;;;AAEjH,mEAA2D;AAC3D,MAAM,WAAW,GAAG,IAAA,wCAAgB,GAAE,CAAC;AACf,qCAAc;AAEtC,mDAA6D;AAApD,yIAAA,OAAO,OAAkB;AAClC,iDAA2D;AAAlD,uIAAA,OAAO,OAAiB;AAEjC,+DAAyE;AAAhE,qJAAA,OAAO,OAAwB;AACxC,+DAAyE;AAAhE,qJAAA,OAAO,OAAwB;AACxC,qDAA+D;AAAtD,2IAAA,OAAO,OAAmB;AACnC,qCAA+C;AAAtC,2HAAA,OAAO,OAAW;AAC3B,+CAAyD;AAAhD,qIAAA,OAAO,OAAgB;AAChC,mDAA4D;AAAnD,yIAAA,OAAO,OAAkB;AAClC,yDAAmE;AAA1D,+IAAA,OAAO,OAAqB;AACrC,qDAA+D;AAAtD,2IAAA,OAAO,OAAmB;AACnC,yCAAmD;AAA1C,+HAAA,OAAO,OAAa;AAC7B,2DAAqE;AAA5D,iJAAA,OAAO,OAAsB;AAEtC,yDAAyE;AAAhE,sHAAA,aAAa,OAAqB;AAE3C,sDAA4B;AAC5B,2DAAiC;AACjC,0DAAgC;AAChC,2DAAiC;AACjC,6DAAmC;AACnC,6DAAmC;AACnC,6DAAmC;AACnC,2DAAiC"}
|
|
@@ -38,17 +38,17 @@ export default function CommandPanel() {
|
|
|
38
38
|
|
|
39
39
|
// Update history only if the command is not the same as the last one
|
|
40
40
|
if (commandHistory.length === 0 || commandHistory[commandHistory.length - 1] !== cmd) {
|
|
41
|
-
setCommandHistory((prevHistory) => [...prevHistory, cmd]);
|
|
41
|
+
setCommandHistory((prevHistory: any) => [...prevHistory, cmd]);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// Reset the history index and clear the command
|
|
45
45
|
setHistoryIndex(-1);
|
|
46
46
|
setCommand('');
|
|
47
47
|
}).catch(error => {
|
|
48
|
-
console.
|
|
48
|
+
console.warn(`Error sending command: ${cmd}`, error);
|
|
49
49
|
});
|
|
50
50
|
} else {
|
|
51
|
-
console.
|
|
51
|
+
console.warn("Command is empty.");
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
|
|
@@ -20,7 +20,9 @@ export default class ConnManager {
|
|
|
20
20
|
private _connector = new RaftConnector(async (systemUtils: RaftSystemUtils) => {
|
|
21
21
|
const systemInfo = await systemUtils.getSystemInfo();
|
|
22
22
|
const sysType = sysTypeManager.createSystemType(systemInfo.SystemName) || sysTypeManager.createDefaultSystemType();
|
|
23
|
-
sysType
|
|
23
|
+
if (sysType && sysType.deviceMgrIF) {
|
|
24
|
+
sysType.deviceMgrIF.setMaxDataPointsToStore(settingsManager.getSetting("maxDatapointsToStore"));
|
|
25
|
+
}
|
|
24
26
|
return sysType;
|
|
25
27
|
});
|
|
26
28
|
|
|
@@ -49,8 +51,22 @@ export default class ConnManager {
|
|
|
49
51
|
return this._connector;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
private async getBleDevice(uuids: string[]): Promise<BluetoothDevice | null> {
|
|
53
|
-
|
|
54
|
+
private async getBleDevice(uuids: string[], serialNo: string | null = null): Promise<BluetoothDevice | null> {
|
|
55
|
+
|
|
56
|
+
// Filter by main service UUID if no serial number provided
|
|
57
|
+
let filtersArray = uuids.map((uuid) => ({ services: [ uuid] }));
|
|
58
|
+
|
|
59
|
+
// Check if a serial number is provided
|
|
60
|
+
if ((serialNo !== null) && (serialNo !== "")) {
|
|
61
|
+
|
|
62
|
+
// Generate a UUID from the base UUID xored with serial number in BCD form
|
|
63
|
+
const baseUUID = "aa76677e-9cfd-4626-0000-000000000000";
|
|
64
|
+
const modifiedUUID = this.generateServiceFilterUUID(baseUUID, serialNo);
|
|
65
|
+
filtersArray = [{ services: [modifiedUUID] }];
|
|
66
|
+
|
|
67
|
+
// console.log(`getBleDevice - modified UUID: ${modifiedUUID}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
54
70
|
try {
|
|
55
71
|
const dev = await navigator.bluetooth.requestDevice({
|
|
56
72
|
filters: filtersArray,
|
|
@@ -58,13 +74,13 @@ export default class ConnManager {
|
|
|
58
74
|
});
|
|
59
75
|
return dev;
|
|
60
76
|
} catch (e) {
|
|
61
|
-
RaftLog.
|
|
77
|
+
RaftLog.warn(`getBleDevice - failed to get device ${e}`);
|
|
62
78
|
return null;
|
|
63
79
|
}
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
// Connect
|
|
67
|
-
public async connect(method: string, locator: string | object, uuids: string[]): Promise<boolean> {
|
|
83
|
+
public async connect(method: string, locator: string | object, uuids: string[], serialNo: string | null = null): Promise<boolean> {
|
|
68
84
|
|
|
69
85
|
// Hook up the connector
|
|
70
86
|
this._connector.setEventListener((evtType, eventEnum, eventName, eventData) => {
|
|
@@ -76,7 +92,7 @@ export default class ConnManager {
|
|
|
76
92
|
await this._connector.initializeChannel(method);
|
|
77
93
|
// Set the connector websocket suffix
|
|
78
94
|
if (method === "WebBLE") {
|
|
79
|
-
const dev = await this.getBleDevice(uuids);
|
|
95
|
+
const dev = await this.getBleDevice(uuids, serialNo);
|
|
80
96
|
return this._connector.connect(dev as object);
|
|
81
97
|
}
|
|
82
98
|
return this._connector.connect(locator);
|
|
@@ -86,4 +102,65 @@ export default class ConnManager {
|
|
|
86
102
|
public disconnect(): Promise<void> {
|
|
87
103
|
return this._connector.disconnect();
|
|
88
104
|
}
|
|
105
|
+
|
|
106
|
+
///////////////////////////////////////////////////////////////////////////////////
|
|
107
|
+
/// @brief Generate a UUID for service filtering based on device serial number
|
|
108
|
+
/// @param baseUUID Base UUID string (e.g., "aa76677e-9cfd-4626-0000-000000000000")
|
|
109
|
+
/// @param serialNo Serial number as an ASCII string (e.g., "1234567890123456")
|
|
110
|
+
/// @returns Modified UUID string
|
|
111
|
+
public generateServiceFilterUUID(baseUUID: string, serialNo: string): string {
|
|
112
|
+
const UUID_128_BYTES = 16;
|
|
113
|
+
|
|
114
|
+
// Convert UUID string to byte array
|
|
115
|
+
let uuidBytes = this.uuidToByteArray(baseUUID);
|
|
116
|
+
|
|
117
|
+
// Convert serial number assuming it is decimal (or hex) digits to bytes
|
|
118
|
+
let serialBytes = this.hexStringToBytes(serialNo);
|
|
119
|
+
|
|
120
|
+
// Limit to 16 bytes (UUID size)
|
|
121
|
+
const bytesToProc = Math.min(serialBytes.length, UUID_128_BYTES);
|
|
122
|
+
|
|
123
|
+
// console.log(`generateServiceFilterUUID - serialBCD: ${serialBCD} bytesToProc: ${bytesToProc}`);
|
|
124
|
+
|
|
125
|
+
// XOR the serial BCD bytes with the UUID bytes
|
|
126
|
+
for (let i = 0; i < bytesToProc; i++) {
|
|
127
|
+
uuidBytes[15 - i] ^= serialBytes[bytesToProc - 1 - i];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Convert back to UUID string format
|
|
131
|
+
return this.byteArrayToUUID(uuidBytes);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/////////////////////////////////////////////////////////////////////////////
|
|
135
|
+
/// @brief Convert UUID string to byte array (Big Endian order)
|
|
136
|
+
public uuidToByteArray(uuid: string): Uint8Array {
|
|
137
|
+
return new Uint8Array(
|
|
138
|
+
uuid.replace(/-/g, "") // Remove dashes
|
|
139
|
+
.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16)) // Convert hex pairs to bytes
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/////////////////////////////////////////////////////////////////////////////
|
|
144
|
+
/// @brief Convert byte array back to UUID string
|
|
145
|
+
public byteArrayToUUID(bytes: Uint8Array): string {
|
|
146
|
+
return [...bytes]
|
|
147
|
+
.map(b => b.toString(16).padStart(2, "0")) // Convert to hex
|
|
148
|
+
.join("")
|
|
149
|
+
.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, "$1-$2-$3-$4-$5"); // Format as UUID
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/////////////////////////////////////////////////////////////////////////////
|
|
153
|
+
/// @brief Convert an hex string to bytes
|
|
154
|
+
/// @param hex string - e.g. "1234567890123456" -> [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]
|
|
155
|
+
/// @returns byte array
|
|
156
|
+
public hexStringToBytes(hex: string): Uint8Array {
|
|
157
|
+
// Pad to ensure even number of characters
|
|
158
|
+
if (hex.length % 2 !== 0) {
|
|
159
|
+
hex = "0" + hex;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return new Uint8Array(
|
|
163
|
+
hex.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []
|
|
164
|
+
);
|
|
165
|
+
}
|
|
89
166
|
}
|
|
@@ -13,7 +13,7 @@ interface InputValues {
|
|
|
13
13
|
[key: string]: number;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const DeviceActionsForm: React.FC<DeviceActionsTableProps> = ({ deviceKey }) => {
|
|
16
|
+
const DeviceActionsForm: React.FC<DeviceActionsTableProps> = ({ deviceKey }: DeviceActionsTableProps) => {
|
|
17
17
|
const deviceManager = connManager.getConnector().getSystemType()?.deviceMgrIF;
|
|
18
18
|
const [deviceActions, setDeviceActions] = useState<DeviceTypeAction[]>([]);
|
|
19
19
|
const [inputValues, setInputValues] = useState<InputValues>({});
|
|
@@ -44,7 +44,7 @@ const DeviceActionsForm: React.FC<DeviceActionsTableProps> = ({ deviceKey }) =>
|
|
|
44
44
|
}, [deviceKey]);
|
|
45
45
|
|
|
46
46
|
const handleInputChange = (name: string, value: number) => {
|
|
47
|
-
setInputValues((prevValues) => ({
|
|
47
|
+
setInputValues((prevValues: any) => ({
|
|
48
48
|
...prevValues,
|
|
49
49
|
[name]: value,
|
|
50
50
|
}));
|
|
@@ -83,7 +83,7 @@ const DevicePanel = ({ deviceKey, lastUpdated }: DevicePanelProps) => {
|
|
|
83
83
|
navigator.clipboard.writeText(csvContent).then(() => {
|
|
84
84
|
console.log("Device values copied to clipboard");
|
|
85
85
|
}).catch(err => {
|
|
86
|
-
console.
|
|
86
|
+
console.warn('Failed to copy: ', err);
|
|
87
87
|
fallbackCopyTextToClipboard(csvContent);
|
|
88
88
|
});
|
|
89
89
|
} else {
|
|
@@ -109,7 +109,7 @@ const DevicePanel = ({ deviceKey, lastUpdated }: DevicePanelProps) => {
|
|
|
109
109
|
document.execCommand("copy");
|
|
110
110
|
// alert("Device values copied to clipboard!");
|
|
111
111
|
} catch (err) {
|
|
112
|
-
console.
|
|
112
|
+
console.warn('Fallback: Oops, unable to copy', err);
|
|
113
113
|
alert("Failed to copy device values to clipboard");
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -35,12 +35,14 @@ export default function Main() {
|
|
|
35
35
|
localStorage.getItem('lastIpAddress') || ''
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
+
const [serialNo, setSerialNo] = useState<string>('');
|
|
39
|
+
|
|
38
40
|
const handleConnect = () => {
|
|
39
41
|
if (ipAddress.trim() === '') {
|
|
40
|
-
console.
|
|
42
|
+
console.warn('No IP address entered');
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
|
-
connManager.connect('WebSocket', ipAddress, []);
|
|
45
|
+
connManager.connect('WebSocket', ipAddress, [], null);
|
|
44
46
|
localStorage.setItem('lastIpAddress', ipAddress);
|
|
45
47
|
};
|
|
46
48
|
|
|
@@ -193,10 +195,18 @@ export default function Main() {
|
|
|
193
195
|
</div>
|
|
194
196
|
<div className="info-box">
|
|
195
197
|
<h3>WebBLE</h3>
|
|
198
|
+
<input
|
|
199
|
+
className="serial-no-input"
|
|
200
|
+
id="serial-no"
|
|
201
|
+
type="text"
|
|
202
|
+
placeholder="Serial No (ignored if empty)"
|
|
203
|
+
value={serialNo}
|
|
204
|
+
onChange={(e) => setSerialNo(e.target.value)}
|
|
205
|
+
/>
|
|
196
206
|
<button
|
|
197
207
|
className="action-button"
|
|
198
208
|
onClick={() => {
|
|
199
|
-
connManager.connect('WebBLE', '', sysTypeManager.getAllServiceUUIDs());
|
|
209
|
+
connManager.connect('WebBLE', '', sysTypeManager.getAllServiceUUIDs(), serialNo);
|
|
200
210
|
}}
|
|
201
211
|
>
|
|
202
212
|
Connect
|
|
@@ -207,7 +217,7 @@ export default function Main() {
|
|
|
207
217
|
<button
|
|
208
218
|
className="action-button"
|
|
209
219
|
onClick={() => {
|
|
210
|
-
connManager.connect('WebSerial', '', []);
|
|
220
|
+
connManager.connect('WebSerial', '', [], null);
|
|
211
221
|
}}
|
|
212
222
|
>
|
|
213
223
|
Connect
|
|
@@ -98,7 +98,7 @@ export default class RICSystemUtils {
|
|
|
98
98
|
const retrieveResult = await this.retrieveInfo();
|
|
99
99
|
return retrieveResult;
|
|
100
100
|
} catch (err) {
|
|
101
|
-
RaftLog.
|
|
101
|
+
RaftLog.warn(`retrieveMartySystemInfo: error ${err}`);
|
|
102
102
|
}
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
@@ -260,7 +260,7 @@ export default class RICSystemUtils {
|
|
|
260
260
|
// Debug
|
|
261
261
|
RaftLog.debug(
|
|
262
262
|
`getHWElemList: found ${hwElemList.hw.length} addons/buspixels`
|
|
263
|
-
|
|
263
|
+
);
|
|
264
264
|
} else if (addToNonAddOnsList) {
|
|
265
265
|
this._hwElemsExcludingAddOns.push(...hwElemList.hw);
|
|
266
266
|
// Debug
|
|
@@ -279,9 +279,9 @@ export default class RICSystemUtils {
|
|
|
279
279
|
try {
|
|
280
280
|
const reports: Array<RaftReportMsg> = [];
|
|
281
281
|
// add callback to subscribe to report messages
|
|
282
|
-
this._msgHandler.reportMsgCallbacksSet("getHWElemCB", function (
|
|
282
|
+
this._msgHandler.reportMsgCallbacksSet("getHWElemCB", async function (
|
|
283
283
|
report: RaftReportMsg
|
|
284
|
-
) {
|
|
284
|
+
): Promise<void> {
|
|
285
285
|
reports.push(report);
|
|
286
286
|
RaftLog.debug(`getHWElemCB Report callback ${JSON.stringify(report)}`);
|
|
287
287
|
});
|
|
@@ -121,6 +121,14 @@ h1 {
|
|
|
121
121
|
width: 100%;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
.serial-no-input {
|
|
125
|
+
border: 1px solid #ccc;
|
|
126
|
+
border-radius: 4px;
|
|
127
|
+
margin-bottom: 10px;
|
|
128
|
+
padding: 10px;
|
|
129
|
+
width: 100%;
|
|
130
|
+
}
|
|
131
|
+
|
|
124
132
|
.command-input {
|
|
125
133
|
padding: 10px;
|
|
126
134
|
margin-bottom: 10px;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robotical/raftjs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Javascript/TS library for Raft library",
|
|
5
5
|
"main": "dist/web/main.js",
|
|
6
6
|
"types": "dist/web/main.d.ts",
|
|
@@ -31,19 +31,18 @@
|
|
|
31
31
|
"watch-all": "tsc -p tsconfig.json --watch & tsc -p tsconfig.react-native.json --watch"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@types/node": "^
|
|
35
|
-
"@types/web-bluetooth": "^0.0.
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
37
|
-
"eslint": "^9.
|
|
38
|
-
"react-native-ble-plx": "^3.
|
|
39
|
-
"typescript": "^5.
|
|
40
|
-
"
|
|
41
|
-
"
|
|
34
|
+
"@types/node": "^22.13.11",
|
|
35
|
+
"@types/web-bluetooth": "^0.0.21",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^8.27.0",
|
|
37
|
+
"eslint": "^9.23.0",
|
|
38
|
+
"react-native-ble-plx": "^3.5.0",
|
|
39
|
+
"typescript": "^5.8.2",
|
|
40
|
+
"rimraf": "^6.0.1",
|
|
41
|
+
"@types/text-encoding": "^0.0.40"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"text-encoding": "^0.7.0",
|
|
45
44
|
"isomorphic-ws": "^5.0.0",
|
|
46
|
-
"tslib": "^2.
|
|
45
|
+
"tslib": "^2.8.1"
|
|
47
46
|
},
|
|
48
47
|
"peerDependencies": {
|
|
49
48
|
"react-native-ble-plx": "*",
|
|
@@ -45,6 +45,8 @@ export default class AttributeHandler {
|
|
|
45
45
|
|
|
46
46
|
} else {
|
|
47
47
|
|
|
48
|
+
// console.log(`RaftAttrHdlr.processMsgAttrGroup ${JSON.stringify(pollRespMetadata)} msgBufIdx ${msgBufIdx} timestampUs ${timestampUs}`);
|
|
49
|
+
|
|
48
50
|
// Iterate over attributes
|
|
49
51
|
for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
|
|
50
52
|
|
|
@@ -56,6 +58,8 @@ export default class AttributeHandler {
|
|
|
56
58
|
continue;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
// console.log(`RaftAttrHdlr.processMsgAttrGroup attr ${attrDef.n} msgBufIdx ${msgBufIdx} timestampUs ${timestampUs} attrDef ${JSON.stringify(attrDef)}`);
|
|
62
|
+
|
|
59
63
|
// Process the attribute
|
|
60
64
|
const { values, newMsgBufIdx } = this.processMsgAttribute(attrDef, msgBuffer, msgBufIdx, msgDataStartIdx);
|
|
61
65
|
if (newMsgBufIdx < 0) {
|
|
@@ -65,7 +69,6 @@ export default class AttributeHandler {
|
|
|
65
69
|
msgBufIdx = newMsgBufIdx;
|
|
66
70
|
newAttrValues.push(values);
|
|
67
71
|
}
|
|
68
|
-
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
// Number of bytes in group
|
|
@@ -142,19 +145,94 @@ export default class AttributeHandler {
|
|
|
142
145
|
// Add the new timestamps
|
|
143
146
|
deviceTimeline.timestampsUs.push(...timestampsUs);
|
|
144
147
|
|
|
148
|
+
// Validate attributes based on the vft field
|
|
149
|
+
this.validateAttributes(pollRespMetadata, devAttrsState, numNewDataPoints);
|
|
150
|
+
|
|
145
151
|
// Return the next message buffer index
|
|
146
152
|
return msgDataStartIdx+pollRespSizeBytes;
|
|
147
153
|
}
|
|
148
154
|
|
|
155
|
+
private validateAttributes(pollRespMetadata: DeviceTypePollRespMetadata, devAttrsState: DeviceAttributesState, numNewDataPoints: number): void {
|
|
156
|
+
// Iterate through all attributes to find those with a vft field
|
|
157
|
+
for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
|
|
158
|
+
const attrDef: DeviceTypeAttribute = pollRespMetadata.a[attrIdx];
|
|
159
|
+
|
|
160
|
+
// Check if this attribute has a vft field
|
|
161
|
+
if (!("vft" in attrDef) || !attrDef.vft) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Get the name of the validating attribute
|
|
166
|
+
const validatingAttrName = attrDef.vft;
|
|
167
|
+
|
|
168
|
+
// Check if the validating attribute exists in the state
|
|
169
|
+
if (!(validatingAttrName in devAttrsState)) {
|
|
170
|
+
console.debug(`Cannot validate attribute ${attrDef.n} as validating attribute ${validatingAttrName} doesn't exist`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Get the current attribute state
|
|
175
|
+
const currentAttr = devAttrsState[attrDef.n];
|
|
176
|
+
const validatingAttr = devAttrsState[validatingAttrName];
|
|
177
|
+
|
|
178
|
+
// Check if both attributes have values
|
|
179
|
+
if (!currentAttr.values.length || !validatingAttr.values.length) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Get the most recent values from both attributes
|
|
184
|
+
const numValues = currentAttr.values.length;
|
|
185
|
+
const startIdx = numValues - numNewDataPoints;
|
|
186
|
+
|
|
187
|
+
// Process each of the new values
|
|
188
|
+
for (let i = 0; i < numNewDataPoints; i++) {
|
|
189
|
+
const valueIdx = startIdx + i;
|
|
190
|
+
if (valueIdx >= 0 && valueIdx < numValues) {
|
|
191
|
+
// Check if the validating attribute's value is 0/false at the same index
|
|
192
|
+
const validatingValueIdx = validatingAttr.values.length - numNewDataPoints + i;
|
|
193
|
+
if (validatingValueIdx >= 0 && validatingValueIdx < validatingAttr.values.length) {
|
|
194
|
+
// If the validating attribute's value is 0 or false, mark the current value as invalid
|
|
195
|
+
if (!validatingAttr.values[validatingValueIdx]) {
|
|
196
|
+
currentAttr.values[valueIdx] = NaN; // Using NaN to represent invalid values
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
149
204
|
private processMsgAttribute(attrDef: DeviceTypeAttribute, msgBuffer: Uint8Array, msgBufIdx: number, msgDataStartIdx: number): { values: number[], newMsgBufIdx: number} {
|
|
150
205
|
|
|
151
206
|
// Current field message string index
|
|
152
207
|
let curFieldBufIdx = msgBufIdx;
|
|
153
208
|
let attrUsesAbsPos = false;
|
|
154
209
|
|
|
155
|
-
// Check for "at"
|
|
210
|
+
// Check for "at" field which means absolute position in the buffer
|
|
156
211
|
if (attrDef.at !== undefined) {
|
|
157
|
-
|
|
212
|
+
// Handle both single value and array of byte positions
|
|
213
|
+
if (Array.isArray(attrDef.at)) {
|
|
214
|
+
// Create a new buffer for non-contiguous data extraction
|
|
215
|
+
const elemSize = structSizeOf(attrDef.t);
|
|
216
|
+
const bytesForType = new Uint8Array(elemSize);
|
|
217
|
+
|
|
218
|
+
// Zero out the buffer
|
|
219
|
+
bytesForType.fill(0);
|
|
220
|
+
|
|
221
|
+
// Copy bytes from the specified positions
|
|
222
|
+
for (let i = 0; i < attrDef.at.length && i < elemSize; i++) {
|
|
223
|
+
const sourceIdx = msgDataStartIdx + attrDef.at[i];
|
|
224
|
+
if (sourceIdx < msgBuffer.length) {
|
|
225
|
+
bytesForType[i] = msgBuffer[sourceIdx];
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Use this buffer for attribute extraction
|
|
230
|
+
msgBuffer = bytesForType;
|
|
231
|
+
curFieldBufIdx = 0;
|
|
232
|
+
} else {
|
|
233
|
+
// Standard absolute position in the buffer
|
|
234
|
+
curFieldBufIdx = msgDataStartIdx + attrDef.at;
|
|
235
|
+
}
|
|
158
236
|
attrUsesAbsPos = true;
|
|
159
237
|
}
|
|
160
238
|
|
|
@@ -194,13 +272,13 @@ export default class AttributeHandler {
|
|
|
194
272
|
// Check for XOR mask
|
|
195
273
|
if ("x" in attrDef) {
|
|
196
274
|
const mask = typeof attrDef.x === "string" ? parseInt(attrDef.x, 16) : attrDef.x as number;
|
|
197
|
-
attrValues = attrValues.map((value) => value ^ mask);
|
|
275
|
+
attrValues = attrValues.map((value) => (value >>> 0) ^ mask);
|
|
198
276
|
}
|
|
199
277
|
|
|
200
278
|
// Check for AND mask
|
|
201
279
|
if ("m" in attrDef) {
|
|
202
280
|
const mask = typeof attrDef.m === "string" ? parseInt(attrDef.m, 16) : attrDef.m as number;
|
|
203
|
-
attrValues = attrValues.map((value) => (maskOnSignedValue ? this.signExtend(value, mask) : value & mask));
|
|
281
|
+
attrValues = attrValues.map((value) => (maskOnSignedValue ? this.signExtend(value, mask) : (value >>> 0) & mask));
|
|
204
282
|
}
|
|
205
283
|
|
|
206
284
|
// Check for a sign-bit
|
|
@@ -219,9 +297,9 @@ export default class AttributeHandler {
|
|
|
219
297
|
if ("s" in attrDef && attrDef.s) {
|
|
220
298
|
const bitshift = attrDef.s as number;
|
|
221
299
|
if (bitshift > 0) {
|
|
222
|
-
attrValues = attrValues.map((value) => (value)
|
|
300
|
+
attrValues = attrValues.map((value) => (value >>> 0) >>> bitshift);
|
|
223
301
|
} else if (bitshift < 0) {
|
|
224
|
-
attrValues = attrValues.map((value) => (value) << -bitshift);
|
|
302
|
+
attrValues = attrValues.map((value) => (value >>> 0) << -bitshift);
|
|
225
303
|
}
|
|
226
304
|
}
|
|
227
305
|
|
|
@@ -237,10 +315,47 @@ export default class AttributeHandler {
|
|
|
237
315
|
attrValues = attrValues.map((value) => (value) + addValue);
|
|
238
316
|
}
|
|
239
317
|
|
|
240
|
-
//
|
|
318
|
+
// Apply lookup table if defined
|
|
319
|
+
if ("lut" in attrDef && attrDef.lut !== undefined) {
|
|
320
|
+
attrValues = attrValues.map((value): number => {
|
|
321
|
+
// Skip NaN values
|
|
322
|
+
if (isNaN(value)) {
|
|
323
|
+
return value;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Search through the lookup table rows for a match
|
|
327
|
+
let defaultValue: number | null = null;
|
|
328
|
+
|
|
329
|
+
for (const row of attrDef.lut || []) {
|
|
330
|
+
// Empty string means default for unmatched values
|
|
331
|
+
if (row.r === "") {
|
|
332
|
+
defaultValue = row.v;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Parse the range string
|
|
337
|
+
if (this.isValueInRangeString(value, row.r)) {
|
|
338
|
+
return row.v;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// If no match found but we have a default, use it
|
|
343
|
+
if (defaultValue !== null) {
|
|
344
|
+
return defaultValue;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Otherwise keep the original value
|
|
348
|
+
return value;
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// const msgBufIdxIn = msgBufIdx;
|
|
353
|
+
|
|
241
354
|
// Move buffer position if using relative positioning
|
|
242
355
|
msgBufIdx += attrUsesAbsPos ? 0 : numBytesConsumed;
|
|
243
356
|
|
|
357
|
+
// console.log(`RaftAttrHdlr.processMsgAttr attr ${attrDef.n} msgBufIdx ${msgBufIdxIn} msgBufIdx ${msgBufIdx} attrUsesAbsPos ${attrUsesAbsPos} numBytesConsumed ${numBytesConsumed} attrValues ${attrValues}`);
|
|
358
|
+
|
|
244
359
|
// if (attrDef.n === "amb0") {
|
|
245
360
|
// console.log(`${new Date().toISOString()} ${attrDef.n} ${attrValues}`);
|
|
246
361
|
// }
|
|
@@ -264,7 +379,7 @@ export default class AttributeHandler {
|
|
|
264
379
|
private extractTimestampAndAdvanceIdx(msgBuffer: Uint8Array, msgBufIdx: number, timestampWrapHandler: DeviceTimeline):
|
|
265
380
|
{ newBufIdx: number, timestampUs: number } {
|
|
266
381
|
|
|
267
|
-
// Check there are enough
|
|
382
|
+
// Check there are enough bytes for the timestamp
|
|
268
383
|
if (msgBufIdx + this.POLL_RESULT_TIMESTAMP_SIZE > msgBuffer.length) {
|
|
269
384
|
return { newBufIdx: -1, timestampUs: 0 };
|
|
270
385
|
}
|
|
@@ -278,8 +393,8 @@ export default class AttributeHandler {
|
|
|
278
393
|
timestampUs = structUnpack(">I", tsBuffer)[0] as number * this.POLL_RESULT_RESOLUTION_US;
|
|
279
394
|
}
|
|
280
395
|
|
|
281
|
-
// Check if time is before lastReportTimeMs - in which case a wrap around occurred to add on the max value
|
|
282
|
-
if (timestampUs < timestampWrapHandler.lastReportTimestampUs) {
|
|
396
|
+
// Check if time is before lastReportTimeMs by more than 100ms - in which case a wrap around occurred to add on the max value
|
|
397
|
+
if (timestampUs + 100000 < timestampWrapHandler.lastReportTimestampUs ) {
|
|
283
398
|
timestampWrapHandler.reportTimestampOffsetUs += this.POLL_RESULT_WRAP_VALUE * this.POLL_RESULT_RESOLUTION_US;
|
|
284
399
|
}
|
|
285
400
|
timestampWrapHandler.lastReportTimestampUs = timestampUs;
|
|
@@ -294,5 +409,42 @@ export default class AttributeHandler {
|
|
|
294
409
|
return { newBufIdx: msgBufIdx, timestampUs: timestampUs };
|
|
295
410
|
}
|
|
296
411
|
|
|
412
|
+
// Helper method to check if a value is in a range string like "42,43,44-45,47"
|
|
413
|
+
private isValueInRangeString(value: number, rangeStr: string): boolean {
|
|
414
|
+
// Round to integer for comparison
|
|
415
|
+
const roundedValue = Math.round(value);
|
|
416
|
+
|
|
417
|
+
// Split the range string by commas
|
|
418
|
+
const parts = rangeStr.split(',');
|
|
419
|
+
|
|
420
|
+
for (const part of parts) {
|
|
421
|
+
// Check if it's a range (contains a hyphen)
|
|
422
|
+
if (part.includes('-')) {
|
|
423
|
+
const [startStr, endStr] = part.split('-');
|
|
424
|
+
|
|
425
|
+
// Handle hex values
|
|
426
|
+
const start = startStr.toLowerCase().startsWith('0x') ?
|
|
427
|
+
parseInt(startStr, 16) : parseInt(startStr, 10);
|
|
428
|
+
const end = endStr.toLowerCase().startsWith('0x') ?
|
|
429
|
+
parseInt(endStr, 16) : parseInt(endStr, 10);
|
|
430
|
+
|
|
431
|
+
if (!isNaN(start) && !isNaN(end) && roundedValue >= start && roundedValue <= end) {
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// Check if it's a single value
|
|
436
|
+
else {
|
|
437
|
+
// Handle hex values
|
|
438
|
+
const partValue = part.toLowerCase().startsWith('0x') ?
|
|
439
|
+
parseInt(part, 16) : parseInt(part, 10);
|
|
440
|
+
|
|
441
|
+
if (!isNaN(partValue) && roundedValue === partValue) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
297
449
|
|
|
298
450
|
}
|
package/src/RaftChannel.ts
CHANGED
|
@@ -22,6 +22,8 @@ export default interface RaftChannel
|
|
|
22
22
|
setMsgHandler(raftMsgHandler: RaftMsgHandler): void;
|
|
23
23
|
sendTxMsg(msg: Uint8Array, sendWithResponse: boolean): Promise<boolean>;
|
|
24
24
|
sendTxMsgNoAwait(msg: Uint8Array, sendWithResponse: boolean): Promise<boolean>;
|
|
25
|
+
sendTxMsgRaw(msg: string): boolean;
|
|
26
|
+
sendTxMsgRawAndWaitForReply<T>(msgPayload: Uint8Array): T;
|
|
25
27
|
requiresSubscription(): boolean;
|
|
26
28
|
ricRestCmdBeforeDisconnect(): string | null;
|
|
27
29
|
fhBatchAckSize(): number;
|