Avionics
Core avionics package for CURE flight computers
Loading...
Searching...
No Matches
DataSaverBigSD.cpp
Go to the documentation of this file.
2#include "ArduinoHAL.h" // for Serial
3
4// one SdFat object for all
5/* static */ SdFat DataSaverBigSD::sd; //NOLINT(readability-identifier-length)
6
7/* ------------------------------------------------------------------------- */
8DataSaverBigSD::DataSaverBigSD(uint8_t csPin) : _csPin(csPin) {}
9
10/* --------------------------- begin() ----------------------------------- */
12 Serial.print(F("Init SD… "));
13 pinMode(_csPin, OUTPUT);
14 if (!sd.begin(_csPin, SD_SCK_MHZ(40))) { // 40 MHz on ESP32‑S3
15 Serial.println(F("fail"));
16 return false;
17 }
18
19 _filePath = nextFreeFilePath();
20 if (!_file.open(_filePath.c_str(), O_WRITE | O_CREAT)) {
21 Serial.println(F("file create fail"));
22 return false;
23 }
24
25 // Pre‑allocate 4 MB so writes stay contiguous (faster & less wear)
26 _file.preAllocate(PRE_ALLOCATE_SIZE_MB * BYTES_PER_MB);
27
28 Serial.print(F("Logging to ")); Serial.println(_filePath.c_str());
29
30 _bufLen = 0;
31 _linesPending = 0;
32 _lastFlushMs = millis();
33 _lastSyncMs = _lastFlushMs;
34 _ready = true;
35 return true;
36}
37
38/* ----------------------- saveDataPoint() ------------------------------- */
39int DataSaverBigSD::saveDataPoint(const DataPoint& dataPoint, uint8_t name) {
40 if (!_ready) {
41 return DS_NOT_READY;
42 }
43
44 // Reserve space left
45 size_t remaining = sizeof(_buf) - _bufLen; // NOLINT(cppcoreguidelines-init-variables)
46
47 // Format the new line
48 int numCharsWritten = snprintf(_buf + _bufLen, remaining, "%lu,%u,%.6f\n", // NOLINT(cppcoreguidelines-init-variables)
49 static_cast<long unsigned int>(dataPoint.timestamp_ms), name, dataPoint.data);
50
51 // Check snprintf result
52 if (numCharsWritten <= 0 || (size_t)numCharsWritten >= remaining) {
53 // Flush current buffer and try again if this line couldn’t fit
54 if (_file.write(_buf, _bufLen) != _bufLen) {
55 return DS_BUFFER_WRITE_FAILED; // failed to write current buffer
56 }
57 _file.sync(); // just to be extra safe during debug
58 _bufLen = 0;
59 _linesPending = 0;
60
61 // Try again (safe now)
62 remaining = sizeof(_buf);
63 numCharsWritten = snprintf(_buf, remaining, "%lu,%u,%.6f\n", static_cast<long unsigned int>(dataPoint.timestamp_ms), name, dataPoint.data);
64 if (numCharsWritten <= 0 || (size_t)numCharsWritten >= remaining) {
65 return DS_LINE_TOO_LONG; // can't encode this line even in an empty buffer
66 }
67 }
68
69 _bufLen += numCharsWritten;
70 ++_linesPending;
71
72 uint32_t const now = millis();
73 bool const bufFull = (_bufLen >= kBufBytes);
74 bool const manyLines = (_linesPending >= kFlushLines);
75 bool const timeUp = (now - _lastFlushMs >= kFlushMs);
76
77 if (bufFull || manyLines || timeUp) {
78 if (_file.write(_buf, _bufLen) != _bufLen) {
79 return DS_FLUSH_FAILED;
80 }
81 _bufLen = 0;
82 _linesPending = 0;
83 _lastFlushMs = now;
84
85 if (now - _lastSyncMs >= SYNC_INTERVAL_MS) {
86 _file.sync();
87 _lastSyncMs = now;
88 }
89 }
90
91 return 0;
92}
93
94
95/* ----------------------------- end() ----------------------------------- */
97 if (!_ready) {
98 return;
99 }
100 if (_bufLen > 0) {
101 _file.write(_buf, _bufLen);
102 _bufLen = 0;
103 }
104 _file.sync();
105 _file.close();
106 _ready = false;
107}
108
109/* ------------------- nextFreeFilePath() -------------------------------- */
110std::string DataSaverBigSD::nextFreeFilePath() {
111 std::array<char, FILE_PATH_BUFFER_SIZE> path;
112 for (uint16_t flightNumber = 0;; ++flightNumber) {
113 snprintf(path.data(), sizeof(path), "/stream-%u.csv", flightNumber);
114 if (!sd.exists(path.data())) {
115 return std::string(path.data());
116 }
117 }
118}
constexpr uint32_t SYNC_INTERVAL_MS
@ DS_BUFFER_WRITE_FAILED
@ DS_LINE_TOO_LONG
@ DS_NOT_READY
@ DS_FLUSH_FAILED
constexpr size_t PRE_ALLOCATE_SIZE_MB
constexpr size_t BYTES_PER_MB
Timestamped float measurement container.
Definition DataPoint.h:11
float data
Definition DataPoint.h:14
uint32_t timestamp_ms
Definition DataPoint.h:13
bool begin()
Initialize the SD card and open a streaming file. Returns true on success.
void end()
Flush pending bytes and close the file.
int saveDataPoint(const DataPoint &dataPoint, uint8_t name) override
Buffer a CSV line (timestamp,name,value) and flush in batches.
DataSaverBigSD(uint8_t csPin=5)
MockSerial Serial
#define O_CREAT
Definition spi_mock.h:101
#define F(x)
Definition spi_mock.h:12
#define O_WRITE
Definition spi_mock.h:100
#define SD_SCK_MHZ(x)
Definition spi_mock.h:103
bool exists(const char *)
Definition spi_mock.h:95