#ifndef MEASURE_H #define MEASURE_H #include #include #include #include #include #include #include #include "ADXL345FastSPI.h" // <-- zgodnie z main.cpp #include #include // 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_; } // 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; 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(){ // Sprawdzamy wszystkie przyciski (UP:5, OK:6, DOWN:7) // GPIO.in obsługuje piny 0-31 uint32_t buttons = GPIO.in; bool ispress = ((buttons & (1UL << BTN_OK)) == 0) || ((buttons & (1UL << BTN_UP)) == 0) || ((buttons & (1UL << BTN_DOWN)) == 0); if(ispress) { isExit = true; measurementActive_ = false; display_.textStatus("Cancelling. Wait!"); } return ispress; } 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