Simplified data storage without eeprom, include timestamps
This commit is contained in:
parent
6bcc22c045
commit
7c2162a5bf
@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
void bluetoothConfigure();
|
void bluetoothConfigure();
|
||||||
|
|
||||||
|
void bluetoothStop();
|
||||||
|
|
||||||
bool bluetoothIsConnected();
|
bool bluetoothIsConnected();
|
||||||
|
|
||||||
// In main.cpp
|
|
||||||
uint32_t secondsUntilNextTemperatureMeasurement();
|
|
||||||
|
|
||||||
uint8_t getWakeupCause();
|
|
90
include/eepromInterface.h
Normal file
90
include/eepromInterface.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct DeviceInfo {
|
||||||
|
|
||||||
|
// The index where the measurement data starts in the eeprom storage
|
||||||
|
uint16_t startIndex;
|
||||||
|
|
||||||
|
// The time when the device was powered on (seconds since 1970)
|
||||||
|
uint32_t deviceStartTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Measurement {
|
||||||
|
|
||||||
|
uint16_t measurementIntervalsSinceDeviceStart;
|
||||||
|
|
||||||
|
uint8_t temperature0;
|
||||||
|
|
||||||
|
uint8_t temperature1;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
constexpr size_t eepromTotalSize = 13350;
|
||||||
|
constexpr uint16_t maxiumDeviceInfoCount = 10;
|
||||||
|
constexpr uint16_t dataStorageStartIndex = sizeof(DeviceInfo) * maxiumDeviceInfoCount;
|
||||||
|
constexpr uint16_t sizeOfMeasurement = sizeof(Measurement);
|
||||||
|
|
||||||
|
class EEPROMInterface {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool isInitialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the storage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
EEPROMInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint8_t startNewDeviceSession();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove all stored data
|
||||||
|
*
|
||||||
|
* @return true The data was deleted
|
||||||
|
* @return false There was an error deleting the data
|
||||||
|
*/
|
||||||
|
bool clearAllData();
|
||||||
|
|
||||||
|
bool writeData(uint8_t* data, uint16_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free space in the buffer
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* @param count
|
||||||
|
* @return uint16_t The number
|
||||||
|
*/
|
||||||
|
uint16_t readData(uint8_t* buffer, uint16_t count);
|
||||||
|
|
||||||
|
uint16_t getStoredByteCount();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The index into the buffer where the next byte should be written
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint16_t writeIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The index into the buffer where the first byte is stored
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint16_t readIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find the write index, the first zero byte after a non-zero byte
|
||||||
|
*
|
||||||
|
* @return uint16_t The write index
|
||||||
|
*/
|
||||||
|
uint16_t findEndIndex();
|
||||||
|
|
||||||
|
uint16_t findStartIndex();
|
||||||
|
};
|
7
include/main.h
Normal file
7
include/main.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t secondsUntilNextTemperatureMeasurement();
|
||||||
|
uint8_t getWakeupCause();
|
||||||
|
uint32_t getUniqueID();
|
@ -6,33 +6,17 @@
|
|||||||
|
|
||||||
constexpr uint8_t temperatureSensorCount = 2;
|
constexpr uint8_t temperatureSensorCount = 2;
|
||||||
|
|
||||||
constexpr size_t storageSize = 80000;
|
|
||||||
constexpr uint16_t storageIntervalInSeconds = 15;
|
|
||||||
constexpr size_t maximumStorageDurationInHours = (storageSize / TEMPERATURE_SENSOR_MAX_COUNT) * storageIntervalInSeconds / 3600;
|
|
||||||
|
|
||||||
// Max size: 7664
|
// Max size: 7664
|
||||||
constexpr size_t maxRtcStorageSize = 7664;
|
constexpr size_t rtcStorageSize = 7580;
|
||||||
constexpr size_t rtcStorageSize = 7550;
|
|
||||||
|
|
||||||
constexpr size_t maxEepromSize = 13350;
|
constexpr size_t maxEepromSize = 13350;
|
||||||
constexpr size_t eepromSize = 13350;
|
|
||||||
|
|
||||||
constexpr size_t totalStorageSize = rtcStorageSize + eepromSize;
|
|
||||||
|
|
||||||
// The minimum temperature to store, in millidegrees celcius
|
// The minimum temperature to store, in millidegrees celcius
|
||||||
// True minimum will be higher by 1°, since two values are reserved
|
// True minimum will be higher by 1°, since two values are reserved
|
||||||
constexpr long temperatureShiftForStorage = -40000;
|
constexpr long temperatureShiftForStorage = -40000;
|
||||||
constexpr long maximumTemperature = temperatureShiftForStorage + 255 * 500;
|
constexpr long maximumTemperature = temperatureShiftForStorage + 255 * 500;
|
||||||
|
|
||||||
constexpr uint8_t temperatureMaximumValue = 255;
|
constexpr uint8_t temperatureMaximumValue = 255;
|
||||||
|
|
||||||
enum class StorageFlags: uint8_t {
|
|
||||||
HasInitializedEEPROM = 1,
|
|
||||||
FailedToInitEEPROM = 2,
|
|
||||||
FailedToWriteEEPROM = 4,
|
|
||||||
RTCStorageOverflow = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
void storageConfigure(bool isFirstRun);
|
void storageConfigure(bool isFirstRun);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,12 +35,14 @@ uint16_t getNumberOfMeasurements();
|
|||||||
|
|
||||||
uint32_t getTotalNumberOfMeasurements();
|
uint32_t getTotalNumberOfMeasurements();
|
||||||
|
|
||||||
|
uint32_t getStartTimeOfCurrentRecording();
|
||||||
|
|
||||||
uint8_t getLastTemperature(uint8_t sensorIndex);
|
uint8_t getLastTemperature(uint8_t sensorIndex);
|
||||||
|
|
||||||
uint16_t getTimeSinceValidTemperature(uint8_t sensorIndex);
|
uint16_t getTimeSinceValidTemperature(uint8_t sensorIndex);
|
||||||
|
|
||||||
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count);
|
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count);
|
||||||
|
|
||||||
void discardAllRecordedBytes();
|
uint16_t getDataChecksum();
|
||||||
|
|
||||||
uint8_t getStorageErrorFlags();
|
void discardAllRecordedBytes();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <Esp.h>
|
#include <Esp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <BLEDevice.h>
|
#include <BLEDevice.h>
|
||||||
#include <BLEUtils.h>
|
#include <BLEUtils.h>
|
||||||
@ -10,6 +11,7 @@
|
|||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "temperature.h"
|
#include "temperature.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
constexpr size_t bluetoothMaxDataSize = 200;
|
constexpr size_t bluetoothMaxDataSize = 200;
|
||||||
|
|
||||||
@ -29,8 +31,6 @@ uint8_t* bluetoothDataBuffer;
|
|||||||
uint8_t* bluetoothResponse;
|
uint8_t* bluetoothResponse;
|
||||||
size_t bluetoothDataCount = 0;
|
size_t bluetoothDataCount = 0;
|
||||||
|
|
||||||
RTC_DATA_ATTR uint32_t deviceStartTime = 0;
|
|
||||||
|
|
||||||
void bluetoothStartAdvertising();
|
void bluetoothStartAdvertising();
|
||||||
void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count);
|
void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count);
|
||||||
|
|
||||||
@ -87,7 +87,6 @@ void bluetoothConfigure() {
|
|||||||
BLEDevice::init(deviceName);
|
BLEDevice::init(deviceName);
|
||||||
server = BLEDevice::createServer();
|
server = BLEDevice::createServer();
|
||||||
server->setCallbacks(&bluetooth);
|
server->setCallbacks(&bluetooth);
|
||||||
|
|
||||||
// Register message service that can receive messages and reply with a static message.
|
// Register message service that can receive messages and reply with a static message.
|
||||||
BLEService *service = server->createService(serviceUUID);
|
BLEService *service = server->createService(serviceUUID);
|
||||||
uint32_t properties = BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_WRITE;
|
uint32_t properties = BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_WRITE;
|
||||||
@ -114,6 +113,11 @@ void bluetoothConfigure() {
|
|||||||
bluetoothStartAdvertising();
|
bluetoothStartAdvertising();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bluetoothStop() {
|
||||||
|
BLEDevice::deinit();
|
||||||
|
esp_bt_controller_disable();
|
||||||
|
}
|
||||||
|
|
||||||
void bluetoothStartAdvertising() {
|
void bluetoothStartAdvertising() {
|
||||||
// Advertise services
|
// Advertise services
|
||||||
BLEAdvertising *advertisement = server->getAdvertising();
|
BLEAdvertising *advertisement = server->getAdvertising();
|
||||||
@ -171,17 +175,6 @@ enum class BluetoothRequest: uint8_t {
|
|||||||
* This may happen when a new temperature recording is performed in between calls
|
* This may happen when a new temperature recording is performed in between calls
|
||||||
*/
|
*/
|
||||||
clearRecordingBuffer = 2,
|
clearRecordingBuffer = 2,
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the absolute start time of the device
|
|
||||||
*
|
|
||||||
* Request:
|
|
||||||
* - Bytes 1-4: Number of seconds since 1970 (uint32_t)
|
|
||||||
*
|
|
||||||
* Response:
|
|
||||||
* - BluetoothResponse::success
|
|
||||||
*/
|
|
||||||
setDeviceStartTime = 3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BluetoothResponse: uint8_t {
|
enum class BluetoothResponse: uint8_t {
|
||||||
@ -237,6 +230,11 @@ void fillInfo() {
|
|||||||
uint16_t value;
|
uint16_t value;
|
||||||
uint32_t value32;
|
uint32_t value32;
|
||||||
|
|
||||||
|
// The unique ID generated on power-on
|
||||||
|
value32 = getUniqueID();
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value32, sizeof(uint32_t));
|
||||||
|
bluetoothDataCount += sizeof(uint32_t);
|
||||||
|
|
||||||
// the number of bytes as a uint16_t (2 bytes)
|
// the number of bytes as a uint16_t (2 bytes)
|
||||||
value = getTotalNumberOfStoredBytes();
|
value = getTotalNumberOfStoredBytes();
|
||||||
memcpy(bluetoothDataBuffer, &value, sizeof(uint16_t));
|
memcpy(bluetoothDataBuffer, &value, sizeof(uint16_t));
|
||||||
@ -268,7 +266,7 @@ void fillInfo() {
|
|||||||
bluetoothDataCount += sizeof(uint16_t);
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
// Total storage size of device
|
// Total storage size of device
|
||||||
value = totalStorageSize;
|
value = rtcStorageSize;
|
||||||
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
bluetoothDataCount += sizeof(uint16_t);
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
@ -277,10 +275,20 @@ void fillInfo() {
|
|||||||
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value32, sizeof(uint32_t));
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value32, sizeof(uint32_t));
|
||||||
bluetoothDataCount += sizeof(uint32_t);
|
bluetoothDataCount += sizeof(uint32_t);
|
||||||
|
|
||||||
// Configured device start time
|
// Start time of current recording
|
||||||
memcpy(bluetoothDataBuffer + bluetoothDataCount, &deviceStartTime, sizeof(uint32_t));
|
value32 = getStartTimeOfCurrentRecording();
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value32, sizeof(uint32_t));
|
||||||
bluetoothDataCount += sizeof(uint32_t);
|
bluetoothDataCount += sizeof(uint32_t);
|
||||||
|
|
||||||
|
// Checksum for all data
|
||||||
|
value = getDataChecksum();
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
|
// The wakeup cause for the current run
|
||||||
|
bluetoothDataBuffer[bluetoothDataCount] = getWakeupCause();
|
||||||
|
bluetoothDataCount += sizeof(uint8_t);
|
||||||
|
|
||||||
// Sensor 0
|
// Sensor 0
|
||||||
|
|
||||||
// Temperature sensor addresses
|
// Temperature sensor addresses
|
||||||
@ -309,9 +317,6 @@ void fillInfo() {
|
|||||||
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
bluetoothDataCount += sizeof(uint16_t);
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
bluetoothDataBuffer[bluetoothDataCount] = getWakeupCause();
|
|
||||||
bluetoothDataCount += sizeof(uint8_t);
|
|
||||||
|
|
||||||
setResponse(BluetoothResponse::success);
|
setResponse(BluetoothResponse::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,17 +355,6 @@ void clearRecordingBuffer(uint8_t* buffer, uint16_t count) {
|
|||||||
setResponseWithoutData(BluetoothResponse::success);
|
setResponseWithoutData(BluetoothResponse::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDeviceStartTime(uint8_t* buffer, uint16_t count) {
|
|
||||||
if (count != sizeof(uint32_t)) {
|
|
||||||
setResponseWithoutData(BluetoothResponse::invalidCommand);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(&deviceStartTime, buffer, sizeof(uint32_t));
|
|
||||||
Serial.print("Device start time: ");
|
|
||||||
Serial.println(deviceStartTime);
|
|
||||||
setResponseWithoutData(BluetoothResponse::success);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count) {
|
void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
setResponseWithoutData(BluetoothResponse::invalidCommand);
|
setResponseWithoutData(BluetoothResponse::invalidCommand);
|
||||||
@ -384,10 +378,6 @@ void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count) {
|
|||||||
getRecordingData(payload, payloadSize);
|
getRecordingData(payload, payloadSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BluetoothRequest::setDeviceStartTime:
|
|
||||||
setDeviceStartTime(payload, payloadSize);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
setResponseWithoutData(BluetoothResponse::unknownCommand);
|
setResponseWithoutData(BluetoothResponse::unknownCommand);
|
||||||
break;
|
break;
|
||||||
|
6
src/eepromInterface.cpp
Normal file
6
src/eepromInterface.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "eepromInterface.h"
|
||||||
|
#include <EEPROM.h>
|
||||||
|
|
||||||
|
EEPROMInterface::EEPROMInterface() {
|
||||||
|
isInitialized = EEPROM.begin(eepromTotalSize);
|
||||||
|
}
|
17
src/main.cpp
17
src/main.cpp
@ -2,6 +2,7 @@
|
|||||||
#include <esp_wifi.h>
|
#include <esp_wifi.h>
|
||||||
#include <driver/rtc_io.h>
|
#include <driver/rtc_io.h>
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "bluetooth.h"
|
#include "bluetooth.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
@ -16,6 +17,9 @@ RTC_DATA_ATTR uint32_t nextTimeToMeasureTemperatureSeconds = 0;
|
|||||||
|
|
||||||
RTC_DATA_ATTR bool isFirstStart = true;
|
RTC_DATA_ATTR bool isFirstStart = true;
|
||||||
|
|
||||||
|
// The unique ID generated whenever the device is powered on
|
||||||
|
RTC_DATA_ATTR uint32_t uniqueID;
|
||||||
|
|
||||||
// Indicate the time until the device should stay awake
|
// Indicate the time until the device should stay awake
|
||||||
// Updated when button is pressed
|
// Updated when button is pressed
|
||||||
uint32_t sleepStartAfterButtonPressOrConnection = 0;
|
uint32_t sleepStartAfterButtonPressOrConnection = 0;
|
||||||
@ -26,6 +30,10 @@ uint8_t getWakeupCause() {
|
|||||||
return wakeupCauseByte;
|
return wakeupCauseByte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t getUniqueID() {
|
||||||
|
return uniqueID;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if enough time has passed for the next temperature measurement
|
* @brief Check if enough time has passed for the next temperature measurement
|
||||||
*
|
*
|
||||||
@ -54,7 +62,8 @@ uint32_t secondsUntilNextTemperatureMeasurement() {
|
|||||||
if (currentTime >= nextTimeToMeasureTemperatureSeconds) {
|
if (currentTime >= nextTimeToMeasureTemperatureSeconds) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return nextTimeToMeasureTemperatureSeconds - currentTime;
|
uint32_t seconds = nextTimeToMeasureTemperatureSeconds - currentTime;
|
||||||
|
return min(seconds, temperatureMeasurementIntervalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +83,7 @@ void deepSleepUntilNextTemperatureMeasurement() {
|
|||||||
Serial.print("Sleeping for ");
|
Serial.print("Sleeping for ");
|
||||||
Serial.print(seconds);
|
Serial.print(seconds);
|
||||||
Serial.println(" seconds");
|
Serial.println(" seconds");
|
||||||
|
bluetoothStop();
|
||||||
esp_deep_sleep(seconds * 1000000);
|
esp_deep_sleep(seconds * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +137,11 @@ void setup() {
|
|||||||
// No need for serial output in production
|
// No need for serial output in production
|
||||||
Serial.begin(serialBaudRate);
|
Serial.begin(serialBaudRate);
|
||||||
|
|
||||||
|
if (isFirstStart) {
|
||||||
|
// Generate unique ID on device start
|
||||||
|
uniqueID = random();
|
||||||
|
}
|
||||||
|
|
||||||
// LED useless inside case
|
// LED useless inside case
|
||||||
// enableLED();
|
// enableLED();
|
||||||
|
|
||||||
|
207
src/storage.cpp
207
src/storage.cpp
@ -3,63 +3,21 @@
|
|||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
#include <esp_attr.h>
|
#include <esp_attr.h>
|
||||||
|
|
||||||
constexpr uint8_t absoluteTemperatureIndicator = 0xFF;
|
|
||||||
|
|
||||||
RTC_DATA_ATTR uint8_t storageFlags = 0;
|
|
||||||
|
|
||||||
// Storage for temperature measurements in RTC memory that survives deep sleep
|
// Storage for temperature measurements in RTC memory that survives deep sleep
|
||||||
RTC_DATA_ATTR uint8_t data[rtcStorageSize];
|
RTC_DATA_ATTR uint8_t data[rtcStorageSize];
|
||||||
RTC_DATA_ATTR uint16_t dataIndex = 0;
|
RTC_DATA_ATTR uint16_t dataIndex = 0; // Index of next byte / total byte count
|
||||||
RTC_DATA_ATTR uint16_t numberOfMeasurements = 0;
|
RTC_DATA_ATTR uint16_t rtcDataSum = 0; // Checksum for the data storage
|
||||||
RTC_DATA_ATTR uint32_t numberOfDiscardedMeasurements = 0;
|
RTC_DATA_ATTR uint16_t numberOfMeasurements = 0; // Current number of measurements (dataIndex / 4)
|
||||||
|
RTC_DATA_ATTR uint32_t numberOfDiscardedMeasurements = 0; // Previous measurements already deleted
|
||||||
|
|
||||||
// The index into EEPROM storage where the next data should be written
|
// The time (in seconds since device start) when the current recording started
|
||||||
RTC_DATA_ATTR uint32_t eepromIndex = 0;
|
RTC_DATA_ATTR uint32_t startTimeOfCurrentRecording = 0;
|
||||||
RTC_DATA_ATTR bool isFirstRunAfterPowerOn = true;
|
|
||||||
|
|
||||||
constexpr uint16_t eepromOffset = sizeof(uint16_t);
|
|
||||||
constexpr uint16_t eepromDataSize = eepromSize - eepromOffset;
|
|
||||||
|
|
||||||
// Keeps the last valid temperatures for each sensor
|
// Keeps the last valid temperatures for each sensor
|
||||||
RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount];
|
RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount];
|
||||||
RTC_DATA_ATTR uint32_t lastValidTemperatureTime[temperatureSensorCount];
|
RTC_DATA_ATTR uint32_t lastValidTemperatureTime[temperatureSensorCount];
|
||||||
RTC_DATA_ATTR uint8_t lastMeasurements[temperatureSensorCount] = {0, 0};
|
RTC_DATA_ATTR uint8_t lastMeasurements[temperatureSensorCount] = {0, 0};
|
||||||
|
|
||||||
void setStorageFlag(StorageFlags flag) {
|
|
||||||
storageFlags |= static_cast<uint8_t>(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearStorageFlag(StorageFlags flag) {
|
|
||||||
storageFlags &= ~static_cast<uint8_t>(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasStorageFlag(StorageFlags flag) {
|
|
||||||
return storageFlags & static_cast<uint8_t>(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasInitializedEEPROM() {
|
|
||||||
return hasStorageFlag(StorageFlags::HasInitializedEEPROM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void didInitializeEEPROM() {
|
|
||||||
setStorageFlag(StorageFlags::HasInitializedEEPROM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupEEPROMIfNeeded() {
|
|
||||||
if (hasInitializedEEPROM()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool success = EEPROM.begin(eepromSize);
|
|
||||||
if (!success) {
|
|
||||||
Serial.println("Failed to set up EEPROM");
|
|
||||||
setStorageFlag(StorageFlags::FailedToInitEEPROM);
|
|
||||||
}
|
|
||||||
Serial.print("EEPROM size: ");
|
|
||||||
Serial.println(eepromSize);
|
|
||||||
clearStorageFlag(StorageFlags::FailedToInitEEPROM);
|
|
||||||
setStorageFlag(StorageFlags::HasInitializedEEPROM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetLastMeasurements() {
|
void resetLastMeasurements() {
|
||||||
for (uint8_t index = 0; index < temperatureSensorCount; index += 1) {
|
for (uint8_t index = 0; index < temperatureSensorCount; index += 1) {
|
||||||
lastTemperatures[index].status == TemperatureStatus::sensorNotFound;
|
lastTemperatures[index].status == TemperatureStatus::sensorNotFound;
|
||||||
@ -74,41 +32,6 @@ void storageConfigure(bool isFirstRun) {
|
|||||||
// Ensure that first values are stored
|
// Ensure that first values are stored
|
||||||
resetLastMeasurements();
|
resetLastMeasurements();
|
||||||
}
|
}
|
||||||
// Initialize EEPROM on every wake
|
|
||||||
// setupEEPROMIfNeeded();
|
|
||||||
//setStorageFlag(StorageFlags::HasInitializedEEPROM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveDataToEEPROMIfNeeded() {
|
|
||||||
if (dataIndex < rtcStorageSize) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setupEEPROMIfNeeded();
|
|
||||||
if (!hasInitializedEEPROM()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write until EEPROM is full
|
|
||||||
uint16_t bytesRemaining = eepromDataSize - eepromIndex;
|
|
||||||
uint16_t bytesToWrite = min(dataIndex, bytesRemaining);
|
|
||||||
EEPROM.writeBytes(eepromIndex, data, bytesToWrite); // TODO: Check that result == bytesToWrite
|
|
||||||
EEPROM.commit();
|
|
||||||
|
|
||||||
// Move remaining data to front of array (if any)
|
|
||||||
uint16_t bytesToKeep = dataIndex - bytesToWrite;
|
|
||||||
memmove(data, data + bytesToWrite, bytesToKeep);
|
|
||||||
dataIndex -= bytesToWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveByteAtCurrentIndex(uint8_t byte) {
|
|
||||||
if (dataIndex >= rtcStorageSize) {
|
|
||||||
setStorageFlag(StorageFlags::RTCStorageOverflow);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data[dataIndex] = byte;
|
|
||||||
dataIndex += 1;
|
|
||||||
//moveDataToEEPROMIfNeeded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t byteForAbsoluteTemperature(Temperature* temp) {
|
uint8_t byteForAbsoluteTemperature(Temperature* temp) {
|
||||||
@ -139,32 +62,28 @@ uint8_t byteForAbsoluteTemperature(Temperature* temp) {
|
|||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsAbsoluteTemperatureRecording(Temperature* temperatures) {
|
|
||||||
if (numberOfMeasurements == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (uint8_t index = 0; index < temperatureSensorCount; index += 1) {
|
|
||||||
if (temperatures[index].status != TemperatureStatus::temperatureIsValid) {
|
|
||||||
// Error value can be encoded as differential (0x00)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Note: If previously only errors, then last value is 0. This also work for differential temperatures
|
|
||||||
long diff = (lastTemperatures[index].value - temperatures[index].value) / 500 + 8;
|
|
||||||
if (diff < 1 || diff > 15) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveTemperatures(Temperature* temperatures) {
|
void saveTemperatures(Temperature* temperatures) {
|
||||||
if (needsAbsoluteTemperatureRecording(temperatures)) {
|
if (numberOfMeasurements == 0) {
|
||||||
// Write absolute temperatures
|
// Adjust start time if new measurement is begun
|
||||||
saveByteAtCurrentIndex(absoluteTemperatureIndicator);
|
startTimeOfCurrentRecording = time(NULL);
|
||||||
|
}
|
||||||
|
if (dataIndex + 4 >= rtcStorageSize) {
|
||||||
|
// Don't add any more measurements if storage is full
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// First: Write timestamp
|
||||||
|
// Timestamp is number of measurement intervals since start of recording
|
||||||
|
uint16_t timestamp = (time(NULL) - startTimeOfCurrentRecording) / 60;
|
||||||
|
memcpy(data + dataIndex, ×tamp, sizeof(uint16_t));
|
||||||
|
rtcDataSum += data[dataIndex] + data[dataIndex+1]; // Update checksum
|
||||||
|
dataIndex += sizeof(uint16_t);
|
||||||
|
|
||||||
for (uint8_t sensorIndex = 0; sensorIndex < temperatureSensorCount; sensorIndex += 1) {
|
for (uint8_t sensorIndex = 0; sensorIndex < temperatureSensorCount; sensorIndex += 1) {
|
||||||
Temperature* temp = &temperatures[sensorIndex];
|
Temperature* temp = &temperatures[sensorIndex];
|
||||||
uint8_t byte = byteForAbsoluteTemperature(temp);
|
uint8_t byte = byteForAbsoluteTemperature(temp);
|
||||||
saveByteAtCurrentIndex(byte);
|
data[dataIndex] = byte;
|
||||||
|
dataIndex += 1;
|
||||||
|
rtcDataSum += byte; // Update checksum
|
||||||
lastMeasurements[sensorIndex] = byte;
|
lastMeasurements[sensorIndex] = byte;
|
||||||
if (temp->status == TemperatureStatus::temperatureIsValid) {
|
if (temp->status == TemperatureStatus::temperatureIsValid) {
|
||||||
// Only update if temperature is valid
|
// Only update if temperature is valid
|
||||||
@ -172,46 +91,11 @@ void saveTemperatures(Temperature* temperatures) {
|
|||||||
lastValidTemperatureTime[sensorIndex] = time(NULL);
|
lastValidTemperatureTime[sensorIndex] = time(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Calculate temperature differences
|
|
||||||
uint8_t valueToStore = 0;
|
|
||||||
for (uint8_t index = 0; index < temperatureSensorCount; index += 1) {
|
|
||||||
Temperature* temp = &temperatures[index];
|
|
||||||
uint8_t diff = 0; // Indicate sensor error
|
|
||||||
if (temp->status == TemperatureStatus::temperatureIsValid) {
|
|
||||||
diff = (lastTemperatures[index].value - temp->value) / 500 + 8;
|
|
||||||
}
|
|
||||||
if (index % 2) {
|
|
||||||
// Store second bits
|
|
||||||
valueToStore |= diff; // Valid range already ensured
|
|
||||||
saveByteAtCurrentIndex(valueToStore);
|
|
||||||
valueToStore = 0;
|
|
||||||
} else {
|
|
||||||
// Store in first four bits
|
|
||||||
valueToStore = (diff << 4);
|
|
||||||
}
|
|
||||||
lastMeasurements[index] = byteForAbsoluteTemperature(temp);
|
|
||||||
|
|
||||||
if (temp->status == TemperatureStatus::temperatureIsValid) {
|
|
||||||
// Only update if temperature is valid
|
|
||||||
lastTemperatures[index].status = TemperatureStatus::temperatureIsValid;
|
|
||||||
lastTemperatures[index].value = temp->value;
|
|
||||||
lastValidTemperatureTime[index] = time(NULL);
|
|
||||||
} else if (lastTemperatures[index].status != TemperatureStatus::temperatureIsValid) {
|
|
||||||
lastTemperatures[index].value = 0;
|
|
||||||
lastValidTemperatureTime[index] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ensure storage with uneven number of sensors
|
|
||||||
if (temperatureSensorCount % 2) {
|
|
||||||
saveByteAtCurrentIndex(valueToStore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
numberOfMeasurements += 1;
|
numberOfMeasurements += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getTotalNumberOfStoredBytes() {
|
uint16_t getTotalNumberOfStoredBytes() {
|
||||||
return dataIndex; // + eepromIndex;
|
return dataIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getNumberOfMeasurements() {
|
uint16_t getNumberOfMeasurements() {
|
||||||
@ -222,48 +106,35 @@ uint32_t getTotalNumberOfMeasurements() {
|
|||||||
return numberOfMeasurements + numberOfDiscardedMeasurements;
|
return numberOfMeasurements + numberOfDiscardedMeasurements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t getStartTimeOfCurrentRecording() {
|
||||||
|
return startTimeOfCurrentRecording;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t getLastTemperature(uint8_t sensorIndex) {
|
uint8_t getLastTemperature(uint8_t sensorIndex) {
|
||||||
return lastMeasurements[sensorIndex];
|
return lastMeasurements[sensorIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getTimeSinceValidTemperature(uint8_t sensorIndex) {
|
uint16_t getTimeSinceValidTemperature(uint8_t sensorIndex) {
|
||||||
return time(NULL) - lastValidTemperatureTime[sensorIndex];
|
return min(time(NULL) - lastValidTemperatureTime[sensorIndex], 65535ul);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) {
|
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) {
|
||||||
// Copy remaining bytes from RTC memory
|
if (offset >= dataIndex) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
uint16_t remainingBytes = dataIndex - offset;
|
uint16_t remainingBytes = dataIndex - offset;
|
||||||
uint16_t bytesToCopy = min(count, remainingBytes);
|
uint16_t bytesToCopy = min(count, remainingBytes);
|
||||||
memcpy(buffer, data + offset, count);
|
memcpy(buffer, data + offset, bytesToCopy);
|
||||||
return bytesToCopy;
|
return bytesToCopy;
|
||||||
/*
|
}
|
||||||
// TODO: Check limits
|
|
||||||
uint16_t eepromByteCount = eepromIndex;
|
uint16_t getDataChecksum() {
|
||||||
uint16_t endIndex = offset + count;
|
return rtcDataSum;
|
||||||
uint16_t eepromStart = min(offset, eepromByteCount);
|
|
||||||
uint16_t eepromEnd = min(endIndex, eepromByteCount);
|
|
||||||
uint16_t bytesToCopyFromEEPROM = eepromEnd - eepromStart;
|
|
||||||
if (bytesToCopyFromEEPROM > 0) {
|
|
||||||
EEPROM.readBytes(eepromStart, buffer, bytesToCopyFromEEPROM); // TODO: Check bytes read
|
|
||||||
// Reduce offset and count to point to RTC memory
|
|
||||||
offset -= bytesToCopyFromEEPROM;
|
|
||||||
count -= bytesToCopyFromEEPROM;
|
|
||||||
}
|
|
||||||
offset -= eepromByteCount;
|
|
||||||
// Copy remaining bytes from RTC memory
|
|
||||||
uint16_t bytesToCopyFromRTC = min(count, dataIndex);
|
|
||||||
memcpy(buffer + bytesToCopyFromEEPROM, data + offset, bytesToCopyFromRTC);
|
|
||||||
return bytesToCopyFromEEPROM + bytesToCopyFromRTC;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void discardAllRecordedBytes() {
|
void discardAllRecordedBytes() {
|
||||||
eepromIndex = 0;
|
|
||||||
dataIndex = 0;
|
dataIndex = 0;
|
||||||
|
rtcDataSum = 0;
|
||||||
numberOfDiscardedMeasurements += numberOfMeasurements;
|
numberOfDiscardedMeasurements += numberOfMeasurements;
|
||||||
numberOfMeasurements = 0;
|
numberOfMeasurements = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getStorageErrorFlags() {
|
|
||||||
return storageFlags;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user