All features working
This commit is contained in:
parent
e1852d2989
commit
a7a8367687
@ -5,7 +5,10 @@
|
|||||||
|
|
||||||
constexpr uint32_t serialBaudRate = 115200;
|
constexpr uint32_t serialBaudRate = 115200;
|
||||||
|
|
||||||
constexpr gpio_num_t wakeupButtonPin = GPIO_NUM_13;
|
// The pin connected to the push button
|
||||||
|
// The button should be connected to GND
|
||||||
|
constexpr gpio_num_t wakeupButtonPin = GPIO_NUM_27;
|
||||||
|
|
||||||
// The time (in seconds) for which the device should stay awake after the button is pressed
|
// The time (in seconds) for which the device should stay awake after the button is pressed
|
||||||
// The device also stays awake as long as a bluetooth connection is active
|
// The device also stays awake as long as a bluetooth connection is active
|
||||||
constexpr uint32_t wakeupDurationAfterButtonPress = 30;
|
constexpr uint32_t wakeupDurationAfterButtonPress = 30;
|
||||||
|
@ -40,6 +40,10 @@ void saveTemperatureAtCurrentIndex(Temperature temp);
|
|||||||
|
|
||||||
uint16_t getTotalNumberOfStoredBytes();
|
uint16_t getTotalNumberOfStoredBytes();
|
||||||
|
|
||||||
|
uint16_t getNumberOfMeasurements();
|
||||||
|
|
||||||
|
uint8_t getLastTemperature(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();
|
void discardAllRecordedBytes();
|
@ -2,8 +2,15 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Note: Pin requires external 4.7kOhm pull-up
|
||||||
|
constexpr uint8_t TEMPERATURE_SENSOR_PIN = 23;
|
||||||
|
|
||||||
constexpr uint8_t TEMPERATURE_SENSOR_MAX_COUNT = 2;
|
constexpr uint8_t TEMPERATURE_SENSOR_MAX_COUNT = 2;
|
||||||
|
|
||||||
|
// The number of bytes composing a temperature sensor address
|
||||||
|
constexpr int TEMPERATURE_SENSOR_ADDRESS_SIZE = 8;
|
||||||
|
|
||||||
constexpr uint8_t temperatureSensorNotAvailable = 0;
|
constexpr uint8_t temperatureSensorNotAvailable = 0;
|
||||||
constexpr uint8_t temperatureSensorFailure = 1;
|
constexpr uint8_t temperatureSensorFailure = 1;
|
||||||
constexpr uint8_t temperatureMinimumValue = 2;
|
constexpr uint8_t temperatureMinimumValue = 2;
|
||||||
@ -32,3 +39,5 @@ struct Temperature {
|
|||||||
void temperatureConfigure();
|
void temperatureConfigure();
|
||||||
|
|
||||||
void temperaturePerformUpdate(Temperature* temperatures);
|
void temperaturePerformUpdate(Temperature* temperatures);
|
||||||
|
|
||||||
|
void copySensorAddress(uint8_t index, uint8_t* buffer);
|
@ -15,5 +15,3 @@ framework = arduino
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
pstolarz/OneWireNg @ ^0.11.2
|
pstolarz/OneWireNg @ ^0.11.2
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_port = /dev/tty.usbserial-0001
|
|
||||||
upload_port = /dev/tty.usbserial-0001
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "bluetooth.h"
|
#include "bluetooth.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "temperature.h"
|
||||||
|
|
||||||
constexpr size_t bluetoothMaxDataSize = 200;
|
constexpr size_t bluetoothMaxDataSize = 200;
|
||||||
|
|
||||||
@ -17,10 +18,10 @@ constexpr uint16_t DEVINFO_MANUFACTURER_UUID = 0x2a29;
|
|||||||
constexpr uint16_t DEVINFO_NAME_UUID = 0x2a24;
|
constexpr uint16_t DEVINFO_NAME_UUID = 0x2a24;
|
||||||
constexpr uint16_t DEVINFO_SERIAL_UUID = 0x2a25;
|
constexpr uint16_t DEVINFO_SERIAL_UUID = 0x2a25;
|
||||||
|
|
||||||
const char* deviceName = "Window";
|
const char* deviceName = "TempTrack";
|
||||||
const char* manufacturerName = "CH";
|
const char* manufacturerName = "CH";
|
||||||
const char* serviceUUID = "22071991-feed-deaf-babe-150420870001";
|
const char* serviceUUID = "22071991-cccc-cccc-cccc-000000000001";
|
||||||
const char* characteristicUUID = "22071991-feed-deaf-babe-150420870002";
|
const char* characteristicUUID = "22071991-cccc-cccc-cccc-000000000002";
|
||||||
|
|
||||||
bool isConnected = false;
|
bool isConnected = false;
|
||||||
uint8_t bluetoothOutgoingBuffer[bluetoothMaxDataSize + 1];
|
uint8_t bluetoothOutgoingBuffer[bluetoothMaxDataSize + 1];
|
||||||
@ -67,7 +68,14 @@ BLE2902 descriptor{};
|
|||||||
BLEServer *server;
|
BLEServer *server;
|
||||||
Receiver receiver{};
|
Receiver receiver{};
|
||||||
|
|
||||||
|
bool bluetoothIsConfigured = false;
|
||||||
|
|
||||||
void bluetoothConfigure() {
|
void bluetoothConfigure() {
|
||||||
|
if (bluetoothIsConfigured) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bluetoothIsConfigured = true;
|
||||||
|
|
||||||
bluetoothDataBuffer = bluetoothOutgoingBuffer + 1;
|
bluetoothDataBuffer = bluetoothOutgoingBuffer + 1;
|
||||||
bluetoothResponse = bluetoothOutgoingBuffer;
|
bluetoothResponse = bluetoothOutgoingBuffer;
|
||||||
|
|
||||||
@ -98,6 +106,8 @@ void bluetoothConfigure() {
|
|||||||
|
|
||||||
characteristic->setValue(chipId);
|
characteristic->setValue(chipId);
|
||||||
service->start();
|
service->start();
|
||||||
|
|
||||||
|
bluetoothStartAdvertising();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bluetoothStartAdvertising() {
|
void bluetoothStartAdvertising() {
|
||||||
@ -123,9 +133,14 @@ enum class BluetoothRequest: uint8_t {
|
|||||||
* - No additional bytes expected
|
* - No additional bytes expected
|
||||||
*
|
*
|
||||||
* Response:
|
* Response:
|
||||||
* - BluetoothResponse::success, plus the number of bytes as a uint16_t (2 bytes)
|
* - BluetoothResponse::success
|
||||||
|
* - the number of bytes as a uint16_t (2 bytes)
|
||||||
|
* - the number of seconds until the next measurement as a uint16_t (2 bytes)
|
||||||
|
* - the number of seconds between measurements as a uint16_t (2 bytes)
|
||||||
|
* - the number of measurements as a uint16_t (2 bytes)
|
||||||
|
* - the number of seconds since power on as a uint32_t (4 bytes)
|
||||||
*/
|
*/
|
||||||
getNumberOfRecordedBytes = 0,
|
getInfo = 0,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request recording data
|
* @brief Request recording data
|
||||||
@ -152,53 +167,14 @@ 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 Request the time since the device was turned on
|
|
||||||
*
|
|
||||||
* Request:
|
|
||||||
* - No additional bytes expected
|
|
||||||
*
|
|
||||||
* Response:
|
|
||||||
* - BluetoothResponse::success, plus the number of seconds as a uint32_t (4 bytes)
|
|
||||||
*/
|
|
||||||
getCurrentTime = 3,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Request the number of seconds until the next measurement is performed
|
|
||||||
*
|
|
||||||
* Request:
|
|
||||||
* - No additional bytes expected
|
|
||||||
*
|
|
||||||
* Response:
|
|
||||||
* - BluetoothResponse::success, plus the number of seconds as a uint16_t (2 bytes)
|
|
||||||
*/
|
|
||||||
getSecondsUntilNextMeasurement = 4,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of seconds
|
|
||||||
*
|
|
||||||
* Request:
|
|
||||||
* - No additional bytes expected
|
|
||||||
*
|
|
||||||
* Response:
|
|
||||||
* - BluetoothResponse::success, plus the number of seconds as a uint16_t (2 bytes)
|
|
||||||
*/
|
|
||||||
getMeasurementInterval = 5,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BluetoothResponse: uint8_t {
|
enum class BluetoothResponse: uint8_t {
|
||||||
|
|
||||||
/**
|
/** The response to the last request is provided */
|
||||||
* @brief The response to the last request is provided
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
success = 0,
|
success = 0,
|
||||||
|
|
||||||
/**
|
/** Invalid command received */
|
||||||
* @brief Invalid command received
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
invalidCommand = 1,
|
invalidCommand = 1,
|
||||||
|
|
||||||
responseTooLarge = 2,
|
responseTooLarge = 2,
|
||||||
@ -245,17 +221,59 @@ void bluetoothDidReceiveData(uint8_t* buffer, size_t count) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t offset;
|
uint32_t currentTime;
|
||||||
|
uint16_t value;
|
||||||
BluetoothRequest request = static_cast<BluetoothRequest>(buffer[0]);
|
BluetoothRequest request = static_cast<BluetoothRequest>(buffer[0]);
|
||||||
switch (request)
|
switch (request) {
|
||||||
{
|
case BluetoothRequest::getInfo:
|
||||||
case BluetoothRequest::getNumberOfRecordedBytes:
|
// BluetoothResponse::success
|
||||||
count = getTotalNumberOfStoredBytes();
|
setResponse(BluetoothResponse::success);
|
||||||
setSuccessResponseWithNumber(count);
|
|
||||||
|
// the number of bytes as a uint16_t (2 bytes)
|
||||||
|
value = getTotalNumberOfStoredBytes();
|
||||||
|
memcpy(bluetoothDataBuffer, &value, sizeof(uint16_t));
|
||||||
|
bluetoothDataCount = sizeof(uint16_t);
|
||||||
|
|
||||||
|
// the number of seconds until the next measurement as a uint16_t (2 bytes)
|
||||||
|
value = secondsUntilNextTemperatureMeasurement();
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
|
// the number of seconds between measurements as a uint16_t (2 bytes)
|
||||||
|
value = temperatureMeasurementIntervalSeconds;
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
|
// the number of measurements as a uint16_t (2 bytes)
|
||||||
|
value = getNumberOfMeasurements();
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
|
// the maximum number of bytes that can be copied
|
||||||
|
value = bluetoothMaxDataSize;
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
|
||||||
|
bluetoothDataCount += sizeof(uint16_t);
|
||||||
|
|
||||||
|
// the number of seconds since power on as a uint32_t (4 bytes)
|
||||||
|
currentTime = time(NULL);
|
||||||
|
memcpy(bluetoothDataBuffer + bluetoothDataCount, ¤tTime, sizeof(uint32_t));
|
||||||
|
bluetoothDataCount += sizeof(uint32_t);
|
||||||
|
|
||||||
|
// The last temperatures
|
||||||
|
bluetoothDataBuffer[bluetoothDataCount] = getLastTemperature(0);
|
||||||
|
bluetoothDataCount += sizeof(uint8_t);
|
||||||
|
bluetoothDataBuffer[bluetoothDataCount] = getLastTemperature(1);
|
||||||
|
bluetoothDataCount += sizeof(uint8_t);
|
||||||
|
|
||||||
|
// Temperature sensor addresses
|
||||||
|
copySensorAddress(0, bluetoothDataBuffer + bluetoothDataCount);
|
||||||
|
bluetoothDataCount += TEMPERATURE_SENSOR_ADDRESS_SIZE;
|
||||||
|
copySensorAddress(1, bluetoothDataBuffer + bluetoothDataCount);
|
||||||
|
bluetoothDataCount += TEMPERATURE_SENSOR_ADDRESS_SIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BluetoothRequest::clearRecordingBuffer:
|
case BluetoothRequest::clearRecordingBuffer:
|
||||||
count = *((uint16_t*) buffer + 1);
|
memcpy(&count, buffer + 1, sizeof(uint16_t));
|
||||||
if (count != getTotalNumberOfStoredBytes()) {
|
if (count != getTotalNumberOfStoredBytes()) {
|
||||||
setResponseWithoutData(BluetoothResponse::invalidNumberOfBytesToDelete);
|
setResponseWithoutData(BluetoothResponse::invalidNumberOfBytesToDelete);
|
||||||
} else {
|
} else {
|
||||||
@ -265,33 +283,20 @@ void bluetoothDidReceiveData(uint8_t* buffer, size_t count) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BluetoothRequest::getRecordingData:
|
case BluetoothRequest::getRecordingData:
|
||||||
if (count != 5) {
|
if (count != sizeof(uint16_t) + sizeof(uint8_t)) {
|
||||||
setResponseWithoutData(BluetoothResponse::invalidCommand);
|
setResponseWithoutData(BluetoothResponse::invalidCommand);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
offset = *((uint16_t*) buffer + 1);
|
memcpy(&value, buffer + sizeof(uint8_t) , sizeof(uint16_t));
|
||||||
count = *((uint16_t*) buffer + 3);
|
memcpy(&count, buffer + sizeof(uint8_t) + sizeof(uint16_t), sizeof(uint16_t));
|
||||||
if (count > bluetoothMaxDataSize) {
|
if (count > bluetoothMaxDataSize) {
|
||||||
setResponseWithoutData(BluetoothResponse::responseTooLarge);
|
setResponseWithoutData(BluetoothResponse::responseTooLarge);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count = getRecordedBytesAtOffset(bluetoothDataBuffer, offset, count);
|
count = getRecordedBytesAtOffset(bluetoothDataBuffer, value, count);
|
||||||
bluetoothDataCount = count;
|
bluetoothDataCount = count;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BluetoothRequest::getCurrentTime:
|
|
||||||
setSuccessResponseWithUInt32(time(NULL));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BluetoothRequest::getSecondsUntilNextMeasurement:
|
|
||||||
count = secondsUntilNextTemperatureMeasurement();
|
|
||||||
setSuccessResponseWithNumber(count);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BluetoothRequest::getMeasurementInterval:
|
|
||||||
setSuccessResponseWithNumber(temperatureMeasurementIntervalSeconds);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
setResponseWithoutData(BluetoothResponse::unknownCommand);
|
setResponseWithoutData(BluetoothResponse::unknownCommand);
|
||||||
break;
|
break;
|
||||||
|
55
src/main.cpp
55
src/main.cpp
@ -7,8 +7,6 @@
|
|||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "temperature.h"
|
#include "temperature.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Temperature samples[temperatureSensorCount];
|
Temperature samples[temperatureSensorCount];
|
||||||
|
|
||||||
// Indicate when the next temperature measurement should be performed
|
// Indicate when the next temperature measurement should be performed
|
||||||
@ -71,7 +69,7 @@ void deepSleepUntilNextTemperatureMeasurement() {
|
|||||||
* @return false The button is not pressed
|
* @return false The button is not pressed
|
||||||
*/
|
*/
|
||||||
bool wakeupButtonIsPressed() {
|
bool wakeupButtonIsPressed() {
|
||||||
return gpio_get_level(wakeupButtonPin) == 1;
|
return gpio_get_level(wakeupButtonPin) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateStayAwakeTime() {
|
void updateStayAwakeTime() {
|
||||||
@ -85,33 +83,38 @@ bool shouldStayAwakeDueToActivity() {
|
|||||||
return bluetoothIsConnected();
|
return bluetoothIsConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void enableLED() {
|
||||||
// Configure LED pin
|
// Configure LED pin
|
||||||
// Equivalent to:
|
// Equivalent to: pinMode(1, OUTPUT);
|
||||||
// pinMode(1, OUTPUT);
|
|
||||||
gpio_config_t ledConfig;
|
gpio_config_t ledConfig;
|
||||||
ledConfig.pin_bit_mask = (1ULL << 1);
|
ledConfig.pin_bit_mask = (1ULL << 1);
|
||||||
ledConfig.mode = GPIO_MODE_OUTPUT;
|
ledConfig.mode = GPIO_MODE_OUTPUT;
|
||||||
ledConfig.pull_down_en = GPIO_PULLDOWN_ENABLE;
|
gpio_config(&ledConfig);
|
||||||
//gpio_config(&ledConfig); // TODO: Enable LED
|
|
||||||
|
|
||||||
// Enable LED, as long as ESP is awake
|
// Enable LED, as long as ESP is awake
|
||||||
// Equivalent to:
|
// Equivalent to: digitalWrite(1, LOW);
|
||||||
// digitalWrite(1, HIGH);
|
gpio_set_level(GPIO_NUM_1, 0); // For this led, low means on
|
||||||
//gpio_set_level(GPIO_NUM_1, 1);
|
}
|
||||||
|
|
||||||
// Configure button pin to wake up ESP from deep sleep on high signal with pulldown
|
void setup() {
|
||||||
// GPIO13 -> RTC_GPIO14
|
//Serial.begin(serialBaudRate);
|
||||||
rtc_gpio_pulldown_en(wakeupButtonPin);
|
|
||||||
rtc_gpio_wakeup_enable(wakeupButtonPin, GPIO_INTR_HIGH_LEVEL);
|
// LED useless inside case
|
||||||
|
//enableLED();
|
||||||
|
|
||||||
|
// Configure button pin to wake up ESP from deep sleep on low signal with pullup
|
||||||
|
rtc_gpio_pullup_en(wakeupButtonPin);
|
||||||
|
esp_sleep_enable_ext0_wakeup(wakeupButtonPin, 0);
|
||||||
|
|
||||||
// Enable EEPROM to persist measurements
|
// Enable EEPROM to persist measurements
|
||||||
// Only needed if sufficient measurements are in RTC memory
|
// Only needed if sufficient measurements are in RTC memory
|
||||||
storageConfigure();
|
storageConfigure();
|
||||||
|
|
||||||
if (wakeupButtonIsPressed()) {
|
// Configure bluetooth if wake button was pressed
|
||||||
|
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
|
||||||
|
Serial.println("Wake after button press");
|
||||||
bluetoothConfigure();
|
bluetoothConfigure();
|
||||||
// Serial.println("Bluetooth configured");
|
updateStayAwakeTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the temperature sensors
|
// Configure the temperature sensors
|
||||||
@ -119,37 +122,29 @@ void setup() {
|
|||||||
temperatureConfigure();
|
temperatureConfigure();
|
||||||
|
|
||||||
// TODO: Remove
|
// TODO: Remove
|
||||||
Serial.begin(serialBaudRate);
|
|
||||||
Serial.println("Setup complete");
|
Serial.println("Setup complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (shouldMeasureTemperature()) {
|
if (shouldMeasureTemperature()) {
|
||||||
|
Serial.println("Measuring");
|
||||||
temperaturePerformUpdate(samples);
|
temperaturePerformUpdate(samples);
|
||||||
saveTemperatures(samples);
|
saveTemperatures(samples);
|
||||||
setNextTemperatureMeasurementInterval();
|
setNextTemperatureMeasurementInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wakeupButtonIsPressed()) {
|
if (wakeupButtonIsPressed()) {
|
||||||
|
bluetoothConfigure(); // Only done once internally
|
||||||
updateStayAwakeTime();
|
updateStayAwakeTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldStayAwakeDueToActivity()) {
|
if (!shouldStayAwakeDueToActivity()) {
|
||||||
|
Serial.print("Sleeping for ");
|
||||||
|
Serial.print(secondsUntilNextTemperatureMeasurement());
|
||||||
|
Serial.println(" seconds");
|
||||||
// May return, if less then one second to wait
|
// May return, if less then one second to wait
|
||||||
// Otherwise control flow starts with setup() again
|
// Otherwise control flow starts with setup() again
|
||||||
deepSleepUntilNextTemperatureMeasurement();
|
deepSleepUntilNextTemperatureMeasurement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
255
|
|
||||||
0
|
|
||||||
0
|
|
||||||
255
|
|
||||||
0
|
|
||||||
0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
@ -11,9 +11,11 @@ constexpr uint32_t eepromChunkSize = 100;
|
|||||||
// 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;
|
||||||
|
RTC_DATA_ATTR uint16_t numberOfMeasurements = 0;
|
||||||
|
|
||||||
// The index into EEPROM storage where the next data should be written
|
// The index into EEPROM storage where the next data should be written
|
||||||
RTC_DATA_ATTR uint32_t eepromIndex = 0;
|
RTC_DATA_ATTR uint32_t eepromIndex = 0;
|
||||||
|
RTC_DATA_ATTR bool isFirstRunAfterPowerOn = true;
|
||||||
|
|
||||||
// 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];
|
||||||
@ -21,7 +23,7 @@ RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount];
|
|||||||
bool didSetupEEPROM = false;
|
bool didSetupEEPROM = false;
|
||||||
|
|
||||||
// On first boot, this is set to true; Afterwards it's remembered to be false
|
// On first boot, this is set to true; Afterwards it's remembered to be false
|
||||||
RTC_DATA_ATTR bool shouldStartNewRecording = true;
|
RTC_DATA_ATTR bool eepromIsConsideredEmpty = true;
|
||||||
|
|
||||||
constexpr uint16_t eepromOffset = 2; // Size of uint16
|
constexpr uint16_t eepromOffset = 2; // Size of uint16
|
||||||
constexpr uint16_t eepromDataSize = eepromSize - eepromOffset;
|
constexpr uint16_t eepromDataSize = eepromSize - eepromOffset;
|
||||||
@ -32,33 +34,36 @@ void setupEEPROMIfNeeded() {
|
|||||||
}
|
}
|
||||||
bool success = EEPROM.begin(eepromSize);
|
bool success = EEPROM.begin(eepromSize);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// Serial.println("Failed to set up EEPROM");
|
Serial.println("Failed to set up EEPROM");
|
||||||
didSetupEEPROM = false;
|
didSetupEEPROM = false;
|
||||||
}
|
}
|
||||||
// Serial.print("EEPROM Size ");
|
Serial.print("EEPROM size: ");
|
||||||
// Serial.print(eepromSize);
|
Serial.println(eepromSize);
|
||||||
// Serial.println(" bytes");
|
|
||||||
didSetupEEPROM = true;
|
didSetupEEPROM = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storageConfigure() {
|
void resetLastMeasurements() {
|
||||||
if (dataIndex >= eepromChunkSize) {
|
|
||||||
// Configure EEPROM at start
|
|
||||||
// May be initialized later
|
|
||||||
setupEEPROMIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that first values are stored
|
|
||||||
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;
|
||||||
|
lastTemperatures[index].value = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void storageConfigure() {
|
||||||
|
if (!isFirstRunAfterPowerOn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isFirstRunAfterPowerOn = false;
|
||||||
|
|
||||||
|
// Ensure that first values are stored
|
||||||
|
resetLastMeasurements();
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t getNumberOfBytesStoredInEEPROM() {
|
uint16_t getNumberOfBytesStoredInEEPROM() {
|
||||||
setupEEPROMIfNeeded();
|
if (eepromIsConsideredEmpty) {
|
||||||
if (shouldStartNewRecording) {
|
return 0; // Discard any previous bytes
|
||||||
return 0; // Discard any
|
|
||||||
}
|
}
|
||||||
|
setupEEPROMIfNeeded();
|
||||||
return EEPROM.readShort(0);
|
return EEPROM.readShort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +76,12 @@ void moveDataToEEPROMIfNeeded() {
|
|||||||
if (eepromIndex >= eepromDataSize) {
|
if (eepromIndex >= eepromDataSize) {
|
||||||
return; // No more space in EEPROM, keep filling RTC memory
|
return; // No more space in EEPROM, keep filling RTC memory
|
||||||
}
|
}
|
||||||
shouldStartNewRecording = false;
|
// Preparing to write new data, so set to false
|
||||||
|
eepromIsConsideredEmpty = false;
|
||||||
|
setupEEPROMIfNeeded();
|
||||||
|
if (!didSetupEEPROM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Write until EEPROM is full
|
// Write until EEPROM is full
|
||||||
uint16_t bytesRemaining = eepromDataSize - eepromIndex;
|
uint16_t bytesRemaining = eepromDataSize - eepromIndex;
|
||||||
@ -89,7 +99,18 @@ void moveDataToEEPROMIfNeeded() {
|
|||||||
void saveByteAtCurrentIndex(uint8_t byte) {
|
void saveByteAtCurrentIndex(uint8_t byte) {
|
||||||
data[dataIndex] = byte;
|
data[dataIndex] = byte;
|
||||||
dataIndex += 1;
|
dataIndex += 1;
|
||||||
Serial.println(byte);
|
}
|
||||||
|
|
||||||
|
uint8_t byteForAbsoluteTemperature(long temp) {
|
||||||
|
// Convert to temperature range
|
||||||
|
long converted = (temp - (temperatureShiftForStorage)) / 500;
|
||||||
|
if (converted < temperatureMinimumValue) {
|
||||||
|
return temperatureMinimumValue;
|
||||||
|
}
|
||||||
|
if (converted > temperatureMaximumValue) {
|
||||||
|
return temperatureMaximumValue;
|
||||||
|
}
|
||||||
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveTemperatureAtCurrentIndex(Temperature temp) {
|
void saveTemperatureAtCurrentIndex(Temperature temp) {
|
||||||
@ -97,15 +118,8 @@ void saveTemperatureAtCurrentIndex(Temperature temp) {
|
|||||||
saveByteAtCurrentIndex(static_cast<uint8_t>(temp.status));
|
saveByteAtCurrentIndex(static_cast<uint8_t>(temp.status));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Convert to temperature range
|
uint8_t byte = byteForAbsoluteTemperature(temp.value);
|
||||||
long converted = (temp.value - (-40000)) / 500;
|
saveByteAtCurrentIndex(byte);
|
||||||
if (converted < temperatureMinimumValue) {
|
|
||||||
saveByteAtCurrentIndex(temperatureMinimumValue);
|
|
||||||
} else if (converted > temperatureMaximumValue) {
|
|
||||||
saveByteAtCurrentIndex(temperatureMaximumValue);
|
|
||||||
} else {
|
|
||||||
saveByteAtCurrentIndex(converted);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsAbsoluteTemperatureRecording(Temperature* temperatures) {
|
bool needsAbsoluteTemperatureRecording(Temperature* temperatures) {
|
||||||
@ -164,12 +178,24 @@ void saveTemperatures(Temperature* temperatures) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
moveDataToEEPROMIfNeeded();
|
moveDataToEEPROMIfNeeded();
|
||||||
|
numberOfMeasurements += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getTotalNumberOfStoredBytes() {
|
uint16_t getTotalNumberOfStoredBytes() {
|
||||||
return getNumberOfBytesStoredInEEPROM() + dataIndex;
|
return getNumberOfBytesStoredInEEPROM() + dataIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t getNumberOfMeasurements() {
|
||||||
|
return numberOfMeasurements;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getLastTemperature(uint8_t sensorIndex) {
|
||||||
|
if (lastTemperatures[sensorIndex].status != TemperatureStatus::temperatureIsValid) {
|
||||||
|
return static_cast<uint8_t>(lastTemperatures[sensorIndex].status);
|
||||||
|
}
|
||||||
|
return byteForAbsoluteTemperature(lastTemperatures[sensorIndex].value);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) {
|
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) {
|
||||||
// TODO: Check limits
|
// TODO: Check limits
|
||||||
uint16_t eepromByteCount = getNumberOfBytesStoredInEEPROM();
|
uint16_t eepromByteCount = getNumberOfBytesStoredInEEPROM();
|
||||||
@ -191,6 +217,9 @@ uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t cou
|
|||||||
}
|
}
|
||||||
|
|
||||||
void discardAllRecordedBytes() {
|
void discardAllRecordedBytes() {
|
||||||
shouldStartNewRecording = true;
|
eepromIsConsideredEmpty = true;
|
||||||
dataIndex = 0;
|
dataIndex = 0;
|
||||||
|
numberOfMeasurements = 0;
|
||||||
|
resetLastMeasurements();
|
||||||
|
|
||||||
}
|
}
|
@ -11,14 +11,9 @@ constexpr int8_t TEMPERATURE_ALARM_LIMIT_HIGH = 80;
|
|||||||
#define INVALID_SENSOR_INDEX 255
|
#define INVALID_SENSOR_INDEX 255
|
||||||
|
|
||||||
constexpr uint8_t TEMPERATURE_SENSOR_ERROR_THRESHOLD = 3;
|
constexpr uint8_t TEMPERATURE_SENSOR_ERROR_THRESHOLD = 3;
|
||||||
// The number of bytes composing a temperature sensor address
|
|
||||||
constexpr int TEMPERATURE_SENSOR_ADDRESS_SIZE = 8;
|
|
||||||
|
|
||||||
constexpr bool TEMPERATURE_SENSOR_PARASITE_POWER = false;
|
constexpr bool TEMPERATURE_SENSOR_PARASITE_POWER = false;
|
||||||
|
|
||||||
// Note: Pin requires external 4.7kOhm pull-up
|
|
||||||
constexpr uint8_t TEMPERATURE_SENSOR_PIN = 13;
|
|
||||||
|
|
||||||
// Indicator if the temperature sensors have been configured
|
// Indicator if the temperature sensors have been configured
|
||||||
RTC_DATA_ATTR bool didConfigureTemperatureSensors = false;
|
RTC_DATA_ATTR bool didConfigureTemperatureSensors = false;
|
||||||
|
|
||||||
@ -67,7 +62,7 @@ uint8_t getSensorIndex(const OneWireNg::Id& id) {
|
|||||||
uint8_t getIndexOfFirstEmptySensorSlot() {
|
uint8_t getIndexOfFirstEmptySensorSlot() {
|
||||||
for (uint8_t sensorIndex = 0; sensorIndex < TEMPERATURE_SENSOR_MAX_COUNT; sensorIndex += 1) {
|
for (uint8_t sensorIndex = 0; sensorIndex < TEMPERATURE_SENSOR_MAX_COUNT; sensorIndex += 1) {
|
||||||
if (!sensors[sensorIndex].isSet) {
|
if (!sensors[sensorIndex].isSet) {
|
||||||
return false;
|
return sensorIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return INVALID_SENSOR_INDEX;
|
return INVALID_SENSOR_INDEX;
|
||||||
@ -85,6 +80,7 @@ uint8_t addNewSensor(const OneWireNg::Id& id) {
|
|||||||
sensors[sensorIndex].address[pos] = id[pos];
|
sensors[sensorIndex].address[pos] = id[pos];
|
||||||
}
|
}
|
||||||
sensors[sensorIndex].isSet = true;
|
sensors[sensorIndex].isSet = true;
|
||||||
|
sensors[sensorIndex].foundDuringCurrentUpdate = true;
|
||||||
availableSensorCount += 1;
|
availableSensorCount += 1;
|
||||||
return sensorIndex;
|
return sensorIndex;
|
||||||
}
|
}
|
||||||
@ -94,6 +90,10 @@ void removeSensorAtIndex(uint8_t sensorIndex) {
|
|||||||
availableSensorCount -= 1;
|
availableSensorCount -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void copySensorAddress(uint8_t index, uint8_t* buffer) {
|
||||||
|
memcpy(buffer, sensors[index].address, TEMPERATURE_SENSOR_ADDRESS_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
void printSensorAddress(const OneWireNg::Id& id) {
|
void printSensorAddress(const OneWireNg::Id& id) {
|
||||||
for (uint8_t i = 0; i < TEMPERATURE_SENSOR_ADDRESS_SIZE; i += 1) {
|
for (uint8_t i = 0; i < TEMPERATURE_SENSOR_ADDRESS_SIZE; i += 1) {
|
||||||
Serial.print(" 0x");
|
Serial.print(" 0x");
|
||||||
@ -124,15 +124,6 @@ void temperatureConfigure() {
|
|||||||
|
|
||||||
scratchpad = reinterpret_cast<DSTherm::Scratchpad*>(&scratchpadBuffer[0]);
|
scratchpad = reinterpret_cast<DSTherm::Scratchpad*>(&scratchpadBuffer[0]);
|
||||||
|
|
||||||
// Write sensor resolution and set limits
|
|
||||||
if (sensorInterface.writeScratchpadAll(
|
|
||||||
TEMPERATURE_ALARM_LIMIT_HIGH,
|
|
||||||
TEMPERATURE_ALARM_LIMIT_LOW,
|
|
||||||
TEMPERATURE_RESOLUTION) != OneWireNg::ErrorCode::EC_SUCCESS) {
|
|
||||||
Serial.println("Failed to set temperature limits and resolution");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear discovery flags
|
// Clear discovery flags
|
||||||
clearFoundIndicatorForAllSensors();
|
clearFoundIndicatorForAllSensors();
|
||||||
|
|
||||||
@ -141,10 +132,10 @@ void temperatureConfigure() {
|
|||||||
uint8_t sensorIndex = getSensorIndex(id);
|
uint8_t sensorIndex = getSensorIndex(id);
|
||||||
if (sensorIndex == INVALID_SENSOR_INDEX) {
|
if (sensorIndex == INVALID_SENSOR_INDEX) {
|
||||||
sensorIndex = addNewSensor(id);
|
sensorIndex = addNewSensor(id);
|
||||||
Serial.print("Added sensor ");
|
Serial.print("Sensor ");
|
||||||
|
Serial.print(sensorIndex);
|
||||||
|
Serial.print(": ");
|
||||||
printSensorAddress(id);
|
printSensorAddress(id);
|
||||||
Serial.print(" at index ");
|
|
||||||
Serial.println(sensorIndex);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Mark existing sensor
|
// Mark existing sensor
|
||||||
@ -165,11 +156,26 @@ void temperatureConfigure() {
|
|||||||
}
|
}
|
||||||
Serial.print("Removed sensor ");
|
Serial.print("Removed sensor ");
|
||||||
printSensorAddressAtIndex(sensorIndex);
|
printSensorAddressAtIndex(sensorIndex);
|
||||||
Serial.print(" at index ");
|
|
||||||
Serial.println(sensorIndex);
|
Serial.println(sensorIndex);
|
||||||
removeSensorAtIndex(sensorIndex);
|
removeSensorAtIndex(sensorIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (availableSensorCount == 0) {
|
||||||
|
Serial.println("No sensors available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print(availableSensorCount);
|
||||||
|
Serial.println(" temperature sensors available");
|
||||||
|
|
||||||
|
// Write sensor resolution and set limits
|
||||||
|
if (sensorInterface.writeScratchpadAll(
|
||||||
|
TEMPERATURE_ALARM_LIMIT_HIGH,
|
||||||
|
TEMPERATURE_ALARM_LIMIT_LOW,
|
||||||
|
TEMPERATURE_RESOLUTION) != OneWireNg::ErrorCode::EC_SUCCESS) {
|
||||||
|
Serial.println("Failed to set temperature limits and resolution");
|
||||||
|
return;
|
||||||
|
}
|
||||||
didConfigureTemperatureSensors = true;
|
didConfigureTemperatureSensors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +189,7 @@ void temperaturePerformUpdate(Temperature* temperatures) {
|
|||||||
for (const auto& id: (OneWireNg&) ow) {
|
for (const auto& id: (OneWireNg&) ow) {
|
||||||
uint8_t sensorIndex = getSensorIndex(id);
|
uint8_t sensorIndex = getSensorIndex(id);
|
||||||
if (sensorIndex == INVALID_SENSOR_INDEX) {
|
if (sensorIndex == INVALID_SENSOR_INDEX) {
|
||||||
|
Serial.println("Invalid sensor");
|
||||||
// Invalid sensor id
|
// Invalid sensor id
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -190,10 +197,13 @@ void temperaturePerformUpdate(Temperature* temperatures) {
|
|||||||
if (sensorInterface.readScratchpad(id, scratchpad) != OneWireNg::EC_SUCCESS) {
|
if (sensorInterface.readScratchpad(id, scratchpad) != OneWireNg::EC_SUCCESS) {
|
||||||
// Invalid CRC
|
// Invalid CRC
|
||||||
temperatures[sensorIndex].status = TemperatureStatus::sensorError;
|
temperatures[sensorIndex].status = TemperatureStatus::sensorError;
|
||||||
|
Serial.println("Invalid CRC");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
temperatures[sensorIndex].value = scratchpad->getTemp(); // In millidegrees Celcius
|
temperatures[sensorIndex].value = scratchpad->getTemp(); // In millidegrees Celcius
|
||||||
temperatures[sensorIndex].status = TemperatureStatus::temperatureIsValid;
|
temperatures[sensorIndex].status = TemperatureStatus::temperatureIsValid;
|
||||||
|
Serial.print(temperatures[sensorIndex].value);
|
||||||
|
Serial.println("°C");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update missing sensors
|
// Update missing sensors
|
||||||
|
Loading…
Reference in New Issue
Block a user