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 #479

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dd0ddab
change EnviroDIY URL to Memphis server and update copyright
tpwrules Jan 24, 2023
cd37b8f
add 8K data buffer for testing
tpwrules Feb 10, 2023
4320fd2
dataPublisherBase: remove redundant zero init of TX buffer
tpwrules Feb 4, 2023
e275718
publishers: refactor transmit buffer usage
tpwrules Feb 10, 2023
40b91c5
publishers/EnviroDIYPublisher: send data as one element arrays
tpwrules Feb 10, 2023
5df9aa6
publishers/EnviroDIYPublisher: buffer log data and send in batches
tpwrules Feb 10, 2023
58a17e9
publishers/EnviroDIYPublisher: move log buffer logic to its own class
tpwrules Feb 10, 2023
bf548d4
only turn modem on when internet connection is needed by a publisher
tpwrules Feb 10, 2023
447f582
dataPublisherBase: correctly retry flushing if modem buffer is full
tpwrules Feb 10, 2023
212ead3
publishers/EnviroDIYPublisher: send initial logged data immediately
tpwrules Feb 10, 2023
e79cbe4
publishers/EnviroDIYPublisher: use more intelligent sending algorithm
tpwrules Feb 10, 2023
8c4e590
LoggerBase: make testing button log immediately using normal procedure
tpwrules Feb 9, 2023
b092f32
flush log buffer immediately when test button is pushed
tpwrules Feb 10, 2023
b98d3e4
libraries/ModularSensors: run clang-format on *.cpp and *.h
tpwrules Mar 16, 2023
fa3aaab
Added begin. Can't figure out why needed.
SRGDamia1 Sep 15, 2023
81b6963
Non-static buffer
SRGDamia1 Sep 21, 2023
ba35c84
steps toward fifo
SRGDamia1 Sep 21, 2023
54bc18a
Made the EnviroDIY host/path/port settable
SRGDamia1 May 20, 2024
7a9f6e6
CR
SRGDamia1 May 20, 2024
2b97787
Re-add testing mode
SRGDamia1 May 20, 2024
055c11a
Decrease buffer size for Mega, fix warnings
SRGDamia1 May 28, 2024
c2f646c
Update Doxygen, add docs for private members
SRGDamia1 Jun 11, 2024
c3a1520
Remove extra emphasized return types.
SRGDamia1 Sep 19, 2024
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
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed

### Added
- Added support for caching readings in RAM and sending in batches.
This currently only works on the EnviroDIY/Monitor My Watershed Publisher.
Thank you to [Thomas Watson](https://github.com/tpwrules) for this work.

### Removed

Expand Down
102 changes: 102 additions & 0 deletions src/LogBuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* @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
clear();
}

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

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) {
// check how many records currently exist
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 the index of the record number just created
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;
}
161 changes: 161 additions & 0 deletions src/LogBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/**
* @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.
*/

// Header Guards
#ifndef SRC_LOGBUFFER_H_
#define SRC_LOGBUFFER_H_

#ifndef MS_LOG_DATA_BUFFER_SIZE
#ifdef ARDUINO_AVR_MEGA2560
#define MS_LOG_DATA_BUFFER_SIZE 2048
#else
/**
* @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.
*/
#define MS_LOG_DATA_BUFFER_SIZE 8192
#endif
#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 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 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 record The record
* @param variable The variable
* @param value The value
*/
void setRecordValue(int record, uint8_t variable, float value);

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

/**
* @brief Gets the value of a particular variable in a particular record.
*
* @param record The record
* @param 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 Index of buffer head.
*/
uint16_t dataBufferTail;
/**
* @brief Index of buffer tail.
*/
uint16_t dataBufferHead;
/**
* @brief The buffer overflow status
*/
bool _bufferOverflow = false;

/**
* @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