66#include " data_handling/DataSaver.h"
77#include < array>
88#include < cstdlib>
9+ #include < limits>
910
1011
1112constexpr uint32_t kMetadataStartAddress = 0x000000 ; // Start writing metadata at the beginning of flash
@@ -60,7 +61,8 @@ class DataSaverSPI : public IDataSaver {
6061 *
6162 * @param dataPoint The data point to save
6263 * @param name An 8-bit “identifier” for the data point (could be a sensor ID)
63- * @return int 0 on success; non-zero on error
64+ * @return int 0 on success, 1 when writes are blocked by post-launch state,
65+ * and -1 on write/buffer error.
6466 */
6567 int saveDataPoint (const DataPoint& dataPoint, uint8_t name) override ;
6668
@@ -69,12 +71,16 @@ class DataSaverSPI : public IDataSaver {
6971 * @param timestamp_ms Timestamp in milliseconds to record.
7072 * @note When to use: emitted internally when gaps exceed
7173 * timestampInterval_ms_, or explicitly in tests.
74+ * @return int 0 on success, 1 when writes are blocked by post-launch state,
75+ * and -1 on non-post-launch write/buffer error.
7276 */
7377 int saveTimestamp (uint32_t timestamp_ms);
7478
7579 /* *
7680 * @brief Initialize the flash chip and metadata.
7781 * @note When to use: call during setup before any saveDataPoint usage.
82+ * @return true when flash is initialized and writable for logging.
83+ * @return false when initialization fails or chip is already in post-launch mode.
7884 */
7985 virtual bool begin () override ;
8086
@@ -116,6 +122,7 @@ class DataSaverSPI : public IDataSaver {
116122 *
117123 * The rocket may not be recovered for several hours, this prevents the cool launch data
118124 * from being overwitten with boring laying-on-the-ground data.
125+ * @param launchTimestamp_ms Timestamp at which launch was detected.
119126 */
120127 void launchDetected (uint32_t launchTimestamp_ms);
121128
@@ -146,6 +153,7 @@ class DataSaverSPI : public IDataSaver {
146153
147154 /* *
148155 * @brief Returns the last timestamp that was actually written to flash.
156+ * @return Last persisted timestamp in milliseconds.
149157 */
150158 uint32_t getLastTimestamp () const {
151159 return lastTimestamp_ms_;
@@ -154,15 +162,24 @@ class DataSaverSPI : public IDataSaver {
154162 /* *
155163 * @brief Returns the last DataPoint that was written (not necessarily
156164 * including timestamp, just the data chunk).
165+ * @return Copy of the last cached data point.
157166 */
158167 DataPoint getLastDataPoint () const {
159168 return lastDataPoint_;
160169 }
161170
171+ /* *
172+ * @brief Returns the launch-protected address computed during launch detection.
173+ * @return Address in flash used as post-launch protection boundary.
174+ */
162175 uint32_t getLaunchWriteAddress () const {
163176 return launchWriteAddress_;
164177 }
165178
179+ /* *
180+ * @brief Returns the next flash address where a full page will be written.
181+ * @return Next write address in flash.
182+ */
166183 uint32_t getNextWriteAddress () const {
167184 return nextWriteAddress_;
168185 }
@@ -178,6 +195,7 @@ class DataSaverSPI : public IDataSaver {
178195 /* *
179196 * @brief Returns whether the flash chip is in post-launch mode
180197 * without updating the post-launch mode flag or reading from flash.
198+ * @return true when in post-launch mode; otherwise false.
181199 */
182200 bool quickGetPostLaunchMode () {
183201 return this ->postLaunchMode_ ;
@@ -211,11 +229,18 @@ class DataSaverSPI : public IDataSaver {
211229 /* *
212230 * @brief Helper to write a block of bytes to flash at the current
213231 * write address and advance that pointer.
232+ * @param data Pointer to bytes to write.
233+ * @param length Number of bytes to write.
234+ * @return true on successful write and pointer advance; otherwise false.
214235 */
215236 bool writeToFlash (const uint8_t * data, size_t length);
216237
217238 /* *
218239 * @brief Helper to read a block of bytes from flash (updates read pointer externally).
240+ * @param readAddress Input/output flash address. Advanced by `length` on success.
241+ * @param buffer Output byte buffer.
242+ * @param length Number of bytes to read.
243+ * @return true on successful read and pointer advance; otherwise false.
219244 */
220245 bool readFromFlash (uint32_t & readAddress, uint8_t * buffer, size_t length);
221246
@@ -228,6 +253,7 @@ class DataSaverSPI : public IDataSaver {
228253 /* *
229254 * @brief Returns the current buffer index
230255 * Useful for testing
256+ * @return Number of bytes currently buffered.
231257 */
232258 size_t getBufferIndex () const {
233259 return bufferIndex_;
@@ -236,20 +262,89 @@ class DataSaverSPI : public IDataSaver {
236262 /* *
237263 * @brief Returns the current buffer flush count
238264 * Useful for testing
265+ * @return Number of successful page flushes.
239266 */
240267 uint32_t getBufferFlushes () const {
241268 return bufferFlushes_;
242269 }
243270
271+ /* *
272+ * @brief Returns whether writes have been stopped by post-launch protection.
273+ * @return true if chip-full post-launch protection latch is set; otherwise false.
274+ */
244275 bool getIsChipFullDueToPostLaunchProtection () const {
245276 return isChipFullDueToPostLaunchProtection_;
246277 }
247278
279+ /* *
280+ * @brief Returns whether startup detected existing post-launch mode metadata.
281+ * @return true if rebooted in post-launch mode; otherwise false.
282+ */
248283 bool getRebootedInPostLaunchMode () const {
249284 return rebootedInPostLaunchMode_;
250285 }
251286
287+ #ifdef UNIT_TEST
288+ /* *
289+ * @brief Test-only helper to override internal post-launch state.
290+ * Resets in-memory state first so the injected state is
291+ * self-consistent and does not depend on prior test writes.
292+ * @param nextWriteAddress_in Next write address to inject.
293+ * @param launchWriteAddress_in Launch-protected address to inject.
294+ * @param postLaunchMode_in Post-launch mode flag to inject.
295+ */
296+ void setPostLaunchStateForTest (uint32_t nextWriteAddress_in,
297+ uint32_t launchWriteAddress_in,
298+ bool postLaunchMode_in) {
299+ clearInternalState ();
300+ nextWriteAddress_ = nextWriteAddress_in;
301+ launchWriteAddress_ = launchWriteAddress_in;
302+ postLaunchMode_ = postLaunchMode_in;
303+ isChipFullDueToPostLaunchProtection_ = false ;
304+ }
305+ #endif
306+
252307private:
308+ /* *
309+ * @brief Normalizes an address into the data region when crossing flash end.
310+ * @param address Candidate flash address.
311+ * @return `address` when in range, otherwise `kDataStartAddress`.
312+ */
313+ uint32_t normalizeDataAddress (uint32_t address) const ;
314+
315+ /* *
316+ * @brief Checks if a sector is protected by post-launch rules.
317+ * @param sectorNumber Sector index to evaluate.
318+ * @return true when sector contains `launchWriteAddress_` and post-launch mode is active.
319+ * @return false otherwise.
320+ */
321+ bool isProtectedLaunchSector (uint32_t sectorNumber) const ;
322+
323+ /* *
324+ * @brief Outcome of attempting to erase a sector before writing into it.
325+ */
326+ enum class SectorEraseResult {
327+ kErased ,
328+ kProtectedSectorLatched ,
329+ kFlashEraseFailed
330+ };
331+
332+ /* *
333+ * @brief Erases a sector for writing and latches post-launch protection if blocked.
334+ * @param sectorNumber Sector index to erase.
335+ * @return SectorEraseResult::kErased on successful erase.
336+ * @return SectorEraseResult::kProtectedSectorLatched when sector is
337+ * post-launch protected (and chip-full is latched).
338+ * @return SectorEraseResult::kFlashEraseFailed when flash erase fails.
339+ */
340+ SectorEraseResult eraseSectorForWriteAndLatchOnProtection (uint32_t sectorNumber);
341+
342+ /* *
343+ * @brief Checks if the upcoming write window would violate post-launch protection.
344+ * @return true when writing must stop and chip-full protection is latched.
345+ * @return false when write may proceed.
346+ */
347+ bool shouldStopForPostLaunchWindow ();
253348
254349 /* *
255350 * @brief Flushes the buffer to flash.
@@ -272,10 +367,20 @@ class DataSaverSPI : public IDataSaver {
272367
273368 // Overloaded functions to add data to the buffer from a Record_t or TimestampRecord_t
274369 // More efficient than callling addDataToBuffer with each part of the record
370+ /* *
371+ * @brief Adds a 5-byte record payload to the page buffer.
372+ * @param record Pointer to packed record bytes.
373+ * @return int 0 on success; -1 on flush/buffer error.
374+ */
275375 int addRecordToBuffer (Record_t * record) {
276376 return addDataToBuffer (reinterpret_cast <const uint8_t *>(record), 5 );
277377 }
278378
379+ /* *
380+ * @brief Adds a 5-byte timestamp record payload to the page buffer.
381+ * @param record Pointer to packed timestamp record bytes.
382+ * @return int 0 on success; -1 on flush/buffer error.
383+ */
279384 int addRecordToBuffer (TimestampRecord_t * record) {
280385 return addDataToBuffer (reinterpret_cast <const uint8_t *>(record), 5 );
281386 }
@@ -287,6 +392,10 @@ class DataSaverSPI : public IDataSaver {
287392 // If the flight computer boots and is already in post launch mode, do not write to flash.
288393 // Calling clearPostLaunchMode() will allow writing to flash again after a reboot.
289394 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();
290399};
291400
292401#endif // DATA_SAVER_SPI_H
0 commit comments