Upload files to "/"
This commit is contained in:
198
sdcard_task.cpp
Normal file
198
sdcard_task.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
#include "sdcard_task.h"
|
||||
#include "serial_task.h"
|
||||
#include <time.h>
|
||||
|
||||
static SPIClass hspi(HSPI);
|
||||
volatile bool sdLoggingActive = false;
|
||||
char currentLogFileName[64] = "";
|
||||
static File logFile;
|
||||
static bool sdReady = false;
|
||||
static SemaphoreHandle_t sdMutex = NULL;
|
||||
|
||||
void sdTaskInit() {
|
||||
sdMutex = xSemaphoreCreateMutex();
|
||||
|
||||
hspi.begin(SD_HSPI_CLK, SD_HSPI_MISO, SD_HSPI_MOSI, SD_HSPI_CS);
|
||||
|
||||
if (!SD.begin(SD_HSPI_CS, hspi, 4000000)) {
|
||||
Serial.println("[SD] Card mount FAILED!");
|
||||
sdReady = false;
|
||||
} else {
|
||||
uint8_t cardType = SD.cardType();
|
||||
if (cardType == CARD_NONE) {
|
||||
Serial.println("[SD] No card detected!");
|
||||
sdReady = false;
|
||||
} else {
|
||||
sdReady = true;
|
||||
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
||||
Serial.printf("[SD] Card mounted. Type: %d, Size: %lluMB\n", cardType, cardSize);
|
||||
hspi.setFrequency(20000000);
|
||||
|
||||
if (!SD.exists(LOG_DIR)) {
|
||||
SD.mkdir(LOG_DIR);
|
||||
Serial.println("[SD] Created /logs directory");
|
||||
}
|
||||
sdCreateNewLogFile();
|
||||
sdLoggingActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
xTaskCreatePinnedToCore(sdLoggingTask, "SDLog", TASK_STACK_SD_LOG,
|
||||
NULL, TASK_PRIORITY_SD_LOG, NULL, 0);
|
||||
}
|
||||
|
||||
bool sdCreateNewLogFile() {
|
||||
if (!sdReady) return false;
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
|
||||
if (logFile) { logFile.flush(); logFile.close(); }
|
||||
|
||||
struct tm timeinfo;
|
||||
time_t now;
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
|
||||
snprintf(currentLogFileName, sizeof(currentLogFileName),
|
||||
"%s/LOG_%04d%02d%02d_%02d%02d%02d.csv",
|
||||
LOG_DIR,
|
||||
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
|
||||
logFile = SD.open(currentLogFileName, FILE_WRITE);
|
||||
if (!logFile) {
|
||||
Serial.printf("[SD] Failed to create: %s\n", currentLogFileName);
|
||||
xSemaphoreGive(sdMutex);
|
||||
return false;
|
||||
}
|
||||
logFile.print(CSV_HEADER);
|
||||
logFile.flush();
|
||||
Serial.printf("[SD] New log file: %s\n", currentLogFileName);
|
||||
xSemaphoreGive(sdMutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sdLoggingTask(void *param) {
|
||||
Serial.println("[Task] SDLog started on core " + String(xPortGetCoreID()));
|
||||
|
||||
TickType_t lastFlush = xTaskGetTickCount();
|
||||
int pendingWrites = 0;
|
||||
char csvLine[LOG_LINE_MAX_LEN + 64];
|
||||
|
||||
while (true) {
|
||||
LogEntry *entry;
|
||||
if (xQueueReceive(queueSD, &entry, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
if (sdLoggingActive && sdReady && logFile) {
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
|
||||
int len = snprintf(csvLine, sizeof(csvLine),
|
||||
"\"%s\",\"%c\",\"", entry->timestamp,
|
||||
entry->direction == 'T' ? 'T' : 'R');
|
||||
|
||||
for (int i = 0; i < entry->dataLen && len < (int)sizeof(csvLine) - 4; i++) {
|
||||
char c = entry->data[i];
|
||||
if (c == '"') { csvLine[len++] = '"'; csvLine[len++] = '"'; }
|
||||
else if (c >= 0x20 && c < 0x7F) { csvLine[len++] = c; }
|
||||
else { len += snprintf(csvLine + len, sizeof(csvLine) - len, "\\x%02X", (uint8_t)c); }
|
||||
}
|
||||
len += snprintf(csvLine + len, sizeof(csvLine) - len, "\"\r\n");
|
||||
logFile.write((uint8_t*)csvLine, len);
|
||||
pendingWrites++;
|
||||
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
vPortFree(entry);
|
||||
}
|
||||
|
||||
if (pendingWrites > 0 &&
|
||||
(xTaskGetTickCount() - lastFlush) > pdMS_TO_TICKS(SD_WRITE_INTERVAL)) {
|
||||
if (logFile) {
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
logFile.flush();
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
pendingWrites = 0;
|
||||
lastFlush = xTaskGetTickCount();
|
||||
}
|
||||
|
||||
if (pendingWrites >= 50) {
|
||||
if (logFile) {
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
logFile.flush();
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
pendingWrites = 0;
|
||||
lastFlush = xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sdStopLogging() {
|
||||
sdLoggingActive = false;
|
||||
if (logFile) {
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
logFile.flush();
|
||||
logFile.close();
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
Serial.println("[SD] Logging stopped");
|
||||
}
|
||||
|
||||
void sdStartLogging() {
|
||||
if (!sdReady) { Serial.println("[SD] Card not ready!"); return; }
|
||||
if (!logFile || !sdLoggingActive) sdCreateNewLogFile();
|
||||
sdLoggingActive = true;
|
||||
Serial.println("[SD] Logging started");
|
||||
}
|
||||
|
||||
String sdGetFileList() {
|
||||
if (!sdReady) return "{\"files\":[]}";
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
|
||||
String json = "{\"files\":[";
|
||||
File dir = SD.open(LOG_DIR);
|
||||
bool first = true;
|
||||
|
||||
if (dir && dir.isDirectory()) {
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
if (!file.isDirectory()) {
|
||||
if (!first) json += ",";
|
||||
first = false;
|
||||
json += "{\"name\":\"";
|
||||
json += file.name();
|
||||
json += "\",\"size\":";
|
||||
json += String(file.size());
|
||||
time_t t = file.getLastWrite();
|
||||
struct tm *tm = localtime(&t);
|
||||
char timeBuf[32];
|
||||
strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", tm);
|
||||
json += ",\"modified\":\"";
|
||||
json += timeBuf;
|
||||
json += "\"}";
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
dir.close();
|
||||
}
|
||||
json += "]}";
|
||||
xSemaphoreGive(sdMutex);
|
||||
return json;
|
||||
}
|
||||
|
||||
bool sdDeleteFile(const char *filename) {
|
||||
if (!sdReady) return false;
|
||||
xSemaphoreTake(sdMutex, portMAX_DELAY);
|
||||
|
||||
char path[128];
|
||||
snprintf(path, sizeof(path), "%s/%s", LOG_DIR, filename);
|
||||
if (sdLoggingActive && strcmp(path, currentLogFileName) == 0) {
|
||||
xSemaphoreGive(sdMutex);
|
||||
return false;
|
||||
}
|
||||
bool result = SD.remove(path);
|
||||
Serial.printf("[SD] Delete %s: %s\n", path, result ? "OK" : "FAIL");
|
||||
xSemaphoreGive(sdMutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool sdCardPresent() { return sdReady; }
|
||||
23
sdcard_task.h
Normal file
23
sdcard_task.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef SDCARD_TASK_H
|
||||
#define SDCARD_TASK_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "config.h"
|
||||
|
||||
extern volatile bool sdLoggingActive;
|
||||
extern char currentLogFileName[64];
|
||||
|
||||
void sdTaskInit();
|
||||
void sdLoggingTask(void *param);
|
||||
bool sdCreateNewLogFile();
|
||||
void sdStopLogging();
|
||||
void sdStartLogging();
|
||||
String sdGetFileList();
|
||||
bool sdDeleteFile(const char *filename);
|
||||
bool sdCardPresent();
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user