* Parses a Modbus response frame into an array of values. * * @param {Uint8Array|Array} frame - Binary Modbus ADU (no CRC) * @returns {Array} Parsed values array for Serial Studio * * Frame Structure: * Byte 0: Slave/Unit address (1-247) * Byte 1: Function code (1-127) or Exception (1
(frame)
| 163 | * Byte 2+: Data payload (varies by function) |
| 164 | */ |
| 165 | function parse(frame) { |
| 166 | frameCount++; |
| 167 | |
| 168 | if (!frame || frame.length < 3) { |
| 169 | debugLog("Frame too short: " + (frame ? frame.length : 0) + " bytes"); |
| 170 | return parsedValues; |
| 171 | } |
| 172 | |
| 173 | var slaveAddress = frame[0]; |
| 174 | var functionCode = frame[1]; |
| 175 | |
| 176 | debugLog("Frame #" + frameCount + ": Slave=" + slaveAddress + |
| 177 | " FC=0x" + functionCode.toString(16) + " Len=" + frame.length); |
| 178 | |
| 179 | //---------------------------------------------------------------------------- |
| 180 | // Exception Response (FC >= 0x80) |
| 181 | //---------------------------------------------------------------------------- |
| 182 | if (functionCode >= 0x80) { |
| 183 | var originalFC = functionCode & 0x7F; |
| 184 | var exceptionCode = frame[2]; |
| 185 | var exception = MODBUS_EXCEPTIONS[exceptionCode] || { name: "UNKNOWN", desc: "Unknown exception" }; |
| 186 | |
| 187 | lastException = { |
| 188 | functionCode: originalFC, |
| 189 | exceptionCode: exceptionCode, |
| 190 | name: exception.name, |
| 191 | description: exception.desc, |
| 192 | timestamp: Date.now() |
| 193 | }; |
| 194 | |
| 195 | console.log("[Modbus Exception] FC=0x" + originalFC.toString(16) + |
| 196 | " Error=0x" + exceptionCode.toString(16) + |
| 197 | " (" + exception.name + ": " + exception.desc + ")"); |
| 198 | |
| 199 | return parsedValues; |
| 200 | } |
| 201 | |
| 202 | //---------------------------------------------------------------------------- |
| 203 | // Read Coils (0x01) / Read Discrete Inputs (0x02) |
| 204 | //---------------------------------------------------------------------------- |
| 205 | if (functionCode === 0x01 || functionCode === 0x02) { |
| 206 | var byteCount = frame[2]; |
| 207 | var bitIndex = 0; |
| 208 | |
| 209 | debugLog("Reading " + (byteCount * 8) + " bits"); |
| 210 | |
| 211 | for (var byteIdx = 0; byteIdx < byteCount && bitIndex < CONFIG.numItems; byteIdx++) { |
| 212 | var dataByte = frame[3 + byteIdx]; |
| 213 | for (var bit = 0; bit < 8 && bitIndex < CONFIG.numItems; bit++) |
| 214 | parsedValues[bitIndex++] = (dataByte >> bit) & 0x01; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | //---------------------------------------------------------------------------- |
| 219 | // Read Holding Registers (0x03) / Read Input Registers (0x04) |
| 220 | //---------------------------------------------------------------------------- |
| 221 | else if (functionCode === 0x03 || functionCode === 0x04) { |
| 222 | var byteCount = frame[2]; |
no test coverage detected