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