STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
CommsMessage.hpp
Go to the documentation of this file.
1#ifndef DAQ_MESSAGE_FACTORY_HPP
2#define DAQ_MESSAGE_FACTORY_HPP
3
4#include <array>
5#include <cstdint>
6#include <cstring>
7#include <tuple>
8#include <type_traits>
9#include <utility>
10
11namespace comms {
12
13// Forward declaration
14template <typename T>
16
17/**
18 * @brief CommsMessage - Template-based message serialization
19 *
20 * Standalone implementation for DAQ system.
21 * Provides type-safe message definition and serialization.
22 */
23template <typename... Fields>
25 std::tuple<Fields...> fields;
26
27 // Default constructor
28 CommsMessage() : fields(std::make_tuple(Fields()...)) {
29 }
30
31 // Variadic constructor
32 CommsMessage(Fields... args) : fields(std::make_tuple(std::forward<Fields>(args)...)) {
33 }
34
35 template <std::size_t Index>
36 auto& getField() {
37 return std::get<Index>(fields);
38 }
39
40 template <std::size_t Index>
41 const auto& getField() const {
42 return std::get<Index>(fields);
43 }
44
45 template <std::size_t Index, typename ValueType>
46 void setField(ValueType&& value) {
47 std::get<Index>(fields) = std::forward<ValueType>(value);
48 }
49
50 constexpr std::size_t get_size() const {
51 return std::tuple_size<std::tuple<Fields...>>::value;
52 }
53
54 // Serialize the tuple to a raw buffer with packed layout
55 // Handles nested CommsMessage structures recursively
56 // CRITICAL: Match FSW's Serializer::write() behavior exactly - flatten nested structures
57 void serialize(uint8_t* buffer) const {
58 std::size_t offset = 0;
59 std::apply(
60 [&](const auto&... field_vals) {
61 ((serialize_field(buffer, offset, field_vals)), ...);
62 },
63 fields);
64 }
65
66 // Deserialize the tuple from a raw buffer with packed layout
67 void deserialize(const uint8_t* buffer) {
68 std::size_t offset = 0;
69 std::apply(
70 [&](auto&... field_vals) {
71 ((std::memcpy(&field_vals, buffer + offset, sizeof(field_vals)),
72 offset += sizeof(field_vals)),
73 ...);
74 },
75 fields);
76 }
77
78 // Compute the serialized size of this message
79 static constexpr std::size_t nbytes() {
80 return (MessageSizeHelper<Fields>::value + ... + 0);
81 }
82
83private:
84 // Helper to serialize a single field (handles nested CommsMessage and std::array)
85 // CRITICAL: Match FSW's Serializer::write() behavior exactly
86 template <typename T>
87 void serialize_field(uint8_t* buffer, std::size_t& offset, const T& field) const {
88 if constexpr (is_comms_message_v<T>) {
89 // Nested CommsMessage - flatten by writing each field individually (matching FSW's
90 // Serializer::write)
91 std::apply(
92 [&](const auto&... nested_fields) {
93 ((serialize_field(buffer, offset, nested_fields)), ...);
94 },
95 field.fields);
96 } else if constexpr (is_std_array_v<T>) {
97 // std::array - write each element individually (matching FSW's Serializer::write for
98 // std::array)
99 for (const auto& item : field) {
100 serialize_field(buffer, offset, item);
101 }
102 } else {
103 // Primitive type - memcpy directly (matching FSW's Serializer::write for
104 // TrivialSerializable)
105 std::memcpy(buffer + offset, &field, sizeof(field));
106 offset += sizeof(field);
107 }
108 }
109
110 // Type trait to detect std::array
111 template <typename T>
112 struct is_std_array : std::false_type {};
113
114 template <typename T, std::size_t N>
115 struct is_std_array<std::array<T, N>> : std::true_type {};
116
117 template <typename T>
118 static constexpr bool is_std_array_v = is_std_array<T>::value;
119
120 // Type trait to detect CommsMessage
121 template <typename T>
122 struct is_comms_message : std::false_type {};
123
124 template <typename... Ts>
125 struct is_comms_message<CommsMessage<Ts...>> : std::true_type {};
126
127 template <typename T>
128 static constexpr bool is_comms_message_v = is_comms_message<T>::value;
129
130 // Helper to calculate size of a type (handles nested CommsMessage)
131 template <typename T>
133 static constexpr std::size_t value = sizeof(T);
134 };
135
136 template <typename... Ts>
138 static constexpr std::size_t value = (MessageSizeHelper<Ts>::value + ... + 0);
139 };
140};
141
142} // namespace comms
143
144// Helper to get message size at compile time (outside namespace for convenience)
145// Handles nested CommsMessage structures recursively
146template <typename T>
147struct MessageSize;
148
149template <typename... Ts>
150struct MessageSize<comms::CommsMessage<Ts...>> {
151 static constexpr std::size_t value = (MessageSize<Ts>::value + ... + 0);
152};
153
154// Base template for non-CommsMessage types (use sizeof)
155template <typename T>
157 static constexpr std::size_t value = sizeof(T);
158};
159
160#endif // DAQ_MESSAGE_FACTORY_HPP
Central message header for all communication messages.
STL namespace.
static constexpr std::size_t value
CommsMessage(Fields... args)
const auto & getField() const
void deserialize(const uint8_t *buffer)
void serialize(uint8_t *buffer) const
void serialize_field(uint8_t *buffer, std::size_t &offset, const T &field) const
constexpr std::size_t get_size() const
void setField(ValueType &&value)
static constexpr std::size_t nbytes()