// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #pragma once #include #ifdef __cplusplus #include #include #include #include #include #include #include #include #include "wpi/DenseMap.h" #include "wpi/StringMap.h" #include "wpi/condition_variable.h" #include "wpi/mutex.h" #endif // __cplusplus /** * A datalog string (for use with string array). */ struct WPI_DataLog_String { /** Contents. */ const char* str; /** Length. */ size_t len; }; #ifdef __cplusplus namespace wpi { class Logger; } // namespace wpi namespace wpi::log { namespace impl { enum ControlRecordType { kControlStart = 0, kControlFinish, kControlSetMetadata }; } // namespace impl /** * A data log. The log file is created immediately upon construction with a * temporary filename. The file may be renamed at any time using the * SetFilename() function. * * The lifetime of the data log object must be longer than any data log entry * objects that refer to it. * * The data log is periodically flushed to disk. It can also be explicitly * flushed to disk by using the Flush() function. * * Finish() is needed only to indicate in the log that a particular entry is * no longer being used (it releases the name to ID mapping). Finish() is not * required to be called for data to be flushed to disk; entries in the log * are written as Append() calls are being made. In fact, Finish() does not * need to be called at all; this is helpful to avoid shutdown races where the * DataLog object might be destroyed before other objects. It's often not a * good idea to call Finish() from destructors for this reason. * * DataLog calls are thread safe. DataLog uses a typical multiple-supplier, * single-consumer setup. Writes to the log are atomic, but there is no * guaranteed order in the log when multiple threads are writing to it; * whichever thread grabs the write mutex first will get written first. * For this reason (as well as the fact that timestamps can be set to * arbitrary values), records in the log are not guaranteed to be sorted by * timestamp. */ class DataLog final { public: /** * Construct a new Data Log. The log will be initially created with a * temporary filename. * * @param dir directory to store the log * @param filename filename to use; if none provided, a random filename is * generated of the form "wpilog_{}.wpilog" * @param period time between automatic flushes to disk, in seconds; * this is a time/storage tradeoff * @param extraHeader extra header data */ explicit DataLog(std::string_view dir = "", std::string_view filename = "", double period = 0.25, std::string_view extraHeader = ""); /** * Construct a new Data Log. The log will be initially created with a * temporary filename. * * @param msglog message logger (will be called from separate thread) * @param dir directory to store the log * @param filename filename to use; if none provided, a random filename is * generated of the form "wpilog_{}.wpilog" * @param period time between automatic flushes to disk, in seconds; * this is a time/storage tradeoff * @param extraHeader extra header data */ explicit DataLog(wpi::Logger& msglog, std::string_view dir = "", std::string_view filename = "", double period = 0.25, std::string_view extraHeader = ""); /** * Construct a new Data Log that passes its output to the provided function * rather than a file. The write function will be called on a separate * background thread and may block. The write function is called with an * empty data array when the thread is terminating. * * @param write write function * @param period time between automatic calls to write, in seconds; * this is a time/storage tradeoff * @param extraHeader extra header data */ explicit DataLog(std::function data)> write, double period = 0.25, std::string_view extraHeader = ""); /** * Construct a new Data Log that passes its output to the provided function * rather than a file. The write function will be called on a separate * background thread and may block. The write function is called with an * empty data array when the thread is terminating. * * @param msglog message logger (will be called from separate thread) * @param write write function * @param period time between automatic calls to write, in seconds; * this is a time/storage tradeoff * @param extraHeader extra header data */ explicit DataLog(wpi::Logger& msglog, std::function data)> write, double period = 0.25, std::string_view extraHeader = ""); ~DataLog(); DataLog(const DataLog&) = delete; DataLog& operator=(const DataLog&) = delete; DataLog(DataLog&&) = delete; DataLog& operator=(const DataLog&&) = delete; /** * Change log filename. * * @param filename filename */ void SetFilename(std::string_view filename); /** * Explicitly flushes the log data to disk. */ void Flush(); /** * Pauses appending of data records to the log. While paused, no data records * are saved (e.g. AppendX is a no-op). Has no effect on entry starts / * finishes / metadata changes. */ void Pause(); /** * Resumes appending of data records to the log. */ void Resume(); /** * Start an entry. Duplicate names are allowed (with the same type), and * result in the same index being returned (Start/Finish are reference * counted). A duplicate name with a different type will result in an error * message being printed to the console and 0 being returned (which will be * ignored by the Append functions). * * @param name Name * @param type Data type * @param metadata Initial metadata (e.g. data properties) * @param timestamp Time stamp (may be 0 to indicate now) * * @return Entry index */ int Start(std::string_view name, std::string_view type, std::string_view metadata = {}, int64_t timestamp = 0); /** * Finish an entry. * * @param entry Entry index * @param timestamp Time stamp (may be 0 to indicate now) */ void Finish(int entry, int64_t timestamp = 0); /** * Updates the metadata for an entry. * * @param entry Entry index * @param metadata New metadata for the entry * @param timestamp Time stamp (may be 0 to indicate now) */ void SetMetadata(int entry, std::string_view metadata, int64_t timestamp = 0); /** * Appends a raw record to the log. * * @param entry Entry index, as returned by Start() * @param data Byte array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendRaw(int entry, std::span data, int64_t timestamp); /** * Appends a raw record to the log. * * @param entry Entry index, as returned by Start() * @param data Byte array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendRaw2(int entry, std::span> data, int64_t timestamp); /** * Appends a boolean record to the log. * * @param entry Entry index, as returned by Start() * @param value Boolean value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendBoolean(int entry, bool value, int64_t timestamp); /** * Appends an integer record to the log. * * @param entry Entry index, as returned by Start() * @param value Integer value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendInteger(int entry, int64_t value, int64_t timestamp); /** * Appends a float record to the log. * * @param entry Entry index, as returned by Start() * @param value Float value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendFloat(int entry, float value, int64_t timestamp); /** * Appends a double record to the log. * * @param entry Entry index, as returned by Start() * @param value Double value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendDouble(int entry, double value, int64_t timestamp); /** * Appends a string record to the log. * * @param entry Entry index, as returned by Start() * @param value String value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendString(int entry, std::string_view value, int64_t timestamp); /** * Appends a boolean array record to the log. * * @param entry Entry index, as returned by Start() * @param arr Boolean array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendBooleanArray(int entry, std::span arr, int64_t timestamp); /** * Appends a boolean array record to the log. * * @param entry Entry index, as returned by Start() * @param arr Boolean array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendBooleanArray(int entry, std::span arr, int64_t timestamp); /** * Appends a boolean array record to the log. * * @param entry Entry index, as returned by Start() * @param arr Boolean array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendBooleanArray(int entry, std::span arr, int64_t timestamp); /** * Appends an integer array record to the log. * * @param entry Entry index, as returned by Start() * @param arr Integer array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendIntegerArray(int entry, std::span arr, int64_t timestamp); /** * Appends a float array record to the log. * * @param entry Entry index, as returned by Start() * @param arr Float array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendFloatArray(int entry, std::span arr, int64_t timestamp); /** * Appends a double array record to the log. * * @param entry Entry index, as returned by Start() * @param arr Double array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendDoubleArray(int entry, std::span arr, int64_t timestamp); /** * Appends a string array record to the log. * * @param entry Entry index, as returned by Start() * @param arr String array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendStringArray(int entry, std::span arr, int64_t timestamp); /** * Appends a string array record to the log. * * @param entry Entry index, as returned by Start() * @param arr String array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendStringArray(int entry, std::span arr, int64_t timestamp); /** * Appends a string array record to the log. * * @param entry Entry index, as returned by Start() * @param arr String array to record * @param timestamp Time stamp (may be 0 to indicate now) */ void AppendStringArray(int entry, std::span arr, int64_t timestamp); private: void WriterThreadMain(std::string_view dir); void WriterThreadMain( std::function data)> write); // must be called with m_mutex held uint8_t* StartRecord(uint32_t entry, uint64_t timestamp, uint32_t payloadSize, size_t reserveSize); uint8_t* Reserve(size_t size); void AppendImpl(std::span data); void AppendStringImpl(std::string_view str); wpi::Logger& m_msglog; mutable wpi::mutex m_mutex; wpi::condition_variable m_cond; bool m_active{true}; bool m_doFlush{false}; bool m_paused{false}; double m_period; std::string m_extraHeader; std::string m_newFilename; class Buffer; std::vector m_free; std::vector m_outgoing; struct EntryInfo { std::string type; int id{0}; }; wpi::StringMap m_entries; wpi::DenseMap m_entryCounts; int m_lastId = 0; std::thread m_thread; }; /** * Log entry base class. */ class DataLogEntry { protected: DataLogEntry() = default; DataLogEntry(DataLog& log, std::string_view name, std::string_view type, std::string_view metadata = {}, int64_t timestamp = 0) : m_log{&log}, m_entry{log.Start(name, type, metadata, timestamp)} {} public: DataLogEntry(const DataLogEntry&) = delete; DataLogEntry& operator=(const DataLogEntry&) = delete; DataLogEntry(DataLogEntry&& rhs) : m_log{rhs.m_log}, m_entry{rhs.m_entry} { rhs.m_log = nullptr; } DataLogEntry& operator=(DataLogEntry&& rhs) { if (m_log) { m_log->Finish(m_entry); } m_log = rhs.m_log; rhs.m_log = nullptr; m_entry = rhs.m_entry; return *this; } explicit operator bool() const { return m_log != nullptr; } /** * Updates the metadata for the entry. * * @param metadata New metadata for the entry * @param timestamp Time stamp (may be 0 to indicate now) */ void SetMetadata(std::string_view metadata, int64_t timestamp = 0) { m_log->SetMetadata(m_entry, metadata, timestamp); } /** * Finishes the entry. * * @param timestamp Time stamp (may be 0 to indicate now) */ void Finish(int64_t timestamp = 0) { m_log->Finish(m_entry, timestamp); } protected: DataLog* m_log = nullptr; int m_entry = 0; }; /** * Log arbitrary byte data. */ class RawLogEntry : public DataLogEntry { public: static constexpr std::string_view kDataType = "raw"; RawLogEntry() = default; RawLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : RawLogEntry{log, name, {}, kDataType, timestamp} {} RawLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : RawLogEntry{log, name, metadata, kDataType, timestamp} {} RawLogEntry(DataLog& log, std::string_view name, std::string_view metadata, std::string_view type, int64_t timestamp = 0) : DataLogEntry{log, name, type, metadata, timestamp} {} /** * Appends a record to the log. * * @param data Data to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span data, int64_t timestamp = 0) { m_log->AppendRaw(m_entry, data, timestamp); } }; /** * Log boolean values. */ class BooleanLogEntry : public DataLogEntry { public: static constexpr std::string_view kDataType = "boolean"; BooleanLogEntry() = default; BooleanLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : BooleanLogEntry{log, name, {}, timestamp} {} BooleanLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param value Value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(bool value, int64_t timestamp = 0) { m_log->AppendBoolean(m_entry, value, timestamp); } }; /** * Log integer values. */ class IntegerLogEntry : public DataLogEntry { public: static constexpr std::string_view kDataType = "int64"; IntegerLogEntry() = default; IntegerLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : IntegerLogEntry{log, name, {}, timestamp} {} IntegerLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param value Value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(int64_t value, int64_t timestamp = 0) { m_log->AppendInteger(m_entry, value, timestamp); } }; /** * Log float values. */ class FloatLogEntry : public DataLogEntry { public: static constexpr std::string_view kDataType = "float"; FloatLogEntry() = default; FloatLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : FloatLogEntry{log, name, {}, timestamp} {} FloatLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param value Value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(float value, int64_t timestamp = 0) { m_log->AppendFloat(m_entry, value, timestamp); } }; /** * Log double values. */ class DoubleLogEntry : public DataLogEntry { public: static constexpr std::string_view kDataType = "double"; DoubleLogEntry() = default; DoubleLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : DoubleLogEntry{log, name, {}, timestamp} {} DoubleLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param value Value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(double value, int64_t timestamp = 0) { m_log->AppendDouble(m_entry, value, timestamp); } }; /** * Log string values. */ class StringLogEntry : public DataLogEntry { public: static constexpr const char* kDataType = "string"; StringLogEntry() = default; StringLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : StringLogEntry{log, name, {}, kDataType, timestamp} {} StringLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : StringLogEntry{log, name, metadata, kDataType, timestamp} {} StringLogEntry(DataLog& log, std::string_view name, std::string_view metadata, std::string_view type, int64_t timestamp = 0) : DataLogEntry{log, name, type, metadata, timestamp} {} /** * Appends a record to the log. * * @param value Value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::string_view value, int64_t timestamp = 0) { m_log->AppendString(m_entry, value, timestamp); } }; /** * Log array of boolean values. */ class BooleanArrayLogEntry : public DataLogEntry { public: static constexpr const char* kDataType = "boolean[]"; BooleanArrayLogEntry() = default; BooleanArrayLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : BooleanArrayLogEntry{log, name, {}, timestamp} {} BooleanArrayLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. For find functions to work, timestamp * must be monotonically increasing. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendBooleanArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::initializer_list arr, int64_t timestamp = 0) { Append(std::span{arr.begin(), arr.end()}, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendBooleanArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::initializer_list arr, int64_t timestamp = 0) { Append(std::span{arr.begin(), arr.end()}, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendBooleanArray(m_entry, arr, timestamp); } }; /** * Log array of integer values. */ class IntegerArrayLogEntry : public DataLogEntry { public: static constexpr const char* kDataType = "int64[]"; IntegerArrayLogEntry() = default; IntegerArrayLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : IntegerArrayLogEntry{log, name, {}, timestamp} {} IntegerArrayLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendIntegerArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::initializer_list arr, int64_t timestamp = 0) { Append({arr.begin(), arr.end()}, timestamp); } }; /** * Log array of float values. */ class FloatArrayLogEntry : public DataLogEntry { public: static constexpr const char* kDataType = "float[]"; FloatArrayLogEntry() = default; FloatArrayLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : FloatArrayLogEntry{log, name, {}, timestamp} {} FloatArrayLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendFloatArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::initializer_list arr, int64_t timestamp = 0) { Append({arr.begin(), arr.end()}, timestamp); } }; /** * Log array of double values. */ class DoubleArrayLogEntry : public DataLogEntry { public: static constexpr const char* kDataType = "double[]"; DoubleArrayLogEntry() = default; DoubleArrayLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : DoubleArrayLogEntry{log, name, {}, timestamp} {} DoubleArrayLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendDoubleArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::initializer_list arr, int64_t timestamp = 0) { Append({arr.begin(), arr.end()}, timestamp); } }; /** * Log array of string values. */ class StringArrayLogEntry : public DataLogEntry { public: static constexpr const char* kDataType = "string[]"; StringArrayLogEntry() = default; StringArrayLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0) : StringArrayLogEntry{log, name, {}, timestamp} {} StringArrayLogEntry(DataLog& log, std::string_view name, std::string_view metadata, int64_t timestamp = 0) : DataLogEntry{log, name, kDataType, metadata, timestamp} {} /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendStringArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::span arr, int64_t timestamp = 0) { m_log->AppendStringArray(m_entry, arr, timestamp); } /** * Appends a record to the log. * * @param arr Values to record * @param timestamp Time stamp (may be 0 to indicate now) */ void Append(std::initializer_list arr, int64_t timestamp = 0) { Append(std::span{arr.begin(), arr.end()}, timestamp); } }; } // namespace wpi::log extern "C" { #endif // __cplusplus /** C-compatible data log (opaque struct). */ struct WPI_DataLog; /** * Construct a new Data Log. The log will be initially created with a * temporary filename. * * @param dir directory to store the log * @param filename filename to use; if none provided, a random filename is * generated of the form "wpilog_{}.wpilog" * @param period time between automatic flushes to disk, in seconds; * this is a time/storage tradeoff * @param extraHeader extra header data */ struct WPI_DataLog* WPI_DataLog_Create(const char* dir, const char* filename, double period, const char* extraHeader); /** * Construct a new Data Log that passes its output to the provided function * rather than a file. The write function will be called on a separate * background thread and may block. The write function is called with an * empty data array (data=NULL, len=0) when the thread is terminating. * * @param write write function * @param ptr pointer to pass to write function ptr parameter * @param period time between automatic calls to write, in seconds; * this is a time/storage tradeoff * @param extraHeader extra header data */ struct WPI_DataLog* WPI_DataLog_Create_Func( void (*write)(void* ptr, const uint8_t* data, size_t len), void* ptr, double period, const char* extraHeader); /** * Releases a data log object. Closes the file and returns resources to the * system. * * @param datalog data log */ void WPI_DataLog_Release(struct WPI_DataLog* datalog); /** * Change log filename. * * @param datalog data log * @param filename filename */ void WPI_DataLog_SetFilename(struct WPI_DataLog* datalog, const char* filename); /** * Explicitly flushes the log data to disk. * * @param datalog data log */ void WPI_DataLog_Flush(struct WPI_DataLog* datalog); /** * Pauses appending of data records to the log. While paused, no data records * are saved (e.g. AppendX is a no-op). Has no effect on entry starts / * finishes / metadata changes. * * @param datalog data log */ void WPI_DataLog_Pause(struct WPI_DataLog* datalog); /** * Resumes appending of data records to the log. * * @param datalog data log */ void WPI_DataLog_Resume(struct WPI_DataLog* datalog); /** * Start an entry. Duplicate names are allowed (with the same type), and * result in the same index being returned (Start/Finish are reference * counted). A duplicate name with a different type will result in an error * message being printed to the console and 0 being returned (which will be * ignored by the Append functions). * * @param datalog data log * @param name Name * @param type Data type * @param metadata Initial metadata (e.g. data properties) * @param timestamp Time stamp (may be 0 to indicate now) * * @return Entry index */ int WPI_DataLog_Start(struct WPI_DataLog* datalog, const char* name, const char* type, const char* metadata, int64_t timestamp); /** * Finish an entry. * * @param datalog data log * @param entry Entry index * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry, int64_t timestamp); /** * Updates the metadata for an entry. * * @param datalog data log * @param entry Entry index * @param metadata New metadata for the entry * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_SetMetadata(struct WPI_DataLog* datalog, int entry, const char* metadata, int64_t timestamp); /** * Appends a raw record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param data Byte array to record * @param len Length of byte array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendRaw(struct WPI_DataLog* datalog, int entry, const uint8_t* data, size_t len, int64_t timestamp); /** * Appends a boolean record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param value Boolean value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendBoolean(struct WPI_DataLog* datalog, int entry, int value, int64_t timestamp); /** * Appends an integer record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param value Integer value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendInteger(struct WPI_DataLog* datalog, int entry, int64_t value, int64_t timestamp); /** * Appends a float record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param value Float value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendFloat(struct WPI_DataLog* datalog, int entry, float value, int64_t timestamp); /** * Appends a double record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param value Double value to record * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendDouble(struct WPI_DataLog* datalog, int entry, double value, int64_t timestamp); /** * Appends a string record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param value String value to record * @param len Length of string * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendString(struct WPI_DataLog* datalog, int entry, const char* value, size_t len, int64_t timestamp); /** * Appends a boolean array record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param arr Boolean array to record * @param len Number of elements in array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendBooleanArray(struct WPI_DataLog* datalog, int entry, const int* arr, size_t len, int64_t timestamp); /** * Appends a boolean array record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param arr Boolean array to record * @param len Number of elements in array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendBooleanArrayByte(struct WPI_DataLog* datalog, int entry, const uint8_t* arr, size_t len, int64_t timestamp); /** * Appends an integer array record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param arr Integer array to record * @param len Number of elements in array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendIntegerArray(struct WPI_DataLog* datalog, int entry, const int64_t* arr, size_t len, int64_t timestamp); /** * Appends a float array record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param arr Float array to record * @param len Number of elements in array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendFloatArray(struct WPI_DataLog* datalog, int entry, const float* arr, size_t len, int64_t timestamp); /** * Appends a double array record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param arr Double array to record * @param len Number of elements in array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendDoubleArray(struct WPI_DataLog* datalog, int entry, const double* arr, size_t len, int64_t timestamp); /** * Appends a string array record to the log. * * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param arr String array to record * @param len Number of elements in array * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendStringArray(struct WPI_DataLog* datalog, int entry, const WPI_DataLog_String* arr, size_t len, int64_t timestamp); #ifdef __cplusplus } // extern "C" #endif // __cplusplus