235 lines
11 KiB
C++
235 lines
11 KiB
C++
/**
|
||
* @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_ */
|