@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.
Files changed (240) hide show
  1. package/.editorconfig +14 -0
  2. package/.gitattributes +11 -0
  3. package/.nvmrc +1 -0
  4. package/TODO.md +1 -0
  5. package/dist/react-native/RaftAttributeHandler.d.ts +14 -0
  6. package/dist/react-native/RaftAttributeHandler.js +375 -0
  7. package/dist/react-native/RaftAttributeHandler.js.map +1 -0
  8. package/dist/react-native/RaftChannel.d.ts +20 -0
  9. package/dist/react-native/RaftChannel.js +12 -0
  10. package/dist/react-native/RaftChannel.js.map +1 -0
  11. package/dist/react-native/RaftChannelBLE.native.d.ts +95 -0
  12. package/dist/react-native/RaftChannelBLE.native.js +483 -0
  13. package/dist/react-native/RaftChannelBLE.native.js.map +1 -0
  14. package/dist/react-native/RaftChannelBLE.web.d.ts +40 -0
  15. package/dist/react-native/RaftChannelBLE.web.js +302 -0
  16. package/dist/react-native/RaftChannelBLE.web.js.map +1 -0
  17. package/dist/react-native/RaftChannelBLEFactory.d.ts +10 -0
  18. package/dist/react-native/RaftChannelBLEFactory.js +17 -0
  19. package/dist/react-native/RaftChannelBLEFactory.js.map +1 -0
  20. package/dist/react-native/RaftChannelBLEScanner.native.d.ts +18 -0
  21. package/dist/react-native/RaftChannelBLEScanner.native.js +138 -0
  22. package/dist/react-native/RaftChannelBLEScanner.native.js.map +1 -0
  23. package/dist/react-native/RaftChannelSimulated.d.ts +42 -0
  24. package/dist/react-native/RaftChannelSimulated.js +1001 -0
  25. package/dist/react-native/RaftChannelSimulated.js.map +1 -0
  26. package/dist/react-native/RaftChannelWebSerial.d.ts +39 -0
  27. package/dist/react-native/RaftChannelWebSerial.js +329 -0
  28. package/dist/react-native/RaftChannelWebSerial.js.map +1 -0
  29. package/dist/react-native/RaftChannelWebSocket.d.ts +30 -0
  30. package/dist/react-native/RaftChannelWebSocket.js +222 -0
  31. package/dist/react-native/RaftChannelWebSocket.js.map +1 -0
  32. package/dist/react-native/RaftCommsStats.d.ts +39 -0
  33. package/dist/react-native/RaftCommsStats.js +128 -0
  34. package/dist/react-native/RaftCommsStats.js.map +1 -0
  35. package/dist/react-native/RaftConnEvents.d.ts +39 -0
  36. package/dist/react-native/RaftConnEvents.js +54 -0
  37. package/dist/react-native/RaftConnEvents.js.map +1 -0
  38. package/dist/react-native/RaftConnector.d.ts +257 -0
  39. package/dist/react-native/RaftConnector.js +671 -0
  40. package/dist/react-native/RaftConnector.js.map +1 -0
  41. package/dist/react-native/RaftCustomAttrHandler.d.ts +6 -0
  42. package/dist/react-native/RaftCustomAttrHandler.js +93 -0
  43. package/dist/react-native/RaftCustomAttrHandler.js.map +1 -0
  44. package/dist/react-native/RaftDeviceInfo.d.ts +71 -0
  45. package/dist/react-native/RaftDeviceInfo.js +50 -0
  46. package/dist/react-native/RaftDeviceInfo.js.map +1 -0
  47. package/dist/react-native/RaftDeviceManager.d.ts +73 -0
  48. package/dist/react-native/RaftDeviceManager.js +812 -0
  49. package/dist/react-native/RaftDeviceManager.js.map +1 -0
  50. package/dist/react-native/RaftDeviceMgrIF.d.ts +19 -0
  51. package/dist/react-native/RaftDeviceMgrIF.js +11 -0
  52. package/dist/react-native/RaftDeviceMgrIF.js.map +1 -0
  53. package/dist/react-native/RaftDeviceMsg.d.ts +9 -0
  54. package/dist/react-native/RaftDeviceMsg.js +11 -0
  55. package/dist/react-native/RaftDeviceMsg.js.map +1 -0
  56. package/dist/react-native/RaftDeviceStates.d.ts +55 -0
  57. package/dist/react-native/RaftDeviceStates.js +81 -0
  58. package/dist/react-native/RaftDeviceStates.js.map +1 -0
  59. package/dist/react-native/RaftFileHandler.d.ts +52 -0
  60. package/dist/react-native/RaftFileHandler.js +502 -0
  61. package/dist/react-native/RaftFileHandler.js.map +1 -0
  62. package/dist/react-native/RaftLog.d.ts +22 -0
  63. package/dist/react-native/RaftLog.js +63 -0
  64. package/dist/react-native/RaftLog.js.map +1 -0
  65. package/dist/react-native/RaftMiniHDLC.d.ts +18 -0
  66. package/dist/react-native/RaftMiniHDLC.js +383 -0
  67. package/dist/react-native/RaftMiniHDLC.js.map +1 -0
  68. package/dist/react-native/RaftMsgHandler.d.ts +62 -0
  69. package/dist/react-native/RaftMsgHandler.js +511 -0
  70. package/dist/react-native/RaftMsgHandler.js.map +1 -0
  71. package/dist/react-native/RaftMsgTrackInfo.d.ts +17 -0
  72. package/dist/react-native/RaftMsgTrackInfo.js +42 -0
  73. package/dist/react-native/RaftMsgTrackInfo.js.map +1 -0
  74. package/dist/react-native/RaftProtocolDefs.d.ts +30 -0
  75. package/dist/react-native/RaftProtocolDefs.js +48 -0
  76. package/dist/react-native/RaftProtocolDefs.js.map +1 -0
  77. package/dist/react-native/RaftPublish.d.ts +2 -0
  78. package/dist/react-native/RaftPublish.js +81 -0
  79. package/dist/react-native/RaftPublish.js.map +1 -0
  80. package/dist/react-native/RaftStreamHandler.d.ts +49 -0
  81. package/dist/react-native/RaftStreamHandler.js +324 -0
  82. package/dist/react-native/RaftStreamHandler.js.map +1 -0
  83. package/dist/react-native/RaftStruct.d.ts +3 -0
  84. package/dist/react-native/RaftStruct.js +258 -0
  85. package/dist/react-native/RaftStruct.js.map +1 -0
  86. package/dist/react-native/RaftSysTypeManager.d.ts +16 -0
  87. package/dist/react-native/RaftSysTypeManager.js +78 -0
  88. package/dist/react-native/RaftSysTypeManager.js.map +1 -0
  89. package/dist/react-native/RaftSystemType.d.ts +30 -0
  90. package/dist/react-native/RaftSystemType.js +3 -0
  91. package/dist/react-native/RaftSystemType.js.map +1 -0
  92. package/dist/react-native/RaftSystemUtils.d.ts +152 -0
  93. package/dist/react-native/RaftSystemUtils.js +463 -0
  94. package/dist/react-native/RaftSystemUtils.js.map +1 -0
  95. package/dist/react-native/RaftTypes.d.ts +216 -0
  96. package/dist/react-native/RaftTypes.js +153 -0
  97. package/dist/react-native/RaftTypes.js.map +1 -0
  98. package/dist/react-native/RaftUpdateEvents.d.ts +33 -0
  99. package/dist/react-native/RaftUpdateEvents.js +46 -0
  100. package/dist/react-native/RaftUpdateEvents.js.map +1 -0
  101. package/dist/react-native/RaftUpdateManager.d.ts +61 -0
  102. package/dist/react-native/RaftUpdateManager.js +621 -0
  103. package/dist/react-native/RaftUpdateManager.js.map +1 -0
  104. package/dist/react-native/RaftUtils.d.ts +128 -0
  105. package/dist/react-native/RaftUtils.js +487 -0
  106. package/dist/react-native/RaftUtils.js.map +1 -0
  107. package/dist/react-native/RaftWifiTypes.d.ts +23 -0
  108. package/dist/react-native/RaftWifiTypes.js +43 -0
  109. package/dist/react-native/RaftWifiTypes.js.map +1 -0
  110. package/dist/react-native/main.d.ts +27 -0
  111. package/dist/react-native/main.js +52 -0
  112. package/dist/react-native/main.js.map +1 -0
  113. package/dist/web/RaftAttributeHandler.js +1 -1
  114. package/dist/web/RaftAttributeHandler.js.map +1 -1
  115. package/dist/web/RaftChannelBLE.web.js +8 -6
  116. package/dist/web/RaftChannelBLE.web.js.map +1 -1
  117. package/dist/web/RaftChannelSimulated.d.ts +10 -0
  118. package/dist/web/RaftChannelSimulated.js +665 -82
  119. package/dist/web/RaftChannelSimulated.js.map +1 -1
  120. package/dist/web/RaftChannelWebSerial.js +2 -2
  121. package/dist/web/RaftChannelWebSerial.js.map +1 -1
  122. package/dist/web/RaftChannelWebSocket.js +16 -1
  123. package/dist/web/RaftChannelWebSocket.js.map +1 -1
  124. package/dist/web/RaftConnector.d.ts +12 -1
  125. package/dist/web/RaftConnector.js +45 -9
  126. package/dist/web/RaftConnector.js.map +1 -1
  127. package/dist/web/RaftCustomAttrHandler.d.ts +2 -0
  128. package/dist/web/RaftCustomAttrHandler.js +54 -26
  129. package/dist/web/RaftCustomAttrHandler.js.map +1 -1
  130. package/dist/web/RaftDeviceInfo.d.ts +3 -1
  131. package/dist/web/RaftDeviceInfo.js +17 -3
  132. package/dist/web/RaftDeviceInfo.js.map +1 -1
  133. package/dist/web/RaftDeviceManager.d.ts +32 -2
  134. package/dist/web/RaftDeviceManager.js +307 -74
  135. package/dist/web/RaftDeviceManager.js.map +1 -1
  136. package/dist/web/RaftDeviceMgrIF.d.ts +5 -1
  137. package/dist/web/RaftDeviceStates.d.ts +20 -2
  138. package/dist/web/RaftDeviceStates.js +25 -4
  139. package/dist/web/RaftDeviceStates.js.map +1 -1
  140. package/dist/web/RaftMsgHandler.js.map +1 -1
  141. package/dist/web/RaftPublish.d.ts +2 -0
  142. package/dist/web/RaftPublish.js +81 -0
  143. package/dist/web/RaftPublish.js.map +1 -0
  144. package/dist/web/RaftStreamHandler.d.ts +11 -0
  145. package/dist/web/RaftStreamHandler.js +68 -1
  146. package/dist/web/RaftStreamHandler.js.map +1 -1
  147. package/dist/web/RaftStruct.js +197 -147
  148. package/dist/web/RaftStruct.js.map +1 -1
  149. package/dist/web/RaftSystemUtils.d.ts +17 -1
  150. package/dist/web/RaftSystemUtils.js +51 -0
  151. package/dist/web/RaftSystemUtils.js.map +1 -1
  152. package/dist/web/RaftTypes.d.ts +21 -0
  153. package/dist/web/RaftTypes.js.map +1 -1
  154. package/dist/web/RaftUpdateManager.js +1 -1
  155. package/dist/web/RaftUpdateManager.js.map +1 -1
  156. package/dist/web/RaftUtils.d.ts +2 -0
  157. package/dist/web/RaftUtils.js +20 -0
  158. package/dist/web/RaftUtils.js.map +1 -1
  159. package/dist/web/main.d.ts +2 -0
  160. package/dist/web/main.js +1 -0
  161. package/dist/web/main.js.map +1 -1
  162. package/eslint.config.mjs +33 -0
  163. package/examples/dashboard/package.json +36 -0
  164. package/examples/dashboard/src/CommandPanel.tsx +147 -0
  165. package/examples/dashboard/src/ConnManager.ts +166 -0
  166. package/examples/dashboard/src/DeviceActionsForm.tsx +133 -0
  167. package/examples/dashboard/src/DeviceAttrsForm.tsx +49 -0
  168. package/examples/dashboard/src/DeviceLineChart.tsx +163 -0
  169. package/examples/dashboard/src/DevicePanel.tsx +247 -0
  170. package/examples/dashboard/src/DeviceStatsPanel.tsx +65 -0
  171. package/examples/dashboard/src/DevicesPanel.tsx +69 -0
  172. package/examples/dashboard/src/DispLedGrid.tsx +110 -0
  173. package/examples/dashboard/src/DispOneLed.tsx +20 -0
  174. package/examples/dashboard/src/LatencyTest.ts +130 -0
  175. package/examples/dashboard/src/LatencyTestPanel.tsx +92 -0
  176. package/examples/dashboard/src/Main.tsx +234 -0
  177. package/examples/dashboard/src/SettingsManager.ts +67 -0
  178. package/examples/dashboard/src/SettingsScreen.tsx +179 -0
  179. package/examples/dashboard/src/StatusPanel.tsx +71 -0
  180. package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +170 -0
  181. package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +125 -0
  182. package/examples/dashboard/src/SystemTypeGeneric/StateInfoGeneric.ts +38 -0
  183. package/examples/dashboard/src/SystemTypeGeneric/SystemTypeGeneric.ts +125 -0
  184. package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
  185. package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
  186. package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
  187. package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
  188. package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
  189. package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
  190. package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
  191. package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
  192. package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +105 -0
  193. package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
  194. package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
  195. package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +119 -0
  196. package/examples/dashboard/src/index.html +15 -0
  197. package/examples/dashboard/src/index.tsx +13 -0
  198. package/examples/dashboard/src/styles.css +570 -0
  199. package/examples/dashboard/tsconfig.json +18 -0
  200. package/jest.config.js +11 -0
  201. package/package.json +49 -52
  202. package/src/RaftAttributeHandler.ts +450 -0
  203. package/src/RaftChannel.ts +32 -0
  204. package/src/RaftChannelBLE.native.ts +617 -0
  205. package/src/RaftChannelBLE.web.ts +374 -0
  206. package/src/RaftChannelBLEFactory.ts +13 -0
  207. package/src/RaftChannelBLEScanner.native.ts +184 -0
  208. package/src/RaftChannelSimulated.ts +1177 -0
  209. package/src/RaftChannelWebSerial.ts +420 -0
  210. package/src/RaftChannelWebSocket.ts +272 -0
  211. package/src/RaftCommsStats.ts +142 -0
  212. package/src/RaftConnEvents.ts +58 -0
  213. package/src/RaftConnector.ts +806 -0
  214. package/src/RaftCustomAttrHandler.ts +117 -0
  215. package/src/RaftDeviceInfo.ts +125 -0
  216. package/src/RaftDeviceManager.ts +1014 -0
  217. package/src/RaftDeviceMgrIF.ts +37 -0
  218. package/src/RaftDeviceMsg.ts +20 -0
  219. package/src/RaftDeviceStates.ts +122 -0
  220. package/src/RaftFileHandler.ts +668 -0
  221. package/src/RaftLog.ts +70 -0
  222. package/src/RaftMiniHDLC.ts +396 -0
  223. package/src/RaftMsgHandler.ts +812 -0
  224. package/src/RaftMsgTrackInfo.ts +51 -0
  225. package/src/RaftProtocolDefs.ts +46 -0
  226. package/src/RaftPublish.ts +92 -0
  227. package/src/RaftStreamHandler.ts +412 -0
  228. package/src/RaftStruct.ts +282 -0
  229. package/src/RaftSysTypeManager.ts +87 -0
  230. package/src/RaftSystemType.ts +34 -0
  231. package/src/RaftSystemUtils.ts +548 -0
  232. package/src/RaftTypes.ts +306 -0
  233. package/src/RaftUpdateEvents.ts +48 -0
  234. package/src/RaftUpdateManager.ts +781 -0
  235. package/src/RaftUtils.ts +514 -0
  236. package/src/RaftWifiTypes.ts +36 -0
  237. package/src/main.ts +40 -0
  238. package/testdata/TestDeviceTypeRecs.json +492 -0
  239. package/tsconfig.json +30 -0
  240. 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": "&deg;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": "&deg;/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": "&deg;/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": "&deg;/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