26#include <interfaces/atomic_ops.h>
69template <
typename T,
typename =
void>
75#define TYPEID_STRUCT(type, character) \
79 static constexpr char VALUE = character; \
96struct TypeID<T,
std::enable_if_t<std::is_enum<T>::value>>
104 static constexpr void print(std::string& mappingString,
105 uint8_t* numberOfTypes,
const char* name)
108 "Unknown TypeID '?'. This type is not supported for "
109 "logging, refer to the error log above for details.");
111 mappingString += std::string(name);
112 mappingString +=
'\0';
114 mappingString +=
'\0';
116 (*numberOfTypes) += 1;
120template <
typename T,
size_t I>
123 static constexpr void print(std::string& mappingString,
124 uint8_t* numberOfTypes,
const char* name)
126 for (
unsigned int i = 0; i < I; i++)
128 mappingString += std::string(name) +
"[" + std::to_string(i) +
"]";
129 mappingString +=
'\0';
131 mappingString +=
'\0';
133 (*numberOfTypes) += 1;
212 template <
typename T>
227 return maxFilenameNumber;
239 static int findNextLogNumber();
241 static std::string getLogName(
int logNumber);
243 static void packThreadLauncher(
void* argv);
245 static void writeThreadLauncher(
void* argv);
257 static constexpr int maxFilenameNumber = 1024;
259#ifndef _ARCH_CORTEXM3_STM32F2
260 static constexpr int maxRecordSize = 512;
261 static constexpr int maxMappingSize = 1024;
262 static constexpr int numRecords = 512;
263 static constexpr int numMappings = 32;
264 static constexpr int numBuffers = 8;
265 static constexpr int bufferSize = 64 * 1024;
267 static constexpr int maxRecordSize = 512;
268 static constexpr int maxMappingSize = 1024;
269 static constexpr int numRecords = 64;
270 static constexpr int numMappings = 16;
271 static constexpr int numBuffers = 8;
272 static constexpr int bufferSize = 4 * 1024;
281 MappingRecord() : size(0) {}
282 uint8_t data[maxMappingSize] = {};
295 Record() : size(0) {}
296 uint8_t data[maxRecordSize] = {};
298 MappingRecord* mapping =
nullptr;
309 template <
typename T>
321 Buffer() : size(0) {}
322 uint8_t data[bufferSize] = {};
328 miosix::Queue<Record*, numRecords> fullRecordsQueue;
329 miosix::Queue<Record*, numRecords> emptyRecordsQueue;
330 miosix::Queue<MappingRecord*, numMappings> emptyMappingsQueue;
331 std::queue<Buffer*, std::list<Buffer*>> fullBufferList;
332 std::queue<Buffer*, std::list<Buffer*>> emptyBufferList;
334 miosix::FastMutex mutex;
335 miosix::ConditionVariable cond;
337 miosix::Thread* packTh =
nullptr;
338 miosix::Thread* writeTh =
nullptr;
340 std::atomic<bool> started{
343 FILE* file =
nullptr;
347 sizeof(int32_t) ==
sizeof(
int),
348 "Int type should be 32 bits in size, if that is not the case "
349 "consider updating the reinterpret_cast in the atomicAdd calls");
357 static int lastMappedLog = -1;
359 if (started ==
false)
361 stats.droppedSamples++;
363 stats.lastWriteError = -1;
368 Record* record =
nullptr;
372 miosix::FastInterruptDisableLock dLock;
373 if (emptyRecordsQueue.IRQget(record) ==
false)
375 stats.droppedSamples++;
381 auto result = socrate::userde::serialize_with_name<T>(
382 mutableCopy, record->data, maxRecordSize);
386 if (result == socrate::userde::Error::BufferTooSmall)
388 emptyRecordsQueue.put(record);
389 miosix::atomicAdd(
reinterpret_cast<int*
>(&stats.tooLargeSamples), 1);
390 TRACE(
"The current record size is not enough to store %s\n",
391 T::reflect().type_name());
395 record->size = socrate::userde::Serde<T>::size() +
396 strlen(T::reflect().type_name()) + 1;
398 if (lastMappedLog != fileNumber)
400 auto mapResult = mapType(t, record);
405 emptyRecordsQueue.put(record);
410 lastMappedLog = fileNumber;
414 record->mapping =
nullptr;
419 fullRecordsQueue.put(record);
421 miosix::atomicAdd(
reinterpret_cast<int*
>(&stats.queuedSamples), 1);
427LoggerResult Logger::mapType(
const T& t, Record*& record)
429 MappingRecord* mapping =
nullptr;
433 miosix::FastInterruptDisableLock dLock;
434 if (emptyMappingsQueue.IRQget(mapping) ==
false)
436 stats.droppedSamples++;
441 std::string mappingString;
442 std::string partialMappingString;
444 uint8_t numberOfTypes =
449 mappingString += T::reflect().type_name();
450 mappingString +=
'\0';
452 T::reflect().for_each_field_type(
453 [&](
const char* name,
auto type)
455 using Type =
typename decltype(type)::Type;
462 mappingString += numberOfTypes;
463 mappingString +=
'\0';
464 mappingString += partialMappingString;
468 if (mappingString.size() > maxRecordSize)
470 emptyMappingsQueue.put(mapping);
472 "The current record size is not enough to store the mapping of "
474 T::reflect().type_name());
479 memcpy(mapping->data, mappingString.c_str(), mappingString.size());
480 mapping->size = mappingString.size();
483 record->mapping = mapping;
485 miosix::atomicAdd(
reinterpret_cast<int*
>(&stats.queuedMappings), 1);
#define TYPEID_STRUCT(type, character)
Buffered logger. Needs to be started before it can be used.
LoggerResult log(const T &t)
Call this function to log a class.
void logStats()
Log logger stats using the logger itself.
std::string getCurrentFileName()
static constexpr unsigned int getMaxFilenameNumber()
Returns the Max Filename number.
int getCurrentLogNumber()
static bool testSDCard()
Tests if the Logger can write to the SD card by opening a file.
void stop()
Call this function to stop the logger.
bool start()
Call this function to start the logger.
Driver for the VN100S IMU.
constexpr char MappingMarker
Marker character for a type mapping.
LoggerResult
Possible outcomes of Logger::log().
@ Dropped
Buffers are currently full, data will not be written. Sorry.
@ Queued
Data has been accepted by the logger and will be written.
@ TooLarge
Data is too large to be logged. Increase maxRecordSize.
@ Ignored
Logger is currently stopped, data will not be written.
Statistics for the logger.
static constexpr char VALUE
static constexpr void print(std::string &mappingString, uint8_t *numberOfTypes, const char *name)
static constexpr void print(std::string &mappingString, uint8_t *numberOfTypes, const char *name)