diff --git a/include/storage.h b/include/storage.h index be4c80f..8563b2b 100644 --- a/include/storage.h +++ b/include/storage.h @@ -17,6 +17,8 @@ constexpr size_t rtcStorageSize = 7600; constexpr size_t maxEepromSize = 13350; constexpr size_t eepromSize = 13350; +constexpr size_t totalStorageSize = rtcStorageSize + eepromSize; + // The minimum temperature to store, in millidegrees celcius // True minimum will be higher by 1°, since two values are reserved constexpr long temperatureShiftForStorage = -40000; @@ -44,6 +46,8 @@ uint16_t getNumberOfMeasurements(); uint8_t getLastTemperature(uint8_t sensorIndex); +uint16_t getTimeSinceValidTemperature(uint8_t sensorIndex); + uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count); void discardAllRecordedBytes(); \ No newline at end of file diff --git a/src/bluetooth.cpp b/src/bluetooth.cpp index 0c039be..f7a6978 100644 --- a/src/bluetooth.cpp +++ b/src/bluetooth.cpp @@ -30,7 +30,7 @@ uint8_t* bluetoothResponse; size_t bluetoothDataCount = 0; void bluetoothStartAdvertising(); -void bluetoothDidReceiveData(uint8_t* buffer, size_t count); +void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count); class BluetoothConnection: public BLEServerCallbacks { @@ -215,86 +215,121 @@ uint16_t readNumberFromReceivedBuffer(uint8_t* buffer) { return *((uint16_t*) buffer + 1); } -void bluetoothDidReceiveData(uint8_t* buffer, size_t count) { +void fillInfo() { + uint16_t value; + + // BluetoothResponse::success + setResponse(BluetoothResponse::success); + + // 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) + uint32_t 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; + + // Time since measurement of sensor 0 + value = getTimeSinceValidTemperature(0); + memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t)); + bluetoothDataCount += sizeof(uint16_t); + + // Time since measurement of sensor 1 + value = getTimeSinceValidTemperature(1); + memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t)); + bluetoothDataCount += sizeof(uint16_t); + + value = totalStorageSize; + memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t)); + bluetoothDataCount += sizeof(uint16_t); +} + +void getRecordingData(uint8_t* buffer, uint16_t count) { + if (count != 2 * sizeof(uint16_t)) { + setResponseWithoutData(BluetoothResponse::invalidCommand); + return; + } + uint16_t byteCount; + memcpy(&byteCount, buffer, sizeof(uint16_t)); + if (byteCount > bluetoothMaxDataSize) { + setResponseWithoutData(BluetoothResponse::responseTooLarge); + return; + } + + uint16_t byteOffset; + memcpy(&byteOffset, buffer + sizeof(uint16_t), sizeof(uint16_t)); + + bluetoothDataCount = getRecordedBytesAtOffset(bluetoothDataBuffer, byteOffset, byteCount); +} + +void clearRecordingBuffer(uint8_t* buffer, uint16_t count) { + if (count != sizeof(uint16_t)) { + setResponseWithoutData(BluetoothResponse::invalidCommand); + return; + } + uint16_t byteCount; + memcpy(&byteCount, buffer, sizeof(uint16_t)); + if (byteCount != getTotalNumberOfStoredBytes()) { + setResponseWithoutData(BluetoothResponse::invalidNumberOfBytesToDelete); + return; + } + + discardAllRecordedBytes(); + setResponseWithoutData(BluetoothResponse::success); +} + +void bluetoothDidReceiveData(uint8_t* buffer, uint16_t count) { if (count < 1) { setResponseWithoutData(BluetoothResponse::invalidCommand); return; } - uint32_t currentTime; - uint16_t value; BluetoothRequest request = static_cast(buffer[0]); switch (request) { case BluetoothRequest::getInfo: - // BluetoothResponse::success - setResponse(BluetoothResponse::success); - - // 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; + fillInfo(); break; case BluetoothRequest::clearRecordingBuffer: - memcpy(&count, buffer + 1, sizeof(uint16_t)); - if (count != getTotalNumberOfStoredBytes()) { - setResponseWithoutData(BluetoothResponse::invalidNumberOfBytesToDelete); - } else { - discardAllRecordedBytes(); - setResponseWithoutData(BluetoothResponse::success); - } + clearRecordingBuffer(buffer + sizeof(uint8_t), count - sizeof(uint8_t)); break; case BluetoothRequest::getRecordingData: - if (count != sizeof(uint16_t) + sizeof(uint8_t)) { - setResponseWithoutData(BluetoothResponse::invalidCommand); - break; - } - memcpy(&value, buffer + sizeof(uint8_t) , sizeof(uint16_t)); - memcpy(&count, buffer + sizeof(uint8_t) + sizeof(uint16_t), sizeof(uint16_t)); - if (count > bluetoothMaxDataSize) { - setResponseWithoutData(BluetoothResponse::responseTooLarge); - break; - } - count = getRecordedBytesAtOffset(bluetoothDataBuffer, value, count); - bluetoothDataCount = count; + getRecordingData(buffer + sizeof(uint8_t), count - sizeof(uint8_t)); break; default: diff --git a/src/main.cpp b/src/main.cpp index 4d341ce..4c4ca63 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -134,7 +134,7 @@ void loop() { setNextTemperatureMeasurementInterval(); } - if (wakeupButtonIsPressed()) { + if (wakeupButtonIsPressed() || bluetoothIsConnected()) { bluetoothConfigure(); // Only done once internally updateStayAwakeTime(); } @@ -146,5 +146,7 @@ void loop() { // May return, if less then one second to wait // Otherwise control flow starts with setup() again deepSleepUntilNextTemperatureMeasurement(); + } else { + delay(100); } } \ No newline at end of file diff --git a/src/storage.cpp b/src/storage.cpp index 37990cc..7c73831 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -19,13 +19,14 @@ RTC_DATA_ATTR bool isFirstRunAfterPowerOn = true; // Keeps the last valid temperatures for each sensor RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount]; +RTC_DATA_ATTR uint32_t lastValidTemperatureTime[temperatureSensorCount]; bool didSetupEEPROM = false; // On first boot, this is set to true; Afterwards it's remembered to be false RTC_DATA_ATTR bool eepromIsConsideredEmpty = true; -constexpr uint16_t eepromOffset = 2; // Size of uint16 +constexpr uint16_t eepromOffset = sizeof(uint16_t); constexpr uint16_t eepromDataSize = eepromSize - eepromOffset; void setupEEPROMIfNeeded() { @@ -46,6 +47,7 @@ void resetLastMeasurements() { for (uint8_t index = 0; index < temperatureSensorCount; index += 1) { lastTemperatures[index].status == TemperatureStatus::sensorNotFound; lastTemperatures[index].value = 0; + lastValidTemperatureTime[index] = 0; } } @@ -146,6 +148,7 @@ void saveTemperatures(Temperature* temperatures) { if (temperatures[sensorIndex].status == TemperatureStatus::temperatureIsValid) { // Only update if temperature is valid lastTemperatures[sensorIndex] = temperatures[sensorIndex]; + lastValidTemperatureTime[sensorIndex] = time(NULL); } } } else { @@ -169,6 +172,7 @@ void saveTemperatures(Temperature* temperatures) { if (temperatures[index].status == TemperatureStatus::temperatureIsValid) { // Only update if temperature is valid lastTemperatures[index] = temperatures[index]; + lastValidTemperatureTime[index] = time(NULL); } } // Ensure storage with uneven number of sensors @@ -196,6 +200,10 @@ uint8_t getLastTemperature(uint8_t sensorIndex) { return byteForAbsoluteTemperature(lastTemperatures[sensorIndex].value); } +uint16_t getTimeSinceValidTemperature(uint8_t sensorIndex) { + return time(NULL) - lastValidTemperatureTime[sensorIndex]; +} + uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) { // TODO: Check limits uint16_t eepromByteCount = getNumberOfBytesStoredInEEPROM(); @@ -221,5 +229,4 @@ void discardAllRecordedBytes() { dataIndex = 0; numberOfMeasurements = 0; resetLastMeasurements(); - } \ No newline at end of file