/*! * * Copyright (c) 2024-2026 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file CloudConnectFrame.h * \author (original) Stephen Quong * \date (original) 24-May-2026 * */ #pragma once #include /*! * \brief CloudConnect frame for communicating between client and CloudConnect. * * Frame layout — header only (payload_length == 0): * * Byte: 0 1 2 3 4 5 6-9 10 11 * ┌─────────┬────────┬────────┬───────────┬────────┐ * │ AA 55 │ topic │ seq_num│ pay_length│hdr_crc │ * │ sync │ uint16 │ uint16 │ uint32 │ uint16 │ * └─────────┴────────┴────────┴───────────┴────────┘ * * Frame layout — with payload (payload_length > 0): * * ┌── 12-byte header ──┬── N bytes payload ──┬── pay_crc (4 B) ──┐ * │ header │ uint8[] │ CRC-32/ISO-HDLC │ * └────────────────────┴─────────────────────┴───────────────────┘ * * Header CRC: CRC-16/CCITT (poly 0x1021, init 0xFFFF, no reflection). * Payload CRC: CRC-32/ISO-HDLC (IEEE 802.3, reflected poly 0xEDB88320). */ class CloudConnectFrame { public: /*! * \brief MQTT topic identifier carried in every frame header */ enum class Topic : quint16 { HighPriority = 0x0001, NormalPriority = 0x0002, DeviceLogFile = 0x0003, TreatmentLogFile = 0x0004, CloudSyncLogFile = 0x0005, }; /*! * \brief Result returned by read() after processing each byte chunk */ enum class ReadState { Incomplete, Complete, HeaderError, PayloadError, }; static QByteArray build(Topic topic, quint16 sequence, const QByteArray &payload = {}); ReadState read(QByteArray &bytes); Topic topic() const; quint16 sequence() const; QByteArray payload() const; void reset(); private: static constexpr int SYNC_SIZE = 2; static constexpr quint8 SYNC[SYNC_SIZE] = {0xAA, 0x55}; static constexpr int HEADER_SIZE = 12; static constexpr int TOPIC_SIZE = 2; static constexpr int SEQUENCE_SIZE = 2; static constexpr int HEADER_CRC_SIZE = 2; static constexpr int PAYLOAD_CRC_SIZE = 4; static constexpr quint32 MAX_PAYLOAD_LEN = 64 * 1024; static quint16 crc16ccitt(const quint8 *data, int len); static quint32 crc32isohdlc(const quint8 *data, int len); QByteArray _headerBuf; Topic _rxTopic = Topic::NormalPriority; quint16 _rxSequence = 0; quint32 _rxPayloadLen = 0; QByteArray _rxPayload; };