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 MiB so writes stay contiguous (faster & less wear)
26 file_.preAllocate(kPreAllocateSize_MiB * kBytesPerMiB_bytes);
27
28 Serial.print(F("Logging to ")); Serial.println(filePath_.c_str());
29
30 bufLen_ = 0;
31 linesPending_ = 0;
32 lastFlushMs_ = static_cast<uint32_t>(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, static_cast<double>(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, static_cast<double>(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 const auto numCharsWritten_u16 = static_cast<uint16_t>(numCharsWritten);
70 bufLen_ = static_cast<uint16_t>(bufLen_ + numCharsWritten_u16);
71 ++linesPending_;
72
73 const auto now = static_cast<uint32_t>(millis());
74 bool const bufFull = (bufLen_ >= kBufSize_bytes);
75 bool const manyLines = (linesPending_ >= kFlushLines);
76 bool const timeUp = (now - lastFlushMs_ >= kFlushMs);
77
78 if (bufFull || manyLines || timeUp) {
79 if (file_.write(buf_, bufLen_) != bufLen_) {
80 return DS_FLUSH_FAILED;
81 }
82 bufLen_ = 0;
83 linesPending_ = 0;
84 lastFlushMs_ = now;
85
86 if (now - lastSyncMs_ >= kSyncInterval_ms) {
87 file_.sync();
88 lastSyncMs_ = now;
89 }
90 }
91
92 return 0;
93}
94
95
96/* ----------------------------- end() ----------------------------------- */
98 if (!ready_) {
99 return;
100 }
101 if (bufLen_ > 0) {
102 file_.write(buf_, bufLen_);
103 bufLen_ = 0;
104 }
105 file_.sync();
106 file_.close();
107 ready_ = false;
108}
109
110/* ------------------- nextFreeFilePath() -------------------------------- */
111std::string DataSaverBigSD::nextFreeFilePath() {
112 std::array<char, kFilePathBufferSize> path;
113 for (uint16_t flightNumber = 0;; ++flightNumber) {
114 snprintf(path.data(), sizeof(path), "/stream-%u.csv", flightNumber);
115 if (!sd_.exists(path.data())) {
116 return std::string(path.data());
117 }
118 }
119}
constexpr size_t kPreAllocateSize_MiB
constexpr size_t kBytesPerMiB_bytes
@ DS_BUFFER_WRITE_FAILED
@ DS_LINE_TOO_LONG
@ DS_NOT_READY
@ DS_FLUSH_FAILED
constexpr uint32_t kSyncInterval_ms
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)
#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