#include "piezoresistive_a_protocol.h" #include #include #include namespace { constexpr quint8 kReplyStart0 = 0x55; // 0x55AA little-endian constexpr quint8 kReplyStart1 = 0xAA; constexpr quint8 kReplyStartAlt0 = 0xAA; constexpr quint8 kReplyStartAlt1 = 0x55; constexpr quint8 kRequestStart0 = 0x55; // 0x55AA little-endian constexpr quint8 kRequestStart1 = 0xAA; quint16 readLe16(const QByteArray& data, int offset) { const quint8 b0 = static_cast(data[offset]); const quint8 b1 = static_cast(data[offset + 1]); return static_cast(b0 | (b1 << 8)); } quint32 readLe32(const QByteArray& data, int offset) { const quint8 b0 = static_cast(data[offset]); const quint8 b1 = static_cast(data[offset + 1]); const quint8 b2 = static_cast(data[offset + 2]); const quint8 b3 = static_cast(data[offset + 3]); return static_cast(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)); } void appendLe16(QByteArray& data, quint16 v) { data.append(static_cast(v & 0xFF)); data.append(static_cast((v >> 8) & 0xFF)); } void appendLe32(QByteArray& data, quint32 v) { data.append(static_cast(v & 0xFF)); data.append(static_cast((v >> 8) & 0xFF)); data.append(static_cast((v >> 16) & 0xFF)); data.append(static_cast((v >> 24) & 0xFF)); } } quint8 PiezoresistiveAFormat::crc8ITU(const QByteArray& data, int length) { quint8 crc = 0x00; const int limit = qMin(length, data.size()); for (int i = 0; i < limit; ++i) { crc ^= static_cast(data[i]); for (int bit = 0; bit < 8; ++bit) { if (crc & 0x80) crc = static_cast((crc << 1) ^ 0x07); else crc = static_cast(crc << 1); } } return static_cast(crc ^ 0x55); } ISerialFormat::ParseResult PiezoresistiveAFormat::tryParse(QByteArray* buffer, QByteArray* packet, QString* error) { if (!buffer || buffer->isEmpty()) return ParseResult::NeedMore; int startIndex = -1; for (int i = 0; i + 1 < buffer->size(); ++i) { if (static_cast((*buffer)[i]) == kReplyStart0 && static_cast((*buffer)[i + 1]) == kReplyStart1) { startIndex = i; break; } if (static_cast((*buffer)[i]) == kReplyStartAlt0 && static_cast((*buffer)[i + 1]) == kReplyStartAlt1) { startIndex = i; break; } } if (startIndex < 0) { const quint8 tail = static_cast(buffer->back()); buffer->clear(); if (tail == kReplyStart0 || tail == kReplyStart1) buffer->append(static_cast(tail)); return ParseResult::NeedMore; } if (startIndex > 0) buffer->remove(0, startIndex); if (buffer->size() < 5) return ParseResult::NeedMore; const quint16 payloadLen = readLe16(*buffer, 2); const int totalLen = 4 + payloadLen + 1; if (buffer->size() < totalLen) return ParseResult::NeedMore; QByteArray candidate = buffer->left(totalLen); buffer->remove(0, totalLen); const quint8 crc = static_cast(candidate.at(candidate.size() - 1)); const quint8 calc = crc8ITU(candidate, candidate.size() - 1); if (crc != calc) { if (error) *error = QStringLiteral("CRC mismatch"); return ParseResult::Invalid; } if (packet) *packet = candidate; if (error) error->clear(); return ParseResult::Ok; } QByteArray PiezoresistiveACodec::buildRequest(const SerialConfig& config, const SensorRequest& request) { QByteArray packet; packet.reserve(15); packet.append(static_cast(kRequestStart0)); packet.append(static_cast(kRequestStart1)); const quint16 payloadLen = 9; appendLe16(packet, payloadLen); packet.append(static_cast(config.deviceAddress)); packet.append(static_cast(0x00)); packet.append(static_cast(0x80 | request.functionCode)); appendLe32(packet, request.startAddress); appendLe16(packet, request.dataLength); const quint8 crc = PiezoresistiveAFormat::crc8ITU(packet, packet.size()); packet.append(static_cast(crc)); return packet; } QByteArray PiezoresistiveACodec::buildGetVersionRequest(const SerialConfig& config) { // TODO:待实现内容(压阻 A 型版本号查询请求帧) Q_UNUSED(config) return QByteArray(); } QByteArray PiezoresistiveACodec::buildGetSpecRequest(const SerialConfig& config) { // TODO:待实现内容(压阻 A 型规格查询请求帧) Q_UNUSED(config) return QByteArray(); } bool PiezoresistiveADecoder::decodeFrame(const QByteArray& packet, DataFrame* frame, QString* error) { if (!frame) { if (error) *error = QStringLiteral("Null frame output"); return false; } if (packet.size() < 15) { if (error) *error = QStringLiteral("Packet too short"); return false; } const quint8 start0 = static_cast(packet[0]); const quint8 start1 = static_cast(packet[1]); const bool startOk = (start0 == kReplyStart0 && start1 == kReplyStart1) || (start0 == kReplyStartAlt0 && start1 == kReplyStartAlt1); if (!startOk) { if (error) *error = QStringLiteral("Bad start bytes"); return false; } const quint16 payloadLen = readLe16(packet, 2); const int totalLen = 4 + payloadLen + 1; if (packet.size() != totalLen) { if (error) *error = QStringLiteral("Length mismatch"); return false; } const quint8 crc = static_cast(packet.at(packet.size() - 1)); const quint8 calc = PiezoresistiveAFormat::crc8ITU(packet, packet.size() - 1); if (crc != calc) { if (error) *error = QStringLiteral("CRC mismatch"); return false; } const quint8 funcRaw = static_cast(packet[6]); const quint16 dataLen = readLe16(packet, 11); const quint8 status = static_cast(packet[13]); if (payloadLen != static_cast(10 + dataLen)) { if (error) *error = QStringLiteral("Payload length mismatch"); return false; } if (status != 0) { if (error) *error = QStringLiteral("Device status error"); return false; } if (packet.size() < 15 + dataLen) { if (error) *error = QStringLiteral("Data length mismatch"); return false; } if ((dataLen % 2) != 0) { if (error) *error = QStringLiteral("Odd data length"); return false; } const int sampleCount = dataLen / 2; QVector values; values.reserve(sampleCount); const int dataOffset = 14; for (int i = 0; i < sampleCount; ++i) { const int offset = dataOffset + i * 2; const quint16 raw = readLe16(packet, offset); values.push_back(static_cast(raw)); } frame->pts = DataFrame::makePts(QDateTime::currentDateTime()); frame->functionCode = (funcRaw >= 0x80) ? static_cast(funcRaw - 0x80) : funcRaw; frame->data = values; if (error) error->clear(); return true; } bool PiezoresistiveADecoder::decodeSpec(const QByteArray& packet, SensorSpec* spec, QString* error) { // TODO:待实现内容(解析压阻 A 型规格回复并写入 SensorSpec) Q_UNUSED(packet) Q_UNUSED(spec) if (error) *error = QStringLiteral("Not implemented"); return false; }