@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,812 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // RaftMsgHandler
4
+ // Part of RaftJS
5
+ //
6
+ // Rob Dobson & Chris Greening 2020-2024
7
+ // (C) 2020-2024 All rights reserved
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+
11
+ import RaftCommsStats from './RaftCommsStats';
12
+ import { RaftMsgTrackInfo } from './RaftMsgTrackInfo';
13
+ import RaftLog from './RaftLog';
14
+ import RaftUtils from './RaftUtils';
15
+ import {
16
+ RICSERIAL_MSG_NUM_POS,
17
+ RICSERIAL_PAYLOAD_POS,
18
+ RICSERIAL_PROTOCOL_POS,
19
+ RICREST_REST_ELEM_CODE_POS,
20
+ RICREST_HEADER_PAYLOAD_POS,
21
+ RICREST_FILEBLOCK_FILEPOS_POS,
22
+ RICREST_FILEBLOCK_PAYLOAD_POS,
23
+ RICREST_BRIDGE_PAYLOAD_POS,
24
+ RICREST_BRIDGE_ID_POS,
25
+ RICRESTElemCode,
26
+ RaftCommsMsgProtocol,
27
+ RaftCommsMsgTypeCode,
28
+ } from './RaftProtocolDefs';
29
+ import RaftMiniHDLC from './RaftMiniHDLC';
30
+ import { RaftBridgeSetupResp, RaftReportMsg } from './RaftTypes';
31
+
32
+ // Message results
33
+ export enum RaftMsgResultCode {
34
+ MESSAGE_RESULT_TIMEOUT,
35
+ MESSAGE_RESULT_OK,
36
+ MESSAGE_RESULT_FAIL,
37
+ MESSAGE_RESULT_UNKNOWN,
38
+ }
39
+
40
+ export interface RaftMessageResult {
41
+ onRxReply(
42
+ msgHandle: number,
43
+ msgRsltCode: RaftMsgResultCode,
44
+ msgRsltJsonObj: object | null,
45
+ ): void;
46
+ onRxUnnumberedMsg(msgRsltJsonObj: object): void;
47
+ onRxFileBlock(
48
+ filePos: number,
49
+ fileBlockData: Uint8Array
50
+ ): void;
51
+ onRxOtherMsgType(payload: Uint8Array, frameTimeMs: number): void;
52
+ }
53
+
54
+ export interface RaftMessageSender {
55
+ sendTxMsg(
56
+ msg: Uint8Array,
57
+ sendWithResponse: boolean,
58
+ ): Promise<boolean>;
59
+ sendTxMsgNoAwait(
60
+ msg: Uint8Array,
61
+ sendWithResponse: boolean,
62
+ ): Promise<boolean>;
63
+ sendTxMsgRaw(msg: string): boolean;
64
+ sendTxMsgRawAndWaitForReply<T>(msgPayload: Uint8Array): T;
65
+ }
66
+
67
+ export default class RaftMsgHandler {
68
+ // Message numbering and tracking
69
+ private _currentMsgNumber = 1;
70
+ private _currentMsgHandle = 1;
71
+ private _msgTrackInfos: Array<RaftMsgTrackInfo> = new Array<RaftMsgTrackInfo>(
72
+ RaftMsgTrackInfo.MAX_MSG_NUM + 1,
73
+ );
74
+ private _msgTrackTimerMs = 50;
75
+ private _msgTrackLastCheckIdx = 0;
76
+
77
+ // report message callback dictionary. Add a callback to subscribe to report messages
78
+ private _reportMsgCallbacks = new Map<string, (report: RaftReportMsg) => Promise<void>>();
79
+
80
+ // Interface to inform of message results
81
+ private _msgResultHandler: RaftMessageResult | null = null;
82
+
83
+ // Interface to send messages
84
+ private _msgSender: RaftMessageSender | null = null;
85
+
86
+ // Comms stats
87
+ private _commsStats: RaftCommsStats;
88
+
89
+ // RaftMiniHDLC - handles part of RICSerial protocol
90
+ private _miniHDLC: RaftMiniHDLC;
91
+
92
+ // Raw message mode
93
+ private _rawMsgMode = false;
94
+
95
+ // Constructor
96
+ constructor(commsStats: RaftCommsStats) {
97
+ this._commsStats = commsStats;
98
+ RaftLog.debug('RaftMsgHandler constructor');
99
+
100
+ // Message tracking
101
+ for (let i = 0; i < this._msgTrackInfos.length; i++) {
102
+ this._msgTrackInfos[i] = new RaftMsgTrackInfo();
103
+ }
104
+
105
+ // Timer for checking messages
106
+ setTimeout(async () => {
107
+ this._onMsgTrackTimer(true);
108
+ }, this._msgTrackTimerMs);
109
+
110
+ // HDLC used to encode/decode the RICREST protocol
111
+ this._miniHDLC = new RaftMiniHDLC();
112
+ this._miniHDLC.setOnRxFrame(this._onHDLCFrameDecode.bind(this));
113
+ }
114
+
115
+ registerForResults(msgResultHandler: RaftMessageResult) {
116
+ this._msgResultHandler = msgResultHandler;
117
+ }
118
+
119
+ registerMsgSender(RaftMessageSender: RaftMessageSender) {
120
+ this._msgSender = RaftMessageSender;
121
+ }
122
+
123
+ handleNewRxMsg(rxMsg: Uint8Array): void {
124
+ this._miniHDLC.addRxBytes(rxMsg);
125
+ // RaftLog.verbose(`handleNewRxMsg len ${rxMsg.length} ${RaftUtils.bufferToHex(rxMsg)}`)
126
+ }
127
+
128
+ // This is currently only for testing and simulated channels
129
+ handleNewRxMsgRaw(rxMsg: Uint8Array, rxMsgType: RaftCommsMsgTypeCode, rxMsgNum: number, rxMsgTimeMs: number): void {
130
+ // Check message types
131
+ if (rxMsgType == RaftCommsMsgTypeCode.MSG_TYPE_RESPONSE) {
132
+ // Convert raw Uint8Array to string assuming UTF-8
133
+ const restStr = new TextDecoder('utf-8').decode(rxMsg);
134
+ this._handleResponseMessages(restStr, rxMsgNum);
135
+ } else if (rxMsgType == RaftCommsMsgTypeCode.MSG_TYPE_REPORT) {
136
+ // Convert raw Uint8Array to string assuming UTF-8
137
+ const restStr = new TextDecoder('utf-8').decode(rxMsg);
138
+ this._handleReportMessages(restStr);
139
+ } else {
140
+ this._msgResultHandler?.onRxOtherMsgType(rxMsg, rxMsgTimeMs);
141
+ }
142
+ }
143
+
144
+ reportMsgCallbacksSet(callbackName: string, callback: (report: RaftReportMsg) => Promise<void>): void {
145
+ this._reportMsgCallbacks.set(callbackName, callback);
146
+ }
147
+
148
+ reportMsgCallbacksDelete(callbackName: string) {
149
+ this._reportMsgCallbacks.delete(callbackName);
150
+ }
151
+
152
+ setRawMsgMode(isRawMode: boolean): void {
153
+ this._rawMsgMode = isRawMode;
154
+ RaftLog.debug(`setRawMsgMode ${isRawMode}`);
155
+ }
156
+
157
+ _onHDLCFrameDecode(rxMsg: Uint8Array, frameTimeMs: number): void {
158
+ // Add to stats
159
+ this._commsStats.msgRx();
160
+
161
+ // Validity
162
+ if (rxMsg.length < RICSERIAL_PAYLOAD_POS) {
163
+ this._commsStats.msgTooShort();
164
+ return;
165
+ }
166
+
167
+ // RaftLog.verbose(`_onHDLCFrameDecode len ${rxMsg.length}`);
168
+
169
+ // Decode the RICFrame header
170
+ let rxMsgNum = rxMsg[RICSERIAL_MSG_NUM_POS] & 0xff;
171
+ let rxProtocol = rxMsg[RICSERIAL_PROTOCOL_POS] & 0x3f;
172
+ let rxMsgType = (rxMsg[RICSERIAL_PROTOCOL_POS] >> 6) & 0x03;
173
+
174
+ // Check for RICREST bridging protocol
175
+ if (rxProtocol == RaftCommsMsgProtocol.MSG_PROTOCOL_BRIDGE_RICREST) {
176
+
177
+ // Debug
178
+ const bridgeID = rxMsg.length > RICREST_BRIDGE_ID_POS ? rxMsg[RICREST_BRIDGE_ID_POS] : 0;
179
+ RaftLog.info(
180
+ `_onHDLCFrameDecode RICREST bridge rx bridgeID ${bridgeID} len ${rxMsg.length}`
181
+ );
182
+
183
+ // Simply remove the wrapper
184
+ rxMsg = rxMsg.slice(RICREST_BRIDGE_PAYLOAD_POS);
185
+
186
+ // Get the message info from the unwrapped message
187
+ rxMsgNum = rxMsg[RICSERIAL_MSG_NUM_POS] & 0xff;
188
+ rxProtocol = rxMsg[RICSERIAL_PROTOCOL_POS] & 0x3f;
189
+ rxMsgType = (rxMsg[RICSERIAL_PROTOCOL_POS] >> 6) & 0x03;
190
+ }
191
+
192
+ // Check for RICREST protocol
193
+ if (rxProtocol == RaftCommsMsgProtocol.MSG_PROTOCOL_RICREST) {
194
+ RaftLog.verbose(
195
+ `_onHDLCFrameDecode RICREST rx msgNum ${rxMsgNum} msgDirn ${rxMsgType} ${RaftUtils.bufferToHex(
196
+ rxMsg,
197
+ )}`,
198
+ );
199
+ // Extract payload
200
+ const ricRestElemCode =
201
+ rxMsg[RICSERIAL_PAYLOAD_POS + RICREST_REST_ELEM_CODE_POS] & 0xff;
202
+ if (
203
+ ricRestElemCode == RICRESTElemCode.RICREST_ELEM_CODE_URL ||
204
+ ricRestElemCode == RICRESTElemCode.RICREST_ELEM_CODE_CMDRESPJSON ||
205
+ ricRestElemCode == RICRESTElemCode.RICREST_ELEM_CODE_COMMAND_FRAME
206
+ ) {
207
+ // These are all text-based messages
208
+ const restStr = RaftUtils.getStringFromBuffer(
209
+ rxMsg,
210
+ RICSERIAL_PAYLOAD_POS + RICREST_HEADER_PAYLOAD_POS,
211
+ rxMsg.length - RICSERIAL_PAYLOAD_POS - RICREST_HEADER_PAYLOAD_POS - 1,
212
+ );
213
+ RaftLog.verbose(
214
+ `_onHDLCFrameDecode RICREST rx elemCode ${ricRestElemCode} ${restStr}`,
215
+ );
216
+
217
+ // Check message types
218
+ if (rxMsgType == RaftCommsMsgTypeCode.MSG_TYPE_RESPONSE) {
219
+
220
+ // Handle response messages
221
+ this._handleResponseMessages(restStr, rxMsgNum);
222
+
223
+ } else if (rxMsgType == RaftCommsMsgTypeCode.MSG_TYPE_REPORT) {
224
+
225
+ // Handle report messages
226
+ this._handleReportMessages(restStr);
227
+
228
+ }
229
+
230
+ } else {
231
+ const binMsgLen = rxMsg.length - RICSERIAL_PAYLOAD_POS - RICREST_HEADER_PAYLOAD_POS;
232
+ RaftLog.verbose(
233
+ `_onHDLCFrameDecode RICREST rx binary message elemCode ${ricRestElemCode} len ${binMsgLen} data ${RaftUtils.bufferToHex(rxMsg)}`,
234
+ );
235
+ if (ricRestElemCode == RICRESTElemCode.RICREST_ELEM_CODE_FILEBLOCK) {
236
+ const filePos = RaftUtils.getBEUint32FromBuf(rxMsg, RICSERIAL_PAYLOAD_POS + RICREST_HEADER_PAYLOAD_POS + RICREST_FILEBLOCK_FILEPOS_POS);
237
+ this._msgResultHandler?.onRxFileBlock(
238
+ filePos,
239
+ rxMsg.slice(RICSERIAL_PAYLOAD_POS + RICREST_HEADER_PAYLOAD_POS + RICREST_FILEBLOCK_PAYLOAD_POS, rxMsg.length));
240
+ }
241
+ }
242
+
243
+ // Other message types
244
+ } else {
245
+ this._msgResultHandler?.onRxOtherMsgType(rxMsg, frameTimeMs);
246
+ }
247
+ }
248
+
249
+ _handleResponseMessages(restStr: string, rxMsgNum: number): void {
250
+ try {
251
+ let msgRsltCode = RaftMsgResultCode.MESSAGE_RESULT_UNKNOWN;
252
+ const msgRsltJsonObj = JSON.parse(restStr);
253
+ if ('rslt' in msgRsltJsonObj) {
254
+ const rsltStr = msgRsltJsonObj.rslt.toLowerCase();
255
+ if (rsltStr === 'ok') {
256
+ RaftLog.verbose(
257
+ `_handleResponseMessages RICREST rslt Ok ${rxMsgNum == 0 ? "unnumbered" : "msgNum " + rxMsgNum.toString()} resp ${msgRsltJsonObj.rslt}`,
258
+ );
259
+ msgRsltCode = RaftMsgResultCode.MESSAGE_RESULT_OK;
260
+ } else if (rsltStr === 'fail') {
261
+ msgRsltCode = RaftMsgResultCode.MESSAGE_RESULT_FAIL;
262
+ RaftLog.warn(
263
+ `_handleResponseMessages RICREST rslt fail ${rxMsgNum == 0 ? "unnumbered" : "msgNum " + rxMsgNum.toString()} resp ${restStr}`,
264
+ );
265
+ } else {
266
+ RaftLog.warn(
267
+ `_handleResponseMessages RICREST rslt not recognized ${rxMsgNum == 0 ? "unnumbered" : "msgNum " + rxMsgNum.toString()}resp ${restStr}`,
268
+ );
269
+ }
270
+
271
+ } else {
272
+ RaftLog.warn(
273
+ `_handleResponseMessages RICREST response doesn't contain rslt ${rxMsgNum == 0 ? "unnumbered" : "msgNum " + rxMsgNum.toString()}resp ${restStr}`,
274
+ );
275
+ }
276
+
277
+ // Handle matching of request and response
278
+ this.msgTrackingRxRespMsg(rxMsgNum, msgRsltCode, msgRsltJsonObj);
279
+
280
+ } catch (excp: unknown) {
281
+ if (excp instanceof Error) {
282
+ RaftLog.warn(
283
+ `_handleResponseMessages Failed to parse JSON ${rxMsgNum == 0 ? "unnumbered" : "msgNum " + rxMsgNum.toString()} JSON STR ${restStr} resp ${excp.toString()}`,
284
+ );
285
+ }
286
+ }
287
+
288
+ }
289
+
290
+ _handleReportMessages(restStr: string): void {
291
+ try {
292
+ const reportMsg: RaftReportMsg = JSON.parse(restStr);
293
+ reportMsg.timeReceived = Date.now();
294
+ RaftLog.debug(`_handleReportMessages ${JSON.stringify(reportMsg)}`);
295
+ this._reportMsgCallbacks.forEach(async (callback) => await callback(reportMsg));
296
+ } catch (excp: unknown) {
297
+ if (excp instanceof Error) {
298
+ RaftLog.warn(
299
+ `_handleReportMessages Failed to parse JSON report ${excp.toString()}`,
300
+ );
301
+ }
302
+ }
303
+ }
304
+
305
+ async sendRICRESTURL<T>(
306
+ cmdStr: string,
307
+ bridgeID: number | undefined = undefined,
308
+ msgTimeoutMs: number | undefined = undefined,
309
+ ): Promise<T> {
310
+ // Send
311
+ return this.sendRICREST(
312
+ cmdStr,
313
+ RICRESTElemCode.RICREST_ELEM_CODE_URL,
314
+ bridgeID,
315
+ msgTimeoutMs,
316
+ );
317
+ }
318
+
319
+ async sendRICRESTCmdFrame<T>(
320
+ cmdStr: string,
321
+ bridgeID: number | undefined = undefined,
322
+ msgTimeoutMs: number | undefined = undefined,
323
+ ): Promise<T> {
324
+ // Send
325
+ return this.sendRICREST(
326
+ cmdStr,
327
+ RICRESTElemCode.RICREST_ELEM_CODE_COMMAND_FRAME,
328
+ bridgeID,
329
+ msgTimeoutMs,
330
+ );
331
+ }
332
+
333
+ async sendRICREST<T>(
334
+ cmdStr: string,
335
+ ricRESTElemCode: RICRESTElemCode,
336
+ bridgeID: number | undefined = undefined,
337
+ msgTimeoutMs: number | undefined = undefined,
338
+ ): Promise<T> {
339
+ // Put cmdStr into buffer
340
+ const cmdStrTerm = new Uint8Array(cmdStr.length + 1);
341
+ RaftUtils.addStringToBuffer(cmdStrTerm, cmdStr, 0);
342
+ cmdStrTerm[cmdStrTerm.length - 1] = 0;
343
+
344
+ // Send
345
+ return this.sendRICRESTBytes(
346
+ cmdStrTerm,
347
+ ricRESTElemCode,
348
+ true,
349
+ bridgeID,
350
+ msgTimeoutMs,
351
+ );
352
+ }
353
+
354
+ async sendRICRESTNoResp(
355
+ cmdStr: string,
356
+ ricRESTElemCode: RICRESTElemCode,
357
+ bridgeID: number | undefined = undefined,
358
+ ): Promise<boolean> {
359
+
360
+ // Check there is a sender
361
+ if (!this._msgSender) {
362
+ return false;
363
+ }
364
+
365
+ // Check for raw message mode (used for testing and simulated channels)
366
+ if (this._rawMsgMode) {
367
+ return this._msgSender.sendTxMsgRaw(cmdStr);
368
+ }
369
+
370
+ // Put cmdStr into buffer
371
+ const cmdBytes = new Uint8Array(cmdStr.length + 1);
372
+ RaftUtils.addStringToBuffer(cmdBytes, cmdStr, 0);
373
+ cmdBytes[cmdBytes.length - 1] = 0;
374
+
375
+ // Form message
376
+ const cmdMsg = new Uint8Array(cmdBytes.length + RICREST_HEADER_PAYLOAD_POS);
377
+ cmdMsg[RICREST_REST_ELEM_CODE_POS] = ricRESTElemCode;
378
+ cmdMsg.set(cmdBytes, RICREST_HEADER_PAYLOAD_POS);
379
+
380
+ // Frame the message
381
+ let framedMsg = this.frameCommsMsg(cmdMsg,
382
+ RaftCommsMsgTypeCode.MSG_TYPE_COMMAND,
383
+ RaftCommsMsgProtocol.MSG_PROTOCOL_RICREST,
384
+ true);
385
+
386
+ // Wrap if bridged
387
+ if (bridgeID !== undefined) {
388
+ framedMsg = this.bridgeCommsMsg(framedMsg, bridgeID);
389
+ }
390
+
391
+ // Encode like HDLC
392
+ const encodedMsg = this._miniHDLC.encode(framedMsg);
393
+
394
+ // Send
395
+ if (!await this._msgSender.sendTxMsg(encodedMsg, false)) {
396
+ RaftLog.warn(`sendRICRESTNoResp failed to send message`);
397
+ this._commsStats.recordMsgNoConnection();
398
+ }
399
+
400
+ return true;
401
+ }
402
+
403
+ async sendRICRESTBytes<T>(
404
+ cmdBytes: Uint8Array,
405
+ ricRESTElemCode: RICRESTElemCode,
406
+ withResponse: boolean,
407
+ bridgeID: number | undefined = undefined,
408
+ msgTimeoutMs: number | undefined = undefined,
409
+ ): Promise<T> {
410
+ // Form message
411
+ const cmdMsg = new Uint8Array(cmdBytes.length + RICREST_HEADER_PAYLOAD_POS);
412
+ cmdMsg[RICREST_REST_ELEM_CODE_POS] = ricRESTElemCode;
413
+ cmdMsg.set(cmdBytes, RICREST_HEADER_PAYLOAD_POS);
414
+
415
+ // Send
416
+ return this.sendMsgAndWaitForReply<T>(
417
+ cmdMsg,
418
+ RaftCommsMsgTypeCode.MSG_TYPE_COMMAND,
419
+ RaftCommsMsgProtocol.MSG_PROTOCOL_RICREST,
420
+ withResponse,
421
+ bridgeID,
422
+ msgTimeoutMs,
423
+ );
424
+ }
425
+
426
+ async sendMsgAndWaitForReply<T>(
427
+ msgPayload: Uint8Array,
428
+ msgDirection: RaftCommsMsgTypeCode,
429
+ msgProtocol: RaftCommsMsgProtocol,
430
+ withResponse: boolean,
431
+ bridgeID: number | undefined = undefined,
432
+ msgTimeoutMs: number | undefined,
433
+ ): Promise<T> {
434
+
435
+ // Check there is a sender
436
+ if (!this._msgSender) {
437
+ throw new Error('sendMsgAndWaitForReply failed no sender');
438
+ }
439
+
440
+ // Check for raw message mode (used for testing and simulated channels)
441
+ if (this._rawMsgMode) {
442
+ return this._msgSender.sendTxMsgRawAndWaitForReply(msgPayload);
443
+ }
444
+
445
+ // Frame the message
446
+ let framedMsg = this.frameCommsMsg(msgPayload, msgDirection, msgProtocol, true);
447
+
448
+ // Wrap if bridged
449
+ if (bridgeID !== undefined) {
450
+ framedMsg = this.bridgeCommsMsg(framedMsg, bridgeID);
451
+ // RaftLog.debug(`sendMsgAndWaitForReply - bridged idx ${bridgeID}`)
452
+ } else {
453
+ // RaftLog.debug(`sendMsgAndWaitForReply - not bridged`)
454
+ }
455
+
456
+ // Encode like HDLC
457
+ const encodedMsg = this._miniHDLC.encode(framedMsg);
458
+
459
+ // Debug
460
+ // RaftLog.debug(
461
+ // `sendMsgAndWaitForReply ${RaftUtils.bufferToHex(encodedMsg)}`,
462
+ // );
463
+
464
+ // Return a promise that will be resolved when a reply is received or timeout occurs
465
+ const promise = new Promise<T>((resolve, reject) => {
466
+
467
+ // Update message tracking
468
+ this.msgTrackingTxCmdMsg<T>(
469
+ encodedMsg,
470
+ withResponse,
471
+ bridgeID,
472
+ msgTimeoutMs,
473
+ resolve,
474
+ reject,
475
+ );
476
+ this._currentMsgHandle++;
477
+ });
478
+
479
+ return promise;
480
+ }
481
+
482
+ frameCommsMsg(
483
+ msgPayload: Uint8Array,
484
+ msgDirection: RaftCommsMsgTypeCode,
485
+ msgProtocol: RaftCommsMsgProtocol,
486
+ isNumbered: boolean,
487
+ ): Uint8Array {
488
+ // Header
489
+ const msgBuf = new Uint8Array(
490
+ msgPayload.length + RICSERIAL_PAYLOAD_POS,
491
+ );
492
+ msgBuf[RICSERIAL_MSG_NUM_POS] = isNumbered ? this._currentMsgNumber & 0xff : 0;
493
+ msgBuf[RICSERIAL_PROTOCOL_POS] = (msgDirection << 6) + msgProtocol;
494
+
495
+ // Payload
496
+ msgBuf.set(msgPayload, RICSERIAL_PAYLOAD_POS);
497
+
498
+ // Return framed message
499
+ return msgBuf;
500
+ }
501
+
502
+ bridgeCommsMsg(
503
+ msgBuf: Uint8Array,
504
+ bridgeID: number
505
+ ) {
506
+ //
507
+ const bridgedMsg = new Uint8Array(msgBuf.length + RICREST_BRIDGE_PAYLOAD_POS);
508
+
509
+ // Bridged messages are unnumbered (msgNum == 0)
510
+ bridgedMsg[RICSERIAL_MSG_NUM_POS] = 0;
511
+ bridgedMsg[RICSERIAL_PROTOCOL_POS] = (RaftCommsMsgTypeCode.MSG_TYPE_COMMAND << 6) + RaftCommsMsgProtocol.MSG_PROTOCOL_BRIDGE_RICREST;
512
+ bridgedMsg[RICREST_BRIDGE_ID_POS] = bridgeID;
513
+ bridgedMsg.set(msgBuf, RICREST_BRIDGE_PAYLOAD_POS);
514
+ return bridgedMsg;
515
+ }
516
+
517
+ msgTrackingTxCmdMsg<T>(
518
+ msgFrame: Uint8Array,
519
+ withResponse: boolean,
520
+ bridgeID: number | undefined = undefined,
521
+ msgTimeoutMs: number | undefined,
522
+ resolve: (arg: T) => void,
523
+ reject: (reason: Error) => void,
524
+ ): void {
525
+ // Record message re-use of number
526
+ if (this._msgTrackInfos[this._currentMsgNumber].msgOutstanding) {
527
+ this._commsStats.recordMsgNumCollision();
528
+ }
529
+ // Set tracking info
530
+ this._msgTrackInfos[this._currentMsgNumber].set(
531
+ true,
532
+ msgFrame,
533
+ withResponse,
534
+ bridgeID,
535
+ this._currentMsgHandle,
536
+ msgTimeoutMs,
537
+ resolve,
538
+ reject,
539
+ );
540
+
541
+ // Debug
542
+ RaftLog.debug(
543
+ `msgTrackingTxCmdMsg msgNum ${this._currentMsgNumber} bridgeID ${bridgeID} msg ${RaftUtils.bufferToHex(msgFrame)} msgOutstanding ${this._msgTrackInfos[this._currentMsgNumber].msgOutstanding
544
+ }`,
545
+ );
546
+
547
+ // Stats
548
+ this._commsStats.msgTx();
549
+
550
+ // Bump msg number
551
+ if (this._currentMsgNumber == RaftMsgTrackInfo.MAX_MSG_NUM) {
552
+ this._currentMsgNumber = 1;
553
+ } else {
554
+ this._currentMsgNumber++;
555
+ }
556
+ }
557
+
558
+ msgTrackingRxRespMsg(
559
+ msgNum: number,
560
+ msgRsltCode: RaftMsgResultCode,
561
+ msgRsltJsonObj: object,
562
+ ) {
563
+ // Check message number
564
+ if (msgNum == 0) {
565
+ // Callback on unnumbered message
566
+ if (this._msgResultHandler !== null)
567
+ this._msgResultHandler.onRxUnnumberedMsg(msgRsltJsonObj);
568
+ return;
569
+ }
570
+ if (msgNum > RaftMsgTrackInfo.MAX_MSG_NUM) {
571
+ RaftLog.warn('msgTrackingRxRespMsg msgNum > 255');
572
+ return;
573
+ }
574
+ if (!this._msgTrackInfos[msgNum].msgOutstanding) {
575
+ RaftLog.warn(`msgTrackingRxRespMsg unmatched msgNum ${msgNum}`);
576
+ this._commsStats.recordMsgNumUnmatched();
577
+ return;
578
+ }
579
+
580
+ // Handle message
581
+ RaftLog.verbose(
582
+ `msgTrackingRxRespMsg Message response received msgNum ${msgNum}`,
583
+ );
584
+ this._commsStats.recordMsgResp(
585
+ Date.now() - this._msgTrackInfos[msgNum].msgSentMs,
586
+ );
587
+ this._msgCompleted(msgNum, msgRsltCode, msgRsltJsonObj);
588
+ }
589
+
590
+ _msgCompleted(
591
+ msgNum: number,
592
+ msgRsltCode: RaftMsgResultCode,
593
+ msgRsltObj: object | null,
594
+ ) {
595
+
596
+ // Lookup message in tracking
597
+ const msgHandle = this._msgTrackInfos[msgNum].msgHandle;
598
+ this._msgTrackInfos[msgNum].msgOutstanding = false;
599
+
600
+ // Check if message result handler should be informed
601
+ if (this._msgResultHandler !== null) {
602
+ this._msgResultHandler.onRxReply(msgHandle, msgRsltCode, msgRsltObj);
603
+ }
604
+
605
+ // Handle reply
606
+ // if (msgRsltCode === RaftMsgResultCode.MESSAGE_RESULT_OK) {
607
+ const resolve = this._msgTrackInfos[msgNum].resolve;
608
+ if (resolve) {
609
+ RaftLog.verbose(`_msgCompleted msgNum ${msgNum} result ${msgRsltCode.toString()} ${JSON.stringify(msgRsltObj)}`);
610
+ (resolve as ((arg: object | null) => void))(msgRsltObj);
611
+ }
612
+ // } else {
613
+ // const reject = this._msgTrackInfos[msgNum].reject;
614
+ // if (reject) {
615
+ // // eslint-disable-next-line @typescript-eslint/no-explicit-any
616
+ // try {
617
+ // RaftLog.debug(`_msgCompleted reject rsltCode ${msgRsltCode}`);
618
+ // // (reject as any)(new Error(`Message failed msgNum ${msgNum} rslt ${msgRsltCode}`));
619
+ // } catch (excp: unknown) {
620
+ // RaftLog.warn(`_msgCompleted reject ${excp}`);
621
+ // }
622
+ // }
623
+ // }
624
+
625
+ // No longer waiting for reply
626
+ this._msgTrackInfos[msgNum].resolve = null;
627
+ this._msgTrackInfos[msgNum].reject = null;
628
+ }
629
+
630
+ // Check message timeouts
631
+ async _onMsgTrackTimer(chainRecall: boolean): Promise<void> {
632
+
633
+ if (this._msgSender !== null) {
634
+ // Handle message tracking
635
+ for (let loopIdx = 0; loopIdx < this._msgTrackInfos.length; loopIdx++) {
636
+
637
+ // Index to check
638
+ const checkIdx = this._msgTrackLastCheckIdx;
639
+ this._msgTrackLastCheckIdx = (checkIdx + 1) % this._msgTrackInfos.length;
640
+
641
+ // Check if message is outstanding
642
+ if (!this._msgTrackInfos[checkIdx].msgOutstanding) continue;
643
+
644
+ // Get message timeout and ensure valid
645
+ let msgTimeoutMs = this._msgTrackInfos[checkIdx].msgTimeoutMs;
646
+ if (msgTimeoutMs === undefined) {
647
+ msgTimeoutMs = RaftMsgTrackInfo.MSG_RESPONSE_TIMEOUT_MS;
648
+ }
649
+
650
+ // Check for timeout (or never sent)
651
+ if ((this._msgTrackInfos[checkIdx].retryCount === 0) || (Date.now() > this._msgTrackInfos[checkIdx].msgSentMs + (msgTimeoutMs * (this._msgTrackInfos[checkIdx].retryCount)))) {
652
+
653
+ // Debug
654
+ RaftLog.verbose(`msgTrackTimer msgNum ${checkIdx} ${this._msgTrackInfos[checkIdx].retryCount === 0 ? 'first send' : 'timeout - retrying'} ${RaftUtils.bufferToHex(this._msgTrackInfos[checkIdx].msgFrame)}`);
655
+ // RaftLog.verbose(`msgTrackTimer msg ${RaftUtils.bufferToHex(this._msgTrackInfos[i].msgFrame)}`);
656
+
657
+ // Handle timeout (or first send)
658
+ if (this._msgTrackInfos[checkIdx].retryCount < RaftMsgTrackInfo.MSG_RETRY_COUNT) {
659
+ this._msgTrackInfos[checkIdx].retryCount++;
660
+ try {
661
+
662
+ // Send the message
663
+ if (!await this._msgSender.sendTxMsg(
664
+ this._msgTrackInfos[checkIdx].msgFrame,
665
+ this._msgTrackInfos[checkIdx].withResponse)) {
666
+ RaftLog.warn(`msgTrackTimer Message send failed msgNum ${checkIdx} ${RaftUtils.bufferToHex(this._msgTrackInfos[checkIdx].msgFrame)}`);
667
+ this._msgCompleted(checkIdx, RaftMsgResultCode.MESSAGE_RESULT_FAIL, null);
668
+ this._commsStats.recordMsgNoConnection();
669
+ }
670
+
671
+ // Message sent ok so break here
672
+ break;
673
+
674
+ } catch (error: unknown) {
675
+ RaftLog.warn(`Retry message failed ${error}`);
676
+ }
677
+ this._commsStats.recordMsgRetry();
678
+ this._msgTrackInfos[checkIdx].msgSentMs = Date.now();
679
+ } else {
680
+ RaftLog.warn(
681
+ `msgTrackTimer TIMEOUT msgNum ${checkIdx} after ${RaftMsgTrackInfo.MSG_RETRY_COUNT} retries ${RaftUtils.bufferToHex(this._msgTrackInfos[checkIdx].msgFrame)}`,
682
+ );
683
+ this._msgCompleted(checkIdx, RaftMsgResultCode.MESSAGE_RESULT_TIMEOUT, null);
684
+ this._commsStats.recordMsgTimeout();
685
+ }
686
+ }
687
+ }
688
+ }
689
+
690
+ // Call again if required
691
+ if (chainRecall) {
692
+ setTimeout(async () => {
693
+ this._onMsgTrackTimer(true);
694
+ }, this._msgTrackTimerMs);
695
+ }
696
+ }
697
+
698
+ encodeFileStreamBlock(blockContents: Uint8Array,
699
+ blockStart: number,
700
+ streamID: number): Uint8Array {
701
+ // Create entire message buffer (including protocol wrappers)
702
+ const msgBuf = new Uint8Array(
703
+ blockContents.length + 4 + RICREST_HEADER_PAYLOAD_POS + RICSERIAL_PAYLOAD_POS,
704
+ );
705
+ let msgBufPos = 0;
706
+
707
+ // RICSERIAL protocol
708
+ msgBuf[msgBufPos++] = 0; // not numbered
709
+ msgBuf[msgBufPos++] =
710
+ (RaftCommsMsgTypeCode.MSG_TYPE_COMMAND << 6) +
711
+ RaftCommsMsgProtocol.MSG_PROTOCOL_RICREST;
712
+
713
+ // RICREST protocol
714
+ msgBuf[msgBufPos++] = RICRESTElemCode.RICREST_ELEM_CODE_FILEBLOCK;
715
+
716
+ // Header
717
+ msgBuf[msgBufPos++] = streamID & 0xff;
718
+ msgBuf[msgBufPos++] = (blockStart >> 16) & 0xff;
719
+ msgBuf[msgBufPos++] = (blockStart >> 8) & 0xff;
720
+ msgBuf[msgBufPos++] = blockStart & 0xff;
721
+
722
+ // Copy block info
723
+ msgBuf.set(blockContents, msgBufPos);
724
+ return msgBuf;
725
+ }
726
+
727
+ async sendFileBlock(
728
+ blockContents: Uint8Array,
729
+ blockStart: number
730
+ ): Promise<boolean> {
731
+ const msgBuf = this.encodeFileStreamBlock(blockContents, blockStart, 0);
732
+
733
+ // // Debug
734
+ // RaftLog.debug(
735
+ // `sendFileBlock frameLen ${msgBuf.length} start ${blockStart} end ${blockEnd} len ${blockLen}`,
736
+ // );
737
+
738
+ // Send
739
+ try {
740
+ // Send
741
+ if (this._msgSender) {
742
+
743
+ // Wrap into HDLC
744
+ const framedMsg = this._miniHDLC.encode(msgBuf);
745
+
746
+ // Send
747
+ return this._msgSender.sendTxMsg(
748
+ framedMsg,
749
+ true,
750
+ // Platform.OS === 'ios',
751
+ );
752
+ }
753
+ } catch (error: unknown) {
754
+ RaftLog.warn(`RaftMsgHandler sendFileBlock error${error}`);
755
+ }
756
+ return false;
757
+ }
758
+
759
+ async sendStreamBlock(
760
+ blockContents: Uint8Array,
761
+ blockStart: number,
762
+ streamID: number,
763
+ ): Promise<boolean> {
764
+
765
+ // Ensure any waiting messages are sent first
766
+ await this._onMsgTrackTimer(false);
767
+
768
+ // Encode message
769
+ const msgBuf = this.encodeFileStreamBlock(blockContents, blockStart, streamID);
770
+
771
+ // // Debug
772
+ // RaftLog.debug(
773
+ // `sendStreamBlock frameLen ${msgBuf.length} start ${blockStart} end ${blockEnd} len ${blockLen}`,
774
+ // );
775
+
776
+ // Send
777
+ try {
778
+ // Send
779
+ if (this._msgSender) {
780
+
781
+ // Wrap into HDLC
782
+ const framedMsg = this._miniHDLC.encode(msgBuf);
783
+
784
+ // Send
785
+ return await this._msgSender.sendTxMsg(
786
+ framedMsg,
787
+ true,
788
+ // Platform.OS === 'ios',
789
+ );
790
+ }
791
+ } catch (error: unknown) {
792
+ RaftLog.warn(`RaftMsgHandler sendStreamBlock error${error}`);
793
+ }
794
+ return false;
795
+ }
796
+
797
+ async createCommsBridge(bridgeSource: string, bridgeName: string, idleCloseSecs = 0): Promise<RaftBridgeSetupResp> {
798
+
799
+ // Establish a bridge
800
+ return await this.sendRICRESTURL<RaftBridgeSetupResp>(
801
+ `commandserial/bridge/setup?port=${bridgeSource}&name=${bridgeName}&idleCloseSecs=${idleCloseSecs}`,
802
+ )
803
+ }
804
+
805
+ async removeCommsBridge(bridgeID: number): Promise<boolean> {
806
+
807
+ // Remove a bridge
808
+ return await this.sendRICRESTURL<boolean>(
809
+ `commandserial/bridge/remove?id=${bridgeID}`,
810
+ )
811
+ }
812
+ }