LittleFS mount OK, updated interface, upload to littlefs from browser
This commit is contained in:
@@ -1,7 +1,26 @@
|
||||
#include "datasave.h"
|
||||
#include <math.h>
|
||||
|
||||
static const size_t min_free = 1024 * 1024; // minimum free space in SPIFFS to allow saving history (1MB)
|
||||
static const size_t min_free = 1024 * 1024; // minimum free space in LittleFS to allow saving history (1MB)
|
||||
|
||||
LITTLEFSGuard::LITTLEFSGuard()
|
||||
{
|
||||
if (!LittleFS.begin(true, "/littlefs", 10, "littlefs"))
|
||||
{
|
||||
LOG_ERROR("Failed to mount LittleFS");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("LittleFS mounted successfully");
|
||||
LOG_INFO("LittleFS Free KBytes:", (LittleFS.totalBytes() - LittleFS.usedBytes()) /1024);
|
||||
}
|
||||
}
|
||||
|
||||
LITTLEFSGuard::~LITTLEFSGuard()
|
||||
{
|
||||
LittleFS.end();
|
||||
LOG_INFO("LittleFS unmounted successfully");
|
||||
}
|
||||
|
||||
void ignitionBoxStatusAverage::filter(int32_t &old, const int32_t value, const uint32_t k)
|
||||
{
|
||||
@@ -42,18 +61,18 @@ void ignitionBoxStatusAverage::update(const ignitionBoxStatus &new_status)
|
||||
filter(m_last.coils12.peak_p_out, new_status.coils12.peak_p_out, m_max_count); // incremental average calculation
|
||||
filter(m_last.coils12.peak_n_out, new_status.coils12.peak_n_out, m_max_count); // incremental average calculation
|
||||
|
||||
m_last.coils34.n_events = new_status.coils34.n_events; // sum events instead of averaging
|
||||
m_last.coils34.n_missed_firing = new_status.coils34.n_missed_firing; // sum missed firings instead of averaging
|
||||
m_last.coils34.spark_status = new_status.coils34.spark_status; // take latest spark status
|
||||
m_last.coils34.sstart_status = new_status.coils34.sstart_status; // take latest soft start status
|
||||
filter(m_last.coils34.spark_delay, new_status.coils34.spark_delay, m_max_count); // incremental average calculation
|
||||
m_last.coils34.n_events = new_status.coils34.n_events; // sum events instead of averaging
|
||||
m_last.coils34.n_missed_firing = new_status.coils34.n_missed_firing; // sum missed firings instead of averaging
|
||||
m_last.coils34.spark_status = new_status.coils34.spark_status; // take latest spark status
|
||||
m_last.coils34.sstart_status = new_status.coils34.sstart_status; // take latest soft start status
|
||||
filter(m_last.coils34.spark_delay, new_status.coils34.spark_delay, m_max_count); // incremental average calculation
|
||||
filter(m_last.coils34.peak_p_in, new_status.coils34.peak_p_in, m_max_count); // incremental average calculation
|
||||
filter(m_last.coils34.peak_n_in, new_status.coils34.peak_n_in, m_max_count); // incremental average calculation
|
||||
filter(m_last.coils34.peak_p_out, new_status.coils34.peak_p_out, m_max_count); // incremental average calculation
|
||||
filter(m_last.coils34.peak_n_out, new_status.coils34.peak_n_out, m_max_count); // incremental average calculation
|
||||
filter(m_last.eng_rpm, new_status.eng_rpm, m_max_count); // incremental average calculation // incremental average calculation
|
||||
filter(m_last.adc_read_time, m_last.adc_read_time, m_max_count); // incremental average calculation
|
||||
m_last.n_queue_errors = new_status.n_queue_errors; // take last of queue errors since it's a cumulative count of errors in the queue, not an average value
|
||||
filter(m_last.eng_rpm, new_status.eng_rpm, m_max_count); // incremental average calculation // incremental average calculation
|
||||
filter(m_last.adc_read_time, m_last.adc_read_time, m_max_count); // incremental average calculation
|
||||
m_last.n_queue_errors = new_status.n_queue_errors; // take last of queue errors since it's a cumulative count of errors in the queue, not an average value
|
||||
|
||||
if (m_count >= m_max_count)
|
||||
{
|
||||
@@ -126,7 +145,8 @@ void save_history(const PSRAMVector<ignitionBoxStatus> &history, const std::file
|
||||
// Initialize SPIFFS
|
||||
if (!SAVE_HISTORY_TO_LITTLEFS)
|
||||
return;
|
||||
// auto spiffs_guard = LITTLEFSGuard(); // use RAII guard to ensure SPIFFS is properly mounted and unmounted
|
||||
|
||||
auto littlefs_guard = LITTLEFSGuard(); // use RAII guard to ensure LittleFS is properly mounted and unmounted
|
||||
|
||||
if (LittleFS.totalBytes() - LittleFS.usedBytes() < min_free) // check if at least 1MB is free for saving history
|
||||
{
|
||||
@@ -142,7 +162,7 @@ void save_history(const PSRAMVector<ignitionBoxStatus> &history, const std::file
|
||||
if (first_save && LittleFS.exists(file_path.c_str()))
|
||||
{
|
||||
first_save = false;
|
||||
save_flags |= std::ios::trunc; // overwrite existing file
|
||||
save_flags |= std::ios::trunc; // overwrite existing file
|
||||
LittleFS.remove(file_path.c_str()); // ensure file is removed before saving to avoid issues with appending to existing file in SPIFFS
|
||||
LOG_INFO("Saving history to LittleFS, new file:", file_path.c_str());
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
// System Includes
|
||||
#include <Arduino.h>
|
||||
#include <DebugLog.h>
|
||||
#include <LittleFS.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <ArduinoJson.h>
|
||||
#include <filesystem>
|
||||
#include <LittleFS.h>
|
||||
|
||||
// Project Includes
|
||||
#include "isr.h"
|
||||
#include "psvector.h"
|
||||
|
||||
const uint32_t max_history = 256;
|
||||
const bool SAVE_HISTORY_TO_LITTLEFS = false; // Set to true to enable saving history to SPIFFS, false to disable
|
||||
static bool first_save = true; // flag to indicate if this is the first save (to write header)
|
||||
const bool SAVE_HISTORY_TO_LITTLEFS = false; // Set to true to enable saving history to LittleFS, false to disable
|
||||
static bool first_save = true; // flag to indicate if this is the first save (to write header)
|
||||
|
||||
struct dataSaveParams
|
||||
{
|
||||
@@ -27,20 +27,8 @@ struct dataSaveParams
|
||||
class LITTLEFSGuard
|
||||
{
|
||||
public:
|
||||
LITTLEFSGuard()
|
||||
{
|
||||
if (!LittleFS.begin(true))
|
||||
{
|
||||
LOG_ERROR("Failed to mount LittleFS");
|
||||
}
|
||||
LOG_INFO("SPIFFS mounted successfully");
|
||||
}
|
||||
|
||||
~LITTLEFSGuard()
|
||||
{
|
||||
LittleFS.end();
|
||||
LOG_INFO("LittleFS unmounted successfully");
|
||||
}
|
||||
LITTLEFSGuard();
|
||||
~LITTLEFSGuard();
|
||||
};
|
||||
|
||||
class ignitionBoxStatusAverage
|
||||
@@ -53,7 +41,8 @@ private:
|
||||
|
||||
public:
|
||||
ignitionBoxStatusAverage() = default;
|
||||
ignitionBoxStatusAverage(const uint32_t max_count) : m_max_count(max_count) {
|
||||
ignitionBoxStatusAverage(const uint32_t max_count) : m_max_count(max_count)
|
||||
{
|
||||
m_data_valid = false;
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define DEBUGLOG_DEFAULT_LOG_LEVEL_INFO
|
||||
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
|
||||
|
||||
// Arduino Libraries
|
||||
#include <Arduino.h>
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <datasave.h>
|
||||
#include <ui.h>
|
||||
|
||||
static File uploadFile;
|
||||
static bool uploadFailed = false;
|
||||
|
||||
// FreeRTOS directives
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -61,11 +64,6 @@ void setup()
|
||||
LOG_DEBUG("ESP32 Heap:", ESP.getHeapSize());
|
||||
LOG_DEBUG("ESP32 Sketch:", ESP.getFreeSketchSpace());
|
||||
|
||||
// Initialize Interrupt pins on PICKUP detectors
|
||||
initTriggerPinsInputs();
|
||||
// Initialize Interrupt pins on SPARK detectors
|
||||
initSparkPinInputs();
|
||||
|
||||
// Init Wifi station
|
||||
LOG_INFO("Initializing WiFi...");
|
||||
WiFi.mode(WIFI_AP);
|
||||
@@ -87,6 +85,11 @@ void setup()
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
// Initialize Interrupt pins on PICKUP detectors
|
||||
initTriggerPinsInputs();
|
||||
// Initialize Interrupt pins on SPARK detectors
|
||||
initSparkPinInputs();
|
||||
}
|
||||
|
||||
void loop()
|
||||
@@ -123,7 +126,15 @@ void loop()
|
||||
.spark_pin_34 = SPARK_PIN_A34},
|
||||
.rt_resets = rtTaskResets{.rst_io_12p = RST_EXT_A12P, .rst_io_12n = RST_EXT_A12N, .rst_io_34p = RST_EXT_A34P, .rst_io_34n = RST_EXT_A34N}};
|
||||
|
||||
LOG_DEBUG("Task Variables OK");
|
||||
if (!rt_taskA_queue || !rt_taskB_queue)
|
||||
{
|
||||
LOG_ERROR("Unable To Create task queues");
|
||||
LOG_ERROR("5 seconds to restart...");
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
esp_restart();
|
||||
}
|
||||
else
|
||||
LOG_DEBUG("Task Variables OK");
|
||||
|
||||
#ifdef CH_B_ENABLE
|
||||
QueueHandle_t rt_taskB_queue = xQueueCreate(max_queue, sizeof(ignitionBoxStatus));
|
||||
@@ -190,6 +201,7 @@ void loop()
|
||||
RT_TASK_PRIORITY,
|
||||
&trigA_TaskHandle,
|
||||
CORE_0);
|
||||
delay(100);
|
||||
|
||||
// Ignition B on Core 1
|
||||
auto ignB_task_success = pdPASS;
|
||||
@@ -202,11 +214,12 @@ void loop()
|
||||
RT_TASK_PRIORITY, // priorità leggermente più alta
|
||||
&trigB_TaskHandle,
|
||||
CORE_1);
|
||||
delay(100);
|
||||
#endif
|
||||
|
||||
if ((ignA_task_success && ignB_task_success) != pdPASS)
|
||||
if (ignA_task_success != pdPASS || ignB_task_success != pdPASS)
|
||||
{
|
||||
LOG_ERROR("Una ble to initialize ISR task");
|
||||
LOG_ERROR("Unable to initialize ISR task");
|
||||
LOG_ERROR("5 seconds to restart...");
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
esp_restart();
|
||||
@@ -219,7 +232,8 @@ void loop()
|
||||
uint32_t counter = 0;
|
||||
uint32_t wait_count = 0;
|
||||
ignitionBoxStatus ign_info;
|
||||
ignitionBoxStatusAverage ign_info_avg(filter_k);
|
||||
ignitionBoxStatusAverage ign_info_avg(filter_k);
|
||||
LITTLEFSGuard fsGuard;
|
||||
|
||||
// Initialize Web page
|
||||
AsyncWebServer server(80);
|
||||
@@ -227,6 +241,67 @@ void loop()
|
||||
ws.onEvent(onWsEvent);
|
||||
server.addHandler(&ws);
|
||||
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
|
||||
|
||||
server.on("/upload", HTTP_POST,
|
||||
[](AsyncWebServerRequest *request) {
|
||||
if (uploadFailed)
|
||||
{
|
||||
request->send(500, "text/plain", "Upload failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
request->send(200, "text/plain", "Upload successful");
|
||||
}
|
||||
},
|
||||
[](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
if (index == 0)
|
||||
{
|
||||
uploadFailed = false;
|
||||
String safeName = filename;
|
||||
int slashIndex = safeName.lastIndexOf('/');
|
||||
if (slashIndex >= 0)
|
||||
{
|
||||
safeName = safeName.substring(slashIndex + 1);
|
||||
}
|
||||
if (safeName.length() == 0)
|
||||
{
|
||||
uploadFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
String filePath = "/" + safeName;
|
||||
if (LittleFS.exists(filePath))
|
||||
{
|
||||
LittleFS.remove(filePath);
|
||||
}
|
||||
|
||||
uploadFile = LittleFS.open(filePath, FILE_WRITE);
|
||||
if (!uploadFile)
|
||||
{
|
||||
uploadFailed = true;
|
||||
LOG_ERROR("Failed to open upload file:", filePath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uploadFailed && uploadFile)
|
||||
{
|
||||
if (uploadFile.write(data, len) != len)
|
||||
{
|
||||
uploadFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (final && uploadFile)
|
||||
{
|
||||
uploadFile.close();
|
||||
if (!uploadFailed)
|
||||
{
|
||||
LOG_INFO("Uploaded file to LittleFS:", filename);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.begin();
|
||||
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
@@ -253,12 +328,12 @@ void loop()
|
||||
auto &hist = *active_history;
|
||||
hist[counter++ % active_history->size()] = ign_info;
|
||||
ign_info_avg.update(ign_info); // update moving average with latest ignition status
|
||||
Serial.print("Data Received: " + String(counter) + "/" + String(hist.size()) + '\r');
|
||||
Serial.print("\033[2K Data Received: " + String(counter) + "/" + String(hist.size()) + '\r');
|
||||
|
||||
if (ws.count() > 0 && counter % 10 == 0) // send data every 10 samples
|
||||
if (ws.count() > 0 && counter % filter_k == 0) // send data every 10 samples
|
||||
{
|
||||
Serial.println();
|
||||
LOG_INFO("Sending average ignition status to websocket clients...");
|
||||
LOG_DEBUG("Sending average ignition status to websocket clients...");
|
||||
auto msg = ign_info_avg.toJson().as<String>();
|
||||
ws.textAll(msg);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@ void rtIgnitionTask(void *pvParameters)
|
||||
#ifdef DEBUG
|
||||
Serial.print("\033[2J"); // clear screen
|
||||
Serial.print("\033[H"); // cursor home
|
||||
LOG_INFO("Iteration [", it++, "]");
|
||||
|
||||
if (!names.contains(pickup_flag))
|
||||
{
|
||||
@@ -267,9 +266,11 @@ void rtIgnitionTask(void *pvParameters)
|
||||
|
||||
// send essage to main loop with ignition info, by copy so local static variable is ok
|
||||
if (rt_queue)
|
||||
{
|
||||
ign_box_sts.timestamp = esp_timer_get_time(); // update data timestamp
|
||||
if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS)
|
||||
ign_box_sts.n_queue_errors = ++n_errors;
|
||||
if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS)
|
||||
ign_box_sts.n_queue_errors = ++n_errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Delete the timeout timer
|
||||
|
||||
0
RotaxMonitor/src/webserver.cpp
Normal file
0
RotaxMonitor/src/webserver.cpp
Normal file
0
RotaxMonitor/src/webserver.h
Normal file
0
RotaxMonitor/src/webserver.h
Normal file
Reference in New Issue
Block a user