@robdobsn/raftjs 1.8.5 → 1.11.5
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/.editorconfig +14 -0
- package/.gitattributes +11 -0
- package/.nvmrc +1 -0
- package/TODO.md +1 -0
- package/dist/react-native/RaftAttributeHandler.d.ts +14 -0
- package/dist/react-native/RaftAttributeHandler.js +375 -0
- package/dist/react-native/RaftAttributeHandler.js.map +1 -0
- package/dist/react-native/RaftChannel.d.ts +20 -0
- package/dist/react-native/RaftChannel.js +12 -0
- package/dist/react-native/RaftChannel.js.map +1 -0
- package/dist/react-native/RaftChannelBLE.native.d.ts +95 -0
- package/dist/react-native/RaftChannelBLE.native.js +483 -0
- package/dist/react-native/RaftChannelBLE.native.js.map +1 -0
- package/dist/react-native/RaftChannelBLE.web.d.ts +40 -0
- package/dist/react-native/RaftChannelBLE.web.js +302 -0
- package/dist/react-native/RaftChannelBLE.web.js.map +1 -0
- package/dist/react-native/RaftChannelBLEFactory.d.ts +10 -0
- package/dist/react-native/RaftChannelBLEFactory.js +17 -0
- package/dist/react-native/RaftChannelBLEFactory.js.map +1 -0
- package/dist/react-native/RaftChannelBLEScanner.native.d.ts +18 -0
- package/dist/react-native/RaftChannelBLEScanner.native.js +138 -0
- package/dist/react-native/RaftChannelBLEScanner.native.js.map +1 -0
- package/dist/react-native/RaftChannelSimulated.d.ts +42 -0
- package/dist/react-native/RaftChannelSimulated.js +1001 -0
- package/dist/react-native/RaftChannelSimulated.js.map +1 -0
- package/dist/react-native/RaftChannelWebSerial.d.ts +39 -0
- package/dist/react-native/RaftChannelWebSerial.js +329 -0
- package/dist/react-native/RaftChannelWebSerial.js.map +1 -0
- package/dist/react-native/RaftChannelWebSocket.d.ts +30 -0
- package/dist/react-native/RaftChannelWebSocket.js +222 -0
- package/dist/react-native/RaftChannelWebSocket.js.map +1 -0
- package/dist/react-native/RaftCommsStats.d.ts +39 -0
- package/dist/react-native/RaftCommsStats.js +128 -0
- package/dist/react-native/RaftCommsStats.js.map +1 -0
- package/dist/react-native/RaftConnEvents.d.ts +39 -0
- package/dist/react-native/RaftConnEvents.js +54 -0
- package/dist/react-native/RaftConnEvents.js.map +1 -0
- package/dist/react-native/RaftConnector.d.ts +257 -0
- package/dist/react-native/RaftConnector.js +671 -0
- package/dist/react-native/RaftConnector.js.map +1 -0
- package/dist/react-native/RaftCustomAttrHandler.d.ts +6 -0
- package/dist/react-native/RaftCustomAttrHandler.js +93 -0
- package/dist/react-native/RaftCustomAttrHandler.js.map +1 -0
- package/dist/react-native/RaftDeviceInfo.d.ts +71 -0
- package/dist/react-native/RaftDeviceInfo.js +50 -0
- package/dist/react-native/RaftDeviceInfo.js.map +1 -0
- package/dist/react-native/RaftDeviceManager.d.ts +73 -0
- package/dist/react-native/RaftDeviceManager.js +812 -0
- package/dist/react-native/RaftDeviceManager.js.map +1 -0
- package/dist/react-native/RaftDeviceMgrIF.d.ts +19 -0
- package/dist/react-native/RaftDeviceMgrIF.js +11 -0
- package/dist/react-native/RaftDeviceMgrIF.js.map +1 -0
- package/dist/react-native/RaftDeviceMsg.d.ts +9 -0
- package/dist/react-native/RaftDeviceMsg.js +11 -0
- package/dist/react-native/RaftDeviceMsg.js.map +1 -0
- package/dist/react-native/RaftDeviceStates.d.ts +55 -0
- package/dist/react-native/RaftDeviceStates.js +81 -0
- package/dist/react-native/RaftDeviceStates.js.map +1 -0
- package/dist/react-native/RaftFileHandler.d.ts +52 -0
- package/dist/react-native/RaftFileHandler.js +502 -0
- package/dist/react-native/RaftFileHandler.js.map +1 -0
- package/dist/react-native/RaftLog.d.ts +22 -0
- package/dist/react-native/RaftLog.js +63 -0
- package/dist/react-native/RaftLog.js.map +1 -0
- package/dist/react-native/RaftMiniHDLC.d.ts +18 -0
- package/dist/react-native/RaftMiniHDLC.js +383 -0
- package/dist/react-native/RaftMiniHDLC.js.map +1 -0
- package/dist/react-native/RaftMsgHandler.d.ts +62 -0
- package/dist/react-native/RaftMsgHandler.js +511 -0
- package/dist/react-native/RaftMsgHandler.js.map +1 -0
- package/dist/react-native/RaftMsgTrackInfo.d.ts +17 -0
- package/dist/react-native/RaftMsgTrackInfo.js +42 -0
- package/dist/react-native/RaftMsgTrackInfo.js.map +1 -0
- package/dist/react-native/RaftProtocolDefs.d.ts +30 -0
- package/dist/react-native/RaftProtocolDefs.js +48 -0
- package/dist/react-native/RaftProtocolDefs.js.map +1 -0
- package/dist/react-native/RaftPublish.d.ts +2 -0
- package/dist/react-native/RaftPublish.js +81 -0
- package/dist/react-native/RaftPublish.js.map +1 -0
- package/dist/react-native/RaftStreamHandler.d.ts +49 -0
- package/dist/react-native/RaftStreamHandler.js +324 -0
- package/dist/react-native/RaftStreamHandler.js.map +1 -0
- package/dist/react-native/RaftStruct.d.ts +3 -0
- package/dist/react-native/RaftStruct.js +258 -0
- package/dist/react-native/RaftStruct.js.map +1 -0
- package/dist/react-native/RaftSysTypeManager.d.ts +16 -0
- package/dist/react-native/RaftSysTypeManager.js +78 -0
- package/dist/react-native/RaftSysTypeManager.js.map +1 -0
- package/dist/react-native/RaftSystemType.d.ts +30 -0
- package/dist/react-native/RaftSystemType.js +3 -0
- package/dist/react-native/RaftSystemType.js.map +1 -0
- package/dist/react-native/RaftSystemUtils.d.ts +152 -0
- package/dist/react-native/RaftSystemUtils.js +463 -0
- package/dist/react-native/RaftSystemUtils.js.map +1 -0
- package/dist/react-native/RaftTypes.d.ts +216 -0
- package/dist/react-native/RaftTypes.js +153 -0
- package/dist/react-native/RaftTypes.js.map +1 -0
- package/dist/react-native/RaftUpdateEvents.d.ts +33 -0
- package/dist/react-native/RaftUpdateEvents.js +46 -0
- package/dist/react-native/RaftUpdateEvents.js.map +1 -0
- package/dist/react-native/RaftUpdateManager.d.ts +61 -0
- package/dist/react-native/RaftUpdateManager.js +621 -0
- package/dist/react-native/RaftUpdateManager.js.map +1 -0
- package/dist/react-native/RaftUtils.d.ts +128 -0
- package/dist/react-native/RaftUtils.js +487 -0
- package/dist/react-native/RaftUtils.js.map +1 -0
- package/dist/react-native/RaftWifiTypes.d.ts +23 -0
- package/dist/react-native/RaftWifiTypes.js +43 -0
- package/dist/react-native/RaftWifiTypes.js.map +1 -0
- package/dist/react-native/main.d.ts +27 -0
- package/dist/react-native/main.js +52 -0
- package/dist/react-native/main.js.map +1 -0
- package/dist/web/RaftAttributeHandler.js +1 -1
- package/dist/web/RaftAttributeHandler.js.map +1 -1
- package/dist/web/RaftChannelBLE.web.js +8 -6
- package/dist/web/RaftChannelBLE.web.js.map +1 -1
- package/dist/web/RaftChannelSimulated.d.ts +10 -0
- package/dist/web/RaftChannelSimulated.js +665 -82
- package/dist/web/RaftChannelSimulated.js.map +1 -1
- package/dist/web/RaftChannelWebSerial.js +2 -2
- package/dist/web/RaftChannelWebSerial.js.map +1 -1
- package/dist/web/RaftChannelWebSocket.js +16 -1
- package/dist/web/RaftChannelWebSocket.js.map +1 -1
- package/dist/web/RaftConnector.d.ts +12 -1
- package/dist/web/RaftConnector.js +45 -9
- package/dist/web/RaftConnector.js.map +1 -1
- package/dist/web/RaftCustomAttrHandler.d.ts +2 -0
- package/dist/web/RaftCustomAttrHandler.js +54 -26
- package/dist/web/RaftCustomAttrHandler.js.map +1 -1
- package/dist/web/RaftDeviceInfo.d.ts +3 -1
- package/dist/web/RaftDeviceInfo.js +17 -3
- package/dist/web/RaftDeviceInfo.js.map +1 -1
- package/dist/web/RaftDeviceManager.d.ts +32 -2
- package/dist/web/RaftDeviceManager.js +307 -74
- package/dist/web/RaftDeviceManager.js.map +1 -1
- package/dist/web/RaftDeviceMgrIF.d.ts +5 -1
- package/dist/web/RaftDeviceStates.d.ts +20 -2
- package/dist/web/RaftDeviceStates.js +25 -4
- package/dist/web/RaftDeviceStates.js.map +1 -1
- package/dist/web/RaftMsgHandler.js.map +1 -1
- package/dist/web/RaftPublish.d.ts +2 -0
- package/dist/web/RaftPublish.js +81 -0
- package/dist/web/RaftPublish.js.map +1 -0
- package/dist/web/RaftStreamHandler.d.ts +11 -0
- package/dist/web/RaftStreamHandler.js +68 -1
- package/dist/web/RaftStreamHandler.js.map +1 -1
- package/dist/web/RaftStruct.js +197 -147
- package/dist/web/RaftStruct.js.map +1 -1
- package/dist/web/RaftSystemUtils.d.ts +17 -1
- package/dist/web/RaftSystemUtils.js +51 -0
- package/dist/web/RaftSystemUtils.js.map +1 -1
- package/dist/web/RaftTypes.d.ts +21 -0
- package/dist/web/RaftTypes.js.map +1 -1
- package/dist/web/RaftUpdateManager.js +1 -1
- package/dist/web/RaftUpdateManager.js.map +1 -1
- package/dist/web/RaftUtils.d.ts +2 -0
- package/dist/web/RaftUtils.js +20 -0
- package/dist/web/RaftUtils.js.map +1 -1
- package/dist/web/main.d.ts +2 -0
- package/dist/web/main.js +1 -0
- package/dist/web/main.js.map +1 -1
- package/eslint.config.mjs +33 -0
- package/examples/dashboard/package.json +36 -0
- package/examples/dashboard/src/CommandPanel.tsx +147 -0
- package/examples/dashboard/src/ConnManager.ts +166 -0
- package/examples/dashboard/src/DeviceActionsForm.tsx +133 -0
- package/examples/dashboard/src/DeviceAttrsForm.tsx +49 -0
- package/examples/dashboard/src/DeviceLineChart.tsx +163 -0
- package/examples/dashboard/src/DevicePanel.tsx +247 -0
- package/examples/dashboard/src/DeviceStatsPanel.tsx +65 -0
- package/examples/dashboard/src/DevicesPanel.tsx +69 -0
- package/examples/dashboard/src/DispLedGrid.tsx +110 -0
- package/examples/dashboard/src/DispOneLed.tsx +20 -0
- package/examples/dashboard/src/LatencyTest.ts +130 -0
- package/examples/dashboard/src/LatencyTestPanel.tsx +92 -0
- package/examples/dashboard/src/Main.tsx +234 -0
- package/examples/dashboard/src/SettingsManager.ts +67 -0
- package/examples/dashboard/src/SettingsScreen.tsx +179 -0
- package/examples/dashboard/src/StatusPanel.tsx +71 -0
- package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +170 -0
- package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +125 -0
- package/examples/dashboard/src/SystemTypeGeneric/StateInfoGeneric.ts +38 -0
- package/examples/dashboard/src/SystemTypeGeneric/SystemTypeGeneric.ts +125 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
- package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
- package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
- package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
- package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
- package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
- package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
- package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +105 -0
- package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
- package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
- package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +119 -0
- package/examples/dashboard/src/index.html +15 -0
- package/examples/dashboard/src/index.tsx +13 -0
- package/examples/dashboard/src/styles.css +570 -0
- package/examples/dashboard/tsconfig.json +18 -0
- package/jest.config.js +11 -0
- package/package.json +49 -52
- package/src/RaftAttributeHandler.ts +450 -0
- package/src/RaftChannel.ts +32 -0
- package/src/RaftChannelBLE.native.ts +617 -0
- package/src/RaftChannelBLE.web.ts +374 -0
- package/src/RaftChannelBLEFactory.ts +13 -0
- package/src/RaftChannelBLEScanner.native.ts +184 -0
- package/src/RaftChannelSimulated.ts +1177 -0
- package/src/RaftChannelWebSerial.ts +420 -0
- package/src/RaftChannelWebSocket.ts +272 -0
- package/src/RaftCommsStats.ts +142 -0
- package/src/RaftConnEvents.ts +58 -0
- package/src/RaftConnector.ts +806 -0
- package/src/RaftCustomAttrHandler.ts +117 -0
- package/src/RaftDeviceInfo.ts +125 -0
- package/src/RaftDeviceManager.ts +1014 -0
- package/src/RaftDeviceMgrIF.ts +37 -0
- package/src/RaftDeviceMsg.ts +20 -0
- package/src/RaftDeviceStates.ts +122 -0
- package/src/RaftFileHandler.ts +668 -0
- package/src/RaftLog.ts +70 -0
- package/src/RaftMiniHDLC.ts +396 -0
- package/src/RaftMsgHandler.ts +812 -0
- package/src/RaftMsgTrackInfo.ts +51 -0
- package/src/RaftProtocolDefs.ts +46 -0
- package/src/RaftPublish.ts +92 -0
- package/src/RaftStreamHandler.ts +412 -0
- package/src/RaftStruct.ts +282 -0
- package/src/RaftSysTypeManager.ts +87 -0
- package/src/RaftSystemType.ts +34 -0
- package/src/RaftSystemUtils.ts +548 -0
- package/src/RaftTypes.ts +306 -0
- package/src/RaftUpdateEvents.ts +48 -0
- package/src/RaftUpdateManager.ts +781 -0
- package/src/RaftUtils.ts +514 -0
- package/src/RaftWifiTypes.ts +36 -0
- package/src/main.ts +40 -0
- package/testdata/TestDeviceTypeRecs.json +492 -0
- package/tsconfig.json +30 -0
- package/tsconfig.react-native.json +29 -0
|
@@ -0,0 +1,1001 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
3
|
+
//
|
|
4
|
+
// RaftChannelSimulated.ts
|
|
5
|
+
// Part of RaftJS
|
|
6
|
+
//
|
|
7
|
+
// Rob Dobson 2020-2025
|
|
8
|
+
// (C) 2020-2025 All rights reserved
|
|
9
|
+
//
|
|
10
|
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const tslib_1 = require("tslib");
|
|
13
|
+
const RaftLog_1 = tslib_1.__importDefault(require("./RaftLog"));
|
|
14
|
+
const RaftConnEvents_1 = require("./RaftConnEvents");
|
|
15
|
+
const RaftProtocolDefs_1 = require("./RaftProtocolDefs");
|
|
16
|
+
class RaftChannelSimulated {
|
|
17
|
+
constructor() {
|
|
18
|
+
// Message handler
|
|
19
|
+
this._raftMsgHandler = null;
|
|
20
|
+
// Is connected
|
|
21
|
+
this._isConnected = false;
|
|
22
|
+
// Simulated device name and rate
|
|
23
|
+
this._simulatedDeviceInfo = null;
|
|
24
|
+
// Simulated device information timer
|
|
25
|
+
this._simulatedDeviceInfoTimers = null;
|
|
26
|
+
this._simulatedDeviceInfoTimeMs = [];
|
|
27
|
+
// Conn event fn
|
|
28
|
+
this._onConnEvent = null;
|
|
29
|
+
// File Handler parameters
|
|
30
|
+
this._requestedBatchAckSize = 10;
|
|
31
|
+
this._requestedFileBlockSize = 500;
|
|
32
|
+
// Simulated device type information - this is a copy of part of DeviceTypeInfo in RaftCore
|
|
33
|
+
this._deviceTypeInfo = {
|
|
34
|
+
"AMG8833": {
|
|
35
|
+
"name": "AMG8833",
|
|
36
|
+
"desc": "Thermal Camera",
|
|
37
|
+
"manu": "Panasonic",
|
|
38
|
+
"type": "AMG8833",
|
|
39
|
+
"clas": ["TCAM"],
|
|
40
|
+
"resp": {
|
|
41
|
+
"b": 128,
|
|
42
|
+
"a": [
|
|
43
|
+
{
|
|
44
|
+
"n": "temp",
|
|
45
|
+
"t": "<h[64]",
|
|
46
|
+
"resolution": "8x8",
|
|
47
|
+
"u": "°C",
|
|
48
|
+
"r": [-55, 125],
|
|
49
|
+
"s": -4,
|
|
50
|
+
"d": 64,
|
|
51
|
+
"f": ".2f",
|
|
52
|
+
"o": "float"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"LSM6DS": {
|
|
58
|
+
"name": "LSM6DS",
|
|
59
|
+
"desc": "6-Axis IMU",
|
|
60
|
+
"manu": "ST",
|
|
61
|
+
"type": "LSM6DS",
|
|
62
|
+
"clas": ["ACC", "GYRO"],
|
|
63
|
+
"resp": {
|
|
64
|
+
"b": 12,
|
|
65
|
+
"a": [
|
|
66
|
+
{
|
|
67
|
+
"n": "gx",
|
|
68
|
+
"t": "<h",
|
|
69
|
+
"u": "°/s",
|
|
70
|
+
"r": [-2000, 2000],
|
|
71
|
+
"d": 16.384,
|
|
72
|
+
"f": ".2f",
|
|
73
|
+
"o": "float"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"n": "gy",
|
|
77
|
+
"t": "<h",
|
|
78
|
+
"u": "°/s",
|
|
79
|
+
"r": [-2000, 2000],
|
|
80
|
+
"d": 16.384,
|
|
81
|
+
"f": ".2f",
|
|
82
|
+
"o": "float"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"n": "gz",
|
|
86
|
+
"t": "<h",
|
|
87
|
+
"u": "°/s",
|
|
88
|
+
"r": [-2000, 2000],
|
|
89
|
+
"d": 16.384,
|
|
90
|
+
"f": ".2f",
|
|
91
|
+
"o": "float"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"n": "ax",
|
|
95
|
+
"t": "<h",
|
|
96
|
+
"u": "g",
|
|
97
|
+
"r": [-4.0, 4.0],
|
|
98
|
+
"d": 8192,
|
|
99
|
+
"f": ".2f",
|
|
100
|
+
"o": "float"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"n": "ay",
|
|
104
|
+
"t": "<h",
|
|
105
|
+
"u": "g",
|
|
106
|
+
"r": [-4.0, 4.0],
|
|
107
|
+
"d": 8192,
|
|
108
|
+
"f": ".2f",
|
|
109
|
+
"o": "float"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"n": "az",
|
|
113
|
+
"t": "<h",
|
|
114
|
+
"u": "g",
|
|
115
|
+
"r": [-4.0, 4.0],
|
|
116
|
+
"d": 8192,
|
|
117
|
+
"f": ".2f",
|
|
118
|
+
"o": "float"
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"LTR-329": {
|
|
124
|
+
"name": "LTR-329",
|
|
125
|
+
"desc": "Visible light and IR Sensor",
|
|
126
|
+
"manu": "Lite On",
|
|
127
|
+
"type": "LTR-329",
|
|
128
|
+
"clas": ["LGHT"],
|
|
129
|
+
"resp": {
|
|
130
|
+
"b": 4,
|
|
131
|
+
"a": [
|
|
132
|
+
{
|
|
133
|
+
"n": "ir",
|
|
134
|
+
"t": "<h",
|
|
135
|
+
"u": "lux",
|
|
136
|
+
"r": [0, 64000],
|
|
137
|
+
"f": "d",
|
|
138
|
+
"o": "uint16"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"n": "visible",
|
|
142
|
+
"t": "<h",
|
|
143
|
+
"u": "lux",
|
|
144
|
+
"r": [0, 64000],
|
|
145
|
+
"f": "d",
|
|
146
|
+
"o": "uint16"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"c": {
|
|
150
|
+
"n": "ltr329_light_calc",
|
|
151
|
+
"c": "int combined = buf[0] + (((uint16_t)buf[1])<<8); out.ir = buf[2] + (((uint16_t)buf[3])<<8); out.visible = combined - out.ir;",
|
|
152
|
+
"j": "let combined = buf[0] + (buf[1] << 8); let ir = buf[2] + (buf[3] << 8); attrValues['ir'].push(ir); attrValues['visible'].push(Math.max(0, combined - ir));"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"LTR-390": {
|
|
157
|
+
"name": "LTR-390",
|
|
158
|
+
"desc": "UV and Visible light sensor",
|
|
159
|
+
"manu": "Lite On",
|
|
160
|
+
"type": "LTR-390",
|
|
161
|
+
"clas": ["LGHT"],
|
|
162
|
+
"resp": {
|
|
163
|
+
"b": 5,
|
|
164
|
+
"a": [
|
|
165
|
+
{
|
|
166
|
+
"n": "ambient",
|
|
167
|
+
"t": "<H",
|
|
168
|
+
"u": "lux",
|
|
169
|
+
"r": [0, 64000],
|
|
170
|
+
"d": 1.25,
|
|
171
|
+
"f": ".2f",
|
|
172
|
+
"o": "float"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"n": "UVI",
|
|
176
|
+
"at": 3,
|
|
177
|
+
"t": "<H",
|
|
178
|
+
"u": "index",
|
|
179
|
+
"r": [0, 64000],
|
|
180
|
+
"d": 24,
|
|
181
|
+
"f": ".3f",
|
|
182
|
+
"o": "float"
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
"actions": []
|
|
187
|
+
},
|
|
188
|
+
"VL53L4CD": {
|
|
189
|
+
"name": "VL53L4CD",
|
|
190
|
+
"desc": "ToF distance sensor with range 0-1.3m",
|
|
191
|
+
"manu": "ST",
|
|
192
|
+
"type": "VL53L4CD",
|
|
193
|
+
"clas": ["DIST"],
|
|
194
|
+
"resp": {
|
|
195
|
+
"b": 3,
|
|
196
|
+
"a": [
|
|
197
|
+
{
|
|
198
|
+
"n": "valid",
|
|
199
|
+
"t": "B",
|
|
200
|
+
"u": "",
|
|
201
|
+
"r": [0, 1],
|
|
202
|
+
"m": "0x04",
|
|
203
|
+
"x": "0x04",
|
|
204
|
+
"s": 2,
|
|
205
|
+
"f": "b",
|
|
206
|
+
"o": "bool",
|
|
207
|
+
"vs": false
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"n": "dist",
|
|
211
|
+
"t": ">H",
|
|
212
|
+
"u": "mm",
|
|
213
|
+
"r": [0, 65535],
|
|
214
|
+
"f": "3d",
|
|
215
|
+
"o": "uint16",
|
|
216
|
+
"vft": "valid"
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
"us": 100000
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"RoboticalServo": {
|
|
223
|
+
"name": "Robotical Servo",
|
|
224
|
+
"desc": "Servo",
|
|
225
|
+
"manu": "Robotical",
|
|
226
|
+
"type": "RoboticalServo",
|
|
227
|
+
"clas": ["SRVO"],
|
|
228
|
+
"resp": {
|
|
229
|
+
"b": 6,
|
|
230
|
+
"a": [
|
|
231
|
+
{
|
|
232
|
+
"n": "angle",
|
|
233
|
+
"t": ">h",
|
|
234
|
+
"r": [-180.0, 180.0],
|
|
235
|
+
"f": ".1f",
|
|
236
|
+
"d": 10,
|
|
237
|
+
"o": "int16",
|
|
238
|
+
"u": "degrees"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"n": "current",
|
|
242
|
+
"t": "b",
|
|
243
|
+
"r": [-128, 127],
|
|
244
|
+
"f": "d",
|
|
245
|
+
"o": "int8"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"n": "state",
|
|
249
|
+
"t": "B",
|
|
250
|
+
"r": [0, 255],
|
|
251
|
+
"f": "02x",
|
|
252
|
+
"o": "uint8"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"n": "velocity",
|
|
256
|
+
"t": ">h",
|
|
257
|
+
"r": [-32768, 32767],
|
|
258
|
+
"f": "d",
|
|
259
|
+
"o": "int16"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
"actions": [
|
|
264
|
+
{
|
|
265
|
+
"n": "angle",
|
|
266
|
+
"t": ">h",
|
|
267
|
+
"w": "0001",
|
|
268
|
+
"wz": "0064",
|
|
269
|
+
"f": ".1f",
|
|
270
|
+
"mul": 10,
|
|
271
|
+
"sub": 0,
|
|
272
|
+
"r": [-180.0, 180.0],
|
|
273
|
+
"d": 0
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"n": "enable",
|
|
277
|
+
"t": "B",
|
|
278
|
+
"w": "20",
|
|
279
|
+
"f": "b",
|
|
280
|
+
"r": [0, 1],
|
|
281
|
+
"d": 1
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
"RoboticalDCMotor": {
|
|
286
|
+
"name": "Robotical DC Motor",
|
|
287
|
+
"desc": "DCmotor",
|
|
288
|
+
"manu": "Robotical",
|
|
289
|
+
"type": "RoboticalDCMotor",
|
|
290
|
+
"clas": ["MOTR"],
|
|
291
|
+
"resp": {
|
|
292
|
+
"b": 4,
|
|
293
|
+
"a": [
|
|
294
|
+
{
|
|
295
|
+
"n": "angle",
|
|
296
|
+
"t": ">h",
|
|
297
|
+
"r": [-180.0, 180.0],
|
|
298
|
+
"f": ".1f",
|
|
299
|
+
"d": 10,
|
|
300
|
+
"o": "int16",
|
|
301
|
+
"u": "degrees"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"n": "current",
|
|
305
|
+
"t": "b",
|
|
306
|
+
"r": [-128, 127],
|
|
307
|
+
"f": "d",
|
|
308
|
+
"o": "int8"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"n": "state",
|
|
312
|
+
"t": "B",
|
|
313
|
+
"r": [0, 255],
|
|
314
|
+
"f": "02x",
|
|
315
|
+
"o": "uint8"
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
},
|
|
319
|
+
"actions": [
|
|
320
|
+
{
|
|
321
|
+
"n": "power",
|
|
322
|
+
"t": ">h",
|
|
323
|
+
"w": "0001",
|
|
324
|
+
"wz": "0064",
|
|
325
|
+
"f": ".1f",
|
|
326
|
+
"mul": 10,
|
|
327
|
+
"sub": 0,
|
|
328
|
+
"r": [-180.0, 180.0],
|
|
329
|
+
"d": 0
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"n": "enable",
|
|
333
|
+
"t": "B",
|
|
334
|
+
"w": "20",
|
|
335
|
+
"f": "b",
|
|
336
|
+
"r": [0, 1],
|
|
337
|
+
"d": 1
|
|
338
|
+
}
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
"RoboticalLEDRing": {
|
|
342
|
+
"name": "Robotical LED Ring",
|
|
343
|
+
"desc": "12 RGB LED Ring",
|
|
344
|
+
"manu": "Robotical",
|
|
345
|
+
"type": "RoboticalLEDRing",
|
|
346
|
+
"clas": ["LED"],
|
|
347
|
+
"resp": {
|
|
348
|
+
"b": 1,
|
|
349
|
+
"a": [
|
|
350
|
+
{
|
|
351
|
+
"n": "status",
|
|
352
|
+
"t": "B",
|
|
353
|
+
"r": [0, 255],
|
|
354
|
+
"f": "02x",
|
|
355
|
+
"o": "uint8"
|
|
356
|
+
}
|
|
357
|
+
]
|
|
358
|
+
},
|
|
359
|
+
"actions": [
|
|
360
|
+
{
|
|
361
|
+
"n": "pixels",
|
|
362
|
+
"t": "BBBB",
|
|
363
|
+
"w": "04",
|
|
364
|
+
"f": "LEDPIX",
|
|
365
|
+
"NX": 3,
|
|
366
|
+
"NY": 1,
|
|
367
|
+
"concat": false,
|
|
368
|
+
"r": [0, 255]
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"n": "brightness",
|
|
372
|
+
"t": "B",
|
|
373
|
+
"w": "FF01",
|
|
374
|
+
"wz": "&p100",
|
|
375
|
+
"f": "b",
|
|
376
|
+
"r": [0, 255],
|
|
377
|
+
"d": 100
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
fhBatchAckSize() { return this._requestedBatchAckSize; }
|
|
384
|
+
fhFileBlockSize() { return this._requestedFileBlockSize; }
|
|
385
|
+
// isConnected
|
|
386
|
+
isConnected() {
|
|
387
|
+
return this._isConnected;
|
|
388
|
+
}
|
|
389
|
+
// Set message handler
|
|
390
|
+
setMsgHandler(raftMsgHandler) {
|
|
391
|
+
this._raftMsgHandler = raftMsgHandler;
|
|
392
|
+
this._raftMsgHandler.setRawMsgMode(true);
|
|
393
|
+
}
|
|
394
|
+
// WebSocket interfaces require subscription to published messages
|
|
395
|
+
requiresSubscription() {
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
// RICREST command before disconnect
|
|
399
|
+
ricRestCmdBeforeDisconnect() {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
// Set onConnEvent handler
|
|
403
|
+
setOnConnEvent(connEventFn) {
|
|
404
|
+
this._onConnEvent = connEventFn;
|
|
405
|
+
}
|
|
406
|
+
// Get connected locator
|
|
407
|
+
getConnectedLocator() {
|
|
408
|
+
return "simulated";
|
|
409
|
+
}
|
|
410
|
+
// Connect to a device
|
|
411
|
+
async connect(locator, connectorOptions) {
|
|
412
|
+
// Debug
|
|
413
|
+
RaftLog_1.default.debug(`RaftChannelSimulated.connect connected ${locator.toString()} options ${JSON.stringify(connectorOptions)}`);
|
|
414
|
+
// Extract SimulatedDeviceInfo from JSON locator
|
|
415
|
+
if (typeof locator === 'string') {
|
|
416
|
+
try {
|
|
417
|
+
const parsedLocator = JSON.parse(locator);
|
|
418
|
+
if (parsedLocator && Array.isArray(parsedLocator)) {
|
|
419
|
+
this._simulatedDeviceInfo = parsedLocator;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch (e) {
|
|
423
|
+
RaftLog_1.default.warn(`RaftChannelSimulated.connect - error parsing locator ${locator}, ${e}`);
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Handle simulated devices
|
|
428
|
+
if (this._simulatedDeviceInfo) {
|
|
429
|
+
// Create timers for simulated devices
|
|
430
|
+
this._simulatedDeviceInfoTimers = [];
|
|
431
|
+
for (let i = 0; i < this._simulatedDeviceInfo.length; i++) {
|
|
432
|
+
const deviceInfo = this._simulatedDeviceInfo[i];
|
|
433
|
+
const deviceName = deviceInfo.name ? deviceInfo.name : `SimulatedDevice${i}`;
|
|
434
|
+
this._simulatedDeviceInfoTimeMs.push(0);
|
|
435
|
+
const deviceRate = deviceInfo.publishRatePerSecond ? deviceInfo.publishRatePerSecond : 1;
|
|
436
|
+
let deviceIntervalMs = 911;
|
|
437
|
+
if ((deviceRate > 0.01) && (deviceRate < 1000)) {
|
|
438
|
+
deviceIntervalMs = Math.floor(1000 / deviceRate);
|
|
439
|
+
}
|
|
440
|
+
const deviceTypeInfo = this._deviceTypeInfo[deviceName];
|
|
441
|
+
if (deviceTypeInfo) {
|
|
442
|
+
const timer = setInterval(() => {
|
|
443
|
+
var _a;
|
|
444
|
+
const msg = this._createSimulatedDeviceInfoMsg(deviceIntervalMs, deviceName, deviceTypeInfo, this._simulatedDeviceInfoTimeMs[i]);
|
|
445
|
+
(_a = this._raftMsgHandler) === null || _a === void 0 ? void 0 : _a.handleNewRxMsgRaw(msg, RaftProtocolDefs_1.RaftCommsMsgTypeCode.MSG_TYPE_PUBLISH, 0, this._simulatedDeviceInfoTimeMs[i]);
|
|
446
|
+
this._simulatedDeviceInfoTimeMs[i] += deviceIntervalMs;
|
|
447
|
+
}, deviceIntervalMs);
|
|
448
|
+
this._simulatedDeviceInfoTimers.push(timer);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
RaftLog_1.default.warn(`RaftChannelSimulated.connect - device type info not found for ${deviceName}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
RaftLog_1.default.warn(`RaftChannelSimulated.connect - no simulated devices found`);
|
|
457
|
+
}
|
|
458
|
+
// Connected
|
|
459
|
+
this._isConnected = true;
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
// Disconnect
|
|
463
|
+
async disconnect() {
|
|
464
|
+
// Not connected
|
|
465
|
+
this._isConnected = false;
|
|
466
|
+
// Clear timers
|
|
467
|
+
if (this._simulatedDeviceInfoTimers) {
|
|
468
|
+
for (const timer of this._simulatedDeviceInfoTimers) {
|
|
469
|
+
clearInterval(timer);
|
|
470
|
+
}
|
|
471
|
+
this._simulatedDeviceInfoTimers = null;
|
|
472
|
+
}
|
|
473
|
+
// Notify connection event
|
|
474
|
+
if (this._onConnEvent) {
|
|
475
|
+
this._onConnEvent(RaftConnEvents_1.RaftConnEvent.CONN_DISCONNECTED);
|
|
476
|
+
}
|
|
477
|
+
// Debug
|
|
478
|
+
RaftLog_1.default.debug(`RaftChannelSimulated.disconnect closed`);
|
|
479
|
+
}
|
|
480
|
+
pauseConnection(pause) {
|
|
481
|
+
RaftLog_1.default.debug(`pauseConnection ${pause} - no effect for this channel type`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
// Send a message
|
|
485
|
+
async sendTxMsg(msg, sendWithResponse) {
|
|
486
|
+
// Check connected
|
|
487
|
+
if (!this._isConnected)
|
|
488
|
+
return false;
|
|
489
|
+
// Debug
|
|
490
|
+
RaftLog_1.default.debug(`RaftChannelSimulated.sendTxMsg ${msg.toString()} sendWithResp ${sendWithResponse.toString()}`);
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
async sendTxMsgNoAwait(msg, sendWithResponse) {
|
|
494
|
+
// Check connected
|
|
495
|
+
if (!this._isConnected)
|
|
496
|
+
return false;
|
|
497
|
+
// Debug
|
|
498
|
+
RaftLog_1.default.debug(`RaftChannelSimulated.sendTxMsgNoAwait ${msg.toString()} sendWithResp ${sendWithResponse.toString()}`);
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
// Method used for testing and simulation should never be called
|
|
502
|
+
sendTxMsgRaw(msg) {
|
|
503
|
+
RaftLog_1.default.debug(`sendTxMsgRaw - not implemented ${msg}`);
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
// Method used for testing and simulation should never be called
|
|
507
|
+
sendTxMsgRawAndWaitForReply(msgPayload) {
|
|
508
|
+
RaftLog_1.default.debug(`sendTxMsgRawAndWaitForReply ${msgPayload}`);
|
|
509
|
+
// Decode the message from Uint8Array to string
|
|
510
|
+
const textDecoder = new TextDecoder('utf-8');
|
|
511
|
+
const decodedString = textDecoder.decode(msgPayload.slice(1)).replace("\0", "").trim();
|
|
512
|
+
RaftLog_1.default.debug(`sendTxMsgRawAndWaitForReply ${decodedString}`);
|
|
513
|
+
// Check for version request
|
|
514
|
+
if (decodedString === "v") {
|
|
515
|
+
// R"({"req":"%s","rslt":"ok","SystemName":"%s","SystemVersion":"%s","Friendly":"%s","SerialNo":"%s","MAC":"%s",%s})",
|
|
516
|
+
const response = {
|
|
517
|
+
req: "v",
|
|
518
|
+
rslt: "ok",
|
|
519
|
+
SystemName: "Simulated",
|
|
520
|
+
SystemVersion: "1.0.0",
|
|
521
|
+
Friendly: "Simulated",
|
|
522
|
+
SerialNo: "123456",
|
|
523
|
+
MAC: "00:00:00:00:00:00"
|
|
524
|
+
};
|
|
525
|
+
return response;
|
|
526
|
+
}
|
|
527
|
+
else if (decodedString.startsWith("sub")) {
|
|
528
|
+
const response = {
|
|
529
|
+
req: decodedString,
|
|
530
|
+
rslt: "ok"
|
|
531
|
+
};
|
|
532
|
+
return response;
|
|
533
|
+
}
|
|
534
|
+
// Check if this is a device type info request
|
|
535
|
+
else if (decodedString.startsWith("devman/typeinfo?")) {
|
|
536
|
+
// Extract the type parameter from the request
|
|
537
|
+
const match = decodedString.match(/type=([^&]+)/);
|
|
538
|
+
if (match && match[1]) {
|
|
539
|
+
const deviceType = match[1];
|
|
540
|
+
// Look up the device type in the _deviceTypeInfo
|
|
541
|
+
if (deviceType in this._deviceTypeInfo) {
|
|
542
|
+
// Prepare response with the device type info
|
|
543
|
+
const response = {
|
|
544
|
+
req: decodedString,
|
|
545
|
+
rslt: "ok",
|
|
546
|
+
devinfo: this._deviceTypeInfo[deviceType]
|
|
547
|
+
};
|
|
548
|
+
RaftLog_1.default.debug(`Device type info for ${deviceType} found, returning response`);
|
|
549
|
+
return response;
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
// Device type not found
|
|
553
|
+
const response = {
|
|
554
|
+
req: decodedString,
|
|
555
|
+
rslt: "err",
|
|
556
|
+
msg: `Device type ${deviceType} not found`
|
|
557
|
+
};
|
|
558
|
+
RaftLog_1.default.warn(`Device type info for ${deviceType} not found`);
|
|
559
|
+
return response;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
// Unknown message
|
|
564
|
+
const response = {
|
|
565
|
+
req: decodedString,
|
|
566
|
+
rslt: "err",
|
|
567
|
+
msg: `Unknown request`
|
|
568
|
+
};
|
|
569
|
+
return response;
|
|
570
|
+
}
|
|
571
|
+
// Create simulated device info message
|
|
572
|
+
_createSimulatedDeviceInfoMsg(deviceIntervalMs, deviceName, deviceTypeInfo, deviceTimeMs) {
|
|
573
|
+
var _a;
|
|
574
|
+
// Make sure we have response metadata
|
|
575
|
+
if (!((_a = deviceTypeInfo === null || deviceTypeInfo === void 0 ? void 0 : deviceTypeInfo.resp) === null || _a === void 0 ? void 0 : _a.a)) {
|
|
576
|
+
return new Uint8Array(0);
|
|
577
|
+
}
|
|
578
|
+
const attributes = deviceTypeInfo.resp.a;
|
|
579
|
+
const dataBlockSizeBytes = deviceTypeInfo.resp.b;
|
|
580
|
+
// Create a buffer for the data
|
|
581
|
+
const dataBuffer = new ArrayBuffer(dataBlockSizeBytes + 2);
|
|
582
|
+
const dataView = new DataView(dataBuffer);
|
|
583
|
+
let bytePos = 0;
|
|
584
|
+
// Add 16 bit big endian deviceTimeMs mod 65536 to the buffer
|
|
585
|
+
dataView.setUint16(bytePos, deviceTimeMs % 65536, false);
|
|
586
|
+
bytePos += 2;
|
|
587
|
+
const handledByCustomGenerator = this._fillCustomRawData(deviceTypeInfo, dataView, bytePos, dataBlockSizeBytes, deviceIntervalMs, deviceTimeMs);
|
|
588
|
+
if (!handledByCustomGenerator) {
|
|
589
|
+
const numAttributes = attributes.length;
|
|
590
|
+
const numSamplesPerCycle = 10;
|
|
591
|
+
const frequencyHz = (deviceIntervalMs > 0)
|
|
592
|
+
? (1000 / deviceIntervalMs) / numSamplesPerCycle
|
|
593
|
+
: 0.1;
|
|
594
|
+
const timeRadians = deviceTimeMs * frequencyHz * (2 * Math.PI) / 1000;
|
|
595
|
+
// Iterate through attributes and fill the payload
|
|
596
|
+
for (let attrIdx = 0; attrIdx < numAttributes; attrIdx++) {
|
|
597
|
+
const attr = attributes[attrIdx];
|
|
598
|
+
const { typeCode, repeatCount, littleEndian } = this._parseAttrType(attr.t);
|
|
599
|
+
const scaledValues = this._generateAttributeScaledValues(attr, attrIdx, repeatCount, numAttributes, timeRadians, deviceTimeMs);
|
|
600
|
+
if (scaledValues.length !== repeatCount) {
|
|
601
|
+
RaftLog_1.default.warn(`RaftChannelSimulated._createSimulatedDeviceInfoMsg - value count mismatch for ${attr.n}`);
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
for (let elemIdx = 0; elemIdx < repeatCount; elemIdx++) {
|
|
605
|
+
const scaledValue = scaledValues[elemIdx];
|
|
606
|
+
const rawValue = this._prepareRawValue(attr, typeCode, scaledValue);
|
|
607
|
+
const nextBytePos = this._writeRawValueToBuffer(dataView, bytePos, typeCode, littleEndian, rawValue);
|
|
608
|
+
if (nextBytePos < 0) {
|
|
609
|
+
RaftLog_1.default.warn(`RaftChannelSimulated._createSimulatedDeviceInfoMsg - buffer overflow writing ${attr.n}`);
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
bytePos = nextBytePos;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
bytePos += dataBlockSizeBytes;
|
|
618
|
+
}
|
|
619
|
+
// Convert the buffer to a byte array
|
|
620
|
+
const dataBytes = new Uint8Array(dataBuffer);
|
|
621
|
+
// Create the JSON message structure (bus key is numeric string to match firmware convention)
|
|
622
|
+
const message = {
|
|
623
|
+
"1": {
|
|
624
|
+
[deviceName]: {
|
|
625
|
+
"_t": deviceTypeInfo.type,
|
|
626
|
+
"_o": 1, // Device is online
|
|
627
|
+
"pub": this._bytesToHexStr(dataBytes)
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
// Convert the JSON to a string and then to Uint8Array with prepended timestamp
|
|
632
|
+
const jsonString = JSON.stringify(message);
|
|
633
|
+
const encodedMsg = new TextEncoder().encode(jsonString);
|
|
634
|
+
const msgWithPrefix = new ArrayBuffer(2 + encodedMsg.byteLength);
|
|
635
|
+
const msgWithPrefixView = new DataView(msgWithPrefix);
|
|
636
|
+
const msgPrefixBytes = new Uint8Array(msgWithPrefix);
|
|
637
|
+
msgWithPrefixView.setUint16(0, 0, false);
|
|
638
|
+
msgPrefixBytes.set(encodedMsg, 2);
|
|
639
|
+
return msgPrefixBytes;
|
|
640
|
+
}
|
|
641
|
+
_parseAttrType(attrType) {
|
|
642
|
+
const repeatMatch = attrType.match(/\[(\d+)\]\s*$/);
|
|
643
|
+
const repeatCount = repeatMatch ? parseInt(repeatMatch[1], 10) : 1;
|
|
644
|
+
const coreType = repeatMatch ? attrType.slice(0, repeatMatch.index) : attrType;
|
|
645
|
+
let littleEndian = false;
|
|
646
|
+
let typeCode = coreType.trim();
|
|
647
|
+
if (typeCode.startsWith("<")) {
|
|
648
|
+
littleEndian = true;
|
|
649
|
+
typeCode = typeCode.slice(1);
|
|
650
|
+
}
|
|
651
|
+
else if (typeCode.startsWith(">")) {
|
|
652
|
+
littleEndian = false;
|
|
653
|
+
typeCode = typeCode.slice(1);
|
|
654
|
+
}
|
|
655
|
+
else if (typeCode === "f") {
|
|
656
|
+
// Match previous behaviour - plain "f" treated as little endian floats
|
|
657
|
+
littleEndian = true;
|
|
658
|
+
}
|
|
659
|
+
return { typeCode, repeatCount, littleEndian };
|
|
660
|
+
}
|
|
661
|
+
_generateAttributeScaledValues(attr, attrIdx, repeatCount, numAttributes, timeRadians, deviceTimeMs) {
|
|
662
|
+
const amplitude = 0.8;
|
|
663
|
+
if (repeatCount > 1) {
|
|
664
|
+
const useThermalGrid = (attr && typeof attr.resolution === "string") || repeatCount >= 16;
|
|
665
|
+
if (useThermalGrid) {
|
|
666
|
+
return this._generateThermalGridValues(attr, repeatCount, timeRadians, deviceTimeMs);
|
|
667
|
+
}
|
|
668
|
+
const values = [];
|
|
669
|
+
for (let elemIdx = 0; elemIdx < repeatCount; elemIdx++) {
|
|
670
|
+
const phaseOffset = (2 * Math.PI * (attrIdx + elemIdx / repeatCount)) / Math.max(1, numAttributes);
|
|
671
|
+
const sinValue = Math.sin(timeRadians + phaseOffset);
|
|
672
|
+
if (Array.isArray(attr.r) && attr.r.length >= 2) {
|
|
673
|
+
const minValue = attr.r[0];
|
|
674
|
+
const maxValue = attr.r[1];
|
|
675
|
+
const midPoint = (maxValue + minValue) / 2;
|
|
676
|
+
const range = (maxValue - minValue) / 2;
|
|
677
|
+
const value = midPoint + sinValue * range * amplitude;
|
|
678
|
+
values.push(Math.min(maxValue, Math.max(minValue, value)));
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
values.push(sinValue * 1000 * amplitude);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return values;
|
|
685
|
+
}
|
|
686
|
+
const phaseOffset = numAttributes > 0 ? (2 * Math.PI * attrIdx) / numAttributes : 0;
|
|
687
|
+
const sinValue = Math.sin(timeRadians + phaseOffset);
|
|
688
|
+
if (Array.isArray(attr.r) && attr.r.length >= 2) {
|
|
689
|
+
const minValue = attr.r[0];
|
|
690
|
+
const maxValue = attr.r[1];
|
|
691
|
+
const midPoint = (maxValue + minValue) / 2;
|
|
692
|
+
const range = (maxValue - minValue) / 2;
|
|
693
|
+
const value = midPoint + sinValue * range * amplitude;
|
|
694
|
+
return [Math.min(maxValue, Math.max(minValue, value))];
|
|
695
|
+
}
|
|
696
|
+
return [sinValue * 1000 * amplitude];
|
|
697
|
+
}
|
|
698
|
+
_generateThermalGridValues(attr, repeatCount, timeRadians, deviceTimeMs) {
|
|
699
|
+
const { rows, cols } = this._getGridDimensions(attr, repeatCount);
|
|
700
|
+
const values = [];
|
|
701
|
+
const ambientBase = 24 + 2 * Math.sin(deviceTimeMs / 7000);
|
|
702
|
+
const hotspotPhase = deviceTimeMs / 3200;
|
|
703
|
+
const hotspotRow = (Math.sin(hotspotPhase) + 1) * (rows - 1) / 2;
|
|
704
|
+
const hotspotCol = (Math.cos(hotspotPhase) + 1) * (cols - 1) / 2;
|
|
705
|
+
const hotspotAmplitude = 6;
|
|
706
|
+
const rawSigma = Math.max(rows, cols) / 3;
|
|
707
|
+
const sigma = Number.isFinite(rawSigma) ? rawSigma : 1;
|
|
708
|
+
for (let idx = 0; idx < repeatCount; idx++) {
|
|
709
|
+
const row = Math.floor(idx / cols);
|
|
710
|
+
const col = idx % cols;
|
|
711
|
+
const dist = Math.hypot(row - hotspotRow, col - hotspotCol);
|
|
712
|
+
const hotspot = hotspotAmplitude * Math.exp(-(dist * dist) / (2 * sigma * sigma));
|
|
713
|
+
const gentleWave = 0.5 * Math.sin(timeRadians + row * 0.35 + col * 0.25);
|
|
714
|
+
let value = ambientBase + hotspot + gentleWave;
|
|
715
|
+
if (Array.isArray(attr.r) && attr.r.length >= 2) {
|
|
716
|
+
value = Math.min(attr.r[1], Math.max(attr.r[0], value));
|
|
717
|
+
}
|
|
718
|
+
values.push(value);
|
|
719
|
+
}
|
|
720
|
+
return values;
|
|
721
|
+
}
|
|
722
|
+
_fillCustomRawData(deviceTypeInfo, dataView, bytePos, dataBlockSizeBytes, deviceIntervalMs, deviceTimeMs) {
|
|
723
|
+
var _a, _b, _c, _d, _e, _f;
|
|
724
|
+
switch (deviceTypeInfo.type) {
|
|
725
|
+
case "LTR-329": {
|
|
726
|
+
if (dataBlockSizeBytes < 4) {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
const frequencyHz = (deviceIntervalMs > 0)
|
|
730
|
+
? (1000 / deviceIntervalMs) / 10
|
|
731
|
+
: 0.1;
|
|
732
|
+
const timeRadians = deviceTimeMs * frequencyHz * (2 * Math.PI) / 1000;
|
|
733
|
+
const range = (_d = (_c = (_b = (_a = deviceTypeInfo.resp) === null || _a === void 0 ? void 0 : _a.a) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.r) !== null && _d !== void 0 ? _d : [0, 64000];
|
|
734
|
+
const minLux = (_e = range[0]) !== null && _e !== void 0 ? _e : 0;
|
|
735
|
+
const maxLux = (_f = range[1]) !== null && _f !== void 0 ? _f : 64000;
|
|
736
|
+
const baseLux = (maxLux + minLux) / 4;
|
|
737
|
+
const amplitudeLux = (maxLux - minLux) / 6;
|
|
738
|
+
let combined = Math.round(baseLux + amplitudeLux * Math.sin(timeRadians));
|
|
739
|
+
combined = Math.max(minLux, Math.min(maxLux, combined));
|
|
740
|
+
const irBase = combined * 0.35;
|
|
741
|
+
const irVariance = (combined * 0.15) * Math.sin(timeRadians + Math.PI / 4);
|
|
742
|
+
let ir = Math.round(irBase + irVariance);
|
|
743
|
+
ir = Math.max(minLux, Math.min(combined, ir));
|
|
744
|
+
dataView.setUint16(bytePos, combined, true);
|
|
745
|
+
dataView.setUint16(bytePos + 2, ir, true);
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
case "LTR-390": {
|
|
749
|
+
if (dataBlockSizeBytes < 5) {
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
const numerator = (deviceIntervalMs > 0) ? (1000 / deviceIntervalMs) : 0;
|
|
753
|
+
const timeRadians = deviceTimeMs * numerator * (2 * Math.PI) / 1000 / 10;
|
|
754
|
+
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
755
|
+
const ambientLux = clamp(8000 + 4500 * Math.sin(timeRadians), 0, 64000);
|
|
756
|
+
const ambientRaw = clamp(Math.round(ambientLux * 1.25), 0, 0xFFFFF);
|
|
757
|
+
dataView.setUint8(bytePos, ambientRaw & 0xFF);
|
|
758
|
+
dataView.setUint8(bytePos + 1, (ambientRaw >> 8) & 0xFF);
|
|
759
|
+
dataView.setUint8(bytePos + 2, (ambientRaw >> 16) & 0x0F);
|
|
760
|
+
const uviIndex = clamp(3.5 + 1.8 * Math.sin(timeRadians + Math.PI / 3), 0, 12);
|
|
761
|
+
const uviRaw = clamp(Math.round(uviIndex * 24), 0, 0xFFFF);
|
|
762
|
+
dataView.setUint16(bytePos + 3, uviRaw, true);
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
case "VL53L4CD": {
|
|
766
|
+
if (dataBlockSizeBytes < 3) {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
const rangeMinMm = 40;
|
|
770
|
+
const rangeMaxMm = 1300;
|
|
771
|
+
const cycleMs = 9000;
|
|
772
|
+
const timeInCycle = deviceTimeMs % cycleMs;
|
|
773
|
+
// Simulate periods where the sensor reports invalid readings (target lost)
|
|
774
|
+
const invalidReading = timeInCycle < 600 ||
|
|
775
|
+
(timeInCycle > 4200 && timeInCycle < 5100) ||
|
|
776
|
+
(timeInCycle > 7800);
|
|
777
|
+
const isValid = !invalidReading;
|
|
778
|
+
// Generate a smooth oscillating distance while valid
|
|
779
|
+
const phase = (deviceTimeMs % cycleMs) / cycleMs;
|
|
780
|
+
const smoothWave = 0.5 * (1 - Math.cos(phase * 2 * Math.PI));
|
|
781
|
+
const slowDrift = 0.05 * Math.sin(deviceTimeMs / 5000);
|
|
782
|
+
const fastRipple = 0.02 * Math.sin(deviceTimeMs / 200);
|
|
783
|
+
const normalized = Math.min(1, Math.max(0, smoothWave + slowDrift + fastRipple));
|
|
784
|
+
let distanceMm = Math.round(rangeMinMm + normalized * (rangeMaxMm - rangeMinMm));
|
|
785
|
+
// Clamp to the reported range
|
|
786
|
+
distanceMm = Math.max(rangeMinMm, Math.min(rangeMaxMm, distanceMm));
|
|
787
|
+
if (!isValid) {
|
|
788
|
+
distanceMm = 0;
|
|
789
|
+
}
|
|
790
|
+
const statusRaw = isValid ? 0x00 : 0x04;
|
|
791
|
+
dataView.setUint8(bytePos, statusRaw);
|
|
792
|
+
dataView.setUint16(bytePos + 1, distanceMm, false);
|
|
793
|
+
return true;
|
|
794
|
+
}
|
|
795
|
+
case "RoboticalLEDRing": {
|
|
796
|
+
if (dataBlockSizeBytes < 1) {
|
|
797
|
+
return false;
|
|
798
|
+
}
|
|
799
|
+
const animationPhase = (deviceTimeMs % 6000) / 6000;
|
|
800
|
+
const patternIndex = Math.floor(animationPhase * 6) % 6;
|
|
801
|
+
const brightness = Math.round((Math.sin(deviceTimeMs / 600) + 1) * 127.5);
|
|
802
|
+
const isAnimating = Math.sin(deviceTimeMs / 1500) > 0;
|
|
803
|
+
const status = ((patternIndex & 0x07) << 4) | Math.min(0x0F, brightness >> 4) | (isAnimating ? 0x80 : 0x00);
|
|
804
|
+
dataView.setUint8(bytePos, status & 0xFF);
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
case "RoboticalDCMotor": {
|
|
808
|
+
if (dataBlockSizeBytes < 4) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
812
|
+
const cycleMs = 3200;
|
|
813
|
+
const cycleIndex = Math.floor(deviceTimeMs / cycleMs);
|
|
814
|
+
const direction = (cycleIndex % 2 === 0) ? 1 : -1;
|
|
815
|
+
const progress = (deviceTimeMs % cycleMs) / cycleMs;
|
|
816
|
+
const baseAngle = (progress * 360) - 180;
|
|
817
|
+
const angleDegrees = direction > 0 ? baseAngle : -baseAngle;
|
|
818
|
+
const angleRaw = clamp(Math.round(angleDegrees * 10), -1800, 1800);
|
|
819
|
+
const ripple = 6 * Math.sin((deviceTimeMs % cycleMs) / 180);
|
|
820
|
+
const loadComponent = Math.abs(baseAngle) * 0.12;
|
|
821
|
+
const currentRaw = clamp(Math.round(24 + loadComponent + ripple), -128, 127);
|
|
822
|
+
const highLoad = Math.abs(loadComponent) > 8;
|
|
823
|
+
const directionBit = direction > 0 ? 0x01 : 0x00;
|
|
824
|
+
const stateRaw = 0x02 | directionBit | (highLoad ? 0x04 : 0x00);
|
|
825
|
+
dataView.setInt16(bytePos, angleRaw, false);
|
|
826
|
+
dataView.setInt8(bytePos + 2, currentRaw);
|
|
827
|
+
dataView.setUint8(bytePos + 3, stateRaw);
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
case "RoboticalServo": {
|
|
831
|
+
if (dataBlockSizeBytes < 6) {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
const swingAmplitudeDeg = 90;
|
|
835
|
+
const cycleMs = 4000;
|
|
836
|
+
const angularSpeedRadPerMs = (2 * Math.PI) / cycleMs;
|
|
837
|
+
const phaseRadians = (deviceTimeMs % cycleMs) * angularSpeedRadPerMs;
|
|
838
|
+
const angleDegrees = swingAmplitudeDeg * Math.sin(phaseRadians);
|
|
839
|
+
const velocityDegPerSec = swingAmplitudeDeg * angularSpeedRadPerMs * 1000 * Math.cos(phaseRadians);
|
|
840
|
+
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
841
|
+
const angleRaw = clamp(Math.round(angleDegrees * 10), -1800, 1800);
|
|
842
|
+
let velocityRaw = Math.round(velocityDegPerSec);
|
|
843
|
+
velocityRaw = clamp(velocityRaw, -32768, 32767);
|
|
844
|
+
let currentRaw = Math.round(20 + 0.08 * Math.abs(velocityDegPerSec));
|
|
845
|
+
currentRaw = clamp(currentRaw, 0, 127);
|
|
846
|
+
const isMoving = Math.abs(velocityDegPerSec) > 5;
|
|
847
|
+
const stateRaw = (0x02) | (isMoving ? 0x01 : 0);
|
|
848
|
+
dataView.setInt16(bytePos, angleRaw, false);
|
|
849
|
+
dataView.setInt8(bytePos + 2, currentRaw);
|
|
850
|
+
dataView.setUint8(bytePos + 3, stateRaw);
|
|
851
|
+
dataView.setInt16(bytePos + 4, velocityRaw, false);
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
default:
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
_getGridDimensions(attr, repeatCount) {
|
|
859
|
+
if (attr && typeof attr.resolution === "string") {
|
|
860
|
+
const match = attr.resolution.match(/(\d+)\s*x\s*(\d+)/i);
|
|
861
|
+
if (match) {
|
|
862
|
+
const rows = parseInt(match[1], 10);
|
|
863
|
+
const cols = parseInt(match[2], 10);
|
|
864
|
+
if (rows > 0 && cols > 0) {
|
|
865
|
+
return { rows, cols };
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
const side = Math.round(Math.sqrt(repeatCount));
|
|
870
|
+
if (side > 0 && side * side === repeatCount) {
|
|
871
|
+
return { rows: side, cols: side };
|
|
872
|
+
}
|
|
873
|
+
return { rows: repeatCount, cols: 1 };
|
|
874
|
+
}
|
|
875
|
+
_prepareRawValue(attr, typeCode, scaledValue) {
|
|
876
|
+
if (this._isFloatType(typeCode)) {
|
|
877
|
+
return scaledValue;
|
|
878
|
+
}
|
|
879
|
+
let raw = scaledValue;
|
|
880
|
+
if (attr && typeof attr.a === "number") {
|
|
881
|
+
raw -= attr.a;
|
|
882
|
+
}
|
|
883
|
+
if (attr && typeof attr.d === "number") {
|
|
884
|
+
raw *= attr.d;
|
|
885
|
+
}
|
|
886
|
+
if (attr && typeof attr.s === "number" && attr.s !== 0) {
|
|
887
|
+
const shift = attr.s;
|
|
888
|
+
const shiftFactor = Math.pow(2, Math.abs(shift));
|
|
889
|
+
if (shift > 0) {
|
|
890
|
+
raw *= shiftFactor;
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
raw /= shiftFactor;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return Math.round(raw);
|
|
897
|
+
}
|
|
898
|
+
_writeRawValueToBuffer(dataView, bytePos, typeCode, littleEndian, rawValue) {
|
|
899
|
+
const valueSize = this._byteSizeForType(typeCode);
|
|
900
|
+
if (valueSize <= 0 || bytePos + valueSize > dataView.byteLength) {
|
|
901
|
+
return -1;
|
|
902
|
+
}
|
|
903
|
+
switch (typeCode) {
|
|
904
|
+
case "b":
|
|
905
|
+
dataView.setInt8(bytePos, this._clampRawValue(rawValue, typeCode));
|
|
906
|
+
break;
|
|
907
|
+
case "c":
|
|
908
|
+
dataView.setInt8(bytePos, this._clampRawValue(rawValue, typeCode));
|
|
909
|
+
break;
|
|
910
|
+
case "B":
|
|
911
|
+
case "C":
|
|
912
|
+
dataView.setUint8(bytePos, this._clampRawValue(rawValue, typeCode));
|
|
913
|
+
break;
|
|
914
|
+
case "?":
|
|
915
|
+
dataView.setUint8(bytePos, rawValue ? 1 : 0);
|
|
916
|
+
break;
|
|
917
|
+
case "h":
|
|
918
|
+
dataView.setInt16(bytePos, this._clampRawValue(rawValue, typeCode), littleEndian);
|
|
919
|
+
break;
|
|
920
|
+
case "H":
|
|
921
|
+
dataView.setUint16(bytePos, this._clampRawValue(rawValue, typeCode), littleEndian);
|
|
922
|
+
break;
|
|
923
|
+
case "i":
|
|
924
|
+
case "l":
|
|
925
|
+
dataView.setInt32(bytePos, this._clampRawValue(rawValue, typeCode), littleEndian);
|
|
926
|
+
break;
|
|
927
|
+
case "I":
|
|
928
|
+
case "L":
|
|
929
|
+
dataView.setUint32(bytePos, this._clampRawValue(rawValue, typeCode), littleEndian);
|
|
930
|
+
break;
|
|
931
|
+
case "f":
|
|
932
|
+
dataView.setFloat32(bytePos, rawValue, littleEndian);
|
|
933
|
+
break;
|
|
934
|
+
case "d":
|
|
935
|
+
dataView.setFloat64(bytePos, rawValue, littleEndian);
|
|
936
|
+
break;
|
|
937
|
+
default:
|
|
938
|
+
RaftLog_1.default.warn(`RaftChannelSimulated._writeRawValueToBuffer - unsupported attribute type ${typeCode}`);
|
|
939
|
+
return -1;
|
|
940
|
+
}
|
|
941
|
+
return bytePos + valueSize;
|
|
942
|
+
}
|
|
943
|
+
_byteSizeForType(typeCode) {
|
|
944
|
+
switch (typeCode) {
|
|
945
|
+
case "b":
|
|
946
|
+
case "B":
|
|
947
|
+
case "c":
|
|
948
|
+
case "C":
|
|
949
|
+
case "?":
|
|
950
|
+
return 1;
|
|
951
|
+
case "h":
|
|
952
|
+
case "H":
|
|
953
|
+
return 2;
|
|
954
|
+
case "i":
|
|
955
|
+
case "I":
|
|
956
|
+
case "l":
|
|
957
|
+
case "L":
|
|
958
|
+
case "f":
|
|
959
|
+
return 4;
|
|
960
|
+
case "d":
|
|
961
|
+
return 8;
|
|
962
|
+
default:
|
|
963
|
+
return 0;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
_clampRawValue(rawValue, typeCode) {
|
|
967
|
+
const value = Math.round(rawValue);
|
|
968
|
+
switch (typeCode) {
|
|
969
|
+
case "b":
|
|
970
|
+
case "c":
|
|
971
|
+
return Math.max(-128, Math.min(127, value));
|
|
972
|
+
case "B":
|
|
973
|
+
case "C":
|
|
974
|
+
case "?":
|
|
975
|
+
return Math.max(0, Math.min(255, value));
|
|
976
|
+
case "h":
|
|
977
|
+
return Math.max(-32768, Math.min(32767, value));
|
|
978
|
+
case "H":
|
|
979
|
+
return Math.max(0, Math.min(65535, value));
|
|
980
|
+
case "i":
|
|
981
|
+
case "l":
|
|
982
|
+
return Math.max(-2147483648, Math.min(2147483647, value));
|
|
983
|
+
case "I":
|
|
984
|
+
case "L":
|
|
985
|
+
return Math.max(0, Math.min(4294967295, value));
|
|
986
|
+
default:
|
|
987
|
+
return value;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
_isFloatType(typeCode) {
|
|
991
|
+
return typeCode === "f" || typeCode === "d";
|
|
992
|
+
}
|
|
993
|
+
// Helper function to convert bytes to hex string
|
|
994
|
+
_bytesToHexStr(bytes) {
|
|
995
|
+
return Array.from(bytes)
|
|
996
|
+
.map(byte => byte.toString(16).padStart(2, '0'))
|
|
997
|
+
.join('');
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
exports.default = RaftChannelSimulated;
|
|
1001
|
+
//# sourceMappingURL=RaftChannelSimulated.js.map
|