Release v1.3.4.2 - fix isEscape bug, power-loss resilience, EEPROM fix, SD mutex, code cleanup

This commit is contained in:
2026-05-10 18:39:11 +02:00
parent 84e2abae14
commit 10d187eb37
29 changed files with 3482 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
#ifndef MEASURE_H
#define MEASURE_H
#include <Arduino.h>
#include <Watchdog.h>
#include <SPI.h>
#include <SD.h>
#include <FS.h>
#include <RTClib.h>
#include <Display.h>
#include "ADXL345FastSPI.h" // <-- zgodnie z main.cpp
#include <Logger.h>
#include <Pinout.h>
// Domyślne parametry akwizycji ADXL345 (mogą być nadpisane w ADXL345FastSPI::begin)
static constexpr uint32_t SPI_HZ = 5000000; // 5 MHz (MODE3)
static constexpr float ODR_HZ = 3200.0f; // maks. ODR
// Zakres ustawiany w main.cpp przez ADXL345FastSPI::begin(..., RANGE_2G, ...)
struct FileInfo {
String path; // np. "/3/00000057.wmt"
uint64_t size; // bajty
bool exists; // true, jeśli ostatni plik istnieje
};
struct SpaceInfo {
double value;
const char *unit; // "GB" | "MB" | "UNKNOWN"
};
class DataCapture {
// --- Nagłówek pliku WMT ---
struct FileHeader {
char magic[3]; // "WMT"
uint16_t version; // 1
uint16_t headerSize; // sizeof(FileHeader)
uint32_t sampleSize; // sizeof(Sample)
uint32_t timestamp; // UNIX startu akwizycji
uint32_t reccount; // liczba rekordów Sample w pliku
} __attribute__((packed));
public:
// --- Rekord próbki ---
struct Sample {
uint32_t offset; // µs od startu akwizycji (wspólny dla ramki)
uint8_t sensor_id; // 0..3
int16_t x, y, z; // surowe ADXL345
bool ready; // 1 = obecna
} __attribute__((packed));
// Konstruktor dopasowany do main.cpp przyjmuje ADXL345FastSPI
DataCapture(ADXL345FastSPI &adxl, Display &display, RTC_DS3231 &rtc, fs::FS &storage, size_t bufferSize = 131072 /* 128 KB */);
~DataCapture();
bool capture(uint32_t captureSeconds, const char *filename);
bool captureAuto(uint32_t captureSeconds, const char *baseDirectory = "/logs");
void printSamplingRate(uint32_t reccount, uint32_t captureSeconds, String filename);
void readHeaderAndPrint(const char *path);
void stop();
bool isActive() const { return measurementActive_; }
String getCurrentCapturePath() const { return currentCapturePath_; }
// SD utils
SpaceInfo freeSpaceMB();
float freeSpaceFloat(bool *isGB = nullptr);
String unixToDateTime(uint32_t ts);
// plik z najwyższym indeksem
FileInfo getLastFileInfo();
bool deleteAllOnSD();
bool isExit = false; // true oznacza przerwanie pomiaru
private:
ADXL345FastSPI &adxl_;
Display &display_;
RTC_DS3231 &rtc_;
fs::FS &_fs;
// Katalogowanie
const String _baseDir = "/";
const String _ext = ".wmt";
const uint8_t _digits = 8;
const uint16_t _maxFilesPerDir = 400;
// Bufor zapisu (PSRAM)
uint8_t *buffer_ = nullptr;
size_t bufferSize_ = 0;
size_t bufferIndex_ = 0;
bool measurementActive_ = false;
String currentCapturePath_ = "";
bool flushToFile(File &f);
static uint8_t crc8(const uint8_t *data, size_t len);
void setTestingIndicator_(bool on, String myDir, String myFile);
bool isEscape(){
bool ispress = (GPIO.in & (1UL << BTN_OK)) == 0;
if(ispress) {
isExit = true;
measurementActive_ = false;
display_.textStatus("Cancelling. Wait!");
}
return ispress;
} // szybkidigitalRead : czy BTN stop???
public:
bool isAllDigits(const char *s);
uint32_t toUint(const char *s);
static const char *basenameFromPath(const char* full);
bool isWmtWithDigits(const char *name, uint32_t &idxOut) const;
String makeIndexedName(uint32_t idx) const;
static String joinPath(const String &a, const String &b);
bool ensureDir(uint32_t dirNum);
uint32_t findHighestNumericDir();
void scanDirForWmt(uint32_t dirNum, uint32_t &count, uint32_t &highestIdx);
bool recursiveDelete(const String &path);
String dirPath(uint32_t dirNum) const;
String allocateNextFilePath();
String generateNextFilename();
void printLastFileInfoSerial();
};
#endif // MEASURE_H