#include "plugins/protocols/modbus_rtu/codec/ModbusRtuCodec.h" #include #include "plugins/protocols/modbus_rtu/framer/ModbusRtuFraming.h" namespace softbus::message_bus::pipeline::protocol { namespace { using softbus::core::models::BusDirection; using softbus::message_bus::pipeline::protocol::modbusrtu::crc16; using softbus::message_bus::pipeline::protocol::modbusrtu::crcOk; void appendCrcLe(QByteArray& adu) { const auto crc = crc16(reinterpret_cast(adu.constData()), static_cast(adu.size())); adu.append(static_cast(crc & 0xFF)); adu.append(static_cast((crc >> 8) & 0xFF)); } } // namespace // 功能 :解码Modbus RTU帧 如果解码失败 则返回false 如果解码成功 则返回true bool decodeModbusRtu(BusDirection dir, const std::uint8_t* p, std::size_t n, ModbusRtuPdu& out, QString* errMsg) { auto fail = [&](const char* msg) { if (errMsg) { *errMsg = QString::fromUtf8(msg); } return false; }; if (!p || n < 4) { return fail("adu_too_short"); } if (p[1] & 0x80) { if (n < 5) { return fail("exception_incomplete"); } if (!crcOk(p, 5)) { return fail("exception_crc"); } out = ModbusExceptionPdu{p[0], p[1], p[2]}; return true; } const std::uint8_t unit = p[0]; const std::uint8_t fc = p[1]; auto parseReadReq = [&]() -> bool { if (n != 8 || !crcOk(p, 8)) { return false; } const std::uint16_t addr = static_cast((p[2] << 8) | p[3]); const std::uint16_t qty = static_cast((p[4] << 8) | p[5]); switch (fc) { case 0x01: out = ReadCoilsRequest{unit, addr, qty}; return true; case 0x02: out = ReadDiscreteInputsRequest{unit, addr, qty}; return true; case 0x03: out = ReadHoldingRegistersRequest{unit, addr, qty}; return true; case 0x04: out = ReadInputRegistersRequest{unit, addr, qty}; return true; default: return false; } }; auto parseWriteSingleReqOrResp = [&]() -> bool { if (n != 8 || !crcOk(p, 8)) { return false; } const std::uint16_t addr = static_cast((p[2] << 8) | p[3]); const std::uint16_t val16 = static_cast((p[4] << 8) | p[5]); if (fc == 0x05) { const std::uint8_t coil = (val16 == 0xFF00) ? 1 : 0; if (dir == BusDirection::Upstream) { out = WriteSingleCoilResponse{unit, addr, coil}; } else { out = WriteSingleCoilRequest{unit, addr, coil}; } return true; } if (fc == 0x06) { if (dir == BusDirection::Upstream) { out = WriteSingleRegisterResponse{unit, addr, val16}; } else { out = WriteSingleRegisterRequest{unit, addr, val16}; } return true; } return false; }; auto parseWriteMultiReq = [&]() -> bool { if (n < 9) { return false; } const std::uint16_t start = static_cast((p[2] << 8) | p[3]); const std::uint16_t qty = static_cast((p[4] << 8) | p[5]); const std::uint8_t byteCount = p[6]; if (n != static_cast(9) + byteCount) { return false; } if (!crcOk(p, n)) { return false; } if (fc == 0x0F) { QVector vals; vals.reserve(byteCount); for (std::uint8_t i = 0; i < byteCount; ++i) { vals.append(p[7 + i]); } out = WriteMultipleCoilsRequest{unit, start, qty, std::move(vals)}; return true; } if (fc == 0x10) { QVector vals; vals.reserve(byteCount / 2); for (std::uint8_t i = 0; i + 1 < byteCount; i += 2) { vals.append(static_cast((p[7 + i] << 8) | p[7 + i + 1])); } out = WriteMultipleRegistersRequest{unit, start, qty, std::move(vals)}; return true; } return false; }; auto parseWriteMultiResp = [&]() -> bool { if (n != 8 || !crcOk(p, 8)) { return false; } const std::uint16_t start = static_cast((p[2] << 8) | p[3]); const std::uint16_t qty = static_cast((p[4] << 8) | p[5]); if (fc == 0x0F) { out = WriteMultipleCoilsResponse{unit, start, qty, {}}; return true; } if (fc == 0x10) { out = WriteMultipleRegistersResponse{unit, start, qty, {}}; return true; } return false; }; // 功能 :解析Modbus的读取响应帧 // function code range 01 02 03 04 auto parseReadResp = [&]() -> bool { if (n < 5) { return false; } const std::uint8_t bc = p[2]; const std::size_t total = static_cast(5) + bc; if (n < total || !crcOk(p, total)) { return false; } if (fc == 0x01) { QVector coils; coils.reserve(bc); for (std::uint8_t i = 0; i < bc; ++i) { coils.append(p[3 + i]); } out = ReadCoilsResponse{unit, std::move(coils)}; return true; } if (fc == 0x02) { QVector inputs; inputs.reserve(bc); for (std::uint8_t i = 0; i < bc; ++i) { inputs.append(p[3 + i]); } out = ReadDiscreteInputsResponse{unit, std::move(inputs)}; return true; } if (fc == 0x03 || fc == 0x04) { QVector regs; regs.reserve(bc / 2); for (std::uint8_t i = 0; i + 1 < bc; i += 2) { regs.append(static_cast((p[3 + i] << 8) | p[3 + i + 1])); } if (fc == 0x03) { out = ReadHoldingRegistersResponse{unit, std::move(regs)}; } else { out = ReadInputRegistersResponse{unit, std::move(regs)}; } return true; } return false; }; // if (dir == BusDirection::Downstream) { // // 功能 :解析Modbus的下行请求帧 // // function code range 01 02 03 04 05 06 0F 10 // if (parseReadReq() || parseWriteSingleReqOrResp() || parseWriteMultiReq()) { // return true; // } // out = ModbusRtuUnsupportedPdu{unit, fc}; // return true; // } // if (dir == BusDirection::Upstream) { // // 功能 :解析Modbus的上行响应帧 // // function code range 01 02 03 04 05 06 0F 10 // if (parseReadResp() || parseWriteSingleReqOrResp() || parseWriteMultiResp()) { // return true; // } // // 功能 :解析Modbus的下行请求帧 // if (parseReadReq() || parseWriteMultiReq()) { // return true; // } // out = ModbusRtuUnsupportedPdu{unit, fc}; // return true; // } if (parseReadReq() || parseWriteSingleReqOrResp() || parseWriteMultiReq() || parseReadResp() || parseWriteMultiResp()) { return true; } out = ModbusRtuUnsupportedPdu{unit, fc}; return true; } bool encodeModbusRtu(const ModbusRtuPdu& pdu, QByteArray& out, QString* errMsg) { auto fail = [&](const char* msg) { if (errMsg) { *errMsg = QString::fromUtf8(msg); } return false; }; out.clear(); if (const auto* ex = std::get_if(&pdu)) { out.append(static_cast(ex->unitId)); out.append(static_cast(ex->function)); out.append(static_cast(ex->exceptionCode)); appendCrcLe(out); return true; } auto encodeReadReq = [&](std::uint8_t unit, std::uint8_t fc, std::uint16_t start, std::uint16_t qty) { out.append(static_cast(unit)); out.append(static_cast(fc)); out.append(static_cast((start >> 8) & 0xFF)); out.append(static_cast(start & 0xFF)); out.append(static_cast((qty >> 8) & 0xFF)); out.append(static_cast(qty & 0xFF)); appendCrcLe(out); return true; }; auto encodeReadRegResp = [&](std::uint8_t unit, std::uint8_t fc, const QVector& regs) { if (regs.size() > 127) { return false; } out.append(static_cast(unit)); out.append(static_cast(fc)); out.append(static_cast(regs.size() * 2)); for (std::uint16_t v : regs) { out.append(static_cast((v >> 8) & 0xFF)); out.append(static_cast(v & 0xFF)); } appendCrcLe(out); return true; }; auto encodeReadBitsResp = [&](std::uint8_t unit, std::uint8_t fc, const QVector& bytes) { if (bytes.size() > 255) { return false; } out.append(static_cast(unit)); out.append(static_cast(fc)); out.append(static_cast(bytes.size())); for (std::uint8_t b : bytes) { out.append(static_cast(b)); } appendCrcLe(out); return true; }; if (const auto* req = std::get_if(&pdu)) { return encodeReadReq(req->unitId, 0x01, req->startAddress, req->quantity); } if (const auto* req = std::get_if(&pdu)) { return encodeReadReq(req->unitId, 0x02, req->startAddress, req->quantity); } if (const auto* req = std::get_if(&pdu)) { return encodeReadReq(req->unitId, 0x03, req->startAddress, req->quantity); } if (const auto* req = std::get_if(&pdu)) { return encodeReadReq(req->unitId, 0x04, req->startAddress, req->quantity); } if (const auto* resp = std::get_if(&pdu)) { if (!encodeReadRegResp(resp->unitId, 0x03, resp->registers)) { return fail("too_many_registers"); } return true; } if (const auto* resp = std::get_if(&pdu)) { if (!encodeReadRegResp(resp->unitId, 0x04, resp->inputRegisters)) { return fail("too_many_registers"); } return true; } if (const auto* resp = std::get_if(&pdu)) { if (!encodeReadBitsResp(resp->unitId, 0x01, resp->coils)) { return fail("too_many_bytes"); } return true; } if (const auto* resp = std::get_if(&pdu)) { if (!encodeReadBitsResp(resp->unitId, 0x02, resp->discreteInputs)) { return fail("too_many_bytes"); } return true; } // TODO: re-enable FC05/06/0F/10 encode branches after type-name collision investigation. return fail("unsupported_encode"); } } // namespace softbus::message_bus::pipeline::protocol