Avionics
Core avionics package for CURE flight computers
Loading...
Searching...
No Matches
DataSaverSPI.h
Go to the documentation of this file.
1#ifndef DATASAVERSPI_H
2#define DATASAVERSPI_H
3
4#include "ArduinoHAL.h"
7#include <array>
8#include <cstdlib>
9#include <limits>
10
11
12constexpr uint32_t kMetadataStartAddress = 0x000000; // Start writing metadata at the beginning of flash
13constexpr uint32_t kDataStartAddress = 0x001000; // Start writing data after 1 sector (4kB) of metadata
14constexpr uint32_t kPostLaunchFlagAddress = 0x000000; // Address of the post-launch flag
15constexpr uint32_t kLaunchStartAddressAddress = 0x000001; // Address of the launch start address (32 bits)
16
17constexpr uint8_t kPostLaunchFlagTrue = 0x00; // Flag to indicate post-launch mode is active
18constexpr uint8_t kPostLaunchFlagFalse = 0x01; // Flag to indicate post-launch mode is not active
19
20constexpr uint8_t kEmptyPageValue = 0xFF;
21
22
23#pragma pack(push, 1) // Pack the struct to avoid padding between the name and datas
24typedef struct { // NOLINT(altera-struct-pack-align)
25 uint8_t name;
26 float data;
27} Record_t;
28
29typedef struct { // NOLINT(altera-struct-pack-align)
30 uint8_t name;
31 uint32_t timestamp_ms;
33#pragma pack(pop) // Stop packing from here on out
34
40class DataSaverSPI : public IDataSaver {
41public:
42
43 static constexpr size_t kBufferSize_bytes = 256;
44
53 DataSaverSPI(uint16_t timestampInterval_ms, Adafruit_SPIFlash *flash);
54
67 int saveDataPoint(const DataPoint& dataPoint, uint8_t name) override;
68
77 int saveTimestamp(uint32_t timestamp_ms);
78
85 virtual bool begin() override;
86
99 bool isPostLaunchMode();
100
107 void clearPostLaunchMode();
108
127 void launchDetected(uint32_t launchTimestamp_ms);
128
136 void dumpData(Stream &serial, bool ignoreEmptyPages);
137
143 void clearInternalState();
144
152 void eraseAllData();
153
158 uint32_t getLastTimestamp() const {
159 return lastTimestamp_ms_;
160 }
161
168 return lastDataPoint_;
169 }
170
175 uint32_t getLaunchWriteAddress() const {
176 return launchWriteAddress_;
177 }
178
183 uint32_t getNextWriteAddress() const {
184 return nextWriteAddress_;
185 }
186
192 lastTimestamp_ms_ = 0;
193 }
194
201 return this->postLaunchMode_;
202 }
203
204private:
205 // Interval at which to store the timestamp in flash.
206 uint16_t timestampInterval_ms_;
207
208 // The last timestamp we actually wrote to flash.
209 uint32_t lastTimestamp_ms_;
210
211 // The timestamp this module was given for launch
212 uint32_t launchTimestamp_ms_;
213
214 // The last data point written
215 DataPoint lastDataPoint_;
216
217 // Flash driver
218 Adafruit_SPIFlash *flash_;
219
220 // Next address in flash at which to write.
221 uint32_t nextWriteAddress_;
222
223 // Address at which launch was detected
224 uint32_t launchWriteAddress_;
225
226 bool postLaunchMode_;
227
228private:
236 bool writeToFlash(const uint8_t* data, size_t length);
237
245 bool readFromFlash(uint32_t& readAddress, uint8_t* buffer, size_t length);
246
247 // Write buffer to improve write performance
248 uint8_t buffer_[kBufferSize_bytes] = {};
249 size_t bufferIndex_ = 0;
250 uint32_t bufferFlushes_ = 0; // Keep track of how many times the buffer has been flushed
251
252public:
258 size_t getBufferIndex() const {
259 return bufferIndex_;
260 }
261
267 uint32_t getBufferFlushes() const {
268 return bufferFlushes_;
269 }
270
276 return isChipFullDueToPostLaunchProtection_;
277 }
278
284 return rebootedInPostLaunchMode_;
285 }
286
287#ifdef UNIT_TEST
296 void setPostLaunchStateForTest(uint32_t nextWriteAddress_in,
297 uint32_t launchWriteAddress_in,
298 bool postLaunchMode_in) {
300 nextWriteAddress_ = nextWriteAddress_in;
301 launchWriteAddress_ = launchWriteAddress_in;
302 postLaunchMode_ = postLaunchMode_in;
303 isChipFullDueToPostLaunchProtection_ = false;
304 }
305#endif
306
307private:
313 uint32_t normalizeDataAddress(uint32_t address) const;
314
321 bool isProtectedLaunchSector(uint32_t sectorNumber) const;
322
326 enum class SectorEraseResult {
327 kErased,
328 kProtectedSectorLatched,
329 kFlashEraseFailed
330 };
331
340 SectorEraseResult eraseSectorForWriteAndLatchOnProtection(uint32_t sectorNumber);
341
347 bool shouldStopForPostLaunchWindow();
348
356 int flushBuffer();
357
365 int addDataToBuffer(const uint8_t* data, size_t length);
366
367
368 // Overloaded functions to add data to the buffer from a Record_t or TimestampRecord_t
369 // More efficient than callling addDataToBuffer with each part of the record
375 int addRecordToBuffer(Record_t * record) {
376 return addDataToBuffer(reinterpret_cast<const uint8_t*>(record), 5);
377 }
378
384 int addRecordToBuffer(TimestampRecord_t * record) {
385 return addDataToBuffer(reinterpret_cast<const uint8_t*>(record), 5);
386 }
387
388 // The chip will keep overwriting data forever unless post launch data is being protected.
389 // Once it wraps back around to the launch write address, it will stop writing data.
390 bool isChipFullDueToPostLaunchProtection_;
391
392 // If the flight computer boots and is already in post launch mode, do not write to flash.
393 // Calling clearPostLaunchMode() will allow writing to flash again after a reboot.
394 bool rebootedInPostLaunchMode_ = false;
395
396 // Tracks which sector has already been pre-erased for the next boundary write.
397 // UINT32_MAX means "no prepared sector".
398 uint32_t preparedSectorNumber_ = std::numeric_limits<uint32_t>::max();
399};
400
401#endif // DATA_SAVER_SPI_H
constexpr uint32_t kDataStartAddress
constexpr uint32_t kMetadataStartAddress
constexpr uint8_t kPostLaunchFlagTrue
constexpr uint32_t kPostLaunchFlagAddress
constexpr uint8_t kPostLaunchFlagFalse
constexpr uint32_t kLaunchStartAddressAddress
constexpr uint8_t kEmptyPageValue
Timestamped float measurement container.
Definition DataPoint.h:11
DataSaverSPI(uint16_t timestampInterval_ms, Adafruit_SPIFlash *flash)
Construct a new DataSaverSPI object.
void resetTimestamp()
Resets the timestamp to 0. Can be used to start a new flight during runtime. Useful for testing.
size_t getBufferIndex() const
Returns the current buffer index Useful for testing.
static constexpr size_t kBufferSize_bytes
uint32_t getLaunchWriteAddress() const
Returns the launch-protected address computed during launch detection.
bool getIsChipFullDueToPostLaunchProtection() const
Returns whether writes have been stopped by post-launch protection.
bool quickGetPostLaunchMode()
Returns whether the flash chip is in post-launch mode without updating the post-launch mode flag or r...
uint32_t getNextWriteAddress() const
Returns the next flash address where a full page will be written.
int saveDataPoint(const DataPoint &dataPoint, uint8_t name) override
Saves a DataPoint to SPI flash.
void clearInternalState()
Reset in-memory pointers without erasing flash contents.
uint32_t getLastTimestamp() const
Returns the last timestamp that was actually written to flash.
bool isPostLaunchMode()
Returns whether the metadata from the flash chip indicates that it contains post-launch data that has...
void clearPostLaunchMode()
Clears the post-launch mode flag on the flash chip **WARNING: This will allow the data to be overwrit...
DataPoint getLastDataPoint() const
Returns the last DataPoint that was written (not necessarily including timestamp, just the data chunk...
void eraseAllData()
Erase the entire flash chip to start fresh.
int saveTimestamp(uint32_t timestamp_ms)
Persist a bare timestamp entry to flash.
uint32_t getBufferFlushes() const
Returns the current buffer flush count Useful for testing.
bool getRebootedInPostLaunchMode() const
Returns whether startup detected existing post-launch mode metadata.
void dumpData(Stream &serial, bool ignoreEmptyPages)
Stream all recorded data to a serial connection.
virtual bool begin() override
Initialize the flash chip and metadata.
void launchDetected(uint32_t launchTimestamp_ms)
Call this when launch is detected to set the post-launch flag and prevent any data from being overwri...
Abstract interface for persisting timestamped data points.
Definition DataSaver.h:13
uint8_t name
float data
uint32_t timestamp_ms