/** * @file UDPSProtocol.h * @brief Shared UDPS binary streaming protocol definitions. * * This header is free of MARTe2-specific types (other than CompilerTypes.h) * so it can be included by both UDPStreamer (DataSource) and DebugService * (Interface), as well as any future component that needs to produce or * consume UDPS packets. * * Protocol overview * ----------------- * Every packet starts with a 17-byte packed header (UDPSPacketHeader). * Large payloads are split into multiple fragments sharing the same counter. * * Packet types: * DATA (0) - signal sample values, Server → Client * CONFIG (1) - signal metadata, Server → Client (sent when set changes) * ACK (2) - counter acknowledgment, Client → Server (optional) * CONNECT (3) - session initiation, Client → Server * DISCONNECT (4) - session teardown, Client → Server or Server → Client * * CONFIG payload: * [uint32 numSigs] * numSigs × UDPSSignalDescriptor (136 bytes each, packed) * [uint8 publishMode] (PublishModeStrict / Accumulate / Decimate) * * DATA payload (Strict / Decimate): * [uint64 HRT timestamp] * per-signal data in CONFIG order (quantised or raw, no padding) * * DATA payload (Accumulate): * [uint64 HRT timestamp] * [uint32 numSamples] * for each signal: if scalar → numSamples elements; else → NumElements once */ #ifndef UDPS_PROTOCOL_H_ #define UDPS_PROTOCOL_H_ #include "CompilerTypes.h" namespace MARTe { /*---------------------------------------------------------------------------*/ /* Magic and packet types */ /*---------------------------------------------------------------------------*/ /** Magic number: ASCII 'UDPS' stored little-endian (0x53504455). */ static const uint32 UDPS_MAGIC = 0x53504455u; /** Packet type constants — must match the Go-side PktXxx constants. */ static const uint8 UDPS_TYPE_DATA = 0u; ///< Server → Client: signal data static const uint8 UDPS_TYPE_CONFIG = 1u; ///< Server → Client: signal config static const uint8 UDPS_TYPE_ACK = 2u; ///< Client → Server: ack counter static const uint8 UDPS_TYPE_CONNECT = 3u; ///< Client → Server: connect request static const uint8 UDPS_TYPE_DISCONNECT = 4u; ///< Client → Server: disconnect /*---------------------------------------------------------------------------*/ /* Wire packet header (17 bytes) */ /*---------------------------------------------------------------------------*/ /** * @brief 17-byte packed UDP packet header, little-endian. * * All fields use unsigned integer types; no padding. Placed at offset 0 * of every UDPS datagram. */ #pragma pack(push, 1) struct UDPSPacketHeader { uint32 magic; ///< Must equal UDPS_MAGIC uint8 type; ///< One of UDPS_TYPE_* uint32 counter; ///< Per-update sequence counter (same for all fragments) uint16 fragmentIdx; ///< 0-based index of this fragment uint16 totalFragments; ///< Total fragments for this update (1 = no fragmentation) uint32 payloadBytes; ///< Payload bytes immediately following this header }; #pragma pack(pop) static const uint32 UDPS_HEADER_SIZE = 17u; ///< sizeof(UDPSPacketHeader) /*---------------------------------------------------------------------------*/ /* Signal type codes (CONFIG wire format) */ /*---------------------------------------------------------------------------*/ /** Compact type codes stored in UDPSSignalDescriptor::typeCode. */ static const uint8 UDPS_TYPECODE_UINT8 = 0u; static const uint8 UDPS_TYPECODE_INT8 = 1u; static const uint8 UDPS_TYPECODE_UINT16 = 2u; static const uint8 UDPS_TYPECODE_INT16 = 3u; static const uint8 UDPS_TYPECODE_UINT32 = 4u; static const uint8 UDPS_TYPECODE_INT32 = 5u; static const uint8 UDPS_TYPECODE_UINT64 = 6u; static const uint8 UDPS_TYPECODE_INT64 = 7u; static const uint8 UDPS_TYPECODE_FLOAT32 = 8u; static const uint8 UDPS_TYPECODE_FLOAT64 = 9u; static const uint8 UDPS_TYPECODE_UNKNOWN = 255u; /*---------------------------------------------------------------------------*/ /* Quantisation and time-mode codes */ /*---------------------------------------------------------------------------*/ /** Quantisation codes stored in UDPSSignalDescriptor::quantType. */ static const uint8 UDPS_QUANT_NONE = 0u; ///< No quantisation; raw wire format static const uint8 UDPS_QUANT_UINT8 = 1u; ///< Map to uint8 [0, 255] static const uint8 UDPS_QUANT_INT8 = 2u; ///< Map to int8 [-127, 127] static const uint8 UDPS_QUANT_UINT16 = 3u; ///< Map to uint16 [0, 65535] static const uint8 UDPS_QUANT_INT16 = 4u; ///< Map to int16 [-32767, 32767] /** Time-mode codes stored in UDPSSignalDescriptor::timeMode. */ static const uint8 UDPS_TIMEMODE_PACKET = 0u; ///< Use packet-level HRT timestamp static const uint8 UDPS_TIMEMODE_FULL_ARRAY = 1u; ///< TimeSignal has NumElements timestamps static const uint8 UDPS_TIMEMODE_FIRST_SAMPLE = 2u; ///< TimeSignal scalar = timestamp of element [0] static const uint8 UDPS_TIMEMODE_LAST_SAMPLE = 3u; ///< TimeSignal scalar = timestamp of element [N-1] /** Sentinel value for UDPSSignalDescriptor::timeSignalIdx when no time signal. */ static const uint32 UDPS_NO_TIME_SIGNAL = 0xFFFFFFFFu; /*---------------------------------------------------------------------------*/ /* Publish mode codes (CONFIG trailing byte) */ /*---------------------------------------------------------------------------*/ static const uint8 UDPS_PUBLISH_STRICT = 0u; ///< One packet per Synchronise() call static const uint8 UDPS_PUBLISH_ACCUMULATE = 1u; ///< Variable batch; flush on size or time static const uint8 UDPS_PUBLISH_DECIMATE = 2u; ///< One packet per Ratio calls /*---------------------------------------------------------------------------*/ /* CONFIG payload — per-signal descriptor */ /*---------------------------------------------------------------------------*/ /** Maximum length of signal name and unit strings in the CONFIG payload. */ static const uint32 UDPS_MAX_SIGNAL_NAME = 64u; static const uint32 UDPS_MAX_UNIT_LEN = 32u; /** Byte size of one serialised UDPSSignalDescriptor on the wire. */ static const uint32 UDPS_SIGNAL_DESC_SIZE = 136u; /** * @brief Wire-format per-signal descriptor embedded in the CONFIG payload. * * Contains only plain C types so it can be memcpy'd directly to/from * the network buffer (little-endian on all supported platforms). * * Size: 64 + 1 + 1 + 1 + 4 + 4 + 8 + 8 + 1 + 8 + 4 + 32 = 136 bytes. */ #pragma pack(push, 1) struct UDPSSignalDescriptor { char8 name[UDPS_MAX_SIGNAL_NAME]; ///< Null-terminated signal name uint8 typeCode; ///< UDPS_TYPECODE_* uint8 quantType; ///< UDPS_QUANT_* uint8 numDimensions; ///< 0=scalar, 1=array, 2=matrix uint32 numRows; ///< Number of rows (or elements for 1D) uint32 numCols; ///< Number of columns (1 for 1D/scalar) float64 rangeMin; ///< Physical range minimum (for quantisation) float64 rangeMax; ///< Physical range maximum (for quantisation) uint8 timeMode; ///< UDPS_TIMEMODE_* float64 samplingRate; ///< Hz; used for FirstSample/LastSample modes uint32 timeSignalIdx; ///< Index of time-ref signal; UDPS_NO_TIME_SIGNAL if none char8 unit[UDPS_MAX_UNIT_LEN]; ///< Null-terminated physical unit string }; #pragma pack(pop) /*---------------------------------------------------------------------------*/ /* TypeDescriptor → UDPS type-code mapping */ /*---------------------------------------------------------------------------*/ /** * @brief Maps a MARTe2 TypeDescriptor to the compact UDPS_TYPECODE_* value. * * Returns UDPS_TYPECODE_UNKNOWN for types that have no UDPS equivalent. * Defined inline to avoid a separate translation unit for this trivial table. */ inline uint8 UDPSTypeDescriptorToCode(TypeDescriptor td) { if (td == UnsignedInteger8Bit) return UDPS_TYPECODE_UINT8; if (td == SignedInteger8Bit) return UDPS_TYPECODE_INT8; if (td == UnsignedInteger16Bit) return UDPS_TYPECODE_UINT16; if (td == SignedInteger16Bit) return UDPS_TYPECODE_INT16; if (td == UnsignedInteger32Bit) return UDPS_TYPECODE_UINT32; if (td == SignedInteger32Bit) return UDPS_TYPECODE_INT32; if (td == UnsignedInteger64Bit) return UDPS_TYPECODE_UINT64; if (td == SignedInteger64Bit) return UDPS_TYPECODE_INT64; if (td == Float32Bit) return UDPS_TYPECODE_FLOAT32; if (td == Float64Bit) return UDPS_TYPECODE_FLOAT64; return UDPS_TYPECODE_UNKNOWN; } /** * @brief Returns the wire byte size of one element for the given type code. * Returns 0 for UDPS_TYPECODE_UNKNOWN. */ inline uint32 UDPSTypeCodeByteSize(uint8 typeCode) { switch (typeCode) { case UDPS_TYPECODE_UINT8: case UDPS_TYPECODE_INT8: return 1u; case UDPS_TYPECODE_UINT16: case UDPS_TYPECODE_INT16: return 2u; case UDPS_TYPECODE_UINT32: case UDPS_TYPECODE_INT32: case UDPS_TYPECODE_FLOAT32: return 4u; case UDPS_TYPECODE_UINT64: case UDPS_TYPECODE_INT64: case UDPS_TYPECODE_FLOAT64: return 8u; default: return 0u; } } /*---------------------------------------------------------------------------*/ /* Inline packet-building helpers */ /*---------------------------------------------------------------------------*/ /** * @brief Serialise a UDPSPacketHeader into the first 17 bytes of @p buf. * @param buf Must have room for at least UDPS_HEADER_SIZE bytes. * @param type Packet type (UDPS_TYPE_*). * @param counter Per-update sequence counter. * @param fragIdx 0-based fragment index. * @param totalFrags Total fragments for this update. * @param payloadBytes Bytes of payload that follow this header. */ inline void UDPSBuildHeader(uint8 *buf, uint8 type, uint32 counter, uint16 fragIdx, uint16 totalFrags, uint32 payloadBytes) { UDPSPacketHeader hdr; hdr.magic = UDPS_MAGIC; hdr.type = type; hdr.counter = counter; hdr.fragmentIdx = fragIdx; hdr.totalFragments = totalFrags; hdr.payloadBytes = payloadBytes; memcpy(buf, &hdr, UDPS_HEADER_SIZE); } } /* namespace MARTe */ #endif /* UDPS_PROTOCOL_H_ */