SD init now happens before Wi-Fi AP startup.

Startup timing is made slower and more forgiving:
recoveryRailOffMs = 400
recoveryRailOnSettleMs = 1200
startupWarmupMs = 2500
If the initial cold-boot mount still fails, it now does one immediate second-chance remount after a short delay before proceeding.
This commit is contained in:
John Poole 2026-04-09 09:21:13 -07:00
commit dba0c9477f
4 changed files with 108 additions and 7 deletions

View file

@ -84,6 +84,8 @@ static constexpr float kExcellentHdop = 1.5f;
static constexpr size_t kBufferedSamples = 10;
static constexpr size_t kMaxSatellites = 64;
static constexpr size_t kStorageBufferBytes = 4096;
static constexpr uint8_t kStorageWriteRetryCount = 3;
static constexpr uint32_t kStorageWriteRetryDelayMs = 25;
static constexpr uint32_t kClockDisciplineRetryMs = 5000;
static constexpr uint32_t kClockPpsWaitTimeoutMs = 1500;
static constexpr uint32_t kClockFreshSampleMs = 2000;

View file

@ -178,6 +178,17 @@ bool StorageManager::openFile() {
return true;
}
bool StorageManager::reopenFileForAppend() {
if (m_file) {
m_file.close();
}
m_file = SD.open(m_path.c_str(), FILE_WRITE);
if (!m_file) {
return false;
}
return true;
}
void StorageManager::writeHeader(const char* runId, const char* bootTimestampUtc) {
if (!m_file || !m_newFile) {
return;
@ -206,9 +217,7 @@ bool StorageManager::writePendingBuffer() {
if (!m_bufferPending[i] || m_bufferLengths[i] == 0) {
continue;
}
const size_t wrote = m_file.write((const uint8_t*)m_buffers[i], m_bufferLengths[i]);
if (wrote != m_bufferLengths[i]) {
m_lastError = "SD.write failed";
if (!writeFully((const uint8_t*)m_buffers[i], m_bufferLengths[i], "buffer")) {
m_ready = false;
return false;
}
@ -226,9 +235,7 @@ bool StorageManager::appendBytes(const char* data, size_t len) {
if (!writePendingBuffer()) {
return false;
}
const size_t wrote = m_file.write((const uint8_t*)data, len);
if (wrote != len) {
m_lastError = "SD.write large block failed";
if (!writeFully((const uint8_t*)data, len, "large")) {
m_ready = false;
return false;
}
@ -256,6 +263,57 @@ bool StorageManager::appendBytes(const char* data, size_t len) {
return true;
}
bool StorageManager::writeFully(const uint8_t* data, size_t len, const char* context) {
if (!m_file || !data || len == 0) {
m_lastError = "writeFully invalid state";
return false;
}
size_t totalWrote = 0;
for (uint8_t attempt = 0; attempt <= kStorageWriteRetryCount; ++attempt) {
const size_t filePos = (size_t)m_file.position();
const size_t fileSize = (size_t)m_file.size();
const size_t wrote = m_file.write(data + totalWrote, len - totalWrote);
if (wrote > 0) {
totalWrote += wrote;
if (totalWrote >= len) {
if (attempt > 0) {
m_lastError = "";
}
return true;
}
}
if (attempt >= kStorageWriteRetryCount) {
const bool stillMounted = mounted();
char err[192];
snprintf(err,
sizeof(err),
"SD.write failed ctx=%s wrote=%u/%u pos=%u size=%u mounted=%s attempts=%u",
context ? context : "?",
(unsigned)totalWrote,
(unsigned)len,
(unsigned)filePos,
(unsigned)fileSize,
stillMounted ? "yes" : "no",
(unsigned)(attempt + 1));
m_lastError = err;
return false;
}
delay(kStorageWriteRetryDelayMs);
if (mounted()) {
if (!reopenFileForAppend()) {
delay(kStorageWriteRetryDelayMs);
}
}
}
m_lastError = "SD.write retry loop exhausted";
return false;
}
bool StorageManager::appendLine(const String& line) {
if (line.endsWith("\n")) {
return appendBytes(line.c_str(), line.length());

View file

@ -40,11 +40,13 @@ class StorageManager {
private:
bool ensureDir();
bool openFile();
bool reopenFileForAppend();
void writeHeader(const char* runId, const char* bootTimestampUtc);
String makeFilePath(const char* runId) const;
bool appendLine(const String& line);
bool appendBytes(const char* data, size_t len);
bool writePendingBuffer();
bool writeFully(const uint8_t* data, size_t len, const char* context);
size_t countLogsRecursive(const char* path) const;
void listFilesRecursive(File& dir, Stream& out);
void eraseLogsRecursive(File& dir);