1. 完整封装并拓展了SD卡文件管理类,支持基本文件管理功能

2. 简单封装了LVGL渲染类,已经封装好了gif渲染功能
3. 修复了硬件厂商提供的驱动的Bug
4. 初步定义了宠物基类的抽象信息
This commit is contained in:
Misaki
2025-09-09 03:40:24 +08:00
parent 28ceb0caf5
commit 4985fee7c2
24 changed files with 996 additions and 22 deletions
@@ -0,0 +1,142 @@
//
// Created by misaki on 2025/9/8.
//
#include "ThreadManager.h"
#include "LVGLRender.h"
#include "I2C_Driver.h"
#include "ST77916.h"
#include "LVGL_Driver.h"
#include <esp_log.h>
LVGLRender* LVGLRender::LVGLRenderInstance = nullptr;
std::mutex LVGLRender::instance_mutex;
uint16_t LVGLRender::fps = 30;
LVGLRender* LVGLRender::getInstance() {
// 双检锁(DCLP),C++11 起 atomic+mutex 组合保证线程安全
LVGLRender* tmp = LVGLRenderInstance;
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(instance_mutex);
tmp = LVGLRenderInstance;
if (tmp == nullptr) {
tmp = new LVGLRender();
LVGLRenderInstance = tmp;
}
}
return tmp;
}
void LVGLRender::LVGL_Update() {
while (true) {
vTaskDelay(LVGL_DELAY_FROM_FPS(LVGLRender::fps));
lv_timer_handler();
}
}
// 构造函数
LVGLRender::LVGLRender() {
ESP_LOGI("LVGL_Render", "LVGL_Render构造函数...初始化媒体驱动...");
I2C_Init();
LCD_Init();
LVGL_Init();
ESP_LOGI("LVGL_Render", "LVGL_Render构造函数...初始化媒体驱动成功...");
ESP_LOGI("LVGL_Render", "LVGL_Render构造函数...创建LVGL心跳...");
ThreadConfig trickConfig;
trickConfig.core_id = 1; // 渲染分配给核1
trickConfig.name = "LVGL_Render_Heartbeat";
trickConfig.priority = 5;
trickConfig.stack_size = 4096; // 给LVGL一个较大的堆栈,避免栈溢出
std::thread tick_thread = ThreadManager::createMemberThread(trickConfig, this, &LVGLRender::LVGL_Update);
tick_thread.detach(); // 线程分离 生命周期跟随主线程结束,线程结束后自动销毁
ESP_LOGI("LVGL_Render", "LVGL_Render构造函数...创建LVGL心跳成功...");
}
LVGLRender::~LVGLRender() {
}
void LVGLRender::log() {
ESP_LOGI("LVGL_Render", "LVGL_Render log...");
}
// 静态:拼出完整路径
std::string LVGLRender::makeFullPath(const std::string& filename)
{
return "/sdcard/" + filename;
}
#include "SDFileManager.h"
std::vector<uint8_t> LVGLRender::readWholeFile(const std::string& path)
{
ESP_LOGI("LVGLRender", "开始读取文件: %s", path.c_str());
// 直接用 SDFileManager 同步读整个文件 TODO: 考虑修改为异步读
std::string content = SDFileManager::getInstance()->readFileSync(path.c_str());
if (content.empty()) {
ESP_LOGE("LVGLRender", "readFileSync 失败或文件为空");
return {};
}
// string -> vector,零拷贝 move
return {content.begin(), content.end()};
}
bool LVGLRender::getGifWH(const uint8_t* raw, uint32_t& w, uint32_t& h)
{
if (!raw || memcmp(raw, "GIF", 3) != 0) {
ESP_LOGE("LVGLRender", "不是合法 GIF 文件头");
return false;
}
// GIF87a/89a 宽高偏移 6~9 字节,小端
w = raw[6] | (raw[7] << 8);
h = raw[8] | (raw[9] << 8);
ESP_LOGI("LVGLRender", "GIF 尺寸: %lu x %lu", w, h);
return true;
}
void LVGLRender::renderGifInternal(const std::vector<uint8_t>& data,
uint32_t w, uint32_t h)
{
// 构造 lv_img_dsc_t —— 数据指针直接指向 vector 内部
static lv_img_dsc_t gif_desc;
gif_desc.header.cf = LV_IMG_CF_RAW_CHROMA_KEYED;
gif_desc.header.always_zero = 0;
gif_desc.header.reserved = 0;
gif_desc.header.w = (lv_coord_t)w;
gif_desc.header.h = (lv_coord_t)h;
gif_desc.data_size = data.size();
gif_desc.data = data.data(); // 指向 vector 内部
// 创建 lv_gif 对象
lv_obj_t* gif = lv_gif_create(lv_scr_act());
lv_gif_set_src(gif, &gif_desc);
lv_obj_center(gif);
ESP_LOGI("LVGLRender", "GIF 已渲染到屏幕");
}
void LVGLRender::RenderGif(const std::string &filename) {
std::string fullPath = makeFullPath(filename);
// 读文件
std::vector<uint8_t> gifBin = readWholeFile(fullPath);
if (gifBin.empty()) return;
// 校验并解析宽高
uint32_t w = 0, h = 0;
if (!getGifWH(gifBin.data(), w, h)) return;
// LVGL 渲染函数
renderGifInternal(gifBin, w, h);
}
@@ -0,0 +1,61 @@
//
// Created by misaki on 2025/9/8.
//
/**
* 本类为单例类,用于实现LVGL的渲染
* 封装了一整套的LVGL渲染流
* 同时兼顾了底层的显示驱动
*/
#pragma once
#define LVGL_DELAY_FROM_FPS(fps) pdMS_TO_TICKS(1000 / (fps))
#include <mutex>
#include <string>
class LVGLRender {
public:
static std::string makeFullPath(const std::string& filename);
public:
static LVGLRender* getInstance();
/**
* 全屏渲染gif动画
* @brief 渲染GIF文件
* @param filename GIF文件路径
*/
void RenderGif(const std::string &filename);
void log();
// gif渲染
private:
/* 同步读整个文件到 vector */
std::vector<uint8_t> readWholeFile(const std::string& path);
/* 从原始数据解析 GIF 宽高 */
bool getGifWH(const uint8_t* raw, uint32_t& w, uint32_t& h);
/* 真正的渲染实现(空壳,先打印日志) */
void renderGifInternal(const std::vector<uint8_t>& data,
uint32_t w, uint32_t h);
private:
explicit LVGLRender(); // 构造函数私有化
~LVGLRender();
LVGLRender(LVGLRender const&) = delete; // 拷贝构造函数私有化
LVGLRender& operator=(LVGLRender const&) = delete;// 赋值运算符私有化
void LVGL_Update(); // 渲染lvgl上下文(持久性线程)
private:
static LVGLRender* LVGLRenderInstance; /// 单例实例
static std::mutex instance_mutex; /// 单例锁
static uint16_t fps; /// 帧率
};
@@ -0,0 +1,505 @@
//
// Created by misaki on 2025/9/9.
//
#include "SDFileManager.h"
#include "SD_MMC.h"
#include <cstring>
#include <vector>
#include <string>
#include <iomanip>
SDFileManager* SDFileManager::SDFileInstance = nullptr;
std::mutex SDFileManager::instance_mutex;
SDFileManager *SDFileManager::getInstance() {
// 双检锁(DCLP),C++11 起 atomic+mutex 组合保证线程安全
SDFileManager* tmp = SDFileInstance;
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(instance_mutex);
tmp = SDFileInstance;
if (tmp == nullptr) {
tmp = new SDFileManager();
SDFileInstance = tmp;
}
}
return tmp;
}
SDFileManager::SDFileManager() : is_initialized(false), current_directory(MOUNT_POINT) {
// 初始化SD卡
init();
// 获取Flash大小
Flash_Searching();
}
SDFileManager::~SDFileManager() {
// 清理资源
}
void SDFileManager::init() {
SD_Init();
is_initialized = true;
}
bool SDFileManager::writeFileSync(const char* path, const char* data) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return false;
}
esp_err_t result = s_example_write_file(path, const_cast<char*>(data));
return result == ESP_OK;
}
std::string SDFileManager::readFileSync(const char* path) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return "";
}
FILE* file = fopen(path, "r");
if (file == nullptr) {
ESP_LOGE("SDFileManager", "Failed to open file: %s", path);
return "";
}
// 获取文件大小
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
// 读取文件内容
std::string content;
content.resize(size);
size_t bytes_read = fread(&content[0], 1, size, file);
fclose(file);
if (bytes_read != static_cast<size_t>(size)) {
ESP_LOGE("SDFileManager", "Failed to read entire file: %s", path);
return "";
}
return content;
}
std::vector<std::string> SDFileManager::listFilesSync(const char* directory, const char* extension) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return {};
}
const int max_files = 50;
char file_names[max_files][100];
uint16_t file_count = Folder_retrieval(directory, extension, file_names, max_files);
std::vector<std::string> files;
for (uint16_t i = 0; i < file_count; ++i) {
files.emplace_back(file_names[i]);
}
return files;
}
FILE* SDFileManager::openFileSync(const char* path, const char* mode) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return nullptr;
}
return Open_File(path);
}
bool SDFileManager::closeFileSync(FILE* file) {
if (file != nullptr) {
return fclose(file) == 0;
}
return false;
}
void SDFileManager::asyncWriteFile(const char* path, const char* data, WriteCallback callback) {
ThreadConfig config = getThreadConfig("write_file");
ThreadManager::createThread(config, [this, path = std::string(path),
data = std::string(data), callback]() {
bool success = this->writeFileSync(path.c_str(), data.c_str());
if (callback) {
callback(success, path.c_str());
}
}).detach(); // 分离线程,使其独立运行
}
void SDFileManager::asyncReadFile(const char* path, ReadCallback callback) {
if (!callback) {
return; // 没有回调函数,异步读取无意义
}
ThreadConfig config = getThreadConfig("read_file");
ThreadManager::createThread(config, [this, path = std::string(path), callback]() {
std::string content = this->readFileSync(path.c_str());
bool success = !content.empty();
callback(success, path.c_str(), content);
}).detach();
}
void SDFileManager::asyncListFiles(const char* directory, const char* extension, ListCallback callback) {
if (!callback) {
return; // 没有回调函数,异步列出文件无意义
}
ThreadConfig config = getThreadConfig("list_files");
ThreadManager::createThread(config, [this, directory = std::string(directory),
extension = std::string(extension ? extension : ""),
callback]() {
std::vector<std::string> files = this->listFilesSync(
directory.c_str(),
extension.empty() ? nullptr : extension.c_str()
);
bool success = !files.empty();
callback(success, files);
}).detach();
}
void SDFileManager::asyncOpenFile(const char* path, const char* mode, OpenCallback callback) {
if (!callback) {
return; // 没有回调函数,异步打开文件无意义
}
ThreadConfig config = getThreadConfig("open_file");
ThreadManager::createThread(config, [this, path = std::string(path),
mode = std::string(mode), callback]() {
FILE* file = this->openFileSync(path.c_str(), mode.c_str());
bool success = (file != nullptr);
callback(success, file);
}).detach();
}
ThreadConfig SDFileManager::getThreadConfig(const char* operation) {
ThreadConfig config;
config.name = "sd_" + std::string(operation);
config.core_id = -1; // 不绑定核心
config.stack_size = 4096;
config.priority = 5;
config.inherit_cfg = false;
return config;
}
// 实现ls命令
std::string SDFileManager::lsCommand(const char* path, bool recursive, bool showDetails) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return "Error: SD card not initialized";
}
std::string fullPath = path;
if (fullPath.empty() || fullPath == ".") {
fullPath = current_directory;
} else if (fullPath[0] != '/') {
// 相对路径
fullPath = current_directory + "/" + fullPath;
}
DIR* dir = opendir(fullPath.c_str());
if (dir == nullptr) {
return "Error: Cannot open directory " + fullPath;
}
std::stringstream result;
struct dirent* entry;
struct stat st;
result << "Directory listing for: " << fullPath << "\n";
result << "----------------------------------------\n";
while ((entry = readdir(dir)) != nullptr) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
std::string entryPath = fullPath + "/" + entry->d_name;
if (stat(entryPath.c_str(), &st) != 0) {
continue;
}
if (showDetails) {
result << getFileInfoString(entry->d_name, &st);
} else {
result << entry->d_name;
}
if (S_ISDIR(st.st_mode)) {
result << "/";
}
result << "\n";
// 递归列出子目录
if (recursive && S_ISDIR(st.st_mode)) {
std::string subDirResult = lsCommand(entryPath.c_str(), true, showDetails);
result << subDirResult;
}
}
closedir(dir);
return result.str();
}
// 实现cat命令
std::string SDFileManager::catCommand(const char* path, bool lineNumbers) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return "Error: SD card not initialized";
}
std::string fullPath = path;
if (fullPath[0] != '/') {
// 相对路径
fullPath = current_directory + "/" + fullPath;
}
FILE* file = fopen(fullPath.c_str(), "r");
if (file == nullptr) {
return "Error: Cannot open file " + fullPath;
}
std::stringstream result;
char buffer[256];
int lineNumber = 1;
while (fgets(buffer, sizeof(buffer), file) != nullptr) {
if (lineNumbers) {
result << std::setw(4) << lineNumber << ": ";
}
result << buffer;
lineNumber++;
}
fclose(file);
return result.str();
}
// 实现pwd命令
std::string SDFileManager::pwdCommand() {
return current_directory;
}
// 实现cd命令
bool SDFileManager::cdCommand(const char* path) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return false;
}
std::string newPath;
if (path[0] == '/') {
// 绝对路径
newPath = path;
} else if (strcmp(path, "..") == 0) {
// 上级目录
size_t pos = current_directory.find_last_of('/');
if (pos != std::string::npos && pos > 0) {
newPath = current_directory.substr(0, pos);
} else {
newPath = "/";
}
} else {
// 相对路径
newPath = current_directory + "/" + path;
}
// 检查路径是否存在且是目录
struct stat st;
if (stat(newPath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
return false;
}
current_directory = newPath;
return true;
}
// 实现mkdir命令
bool SDFileManager::mkdirCommand(const char* path) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return false;
}
std::string fullPath = path;
if (fullPath[0] != '/') {
// 相对路径
fullPath = current_directory + "/" + fullPath;
}
// 创建目录
int result = mkdir(fullPath.c_str(), 0777);
return result == 0;
}
// 实现rm命令
bool SDFileManager::rmCommand(const char* path, bool recursive) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return false;
}
std::string fullPath = path;
if (fullPath[0] != '/') {
// 相对路径
fullPath = current_directory + "/" + fullPath;
}
struct stat st;
if (stat(fullPath.c_str(), &st) != 0) {
return false;
}
if (S_ISDIR(st.st_mode)) {
if (recursive) {
return removeDirectoryRecursive(fullPath.c_str());
} else {
// 非递归删除空目录
return rmdir(fullPath.c_str()) == 0;
}
} else {
// 删除文件
return remove(fullPath.c_str()) == 0;
}
}
// 实现stat命令
std::string SDFileManager::statCommand(const char* path) {
std::lock_guard<std::mutex> lock(file_operation_mutex);
if (!is_initialized) {
ESP_LOGE("SDFileManager", "SD card not initialized");
return "Error: SD card not initialized";
}
std::string fullPath = path;
if (fullPath[0] != '/') {
// 相对路径
fullPath = current_directory + "/" + fullPath;
}
struct stat st;
if (stat(fullPath.c_str(), &st) != 0) {
return "Error: Cannot get file status for " + fullPath;
}
return getFileInfoString(fullPath.c_str(), &st);
}
// 辅助方法:递归删除目录
bool SDFileManager::removeDirectoryRecursive(const char* path) {
DIR* dir = opendir(path);
if (dir == nullptr) {
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
std::string entryPath = std::string(path) + "/" + entry->d_name;
struct stat st;
if (stat(entryPath.c_str(), &st) != 0) {
continue;
}
if (S_ISDIR(st.st_mode)) {
if (!removeDirectoryRecursive(entryPath.c_str())) {
closedir(dir);
return false;
}
} else {
if (remove(entryPath.c_str()) != 0) {
closedir(dir);
return false;
}
}
}
closedir(dir);
return rmdir(path) == 0;
}
// 辅助方法:获取文件信息字符串
std::string SDFileManager::getFileInfoString(const char* path, const struct stat* st) {
std::stringstream info;
// 文件类型和权限
info << getFileTypeString(st->st_mode);
info << ((st->st_mode & S_IRUSR) ? "r" : "-");
info << ((st->st_mode & S_IWUSR) ? "w" : "-");
info << ((st->st_mode & S_IXUSR) ? "x" : "-");
info << ((st->st_mode & S_IRGRP) ? "r" : "-");
info << ((st->st_mode & S_IWGRP) ? "w" : "-");
info << ((st->st_mode & S_IXGRP) ? "x" : "-");
info << ((st->st_mode & S_IROTH) ? "r" : "-");
info << ((st->st_mode & S_IWOTH) ? "w" : "-");
info << ((st->st_mode & S_IXOTH) ? "x" : "-");
// 文件大小
info << " " << std::setw(10) << formatFileSize(st->st_size);
// 最后修改时间
struct tm* timeinfo = localtime(&st->st_mtime);
char timeBuf[20];
strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M", timeinfo);
info << " " << timeBuf;
// 文件名
info << " " << path;
return info.str();
}
// 辅助方法:获取文件类型字符串
std::string SDFileManager::getFileTypeString(mode_t mode) {
if (S_ISREG(mode)) return "-"; // 普通文件
if (S_ISDIR(mode)) return "d"; // 目录
if (S_ISCHR(mode)) return "c"; // 字符设备
if (S_ISBLK(mode)) return "b"; // 块设备
if (S_ISFIFO(mode)) return "p"; // 管道
if (S_ISLNK(mode)) return "l"; // 符号链接
if (S_ISSOCK(mode)) return "s"; // 套接字
return "?"; // 未知类型
}
// 辅助方法:格式化文件大小
std::string SDFileManager::formatFileSize(size_t size) {
std::stringstream ss;
if (size < 1024) {
ss << size << " B";
} else if (size < 1024 * 1024) {
ss << std::fixed << std::setprecision(1) << (size / 1024.0) << " KB";
} else if (size < 1024 * 1024 * 1024) {
ss << std::fixed << std::setprecision(1) << (size / (1024.0 * 1024.0)) << " MB";
} else {
ss << std::fixed << std::setprecision(1) << (size / (1024.0 * 1024.0 * 1024.0)) << " GB";
}
return ss.str();
}
@@ -0,0 +1,178 @@
//
// Created by misaki on 2025/9/9.
//
/**
* 本模块用于管理SD卡文件
* 同样为单例类
* 支持异步读取和写入
*/
#pragma once
#include <mutex>
#include <functional>
#include <vector>
#include <string>
#include "ThreadManager.h"
#include "SD_MMC.h"
class SDFileManager {
public:
// 文件操作回调函数类型定义
using WriteCallback = std::function<void(bool success, const char* path)>;
using ReadCallback = std::function<void(bool success, const char* path, const std::string& content)>;
using ListCallback = std::function<void(bool success, const std::vector<std::string>& files)>;
using OpenCallback = std::function<void(bool success, FILE* file)>;
static SDFileManager* getInstance();
// 同步文件操作
/**
* 同步写入文件
* @param path 文件路径
* @param data 数据
* @return 是否成功
*/
bool writeFileSync(const char* path, const char* data);
/**
* 同步读取文件
* @param path 文件路径
* @return 文件内容
*/
std::string readFileSync(const char* path);
/**
* 同步列出目录下的文件
* @param directory 目录路径
* @param extension 文件扩展名
* @return 文件列表
*/
std::vector<std::string> listFilesSync(const char* directory, const char* extension = nullptr);
/**
* 同步打开文件
* @param path 文件路径
* @param mode 模式
* @return 文件指针
*/
FILE* openFileSync(const char* path, const char* mode = "rb");
/**
* 同步关闭文件
* @param file 文件指针
* @return 是否成功
*/
bool closeFileSync(FILE* file);
// 异步文件操作
/**
* 异步写入文件
* @param path 文件路径
* @param data 数据
* @param callback 回调函数
*/
void asyncWriteFile(const char* path, const char* data, WriteCallback callback = nullptr);
/**
* 异步读取文件
* @param path 文件路径
* @param callback 回调函数
*/
void asyncReadFile(const char* path, ReadCallback callback = nullptr);
/**
* 异步列出目录下的文件
* @param directory 目录路径
* @param extension 文件扩展名
* @param callback 回调函数
*/
void asyncListFiles(const char* directory, const char* extension, ListCallback callback = nullptr);
/**
* 异步打开文件
* @param path 文件路径
* @param mode 模式
* @param callback 回调函数
*/
void asyncOpenFile(const char* path, const char* mode, OpenCallback callback = nullptr);
/**
* 类似Linux的ls命令,列出目录内容
* @param path 目录路径
* @param recursive 是否递归列出子目录
* @param showDetails 是否显示详细信息(大小、类型等)
* @return 格式化后的目录列表字符串
*/
std::string lsCommand(const char* path, bool recursive = false, bool showDetails = false);
/**
* 类似Linux的cat命令,显示文件内容
* @param path 文件路径
* @param lineNumbers 是否显示行号
* @return 文件内容字符串
*/
std::string catCommand(const char* path, bool lineNumbers = false);
/**
* 类似Linux的pwd命令,获取当前工作目录
* @return 当前工作目录
*/
std::string pwdCommand();
/**
* 类似Linux的cd命令,改变当前工作目录
* @param path 目标目录路径
* @return 是否成功
*/
bool cdCommand(const char* path);
/**
* 类似Linux的mkdir命令,创建目录
* @param path 目录路径
* @return 是否成功
*/
bool mkdirCommand(const char* path);
/**
* 类似Linux的rm命令,删除文件或目录
* @param path 文件或目录路径
* @param recursive 是否递归删除目录
* @return 是否成功
*/
bool rmCommand(const char* path, bool recursive = false);
/**
* 类似Linux的stat命令,获取文件/目录信息
* @param path 文件或目录路径
* @return 文件信息字符串
*/
std::string statCommand(const char* path);
// 获取SD卡和Flash信息
uint32_t getSDCardSize() const { return SDCard_Size; }
uint32_t getFlashSize() const { return Flash_Size; }
private:
explicit SDFileManager(); // 私有构造函数,确保单例
~SDFileManager();
SDFileManager(SDFileManager const&) = delete; // 禁止拷贝构造
SDFileManager& operator=(SDFileManager const&) = delete; // 禁止赋值构造
// 初始化SD卡
void init();
// 辅助方法
std::string getFileInfoString(const char* path, const struct stat* st);
std::string getFileTypeString(mode_t mode);
std::string formatFileSize(size_t size);
bool removeDirectoryRecursive(const char* path);
// 线程配置
ThreadConfig getThreadConfig(const char* operation);
private:
static SDFileManager* SDFileInstance; // 单例实例
static std::mutex instance_mutex; // 实例互斥锁
std::mutex file_operation_mutex; // 文件操作互斥锁
bool is_initialized; // SD卡初始化状态
std::string current_directory; // 当前工作目录
};
@@ -124,9 +124,11 @@ public:
if (extra) {
ss << extra;
}
ss << "Core id: " << xPortGetCoreID()
<< ", prio: " << uxTaskPriorityGet(nullptr)
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
ss
<< ", 任务名: " << pcTaskGetName(nullptr)
<< "核心 id: " << xPortGetCoreID()
<< ", 优先级: " << uxTaskPriorityGet(nullptr)
<< ", 栈剩余空间: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
ESP_LOGI(pcTaskGetName(nullptr), "%s", ss.str().c_str());
}
@@ -68,7 +68,5 @@ bool WifiConnectors::isWifiConnect() {
void WifiConnectors::log() {
ESP_LOGI("WifiConnectors", "WifiConnectors log");
WIFI_Scan();
}
@@ -5,6 +5,8 @@
#include <string>
#include <mutex>
class WifiConnectors{
// 显然,Wifi连接必须是单例的,否则必然出现冲突