Update to 2.0.1
This commit is contained in:
559
main/timer_manager.cc
Normal file
559
main/timer_manager.cc
Normal file
@@ -0,0 +1,559 @@
|
||||
#include "timer_manager.h"
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
const char* TimerManager::TAG = "TimerManager";
|
||||
|
||||
TimerManager::TimerManager() : is_running_(false) {
|
||||
ESP_LOGI(TAG, "TimerManager initialized");
|
||||
}
|
||||
|
||||
TimerManager::~TimerManager() {
|
||||
StopManager();
|
||||
ESP_LOGI(TAG, "TimerManager destroyed");
|
||||
}
|
||||
|
||||
std::string TimerManager::CreateCountdownTimer(const std::string& name,
|
||||
uint32_t duration_ms,
|
||||
const std::string& description) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
TimerTask task;
|
||||
task.id = GenerateTaskId();
|
||||
task.name = name;
|
||||
task.type = TimerType::COUNTDOWN;
|
||||
task.status = TimerStatus::PENDING;
|
||||
task.duration_ms = duration_ms;
|
||||
task.description = description;
|
||||
task.created_time = time(nullptr);
|
||||
|
||||
tasks_[task.id] = task;
|
||||
|
||||
ESP_LOGI(TAG, "Created countdown timer: %s (ID: %s, Duration: %u ms)",
|
||||
name.c_str(), task.id.c_str(), duration_ms);
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
std::string TimerManager::CreateDelayedMcpTask(const std::string& name,
|
||||
uint32_t delay_ms,
|
||||
const std::string& mcp_tool_name,
|
||||
const std::string& mcp_tool_args,
|
||||
const std::string& description) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
TimerTask task;
|
||||
task.id = GenerateTaskId();
|
||||
task.name = name;
|
||||
task.type = TimerType::DELAYED_EXEC;
|
||||
task.status = TimerStatus::PENDING;
|
||||
task.duration_ms = delay_ms;
|
||||
task.mcp_tool_name = mcp_tool_name;
|
||||
task.mcp_tool_args = mcp_tool_args;
|
||||
task.description = description;
|
||||
task.created_time = time(nullptr);
|
||||
|
||||
tasks_[task.id] = task;
|
||||
|
||||
ESP_LOGI(TAG, "Created delayed MCP task: %s (ID: %s, Delay: %u ms, Tool: %s)",
|
||||
name.c_str(), task.id.c_str(), delay_ms, mcp_tool_name.c_str());
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
std::string TimerManager::CreatePeriodicTask(const std::string& name,
|
||||
uint32_t interval_ms,
|
||||
int repeat_count,
|
||||
const std::string& mcp_tool_name,
|
||||
const std::string& mcp_tool_args,
|
||||
const std::string& description) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
TimerTask task;
|
||||
task.id = GenerateTaskId();
|
||||
task.name = name;
|
||||
task.type = TimerType::PERIODIC;
|
||||
task.status = TimerStatus::PENDING;
|
||||
task.interval_ms = interval_ms;
|
||||
task.repeat_count = repeat_count;
|
||||
task.current_repeat = 0;
|
||||
task.mcp_tool_name = mcp_tool_name;
|
||||
task.mcp_tool_args = mcp_tool_args;
|
||||
task.description = description;
|
||||
task.created_time = time(nullptr);
|
||||
|
||||
tasks_[task.id] = task;
|
||||
|
||||
ESP_LOGI(TAG, "Created periodic task: %s (ID: %s, Interval: %u ms, Repeat: %d)",
|
||||
name.c_str(), task.id.c_str(), interval_ms, repeat_count);
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
std::string TimerManager::CreateScheduledTask(const std::string& name,
|
||||
time_t scheduled_time,
|
||||
const std::string& mcp_tool_name,
|
||||
const std::string& mcp_tool_args,
|
||||
const std::string& description) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
TimerTask task;
|
||||
task.id = GenerateTaskId();
|
||||
task.name = name;
|
||||
task.type = TimerType::SCHEDULED;
|
||||
task.status = TimerStatus::PENDING;
|
||||
task.scheduled_time = scheduled_time;
|
||||
task.mcp_tool_name = mcp_tool_name;
|
||||
task.mcp_tool_args = mcp_tool_args;
|
||||
task.description = description;
|
||||
task.created_time = time(nullptr);
|
||||
|
||||
tasks_[task.id] = task;
|
||||
|
||||
ESP_LOGI(TAG, "Created scheduled task: %s (ID: %s, Time: %ld)",
|
||||
name.c_str(), task.id.c_str(), scheduled_time);
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
bool TimerManager::StartTask(const std::string& task_id) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
auto it = tasks_.find(task_id);
|
||||
if (it == tasks_.end()) {
|
||||
ESP_LOGE(TAG, "Task not found: %s", task_id.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
TimerTask& task = it->second;
|
||||
|
||||
if (task.status != TimerStatus::PENDING) {
|
||||
ESP_LOGW(TAG, "Task %s is not in pending status", task_id.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 创建FreeRTOS定时器
|
||||
TimerHandle_t timer_handle = xTimerCreate(
|
||||
task.name.c_str(),
|
||||
pdMS_TO_TICKS(task.duration_ms),
|
||||
(task.type == TimerType::PERIODIC) ? pdTRUE : pdFALSE,
|
||||
(void*)task_id.c_str(),
|
||||
TimerCallback
|
||||
);
|
||||
|
||||
if (timer_handle == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create timer for task: %s", task_id.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
timers_[task_id] = timer_handle;
|
||||
task.status = TimerStatus::RUNNING;
|
||||
task.start_time = time(nullptr);
|
||||
|
||||
if (xTimerStart(timer_handle, 0) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Failed to start timer for task: %s", task_id.c_str());
|
||||
xTimerDelete(timer_handle, 0);
|
||||
timers_.erase(task_id);
|
||||
task.status = TimerStatus::FAILED;
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Started task: %s", task_id.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimerManager::StopTask(const std::string& task_id) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
auto it = tasks_.find(task_id);
|
||||
if (it == tasks_.end()) {
|
||||
ESP_LOGE(TAG, "Task not found: %s", task_id.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
TimerTask& task = it->second;
|
||||
|
||||
if (task.status != TimerStatus::RUNNING) {
|
||||
ESP_LOGW(TAG, "Task %s is not running", task_id.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto timer_it = timers_.find(task_id);
|
||||
if (timer_it != timers_.end()) {
|
||||
xTimerStop(timer_it->second, 0);
|
||||
xTimerDelete(timer_it->second, 0);
|
||||
timers_.erase(timer_it);
|
||||
}
|
||||
|
||||
task.status = TimerStatus::CANCELLED;
|
||||
task.end_time = time(nullptr);
|
||||
|
||||
ESP_LOGI(TAG, "Stopped task: %s", task_id.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimerManager::CancelTask(const std::string& task_id) {
|
||||
return StopTask(task_id);
|
||||
}
|
||||
|
||||
bool TimerManager::DeleteTask(const std::string& task_id) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
// 先停止任务
|
||||
StopTask(task_id);
|
||||
|
||||
auto it = tasks_.find(task_id);
|
||||
if (it == tasks_.end()) {
|
||||
ESP_LOGE(TAG, "Task not found: %s", task_id.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
tasks_.erase(it);
|
||||
ESP_LOGI(TAG, "Deleted task: %s", task_id.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
TimerTask* TimerManager::GetTask(const std::string& task_id) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
auto it = tasks_.find(task_id);
|
||||
if (it == tasks_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
std::vector<TimerTask> TimerManager::GetAllTasks() {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
std::vector<TimerTask> result;
|
||||
|
||||
for (const auto& pair : tasks_) {
|
||||
result.push_back(pair.second);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TimerTask> TimerManager::GetTasksByStatus(TimerStatus status) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
std::vector<TimerTask> result;
|
||||
|
||||
for (const auto& pair : tasks_) {
|
||||
if (pair.second.status == status) {
|
||||
result.push_back(pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TimerTask> TimerManager::GetRunningTasks() {
|
||||
return GetTasksByStatus(TimerStatus::RUNNING);
|
||||
}
|
||||
|
||||
std::vector<TimerTask> TimerManager::GetUpcomingTasks(int minutes) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
std::vector<TimerTask> result;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
time_t future_time = now + (minutes * 60);
|
||||
|
||||
for (const auto& pair : tasks_) {
|
||||
const TimerTask& task = pair.second;
|
||||
if (task.status == TimerStatus::PENDING &&
|
||||
task.scheduled_time >= now &&
|
||||
task.scheduled_time <= future_time) {
|
||||
result.push_back(task);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int TimerManager::GetTaskCount() {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
return tasks_.size();
|
||||
}
|
||||
|
||||
int TimerManager::GetTaskCountByStatus(TimerStatus status) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
int count = 0;
|
||||
|
||||
for (const auto& pair : tasks_) {
|
||||
if (pair.second.status == status) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int TimerManager::GetTaskCountByType(TimerType type) {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
int count = 0;
|
||||
|
||||
for (const auto& pair : tasks_) {
|
||||
if (pair.second.type == type) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void TimerManager::StartManager() {
|
||||
if (is_running_) {
|
||||
ESP_LOGW(TAG, "TimerManager is already running");
|
||||
return;
|
||||
}
|
||||
|
||||
is_running_ = true;
|
||||
worker_thread_ = std::thread(&TimerManager::TaskWorker, this);
|
||||
|
||||
ESP_LOGI(TAG, "TimerManager started");
|
||||
}
|
||||
|
||||
void TimerManager::StopManager() {
|
||||
if (!is_running_) {
|
||||
return;
|
||||
}
|
||||
|
||||
is_running_ = false;
|
||||
|
||||
if (worker_thread_.joinable()) {
|
||||
worker_thread_.join();
|
||||
}
|
||||
|
||||
// 停止所有定时器
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
for (auto& pair : timers_) {
|
||||
xTimerStop(pair.second, 0);
|
||||
xTimerDelete(pair.second, 0);
|
||||
}
|
||||
timers_.clear();
|
||||
|
||||
ESP_LOGI(TAG, "TimerManager stopped");
|
||||
}
|
||||
|
||||
bool TimerManager::IsRunning() {
|
||||
return is_running_;
|
||||
}
|
||||
|
||||
void TimerManager::SetTaskCompletedCallback(std::function<void(const TimerTask&)> callback) {
|
||||
task_completed_callback_ = callback;
|
||||
}
|
||||
|
||||
void TimerManager::SetTaskFailedCallback(std::function<void(const TimerTask&, const std::string&)> callback) {
|
||||
task_failed_callback_ = callback;
|
||||
}
|
||||
|
||||
bool TimerManager::SaveToStorage() {
|
||||
// TODO: 实现数据持久化到NVS或SPIFFS
|
||||
ESP_LOGW(TAG, "SaveToStorage not implemented yet");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimerManager::LoadFromStorage() {
|
||||
// TODO: 实现从NVS或SPIFFS加载数据
|
||||
ESP_LOGW(TAG, "LoadFromStorage not implemented yet");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string TimerManager::ExportToJson() {
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
|
||||
std::stringstream json;
|
||||
json << "{\"tasks\":[";
|
||||
|
||||
bool first = true;
|
||||
for (const auto& pair : tasks_) {
|
||||
if (!first) json << ",";
|
||||
first = false;
|
||||
|
||||
const TimerTask& task = pair.second;
|
||||
json << "{"
|
||||
<< "\"id\":\"" << task.id << "\","
|
||||
<< "\"name\":\"" << task.name << "\","
|
||||
<< "\"description\":\"" << task.description << "\","
|
||||
<< "\"duration_ms\":" << task.duration_ms << ","
|
||||
<< "\"interval_ms\":" << task.interval_ms << ","
|
||||
<< "\"repeat_count\":" << task.repeat_count << ","
|
||||
<< "\"current_repeat\":" << task.current_repeat << ","
|
||||
<< "\"created_time\":" << task.created_time << ","
|
||||
<< "\"start_time\":" << task.start_time << ","
|
||||
<< "\"end_time\":" << task.end_time << ","
|
||||
<< "\"scheduled_time\":" << task.scheduled_time << ","
|
||||
<< "\"mcp_tool_name\":\"" << task.mcp_tool_name << "\","
|
||||
<< "\"mcp_tool_args\":\"" << task.mcp_tool_args << "\","
|
||||
<< "\"user_data\":\"" << task.user_data << "\",";
|
||||
|
||||
std::string status_str;
|
||||
switch (task.status) {
|
||||
case TimerStatus::PENDING: status_str = "pending"; break;
|
||||
case TimerStatus::RUNNING: status_str = "running"; break;
|
||||
case TimerStatus::COMPLETED: status_str = "completed"; break;
|
||||
case TimerStatus::CANCELLED: status_str = "cancelled"; break;
|
||||
case TimerStatus::FAILED: status_str = "failed"; break;
|
||||
}
|
||||
json << "\"status\":\"" << status_str << "\",";
|
||||
|
||||
std::string type_str;
|
||||
switch (task.type) {
|
||||
case TimerType::COUNTDOWN: type_str = "countdown"; break;
|
||||
case TimerType::DELAYED_EXEC: type_str = "delayed_exec"; break;
|
||||
case TimerType::PERIODIC: type_str = "periodic"; break;
|
||||
case TimerType::SCHEDULED: type_str = "scheduled"; break;
|
||||
}
|
||||
json << "\"type\":\"" << type_str << "\"";
|
||||
|
||||
json << "}";
|
||||
}
|
||||
|
||||
json << "]}";
|
||||
return json.str();
|
||||
}
|
||||
|
||||
std::string TimerManager::GenerateTaskId() {
|
||||
static int counter = 0;
|
||||
return "task_" + std::to_string(++counter) + "_" + std::to_string(time(nullptr));
|
||||
}
|
||||
|
||||
void TimerManager::TaskWorker() {
|
||||
ESP_LOGI(TAG, "Task worker thread started");
|
||||
|
||||
while (is_running_) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// 检查定时任务
|
||||
std::lock_guard<std::mutex> lock(tasks_mutex_);
|
||||
time_t now = time(nullptr);
|
||||
|
||||
for (auto& pair : tasks_) {
|
||||
TimerTask& task = pair.second;
|
||||
|
||||
if (task.status == TimerStatus::PENDING &&
|
||||
task.type == TimerType::SCHEDULED &&
|
||||
now >= task.scheduled_time) {
|
||||
|
||||
ESP_LOGI(TAG, "Executing scheduled task: %s", task.id.c_str());
|
||||
ExecuteTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Task worker thread stopped");
|
||||
}
|
||||
|
||||
void TimerManager::ExecuteTask(TimerTask& task) {
|
||||
task.status = TimerStatus::RUNNING;
|
||||
task.start_time = time(nullptr);
|
||||
|
||||
bool success = true;
|
||||
std::string error_msg;
|
||||
|
||||
try {
|
||||
if (!task.mcp_tool_name.empty()) {
|
||||
success = ExecuteMcpTool(task.mcp_tool_name, task.mcp_tool_args);
|
||||
if (!success) {
|
||||
error_msg = "MCP tool execution failed";
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
success = false;
|
||||
error_msg = e.what();
|
||||
} catch (...) {
|
||||
success = false;
|
||||
error_msg = "Unknown error occurred";
|
||||
}
|
||||
|
||||
task.end_time = time(nullptr);
|
||||
|
||||
if (success) {
|
||||
if (task.type == TimerType::PERIODIC) {
|
||||
task.current_repeat++;
|
||||
if (task.repeat_count == -1 || task.current_repeat < task.repeat_count) {
|
||||
// 继续下一次重复
|
||||
task.status = TimerStatus::PENDING;
|
||||
ESP_LOGI(TAG, "Periodic task %s completed repeat %d/%d",
|
||||
task.id.c_str(), task.current_repeat, task.repeat_count);
|
||||
} else {
|
||||
// 所有重复完成
|
||||
task.status = TimerStatus::COMPLETED;
|
||||
ESP_LOGI(TAG, "Periodic task %s completed all repeats", task.id.c_str());
|
||||
NotifyTaskCompleted(task);
|
||||
}
|
||||
} else {
|
||||
task.status = TimerStatus::COMPLETED;
|
||||
ESP_LOGI(TAG, "Task %s completed successfully", task.id.c_str());
|
||||
NotifyTaskCompleted(task);
|
||||
}
|
||||
} else {
|
||||
task.status = TimerStatus::FAILED;
|
||||
ESP_LOGE(TAG, "Task %s failed: %s", task.id.c_str(), error_msg.c_str());
|
||||
NotifyTaskFailed(task, error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
bool TimerManager::ExecuteMcpTool(const std::string& tool_name, const std::string& args) {
|
||||
// TODO: 实现MCP工具执行
|
||||
ESP_LOGW(TAG, "ExecuteMcpTool not implemented yet: %s with args: %s",
|
||||
tool_name.c_str(), args.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimerManager::UpdateTaskStatus(TimerTask& task, TimerStatus status) {
|
||||
task.status = status;
|
||||
if (status == TimerStatus::RUNNING) {
|
||||
task.start_time = time(nullptr);
|
||||
} else if (status == TimerStatus::COMPLETED || status == TimerStatus::FAILED) {
|
||||
task.end_time = time(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerManager::NotifyTaskCompleted(const TimerTask& task) {
|
||||
if (task_completed_callback_) {
|
||||
task_completed_callback_(task);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerManager::NotifyTaskFailed(const TimerTask& task, const std::string& error) {
|
||||
if (task_failed_callback_) {
|
||||
task_failed_callback_(task, error);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerManager::TimerCallback(TimerHandle_t timer_handle) {
|
||||
const char* task_id = (const char*)pvTimerGetTimerID(timer_handle);
|
||||
|
||||
ESP_LOGI(TAG, "Timer callback triggered for task: %s", task_id);
|
||||
|
||||
// 获取任务管理器实例
|
||||
TimerManager& manager = TimerManager::GetInstance();
|
||||
|
||||
std::lock_guard<std::mutex> lock(manager.tasks_mutex_);
|
||||
|
||||
auto it = manager.tasks_.find(task_id);
|
||||
if (it != manager.tasks_.end()) {
|
||||
TimerTask& task = it->second;
|
||||
|
||||
if (task.type == TimerType::COUNTDOWN) {
|
||||
// 倒计时完成
|
||||
task.status = TimerStatus::COMPLETED;
|
||||
task.end_time = time(nullptr);
|
||||
ESP_LOGI(TAG, "Countdown timer %s completed", task_id);
|
||||
manager.NotifyTaskCompleted(task);
|
||||
} else if (task.type == TimerType::DELAYED_EXEC) {
|
||||
// 延时执行MCP工具
|
||||
manager.ExecuteTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除一次性定时器
|
||||
if (xTimerIsTimerActive(timer_handle) == pdFALSE) {
|
||||
xTimerDelete(timer_handle, 0);
|
||||
manager.timers_.erase(task_id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user