Skyward boardcore
Loading...
Searching...
No Matches
SyncPacketQueue.h
Go to the documentation of this file.
1/* Copyright (c) 2019-2022 Skyward Experimental Rocketry
2 * Authors: Alvise de'Faveri Tron, Davide Mor, Alberto Nidasio
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
26#include <miosix.h>
27#include <utils/Debug.h>
28
29#include <cstdint>
30#include <list>
31#include <ostream>
32#include <stdexcept>
33#include <string>
34#include <vector>
35
36#include "CircularBuffer.h"
37
38using miosix::ConditionVariable;
39using miosix::FastMutex;
40using miosix::Lock;
41using std::range_error;
42
43namespace Boardcore
44{
45
54template <unsigned int len>
55class Packet
56{
57public:
61 Packet() { content.reserve(len); };
62
66 ~Packet() { content.clear(); };
67
78 size_t append(const uint8_t* msg, size_t msgLen);
79
83 inline void markAsReady() { ready = true; }
84
91 size_t dump(uint8_t* buf);
92
96 void clear();
97
101 inline bool isFull() const { return content.size() == len; }
102
106 inline bool isEmpty() const { return content.size() == 0; }
107
111 inline bool isReady() const { return ready; }
112
116 inline uint64_t getTimestamp() const { return timestamp; }
117
121 inline size_t size() const { return content.size(); }
122
126 inline unsigned int maxSize() const { return len; }
127
132 inline unsigned int getMsgCount() const { return msgCounter; }
133
139 void print(std::ostream& os) const;
140
141 // The buffer itself
142 std::vector<uint8_t> content;
143
144private:
145 unsigned int msgCounter = 0;
146 uint64_t timestamp = 0;
147 bool ready = false;
148};
149
150template <unsigned int len>
151size_t Packet<len>::append(const uint8_t* msg, size_t msgLen)
152{
153 size_t remaining = len - content.size();
154 msgLen = std::min(remaining, msgLen);
155
156 if (msgLen != 0)
157 {
158 // Set the packet's timestamp when the first message is inserted
159 if (content.size() == 0)
160 timestamp = TimestampTimer::getTimestamp();
161
162 // Append the message to the packet
163 content.insert(content.end(), msg, msg + msgLen);
164 msgCounter++;
165 }
166
167 return msgLen;
168}
169
170template <unsigned int len>
172{
173 content.clear();
174 msgCounter = 0;
175 timestamp = 0;
176 ready = false;
177}
178
179template <unsigned int len>
180size_t Packet<len>::dump(uint8_t* buf)
181{
182 std::copy(content.begin(), content.end(), buf);
183 return content.size();
184}
185
186template <unsigned int len>
187void Packet<len>::print(std::ostream& os) const
188{
189 os << "timestamp=" << timestamp << ", ready=" << ready
190 << ", size=" << content.size() << ", msgCounter=" << msgCounter
191 << ", content= ";
192
193 for (auto const& i : content)
194 os << i;
195 os << '\n';
196}
197
208template <unsigned int pktLen, unsigned int pktNum>
210{
211public:
226 bool put(uint8_t* msg, size_t msgLen)
227 {
228 // Check if the message is empty
229 if (msgLen == 0)
230 return false;
231
232 // Check if the queue can hold the packet
233 if (msgLen > pktLen * pktNum)
234 return false;
235
236 {
237 // Lock the mutex on the buffer
238 Lock<FastMutex> l(mutex);
239
240 // Add an element if there isn't any
241 if (buffer.count() == 0)
242 buffer.put({});
243
244 // Write all the packet
245 while (msgLen > 0)
246 {
247 // If the last packet is ready append a new one
248 if (buffer.last().isReady())
249 buffer.put({});
250
251 // Append what data is possible to the last packet
252 size_t appendedLength = buffer.last().append(msg, msgLen);
253
254 // If the packet is full mark it as ready
255 if (buffer.last().isFull())
256 buffer.last().markAsReady();
257
258 // Go forward in the data
259 msgLen -= appendedLength;
260 msg += appendedLength;
261 }
262 }
263
264 // Wake all waiting threads
265 condVerNotEmpty.broadcast();
266
267 return true;
268 }
269
273 const Packet<pktLen> get()
274 {
275 Lock<FastMutex> l(mutex);
276 return buffer.get();
277 }
278
282 const Packet<pktLen> pop()
283 {
284 Lock<FastMutex> l(mutex);
285 return buffer.pop();
286 }
287
291 bool isFull()
292 {
293 Lock<FastMutex> l(mutex);
294
295 if (buffer.count() > 0)
296 return buffer.isFull() && buffer.last().isReady();
297 else
298 return false;
299 }
300
304 bool isEmpty()
305 {
306 Lock<FastMutex> l(mutex);
307 return buffer.isEmpty();
308 }
309
316 {
317 Lock<FastMutex> l(mutex);
318 if (buffer.isEmpty())
319 condVerNotEmpty.wait(mutex);
320 }
321
325 size_t countReady()
326 {
327 Lock<FastMutex> l(mutex);
328
329 if (!buffer.isEmpty())
330 {
331 return buffer.last().isReady() ? buffer.count()
332 : buffer.count() - 1;
333 }
334 else
335 {
336 return 0;
337 }
338 }
339
345 {
346 Lock<FastMutex> l(mutex);
347 return buffer.count();
348 }
349
350private:
351 FastMutex mutex;
352 ConditionVariable condVerNotEmpty;
353 CircularBuffer<Packet<pktLen>, pktNum> buffer;
354};
355
356} // namespace Boardcore
The Packet class is used for packing together messages with variable lengths into a fixed size packet...
~Packet()
Clears the buffer.
unsigned int maxSize() const
std::vector< uint8_t > content
uint64_t getTimestamp() const
size_t dump(uint8_t *buf)
Copies the content of the payload at the given address.
void markAsReady()
Mark the packet as ready.
Packet()
Reserves a fixed length for the packet.
void print(std::ostream &os) const
Print information about this object.
void clear()
Clear the buffer and reset members.
unsigned int getMsgCount() const
size_t append(const uint8_t *msg, size_t msgLen)
Append a given message to the packet.
size_t size() const
A SyncPacketQueue is a SyncCircularBuffer of Packets.
const Packet< pktLen > get()
bool put(uint8_t *msg, size_t msgLen)
Try to append a given message to the packets queue.
void waitUntilNotEmpty()
Blocks the calling thread until the queue is not empty.
const Packet< pktLen > pop()
uint64_t getTimestamp()
Returns the current timer value in microseconds.
This file includes all the types the logdecoder script will decode.