forked from Akcelerometry_drgania_WMT/PI_mikrokontroler
Merge pull request 'WMT_PW' (#1) from WMT_PW into main
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
class ADXL345FastSPI {
|
class ADXL345FastSPI {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MAX_SENSORS = 4; // Maksymalna liczba ADXL345
|
|
||||||
|
|
||||||
enum Rate { RATE_100HZ, RATE_200HZ, RATE_400HZ, RATE_800HZ, RATE_1600HZ, RATE_3200HZ };
|
enum Rate { RATE_100HZ, RATE_200HZ, RATE_400HZ, RATE_800HZ, RATE_1600HZ, RATE_3200HZ };
|
||||||
enum Range { RANGE_2G, RANGE_4G, RANGE_8G, RANGE_16G };
|
enum Range { RANGE_2G, RANGE_4G, RANGE_8G, RANGE_16G };
|
||||||
|
|
||||||
@@ -58,7 +56,7 @@ public:
|
|||||||
uint8_t refreshActiveMask();
|
uint8_t refreshActiveMask();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t MAX_NUM = MAX_SENSORS;
|
static constexpr uint8_t MAX_NUM = 4; // MAX Ilość ADXL345
|
||||||
|
|
||||||
SPIClass* spi_ = &SPI;
|
SPIClass* spi_ = &SPI;
|
||||||
ADXL345FreshSPI dev_[MAX_NUM];
|
ADXL345FreshSPI dev_[MAX_NUM];
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ struct Config {
|
|||||||
char restUser[30]; // login RestAPI
|
char restUser[30]; // login RestAPI
|
||||||
char restPass[50]; // hasło RestAPi
|
char restPass[50]; // hasło RestAPi
|
||||||
uint8_t apiKey[32]; // Klucz API KEY
|
uint8_t apiKey[32]; // Klucz API KEY
|
||||||
uint32_t pause; // Pomiar co milisekund (ms)
|
uint16_t pause; // Pomiar co sekund
|
||||||
uint8_t duration; // Czas pomiaru w sekundach 1-25
|
uint8_t duration; // Czas pomiaru w sekundach 1-25
|
||||||
char S0[12]; // nazwy czujników 1-8
|
char S0[12]; // nazwy czujników 1-8
|
||||||
char S1[12];
|
char S1[12];
|
||||||
@@ -53,7 +53,6 @@ struct Config {
|
|||||||
|
|
||||||
// Global config declaration
|
// Global config declaration
|
||||||
extern Config config;
|
extern Config config;
|
||||||
static_assert(sizeof(Config) + 1 <= EEPROM_SIZE, "Config struct exceeds EEPROM!");
|
|
||||||
|
|
||||||
class ConfigManager {
|
class ConfigManager {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ public:
|
|||||||
void readHeaderAndPrint(const char *path);
|
void readHeaderAndPrint(const char *path);
|
||||||
void stop();
|
void stop();
|
||||||
bool isActive() const { return measurementActive_; }
|
bool isActive() const { return measurementActive_; }
|
||||||
String getCurrentCapturePath() const { return currentCapturePath_; }
|
|
||||||
|
|
||||||
// SD utils
|
// SD utils
|
||||||
SpaceInfo freeSpaceMB();
|
SpaceInfo freeSpaceMB();
|
||||||
@@ -89,7 +88,6 @@ private:
|
|||||||
size_t bufferSize_ = 0;
|
size_t bufferSize_ = 0;
|
||||||
size_t bufferIndex_ = 0;
|
size_t bufferIndex_ = 0;
|
||||||
bool measurementActive_ = false;
|
bool measurementActive_ = false;
|
||||||
String currentCapturePath_ = "";
|
|
||||||
|
|
||||||
bool flushToFile(File &f);
|
bool flushToFile(File &f);
|
||||||
static uint8_t crc8(const uint8_t *data, size_t len);
|
static uint8_t crc8(const uint8_t *data, size_t len);
|
||||||
@@ -99,7 +97,7 @@ private:
|
|||||||
bool ispress = (GPIO.in & (1UL << BTN_OK)) == 0;
|
bool ispress = (GPIO.in & (1UL << BTN_OK)) == 0;
|
||||||
if(ispress) {
|
if(ispress) {
|
||||||
isExit = true;
|
isExit = true;
|
||||||
measurementActive_ = false;
|
measurementActive_;
|
||||||
display_.textStatus("Cancelling. Wait!");
|
display_.textStatus("Cancelling. Wait!");
|
||||||
}
|
}
|
||||||
return ispress;
|
return ispress;
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WebServer.h>
|
#include <WebServer.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
|
#include <DNSServer.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266mDNS.h>
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <DNSServer.h>
|
||||||
#endif
|
#endif
|
||||||
//#include <Pinout.h>
|
//#include <Pinout.h>
|
||||||
//#include <IPAddress.h>
|
//#include <IPAddress.h>
|
||||||
@@ -42,6 +44,12 @@ class WiFiManager {
|
|||||||
int rssiToPercent(int rssi); // rssi na procenty
|
int rssiToPercent(int rssi); // rssi na procenty
|
||||||
int8_t getRSSI();
|
int8_t getRSSI();
|
||||||
|
|
||||||
|
void handleClient();
|
||||||
|
void startCaptivePortal();
|
||||||
|
void handleRoot();
|
||||||
|
void handleSave();
|
||||||
|
void handleNotFound();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aktualizacja systemu przez internet z adresu config.updateUrl.
|
* Aktualizacja systemu przez internet z adresu config.updateUrl.
|
||||||
* @param allowInsecureTLS true => dla https wyłącz weryfikację certyfikatu.
|
* @param allowInsecureTLS true => dla https wyłącz weryfikację certyfikatu.
|
||||||
@@ -61,6 +69,10 @@ class WiFiManager {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool isAccessPoint = false;
|
bool isAccessPoint = false;
|
||||||
|
bool captivePortalActive = false;
|
||||||
|
WebServer server{80};
|
||||||
|
DNSServer dnsServer;
|
||||||
|
int expectedCaptchaAnswer = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WIFIMANAGER_H
|
#endif // WIFIMANAGER_H
|
||||||
|
|||||||
24
include/Uploader.h
Normal file
24
include/Uploader.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef UPLOADER_H
|
||||||
|
#define UPLOADER_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Display.h"
|
||||||
|
#include "Watchdog.h"
|
||||||
|
|
||||||
|
class Uploader {
|
||||||
|
public:
|
||||||
|
Uploader(Display &display);
|
||||||
|
void processQueue(int maxFiles = 3);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Display &_display;
|
||||||
|
String loadCACert(const char* path);
|
||||||
|
bool sendFile(String filePath, String& caCert);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef VERSION_H
|
#ifndef VERSION_H
|
||||||
#define VERSION_H
|
#define VERSION_H
|
||||||
|
|
||||||
#define VERSION "1.3.4.2"
|
#define VERSION "1.3.4.1"
|
||||||
|
|
||||||
// 1: graphical 128x64, 2: LCD I2C Text 4x20
|
// 1: graphical 128x64, 2: LCD I2C Text 4x20
|
||||||
#define LCD_TYPE 2
|
#define LCD_TYPE 2
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ bool APIClient::uploadMeasurement(const String &filePath) {
|
|||||||
|
|
||||||
// Multipart body: head + file data + tail
|
// Multipart body: head + file data + tail
|
||||||
client.print(head);
|
client.print(head);
|
||||||
|
ESP_LOGI(TAG_API, "DEBUG: Beginning file read loop");
|
||||||
|
|
||||||
uint8_t buffer[2048];
|
uint8_t buffer[2048];
|
||||||
while (file.available()) {
|
while (file.available()) {
|
||||||
@@ -79,8 +80,10 @@ bool APIClient::uploadMeasurement(const String &filePath) {
|
|||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG_API, "DEBUG: File read loop finished. Writing tail.");
|
||||||
client.print(tail);
|
client.print(tail);
|
||||||
file.close();
|
file.close();
|
||||||
|
ESP_LOGI(TAG_API, "DEBUG: Tail written. Waiting for response...");
|
||||||
|
|
||||||
// --- Parsowanie odpowiedzi ---
|
// --- Parsowanie odpowiedzi ---
|
||||||
int httpCode = 0;
|
int httpCode = 0;
|
||||||
@@ -98,6 +101,7 @@ bool APIClient::uploadMeasurement(const String &filePath) {
|
|||||||
}
|
}
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
}
|
}
|
||||||
|
ESP_LOGI(TAG_API, "DEBUG: Header parsing loop finished. httpCode: %d", httpCode);
|
||||||
|
|
||||||
String responseBody = "";
|
String responseBody = "";
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ void ConfigManager::readConfig() {
|
|||||||
// Save config to EEPROM
|
// Save config to EEPROM
|
||||||
void ConfigManager::saveConfig() {
|
void ConfigManager::saveConfig() {
|
||||||
ESP_LOGI(TAG_CONF, "SAVE CONFIG");
|
ESP_LOGI(TAG_CONF, "SAVE CONFIG");
|
||||||
EEPROM.begin(EEPROM_SIZE);
|
|
||||||
EEPROM.put(1, config);
|
EEPROM.put(1, config);
|
||||||
EEPROM.write(0, 253);
|
EEPROM.write(0, 253);
|
||||||
if (EEPROM.commit()) {
|
if (EEPROM.commit()) {
|
||||||
@@ -47,6 +46,7 @@ void ConfigManager::saveConfig() {
|
|||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG_CONF, "Error save config");
|
ESP_LOGE(TAG_CONF, "Error save config");
|
||||||
}
|
}
|
||||||
|
EEPROM.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigManager::generateApiKey(uint8_t *buf, size_t len) {
|
void ConfigManager::generateApiKey(uint8_t *buf, size_t len) {
|
||||||
|
|||||||
@@ -158,9 +158,7 @@ void Display::showAccel(float a, float b, float c) {
|
|||||||
|
|
||||||
void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long licznik, bool refresh){
|
void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long licznik, bool refresh){
|
||||||
if(refresh){
|
if(refresh){
|
||||||
oyear = 0; omonth = 0; oday = 0;
|
oyear, omonth, oday, ohour, omin, osec, ospace, oadxlcnt = 100;
|
||||||
ohour = 0; omin = 0; osec = 0;
|
|
||||||
ospace = 0; oadxlcnt = 100;
|
|
||||||
_lcd->clear();
|
_lcd->clear();
|
||||||
_lcd->setCursor(0, 0);
|
_lcd->setCursor(0, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
181
src/Measure.cpp
181
src/Measure.cpp
@@ -78,6 +78,152 @@ bool DataCapture::captureAuto(uint32_t captureSeconds, const char * /*baseDirect
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- main measure function ---
|
// --- main measure function ---
|
||||||
|
// bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
||||||
|
// Watchdog::feed();
|
||||||
|
// if (!buffer_) {
|
||||||
|
// ESP_LOGE(TAG_CAPTURE, "No buffer - cancel.");
|
||||||
|
// display_.textStatus("Buffer error");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// ESP_LOGI(TAG_CAPTURE, "Capture %u sec. -> %s", (unsigned)captureSeconds, filename);
|
||||||
|
|
||||||
|
// File dataFile = _fs.open(filename, FILE_WRITE);
|
||||||
|
// if (!dataFile) {
|
||||||
|
// ESP_LOGE(TAG_CAPTURE, "Can't open file: %s", filename);
|
||||||
|
// char buf[100];
|
||||||
|
// snprintf(buf, sizeof(buf), "Can't open: %s", filename);
|
||||||
|
// display_.textStatus(buf);
|
||||||
|
// //s2etTestingIndicator_(false, _baseDir, filename);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Bufory RAMKI (po 1 próbce z każdego sensora)
|
||||||
|
// static const uint8_t MAXN = 7; // zgodnie z projektem
|
||||||
|
// int16_t X[MAXN]{}, Y[MAXN]{}, Z[MAXN]{};
|
||||||
|
// uint32_t TS[MAXN]{};
|
||||||
|
|
||||||
|
// Watchdog::feed();
|
||||||
|
// const uint32_t tStart_us = micros();
|
||||||
|
// const uint32_t captureDuration_us = captureSeconds * 1000000UL;
|
||||||
|
|
||||||
|
// // Czas startu (UTC) — tylko w nagłówku!
|
||||||
|
// const DateTime now = rtc_.now();
|
||||||
|
// const int32_t unix_start = now.unixtime();
|
||||||
|
|
||||||
|
// // Nagłówek
|
||||||
|
// FileHeader hdr;
|
||||||
|
// memcpy(hdr.magic, "WMT", 3);
|
||||||
|
// hdr.version = 1;
|
||||||
|
// hdr.headerSize = sizeof(FileHeader);
|
||||||
|
// hdr.sampleSize = sizeof(Sample);
|
||||||
|
// hdr.timestamp = unix_start;
|
||||||
|
// hdr.reccount = 0;
|
||||||
|
|
||||||
|
// if (dataFile.write(reinterpret_cast<const uint8_t*>(&hdr), sizeof(hdr)) != sizeof(hdr)) {
|
||||||
|
// ESP_LOGE(TAG_CAPTURE, "Header write failed");
|
||||||
|
// display_.textStatus("Header SD failed");
|
||||||
|
// dataFile.close();
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// measurementActive_ = true;
|
||||||
|
// bufferIndex_ = 0;
|
||||||
|
// setTestingIndicator_(true, _baseDir, filename);
|
||||||
|
|
||||||
|
// uint32_t frames = 0; // liczba zebranych „ramek”
|
||||||
|
// const uint8_t presentCnt = adxl_.size(); // wykryte sensory (wg begin)
|
||||||
|
|
||||||
|
// // --- Pętla akwizycji wyrównanych ramek ---
|
||||||
|
// while (measurementActive_) {
|
||||||
|
// if(isEscape()) break; // wyjście z pętli gdy OK przerwie
|
||||||
|
// uint32_t now_us = micros();
|
||||||
|
// if ((now_us - tStart_us) >= captureDuration_us) break;
|
||||||
|
|
||||||
|
// // 1) Czekamy aż KAŻDY obecny sensor ma >= 1 próbkę w FIFO (DATA_READY)
|
||||||
|
// while (!adxl_.availableAll()) {
|
||||||
|
// if(isEscape()) break; //????? sprawdź kHz pomiaru!
|
||||||
|
// // krótki spin; unikamy delay(1), aby nie zrywać 3.2 kHz
|
||||||
|
// // (opcjonalnie yield(); jeśli system wymaga)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 2) Zdejmij po 1 NAJSTARSZEJ próbce z każdego sensora (STREAM FIFO)
|
||||||
|
// const uint8_t got = adxl_.readAlignedOnce(X, Y, Z, TS);
|
||||||
|
// if (got != presentCnt) {
|
||||||
|
// // rzadki przypadek – niepełna ramka; pomiń
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 3) Wspólny timestamp ramki: minimalny z TS[i]
|
||||||
|
// uint32_t tmin = UINT32_MAX;
|
||||||
|
// for (uint8_t i = 0; i < MAXN; ++i) {
|
||||||
|
// if (!adxl_.isPresent(i)) continue;
|
||||||
|
// if (TS[i] < tmin) tmin = TS[i];
|
||||||
|
// }
|
||||||
|
// const uint32_t frame_offset_us = tmin - tStart_us;
|
||||||
|
|
||||||
|
// // 4) Zapis 7 rekordów Sample do bufora
|
||||||
|
// for (uint8_t i = 0; i < MAXN; ++i) {
|
||||||
|
// if (!adxl_.isPresent(i)) continue;
|
||||||
|
|
||||||
|
// // Konstruuj rekord bezpośrednio w buforze (bez memcpy)
|
||||||
|
// if (bufferIndex_ + sizeof(Sample) > bufferSize_) {
|
||||||
|
// if (!flushToFile(dataFile)) { measurementActive_ = false; break; }
|
||||||
|
// }
|
||||||
|
// Sample *dst = reinterpret_cast<Sample*>(buffer_ + bufferIndex_);
|
||||||
|
// dst->offset = frame_offset_us;
|
||||||
|
// dst->sensor_id = i;
|
||||||
|
// dst->x = X[i]; dst->y = Y[i]; dst->z = Z[i];
|
||||||
|
// dst->ready = true;
|
||||||
|
// bufferIndex_ += sizeof(Sample);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!measurementActive_) break;
|
||||||
|
// frames++;
|
||||||
|
// // Watchdog rzadziej, żeby nie zwiększać jittera
|
||||||
|
// if ((frames & 0xFF) == 0) Watchdog::feed();
|
||||||
|
// } // while
|
||||||
|
// // Statystyki
|
||||||
|
// ESP_LOGI(TAG_CAPTURE, "Frames: %u, sensors: %u", (unsigned)frames, (unsigned)presentCnt);
|
||||||
|
// printSamplingRate(frames, captureSeconds); // liczymy ramki/sek.
|
||||||
|
|
||||||
|
// // Domknij bufor
|
||||||
|
// if (bufferIndex_ > 0) {
|
||||||
|
// if (!flushToFile(dataFile)) {
|
||||||
|
// Watchdog::feed();
|
||||||
|
// ESP_LOGE(TAG_CAPTURE, "Finish save error.");
|
||||||
|
// display_.textStatus("Save SD error");
|
||||||
|
// delay(1000);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ESP_LOGI(TAG_CAPTURE, "Saved to SD successful");
|
||||||
|
// display_.textStatus("Saved SD OK");
|
||||||
|
// delay(700);
|
||||||
|
// // Uzupełnij nagłówek o liczbę rekordów (Sample)
|
||||||
|
// hdr.reccount = frames * presentCnt;
|
||||||
|
// dataFile.seek(0);
|
||||||
|
// dataFile.write(reinterpret_cast<const uint8_t*>(&hdr), sizeof(hdr));
|
||||||
|
// dataFile.flush();
|
||||||
|
// dataFile.close();
|
||||||
|
|
||||||
|
// //setTestingIndicator_(false, _baseDir, filename);
|
||||||
|
|
||||||
|
// bool ok = measurementActive_;
|
||||||
|
// measurementActive_ = false;
|
||||||
|
|
||||||
|
// if (ok) {
|
||||||
|
// ESP_LOGI(TAG_CAPTURE, "Successful");
|
||||||
|
// display_.textStatus("Successfull");
|
||||||
|
// Watchdog::feed();
|
||||||
|
// return true;
|
||||||
|
// } else {
|
||||||
|
// ESP_LOGE(TAG_CAPTURE, "Measurement aborted");
|
||||||
|
// display_.textStatus("Aborted");
|
||||||
|
// Watchdog::feed();
|
||||||
|
// return false;f
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// --- main measure function --- V2
|
||||||
bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
if (!buffer_) {
|
if (!buffer_) {
|
||||||
@@ -90,12 +236,10 @@ bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
|||||||
const uint8_t presentCnt = adxl_.size();
|
const uint8_t presentCnt = adxl_.size();
|
||||||
const size_t frameSize = presentCnt * sizeof(Sample);
|
const size_t frameSize = presentCnt * sizeof(Sample);
|
||||||
|
|
||||||
currentCapturePath_ = String(filename);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG_CAPTURE, "Start RAM capture: %u sec.", (unsigned)captureSeconds);
|
ESP_LOGI(TAG_CAPTURE, "Start RAM capture: %u sec.", (unsigned)captureSeconds);
|
||||||
display_.textStatus("Sampling...");
|
display_.textStatus("Sampling...");
|
||||||
|
|
||||||
static constexpr uint8_t MAXN = ADXL345FastSPI::MAX_SENSORS;
|
static const uint8_t MAXN = 7;
|
||||||
int16_t X[MAXN]{}, Y[MAXN]{}, Z[MAXN]{};
|
int16_t X[MAXN]{}, Y[MAXN]{}, Z[MAXN]{};
|
||||||
uint32_t TS[MAXN]{};
|
uint32_t TS[MAXN]{};
|
||||||
|
|
||||||
@@ -181,21 +325,16 @@ bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
|||||||
hdr.reccount = frames * presentCnt;
|
hdr.reccount = frames * presentCnt;
|
||||||
|
|
||||||
// Zapis nagłówka
|
// Zapis nagłówka
|
||||||
size_t hdrWritten = dataFile.write(reinterpret_cast<const uint8_t*>(&hdr), sizeof(hdr));
|
dataFile.write(reinterpret_cast<const uint8_t*>(&hdr), sizeof(hdr));
|
||||||
if (hdrWritten != sizeof(hdr)) {
|
|
||||||
ESP_LOGE(TAG_CAPTURE, "Header write failed!");
|
|
||||||
dataFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zapis całego bufora PSRAM jednym ciągiem
|
// Zapis całego bufora PSRAM jednym ciągiem
|
||||||
size_t written = dataFile.write(buffer_, bufferIndex_);
|
size_t written = dataFile.write(buffer_, bufferIndex_);
|
||||||
|
|
||||||
if (written == bufferIndex_) {
|
if (written == bufferIndex_) {
|
||||||
ESP_LOGI(TAG_CAPTURE, "SD Save Successful: %u bytes", (unsigned)written);
|
ESP_LOGI(TAG_CAPTURE, "SD Save Successful: %u bytes", (unsigned)written);
|
||||||
dataFile.flush(); // Power-loss resilience: wymuszenie zapisu na kartę
|
//display_.textStatus("Save OK");
|
||||||
display_.textStatus(basenameFromPath(filename));
|
display_.textStatus(basenameFromPath(filename));
|
||||||
delay(500);
|
delay(2000); // Tutaj zrob to inaczej
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG_CAPTURE, "SD Write Error!");
|
ESP_LOGE(TAG_CAPTURE, "SD Write Error!");
|
||||||
display_.textStatus("SD Write Err");
|
display_.textStatus("SD Write Err");
|
||||||
@@ -203,7 +342,6 @@ bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
|||||||
|
|
||||||
dataFile.close();
|
dataFile.close();
|
||||||
printSamplingRate(frames, captureSeconds, filename);
|
printSamplingRate(frames, captureSeconds, filename);
|
||||||
currentCapturePath_ = "";
|
|
||||||
return (written == bufferIndex_);
|
return (written == bufferIndex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +387,7 @@ void DataCapture::printSamplingRate(uint32_t reccount, uint32_t captureSeconds,
|
|||||||
ESP_LOGI(TAG_CAPTURE,"Rate: %.3f kHz (frames)", fs_kHz);
|
ESP_LOGI(TAG_CAPTURE,"Rate: %.3f kHz (frames)", fs_kHz);
|
||||||
display_.displaySampleRateSummary(reccount, captureSeconds, fs_kHz, filename);
|
display_.displaySampleRateSummary(reccount, captureSeconds, fs_kHz, filename);
|
||||||
display_.textStatus("Summary");
|
display_.textStatus("Summary");
|
||||||
delay(500);
|
delay(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Zarządzanie katalogami/plikiem ---
|
// --- Zarządzanie katalogami/plikiem ---
|
||||||
@@ -371,7 +509,7 @@ const char *DataCapture::basenameFromPath(const char *full) { const char *slash
|
|||||||
bool DataCapture::isWmtWithDigits(const char* name, uint32_t& idxOut) const {
|
bool DataCapture::isWmtWithDigits(const char* name, uint32_t& idxOut) const {
|
||||||
size_t nlen = strlen(name), extLen = _ext.length();
|
size_t nlen = strlen(name), extLen = _ext.length();
|
||||||
if (nlen != (size_t)_digits + extLen) return false;
|
if (nlen != (size_t)_digits + extLen) return false;
|
||||||
if (strncmp(name + _digits, _ext.c_str(), extLen) != 0 && strncmp(name + _digits, ".upl", 4) != 0) return false;
|
if (strncmp(name + _digits, _ext.c_str(), extLen) != 0) return false;
|
||||||
for (uint8_t i = 0; i < _digits; ++i) if (name[i] < '0' || name[i] > '9') return false;
|
for (uint8_t i = 0; i < _digits; ++i) if (name[i] < '0' || name[i] > '9') return false;
|
||||||
char buf[16]; memcpy(buf, name, _digits); buf[_digits] = '\0';
|
char buf[16]; memcpy(buf, name, _digits); buf[_digits] = '\0';
|
||||||
idxOut = (uint32_t)strtoul(buf, nullptr, 10); return true;
|
idxOut = (uint32_t)strtoul(buf, nullptr, 10); return true;
|
||||||
@@ -395,7 +533,6 @@ uint32_t DataCapture::findHighestNumericDir() {
|
|||||||
if (!root || !root.isDirectory()) return 0;
|
if (!root || !root.isDirectory()) return 0;
|
||||||
uint32_t maxDir = 0;
|
uint32_t maxDir = 0;
|
||||||
for (File f = root.openNextFile(); f; f = root.openNextFile()) {
|
for (File f = root.openNextFile(); f; f = root.openNextFile()) {
|
||||||
Watchdog::feed();
|
|
||||||
if (f.isDirectory()) {
|
if (f.isDirectory()) {
|
||||||
const char *nm = basenameFromPath(f.name());
|
const char *nm = basenameFromPath(f.name());
|
||||||
if (isAllDigits(nm)) { uint32_t v = toUint(nm); if (v > maxDir) maxDir = v; }
|
if (isAllDigits(nm)) { uint32_t v = toUint(nm); if (v > maxDir) maxDir = v; }
|
||||||
@@ -411,8 +548,7 @@ void DataCapture::scanDirForWmt(uint32_t dirNum, uint32_t &count, uint32_t &high
|
|||||||
File dir = _fs.open(path);
|
File dir = _fs.open(path);
|
||||||
if (!dir || !dir.isDirectory()) return;
|
if (!dir || !dir.isDirectory()) return;
|
||||||
for (File f = dir.openNextFile(); f; f = dir.openNextFile()) {
|
for (File f = dir.openNextFile(); f; f = dir.openNextFile()) {
|
||||||
Watchdog::feed();
|
if (f.isDirectory()) { Watchdog::feed(); f.close(); continue; }
|
||||||
if (f.isDirectory()) { f.close(); continue; }
|
|
||||||
const char* base = basenameFromPath(f.name());
|
const char* base = basenameFromPath(f.name());
|
||||||
uint32_t idx = 0;
|
uint32_t idx = 0;
|
||||||
if (isWmtWithDigits(base, idx)) { count++; if (idx > highestIdx) highestIdx = idx; }
|
if (isWmtWithDigits(base, idx)) { count++; if (idx > highestIdx) highestIdx = idx; }
|
||||||
@@ -453,8 +589,15 @@ void DataCapture::printLastFileInfoSerial() {
|
|||||||
snprintf(buf, sizeof(buf), "Size:%.2f KB", kb);
|
snprintf(buf, sizeof(buf), "Size:%.2f KB", kb);
|
||||||
display_.textStatus(buf);
|
display_.textStatus(buf);
|
||||||
#else
|
#else
|
||||||
ESP_LOGI(TAG_CAPTURE, "Last file: %s", info.path.c_str());
|
// Wariant zachowawczy dla platform bez %llu; pokazujemy rozmiar w MB/KB.
|
||||||
ESP_LOGI(TAG_CAPTURE, "Size: %.2f MB", mb);
|
ESP_LOGI(TAG_CAPTURE, "Last file info: "));
|
||||||
|
ESP_LOGI(TAG_CAPTURE, info.path);
|
||||||
|
ESP_LOGI(TAG_CAPTURE, "Size: "));
|
||||||
|
ESP_LOGI(TAG_CAPTURE, mb);
|
||||||
|
//ESP_LOGI(TAG_CAPTURE, " MB"));
|
||||||
|
//Serial.print(F(" ("));
|
||||||
|
//Serial.print(kb, 2);
|
||||||
|
//Serial.println(F(" KB)"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,4 +272,95 @@ bool WiFiManager::performOTAUpdate(bool allowInsecureTLS, std::function<void(int
|
|||||||
ESP_LOGE(WIFI, "[OTA] Błąd (%d): %s", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
ESP_LOGE(WIFI, "[OTA] Błąd (%d): %s", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::startCaptivePortal() {
|
||||||
|
if (captivePortalActive) {
|
||||||
|
ESP_LOGI(WIFI, "Captive Portal is already running.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(WIFI, "Starting Captive Portal");
|
||||||
|
setupAccessPoint(ssidAP.c_str(), passwordAP.c_str());
|
||||||
|
|
||||||
|
// Start DNS Server
|
||||||
|
const byte DNS_PORT = 53;
|
||||||
|
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
|
||||||
|
|
||||||
|
// Start Web Server
|
||||||
|
server.on("/", std::bind(&WiFiManager::handleRoot, this));
|
||||||
|
server.on("/save", HTTP_POST, std::bind(&WiFiManager::handleSave, this));
|
||||||
|
server.onNotFound(std::bind(&WiFiManager::handleNotFound, this));
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
captivePortalActive = true;
|
||||||
|
ESP_LOGI(WIFI, "Captive Portal Started");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::handleClient() {
|
||||||
|
if (captivePortalActive) {
|
||||||
|
dnsServer.processNextRequest();
|
||||||
|
server.handleClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::handleRoot() {
|
||||||
|
int bases[] = {2, 2, 2, 2, 3, 3, 10, 10};
|
||||||
|
int vals[] = {4, 8, 16, 32, 9, 27, 100, 1000};
|
||||||
|
int answers[] = {2, 3, 4, 5, 2, 3, 2, 3};
|
||||||
|
int idx = random(0, 8);
|
||||||
|
int base = bases[idx];
|
||||||
|
int val = vals[idx];
|
||||||
|
expectedCaptchaAnswer = answers[idx];
|
||||||
|
|
||||||
|
String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
|
||||||
|
html += "<style>body{font-family: Arial, sans-serif; text-align: center; margin:0; padding: 20px;}";
|
||||||
|
html += "input[type=text], input[type=password], input[type=number] {width: 100%; padding: 12px; margin: 8px 0; display: inline-block; border: 1px solid #ccc; box-sizing: border-box;}";
|
||||||
|
html += "input[type=submit] {background-color: #4CAF50; color: white; padding: 14px 20px; margin: 8px 0; border: none; cursor: pointer; width: 100%;}";
|
||||||
|
html += "input[type=submit]:hover {opacity: 0.8;}";
|
||||||
|
html += ".container {max-width: 400px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 5px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);}</style></head><body>";
|
||||||
|
html += "<h2>WiFi Configuration</h2>";
|
||||||
|
html += "<div class=\"container\">";
|
||||||
|
html += "<form action=\"/save\" method=\"POST\">";
|
||||||
|
html += "<label for=\"ssid\"><b>SSID</b></label>";
|
||||||
|
html += "<input type=\"text\" placeholder=\"Enter SSID\" name=\"ssid\" required>";
|
||||||
|
html += "<label for=\"password\"><b>Password</b></label>";
|
||||||
|
html += "<input type=\"password\" placeholder=\"Enter Password\" name=\"password\" required>";
|
||||||
|
html += "<label for=\"captcha\"><b>Captcha: What is log<sub>" + String(base) + "</sub>(" + String(val) + ")?</b></label>";
|
||||||
|
html += "<input type=\"number\" placeholder=\"Enter Answer\" name=\"captcha\" required>";
|
||||||
|
html += "<input type=\"submit\" value=\"Save and Restart\">";
|
||||||
|
html += "</form></div></body></html>";
|
||||||
|
|
||||||
|
server.send(200, "text/html", html);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::handleSave() {
|
||||||
|
String ssid = server.arg("ssid");
|
||||||
|
String pass = server.arg("password");
|
||||||
|
String captchaStr = server.arg("captcha");
|
||||||
|
|
||||||
|
if (captchaStr.toInt() != expectedCaptchaAnswer) {
|
||||||
|
server.send(400, "text/plain", "Incorrect Captcha. Please go back and try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssid.length() > 0) {
|
||||||
|
File f = SD.open("/wifi.txt", FILE_APPEND);
|
||||||
|
if (f) {
|
||||||
|
f.println(ssid + ";" + pass);
|
||||||
|
f.close();
|
||||||
|
server.send(200, "text/plain", "Credentials saved successfully! The device will now restart and try to connect.");
|
||||||
|
delay(2000);
|
||||||
|
ESP.restart();
|
||||||
|
} else {
|
||||||
|
server.send(500, "text/plain", "Failed to open wifi.txt on SD card for appending.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
server.send(400, "text/plain", "SSID cannot be empty.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::handleNotFound() {
|
||||||
|
server.sendHeader("Location", String("http://") + WiFi.softAPIP().toString(), true);
|
||||||
|
server.send(302, "text/plain", "");
|
||||||
}
|
}
|
||||||
@@ -16,34 +16,63 @@ String UploadManager::getCurrentTimestamp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UploadManager::appendLog(const String& filePath, const String& status) {
|
void UploadManager::appendLog(const String& filePath, const String& status) {
|
||||||
// Legacy CSV log removed to fix O(N^2) SD card bottleneck
|
File f = SD.open(LOG_FILE, FILE_APPEND);
|
||||||
|
if (f) {
|
||||||
|
f.printf("%s,%s,%s\n", getCurrentTimestamp().c_str(), filePath.c_str(), status.c_str());
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UploadManager::isAlreadyUploaded(const String& filePath) {
|
bool UploadManager::isAlreadyUploaded(const String& filePath) {
|
||||||
// We now rely on file extensions (.wmt = pending, .upl = uploaded)
|
File f = SD.open(LOG_FILE, FILE_READ);
|
||||||
return false;
|
if (!f) return false;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
while (f.available()) {
|
||||||
|
String line = f.readStringUntil('\n');
|
||||||
|
line.trim();
|
||||||
|
if (line.length() == 0) continue;
|
||||||
|
|
||||||
|
int firstComma = line.indexOf(',');
|
||||||
|
if (firstComma < 0) continue;
|
||||||
|
int secondComma = line.indexOf(',', firstComma + 1);
|
||||||
|
if (secondComma < 0) continue;
|
||||||
|
|
||||||
|
String logPath = line.substring(firstComma + 1, secondComma);
|
||||||
|
String logStatus = line.substring(secondComma + 1);
|
||||||
|
|
||||||
|
if (logPath == filePath) {
|
||||||
|
if (logStatus == "OK") found = true;
|
||||||
|
else found = false; // A retry might be needed if last status wasn't OK
|
||||||
|
}
|
||||||
|
Watchdog::feed();
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UploadManager::uploadFile(const String& filePath) {
|
void UploadManager::uploadFile(const String& filePath) {
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (isAlreadyUploaded(filePath)) {
|
||||||
ESP_LOGE(TAG_UPLOAD, "No WiFi. Cannot upload %s", filePath.c_str());
|
ESP_LOGI(TAG_UPLOAD, "File %s is already uploaded.", filePath.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
ESP_LOGE(TAG_UPLOAD, "No WiFi. Cannot upload %s", filePath.c_str());
|
||||||
|
appendLog(filePath, "ERROR: No WiFi");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: Before apiClient.uploadMeasurement");
|
||||||
bool success = apiClient.uploadMeasurement(filePath);
|
bool success = apiClient.uploadMeasurement(filePath);
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: After apiClient.uploadMeasurement. Success: %d", success);
|
||||||
if (success) {
|
if (success) {
|
||||||
String newPath = filePath;
|
appendLog(filePath, "OK");
|
||||||
newPath.replace(".wmt", ".upl");
|
|
||||||
if (SD.rename(filePath, newPath)) {
|
|
||||||
ESP_LOGI(TAG_UPLOAD, "Renamed %s to .upl", filePath.c_str());
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG_UPLOAD, "Rename to .upl failed for %s", filePath.c_str());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
ESP_LOGE(TAG_UPLOAD, "WiFi lost during upload");
|
appendLog(filePath, "ERROR: WiFi lost during upload");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG_UPLOAD, "Upload Failed");
|
appendLog(filePath, "ERROR: Upload Failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,43 +81,42 @@ void UploadManager::processPendingUploads() {
|
|||||||
if (WiFi.status() != WL_CONNECTED) return;
|
if (WiFi.status() != WL_CONNECTED) return;
|
||||||
|
|
||||||
ESP_LOGI(TAG_UPLOAD, "Checking for pending uploads...");
|
ESP_LOGI(TAG_UPLOAD, "Checking for pending uploads...");
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: findHighestNumericDir()");
|
||||||
uint32_t highestDir = capture_.findHighestNumericDir();
|
uint32_t highestDir = capture_.findHighestNumericDir();
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: highestDir: %u", highestDir);
|
||||||
if (highestDir == 0) return;
|
if (highestDir == 0) return;
|
||||||
|
|
||||||
for (uint32_t d = 1; d <= highestDir; d++) {
|
for (uint32_t d = 1; d <= highestDir; d++) {
|
||||||
String path = capture_.dirPath(d);
|
String path = capture_.dirPath(d);
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: Scanning dir: %s", path.c_str());
|
||||||
File dir = SD.open(path);
|
File dir = SD.open(path);
|
||||||
if (!dir || !dir.isDirectory()) {
|
if (!dir || !dir.isDirectory()) {
|
||||||
if(dir) dir.close();
|
if(dir) dir.close();
|
||||||
vTaskDelay(1); // yield do IDLE0 między katalogami
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (File f = dir.openNextFile(); f; f = dir.openNextFile()) {
|
for (File f = dir.openNextFile(); f; f = dir.openNextFile()) {
|
||||||
vTaskDelay(1); // yield do IDLE0 przy każdym pliku — zapobiega głodzeniu WDT
|
|
||||||
if (f.isDirectory()) { f.close(); continue; }
|
if (f.isDirectory()) { f.close(); continue; }
|
||||||
String childPath = String(f.name());
|
String childPath = String(f.name());
|
||||||
if (!childPath.startsWith("/")) {
|
if (!childPath.startsWith("/")) {
|
||||||
childPath = path + "/" + childPath;
|
childPath = path + "/" + childPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (childPath.endsWith(".wmt")) {
|
||||||
|
if (!isAlreadyUploaded(childPath)) {
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "Found pending file: %s", childPath.c_str());
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: Calling uploadFile()");
|
||||||
|
uploadFile(childPath);
|
||||||
|
ESP_LOGI(TAG_UPLOAD, "DEBUG: Finished uploadFile(), delaying 1000ms");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
// Pomijamy pliki .upl (już wgrane) i inne rozszerzenia
|
|
||||||
if (!childPath.endsWith(".wmt")) continue;
|
|
||||||
|
|
||||||
// Pomijamy plik aktualnie zapisywany przez pomiar
|
|
||||||
if (childPath == capture_.getCurrentCapturePath()) continue;
|
|
||||||
|
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
dir.close();
|
dir.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG_UPLOAD, "Found pending file: %s", childPath.c_str());
|
|
||||||
uploadFile(childPath);
|
|
||||||
// Krótka przerwa po uploaderze — pozwala IDLE0 na reset WDT
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(200));
|
|
||||||
}
|
}
|
||||||
dir.close();
|
dir.close();
|
||||||
}
|
}
|
||||||
|
|||||||
79
src/Uploader.cpp
Normal file
79
src/Uploader.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include "Uploader.h"
|
||||||
|
|
||||||
|
Uploader::Uploader(Display &display) : _display(display) {}
|
||||||
|
|
||||||
|
void Uploader::processQueue(int maxFiles) {
|
||||||
|
if (WiFi.status() != WL_CONNECTED) return;
|
||||||
|
|
||||||
|
String caCert = loadCACert("/cert.pem");
|
||||||
|
if (caCert == "") {
|
||||||
|
ESP_LOGE("UPLOADER", "Brak cert.pem na SD!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sentCount = 0;
|
||||||
|
File root = SD.open("/");
|
||||||
|
|
||||||
|
// Przeszukiwanie folderów numerycznych stworzonych przez Measure.cpp
|
||||||
|
while (File folder = root.openNextFile()) {
|
||||||
|
if (sentCount >= maxFiles) break;
|
||||||
|
if (folder.isDirectory()) {
|
||||||
|
File dir = SD.open(folder.path());
|
||||||
|
while (File file = dir.openNextFile()) {
|
||||||
|
if (sentCount >= maxFiles) break;
|
||||||
|
|
||||||
|
String fileName = file.name();
|
||||||
|
if (fileName.endsWith(".wmt")) {
|
||||||
|
_display.textStatus("SSL UPLOADING...");
|
||||||
|
if (sendFile(String(file.path()), caCert)) {
|
||||||
|
String oldPath = String(file.path());
|
||||||
|
String newPath = oldPath;
|
||||||
|
newPath.replace(".wmt", ".sent");
|
||||||
|
file.close();
|
||||||
|
SD.rename(oldPath.c_str(), newPath.c_str());
|
||||||
|
sentCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
folder.close();
|
||||||
|
}
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uploader::sendFile(String filePath, String& caCert) {
|
||||||
|
File f = SD.open(filePath, FILE_READ);
|
||||||
|
if (!f) return false;
|
||||||
|
|
||||||
|
WiFiClientSecure client;
|
||||||
|
client.setCACert(caCert.c_str());
|
||||||
|
HTTPClient http;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if (http.begin(client, "https://api.pwojtaszek.codes/upload")) {
|
||||||
|
http.addHeader("Content-Type", "application/octet-stream");
|
||||||
|
http.addHeader("X-File-Name", filePath);
|
||||||
|
http.addHeader("X-Device-ID", config.hostname);
|
||||||
|
|
||||||
|
int code = http.sendRequest("POST", &f, f.size());
|
||||||
|
if (code == 200) {
|
||||||
|
ESP_LOGI("UPLOADER", "Upload OK: %s", filePath.c_str());
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE("UPLOADER", "Error: %d", code);
|
||||||
|
}
|
||||||
|
http.end();
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Uploader::loadCACert(const char* path) {
|
||||||
|
File f = SD.open(path);
|
||||||
|
if (!f) return "";
|
||||||
|
String cert = f.readString();
|
||||||
|
f.close();
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
66
src/main.cpp
66
src/main.cpp
@@ -24,7 +24,8 @@
|
|||||||
SPIClass SPI_ADXL(FSPI); // SPI2 (VSPI)
|
SPIClass SPI_ADXL(FSPI); // SPI2 (VSPI)
|
||||||
SPIClass SPI_SD(HSPI); // SPI3 (HSPI)
|
SPIClass SPI_SD(HSPI); // SPI3 (HSPI)
|
||||||
|
|
||||||
|
float x, y, z = 0; // Dane odczytane z akcelerometru
|
||||||
|
String name;
|
||||||
|
|
||||||
bool isRebootRequired = false;
|
bool isRebootRequired = false;
|
||||||
bool isAccelExists = false; // Czy istnieje jakiś podłączony do SPI czujnik
|
bool isAccelExists = false; // Czy istnieje jakiś podłączony do SPI czujnik
|
||||||
@@ -52,23 +53,7 @@ UploadManager uploadManager(apiClient, rtc, capture);
|
|||||||
Thread wifiTestThread = Thread(); // Cykliczny test WiFi
|
Thread wifiTestThread = Thread(); // Cykliczny test WiFi
|
||||||
Thread offlineThread = Thread(); // Jeśli offline
|
Thread offlineThread = Thread(); // Jeśli offline
|
||||||
Thread measureThread = Thread(); // Pomiar i zapis na SD
|
Thread measureThread = Thread(); // Pomiar i zapis na SD
|
||||||
|
Thread uploadThread = Thread(); // Background upload
|
||||||
TaskHandle_t uploadTaskHandle = NULL;
|
|
||||||
SemaphoreHandle_t sdMutex = NULL; // Mutex chroniący dostęp do karty SD
|
|
||||||
|
|
||||||
void uploadTaskCode(void *parameter) {
|
|
||||||
Watchdog::addThisTask();
|
|
||||||
while(true) {
|
|
||||||
if (config.connect && WiFi.status() == WL_CONNECTED && !testingNow) {
|
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
|
||||||
uploadManager.processPendingUploads();
|
|
||||||
xSemaphoreGive(sdMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Watchdog::feed();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////// PROTOTYPY /////////////////
|
//////// PROTOTYPY /////////////////
|
||||||
void setup();
|
void setup();
|
||||||
@@ -193,9 +178,6 @@ void setup() {
|
|||||||
ESP_LOGI(TAG_MAIN, "SD Card OK");
|
ESP_LOGI(TAG_MAIN, "SD Card OK");
|
||||||
display.print("OK");
|
display.print("OK");
|
||||||
|
|
||||||
// Inicjalizacja mutex SD (po SD.begin)
|
|
||||||
sdMutex = xSemaphoreCreateMutex();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG_MAIN, "ADXL345 SPI3 SCK: %d, MISO: %d, MOSI: %d", CLK_ADSX, MISO_ADSX, MOSI_ADSX);
|
ESP_LOGI(TAG_MAIN, "ADXL345 SPI3 SCK: %d, MISO: %d, MOSI: %d", CLK_ADSX, MISO_ADSX, MOSI_ADSX);
|
||||||
SPI_ADXL.begin(CLK_ADSX, MISO_ADSX, MOSI_ADSX);
|
SPI_ADXL.begin(CLK_ADSX, MISO_ADSX, MOSI_ADSX);
|
||||||
|
|
||||||
@@ -242,16 +224,8 @@ void setup() {
|
|||||||
measureThread.setInterval(config.pause); // Test co X sekund
|
measureThread.setInterval(config.pause); // Test co X sekund
|
||||||
|
|
||||||
if(config.connect){
|
if(config.connect){
|
||||||
xTaskCreatePinnedToCore(
|
uploadThread.onRun([]() { uploadManager.processPendingUploads(); });
|
||||||
uploadTaskCode, // Funkcja zadania
|
uploadThread.setInterval(60000); // Co 1 minutę sprawdzaj zaległe
|
||||||
"UploadTask", // Nazwa zadania
|
|
||||||
8192, // Rozmiar stosu
|
|
||||||
NULL, // Parametr
|
|
||||||
1, // Priorytet (1 - niski, domyślna pętla ma 1 na Core 1)
|
|
||||||
&uploadTaskHandle,// Uchwyt
|
|
||||||
0 // Przypięcie do rdzenia 0 (Wi-Fi działa domyślnie na 0)
|
|
||||||
);
|
|
||||||
ESP_LOGI(TAG_MAIN, "Upload task created on Core 0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dodanie taska loop do WDT
|
// Dodanie taska loop do WDT
|
||||||
@@ -367,19 +341,27 @@ void measure(){
|
|||||||
snprintf(btime, sizeof(btime), "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
|
snprintf(btime, sizeof(btime), "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
|
||||||
display.initMeasure(config.measure, testingNow, runMeasure, config.pause, config.duration, config.connect, licznik, bdate, btime);
|
display.initMeasure(config.measure, testingNow, runMeasure, config.pause, config.duration, config.connect, licznik, bdate, btime);
|
||||||
ESP_LOGI(TAG_MAIN, "MEASURE RUNNING");
|
ESP_LOGI(TAG_MAIN, "MEASURE RUNNING");
|
||||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
//delay(1000);
|
||||||
capture.captureAuto(config.duration, "/");
|
capture.captureAuto(config.duration, "/");
|
||||||
|
|
||||||
testingNow = false;
|
testingNow = false;
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
if(!capture.isExit){
|
if(!capture.isExit){
|
||||||
capture.printLastFileInfoSerial();
|
capture.printLastFileInfoSerial();
|
||||||
|
ESP_LOGI(TAG_MAIN, "DEBUG: before readHeaderAndPrint");
|
||||||
capture.readHeaderAndPrint(capture.generateNextFilename().c_str());
|
capture.readHeaderAndPrint(capture.generateNextFilename().c_str());
|
||||||
ESP_LOGI(TAG_MAIN, "MEASURE FINISH");
|
ESP_LOGI(TAG_MAIN, "MEASURE FINISH");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG_MAIN, "MEASURE INTERRUPT");
|
ESP_LOGI(TAG_MAIN, "MEASURE INTERRUPT");
|
||||||
|
//runMeasure = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG_MAIN, "DEBUG: Checking WiFi status for upload");
|
||||||
|
if (config.connect && WiFi.status() == WL_CONNECTED) {
|
||||||
|
ESP_LOGI(TAG_MAIN, "TRIGGER UPLOAD PENDING...");
|
||||||
|
ESP_LOGI(TAG_MAIN, "DEBUG: Before uploadManager.processPendingUploads()");
|
||||||
|
uploadManager.processPendingUploads();
|
||||||
|
ESP_LOGI(TAG_MAIN, "DEBUG: After uploadManager.processPendingUploads()");
|
||||||
}
|
}
|
||||||
xSemaphoreGive(sdMutex);
|
|
||||||
|
|
||||||
runMeasure = false;
|
runMeasure = false;
|
||||||
ESP_LOGI(TAG_MAIN, "DISPLAY Offline");
|
ESP_LOGI(TAG_MAIN, "DISPLAY Offline");
|
||||||
@@ -421,6 +403,18 @@ void loop() {
|
|||||||
if(settings.isPressed(3)) settingsDevice(); // DOWN
|
if(settings.isPressed(3)) settingsDevice(); // DOWN
|
||||||
if(settings.isPressed(1)) toogleMode(); // UP
|
if(settings.isPressed(1)) toogleMode(); // UP
|
||||||
|
|
||||||
|
if (settings.readBtnUp() && settings.readBtnOk()) {
|
||||||
|
ESP_LOGI(TAG_MAIN, "Manual AP Mode trigger");
|
||||||
|
wifi.startCaptivePortal();
|
||||||
|
display.clear();
|
||||||
|
display.textCenter(1, "AP MODE");
|
||||||
|
display.textCenter(2, "192.168.4.1");
|
||||||
|
while(settings.readBtnUp() && settings.readBtnOk()) {
|
||||||
|
Watchdog::feed();
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(testingNow) {
|
if(testingNow) {
|
||||||
if((runMeasure) && (settings.isPressed(2))){
|
if((runMeasure) && (settings.isPressed(2))){
|
||||||
runMeasure = false;
|
runMeasure = false;
|
||||||
@@ -432,6 +426,9 @@ void loop() {
|
|||||||
if(wifiTestThread.shouldRun() && (config.connect))
|
if(wifiTestThread.shouldRun() && (config.connect))
|
||||||
wifiTestThread.run();
|
wifiTestThread.run();
|
||||||
|
|
||||||
|
if(uploadThread.shouldRun() && config.connect)
|
||||||
|
uploadThread.run();
|
||||||
|
|
||||||
if(offlineThread.shouldRun() && (!config.connect)){
|
if(offlineThread.shouldRun() && (!config.connect)){
|
||||||
offlineThread.run();
|
offlineThread.run();
|
||||||
}
|
}
|
||||||
@@ -460,6 +457,7 @@ void loop() {
|
|||||||
reboot();
|
reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wifi.handleClient();
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
delay(20); // 100
|
delay(20); // 100
|
||||||
licznik ++;
|
licznik ++;
|
||||||
|
|||||||
Reference in New Issue
Block a user