Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement batch transmission and better testing features #453

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/data_saving/data_saving.ino
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ void loop() {
// NOTE: The testingISR attached to the button at the end of the "setup()"
// function turns on the startTesting flag. So we know if that flag is set
// then we want to run the testing mode function.
if (Logger::startTesting) loggerAllVars.testingMode();
if (Logger::startTesting) loggerAllVars.benchTestingMode();

// Call the processor sleep
// Only need to do this for one of the loggers
Expand Down
2 changes: 1 addition & 1 deletion examples/menu_a_la_carte/menu_a_la_carte.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3314,7 +3314,7 @@ void loop() {
altSoftSerial.begin(9600);
#endif

dataLogger.testingMode();
dataLogger.benchTestingMode();
}

#ifdef BUILD_TEST_ALTSOFTSERIAL
Expand Down
97 changes: 97 additions & 0 deletions src/LogBuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* @file LogBuffer.cpp
* @copyright 2023 Thomas Watson
* Part of the EnviroDIY ModularSensors library for Arduino
* @author Thomas Watson <twatson52@icloud.com>
*
* @brief Implements the LogBuffer class.
*
* This class buffers logged timestamps and variable values for transmission.
*/
#include "LogBuffer.h"

#include <string.h>

// Constructor
LogBuffer::LogBuffer() {}
// Destructor
LogBuffer::~LogBuffer() {}

void LogBuffer::setNumVariables(uint8_t numVariables_) {
// each record is one uint32_t to hold the timestamp, plus N floats to hold
// each variable's value
recordSize = sizeof(uint32_t) + sizeof(float) * numVariables_;
numVariables = numVariables_;

// this scrambles all the data in the buffer so clear it out
numRecords = 0;
}

void LogBuffer::clear(void) {
// clear out the buffer
numRecords = 0;
}

uint8_t LogBuffer::getNumVariables(void) {
return numVariables;
}

int LogBuffer::getNumRecords(void) {
return numRecords;
}

uint8_t LogBuffer::getPercentFull(void) {
uint32_t bytesFull = (uint32_t)numRecords * (uint32_t)recordSize;
uint32_t bytesTotal = MS_LOG_DATA_BUFFER_SIZE;

return (uint8_t)((bytesFull * (uint32_t)100) / bytesTotal);
}

int LogBuffer::addRecord(uint32_t timestamp) {
int record = numRecords;
// compute position of the new record's timestamp in the buffer
// (the timestamp is the first data in the record)
size_t pos = record * recordSize;
// verify we have sufficient space for the record and bail if not
if (MS_LOG_DATA_BUFFER_SIZE - pos < recordSize) { return -1; }

// write the timestamp to the record
memcpy(static_cast<void*>(&dataBuffer[pos]), static_cast<void*>(&timestamp),
sizeof(uint32_t));
numRecords += 1; // just added another record

return record;
}

void LogBuffer::setRecordValue(int record, uint8_t variable, float value) {
// compute position of this value in the buffer
size_t pos = record * recordSize + sizeof(uint32_t) +
variable * sizeof(float);

// write the value to the record
memcpy(static_cast<void*>(&dataBuffer[pos]), static_cast<void*>(&value),
sizeof(float));
}

uint32_t LogBuffer::getRecordTimestamp(int record) {
// read the timestamp from the record (which is the first data in it)
uint32_t timestamp;
memcpy(static_cast<void*>(&timestamp),
static_cast<void*>(&dataBuffer[record * recordSize]),
sizeof(uint32_t));

return timestamp;
}

float LogBuffer::getRecordValue(int record, uint8_t variable) {
// compute position of this value in the buffer
size_t pos = record * recordSize + sizeof(uint32_t) +
variable * sizeof(float);

// read the value from the record
float value;
memcpy(static_cast<void*>(&value), static_cast<void*>(&dataBuffer[pos]),
sizeof(float));

return value;
}
145 changes: 145 additions & 0 deletions src/LogBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
* @file LogBuffer.h
* @copyright 2023 Thomas Watson
* Part of the EnviroDIY ModularSensors library for Arduino
* @author Thomas Watson <twatson52@icloud.com>
*
* @brief Implements the LogBuffer class.
*
* This class buffers logged timestamps and variable values for transmission.
*/

// Header Guards
#ifndef SRC_LOGBUFFER_H_
#define SRC_LOGBUFFER_H_

/**
* @def MS_LOG_DATA_BUFFER_SIZE
* @brief Log Data Buffer
*
* This determines how much RAM is reserved to buffer log records before
* transmission. Each record consumes 4 bytes for the timestamp plus 4 bytes
* for each logged variable. Increasing this value too far can crash the
* device! The number of log records buffered is controlled by sendEveryX.
*
* This can be changed by setting the build flag MS_LOG_DATA_BUFFER_SIZE when
* compiling. 8192 bytes is a safe value for the Mayfly 1.1 with six variables.
*/
#ifndef MS_LOG_DATA_BUFFER_SIZE
#define MS_LOG_DATA_BUFFER_SIZE 8192
#endif

#include <stddef.h>
#include <inttypes.h>

/**
* @brief This class buffers logged timestamps and variable values for
* transmission. The log is divided into a number of records. Each record
* stores the timestamp of the record as a uint32_t, then the value of each
* variable as a float at that time.
*/
class LogBuffer {
public:
/**
* @brief Constructs a new empty buffer which stores no variables or values.
*/
LogBuffer();
/**
* @brief Destroys the buffer.
*/
virtual ~LogBuffer();

/**
* @brief Sets the number of variables the buffer will store in each record.
* Clears the buffer as a side effect.
*
* @param[in] numVariables_ The number of variables to store.
*/
void setNumVariables(uint8_t numVariables_);

/**
* @brief Gets the number of variables that will be stored in each record.
*
* @return The variable count.
*/
uint8_t getNumVariables(void);

/**
* @brief Clears all records from the log.
*/
void clear(void);

/**
* @brief Gets the number of records currently in the log.
*
* @return The number of records.
*/
int getNumRecords(void);

/**
* @brief Computes the percentage full of the buffer.
*
* @return The current percent full.
*/
uint8_t getPercentFull(void);

/**
* @brief Adds a new record with the given timestamp.
*
* @param[in] timestamp The timestamp
*
* @return Index of the new record, or -1 if there was no space.
*/
int addRecord(uint32_t timestamp);

/**
* @brief Sets the value of a particular variable in a particular record.
*
* @param[in] record The record
* @param[in] variable The variable
* @param[in] value The value
*/
void setRecordValue(int record, uint8_t variable, float value);

/**
* @brief Gets the timestamp of a particular record.
*
* @param[in] record The record
*
* @return The record's timestamp.
*/
uint32_t getRecordTimestamp(int record);

/**
* @brief Gets the value of a particular vaiable in a particular record.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in variable

*
* @param[in] record The record
* @param[in] variable The variable
*
* @return The variable's value.
*/
float getRecordValue(int record, uint8_t variable);

protected:
/**
* @brief Buffer which stores the log data.
*/
uint8_t dataBuffer[MS_LOG_DATA_BUFFER_SIZE];

/**
* @brief Number of records currently in the buffer.
*/
int numRecords;

/**
* @brief Size in bytes of each record in the buffer.
*/
size_t recordSize;

/**
* @brief Number of variables stored in each record in the buffer.
*/
uint8_t numVariables;
};

#endif // SRC_LOGBUFFER_H_
Loading
Loading