54template<
typename MsgType,
typename Storage = StaticVector<MsgType, 64>>
57 using Clock = std::chrono::steady_clock;
72 std::lock_guard<std::mutex> lock(m_mutex);
80 m_buffer.push_back(msg);
90 template<
typename InputIt>
92 std::lock_guard<std::mutex> lock(m_mutex);
93 for (
auto it = first; it != last; ++it) {
98 m_buffer.push_back(*it);
111 template<
typename Adapter>
114 std::size_t messageCount = 0;
117 std::lock_guard<std::mutex> lock(m_mutex);
126 if (m_buffer.empty()) {
131 localBuffer = std::move(m_buffer);
132 m_buffer = Storage{};
133 messageCount = localBuffer.size();
137 return SendBuffer(adapter, std::move(localBuffer), messageCount);
146 template<
typename Adapter>
149 std::size_t messageCount = 0;
152 std::lock_guard<std::mutex> lock(m_mutex);
155 if (m_buffer.empty()) {
160 localBuffer = std::move(m_buffer);
161 m_buffer = Storage{};
162 messageCount = localBuffer.size();
166 return SendBuffer(adapter, std::move(localBuffer), messageCount);
173 std::lock_guard<std::mutex> lock(m_mutex);
174 return m_buffer.size();
181 std::lock_guard<std::mutex> lock(m_mutex);
198 std::lock_guard<std::mutex> lock(m_mutex);
203 std::lock_guard<std::mutex> lock(m_mutex);
211 std::lock_guard<std::mutex> lock(m_mutex);
222 template<
typename Adapter>
223 bool SendBuffer(Adapter& adapter, Storage&& buffer, std::size_t messageCount) {
226 packet.
messages = std::move(buffer);
229 m_wireBuffer.clear();
231 std::lock_guard<std::mutex> lock(m_mutex);
237 if (!adapter.SendBytes(m_wireBuffer.data(), m_wireBuffer.size())) {
238 std::lock_guard<std::mutex> lock(m_mutex);
245 std::lock_guard<std::mutex> lock(m_mutex);
252 TelemetryAccumulatorConfig m_config;
254 std::vector<uint8_t> m_wireBuffer;
255 std::size_t m_tickCount{0};
257 mutable std::mutex m_mutex;
259 void DropOldestUnlocked() {
260 if (m_buffer.empty()) {
265 for (std::size_t i = 1; i < m_buffer.size(); ++i) {
266 m_buffer[i - 1] = std::move(m_buffer[i]);
275template<
typename MsgType>
281template<
typename MsgType, std::
size_t Capacity = 64>
Accumulates high-frequency telemetry data and batches into packets.
bool Record(const MsgType &msg)
Record a telemetry reading.
std::chrono::steady_clock Clock
void RecordBatch(InputIt first, InputIt last)
Record multiple telemetry readings at once.
bool MaybeFlush(Adapter &adapter)
Flush if interval has elapsed.
Metrics GetMetrics() const
void SetConfig(const TelemetryAccumulatorConfig &config)
Update configuration.
void Clear()
Clear all buffered messages without sending.
std::size_t BufferedCount() const
Get the number of buffered messages waiting to be sent.
TelemetryAccumulator(TelemetryAccumulatorConfig config={})
bool ForceFlush(Adapter &adapter)
Force an immediate flush regardless of interval.
bool EncodeTypedPacket(const TypedPacket< MsgType, Storage > &packet, uint8_t *output, std::size_t capacity, std::size_t &bytesWritten)
Encode a typed packet to a pre-allocated buffer.
BCNP packet structures, encoding, and decoding utilities.
Fixed-capacity vector with stack allocation (no heap).
Configuration for telemetry accumulator.
std::size_t maxBufferedMessages
Maximum messages to accumulate before forcing a flush.
std::size_t flushIntervalTicks
Flush interval: send telemetry every N control loop ticks.
uint64_t messagesRecorded
Generic packet containing messages of a specific type.