Files
HPPA/HPPA/TimedDataCollectionDataStructures.cpp
tangchao0503 f69edcf2c9 add,计划采集10:
解决偶发单反唤起失败问题;

任务文件要求:
1、高光谱必须在前面,没有顺序要求,因为在执行高光谱任务前会预热卤素灯,所有高光谱任务完成后才关闭卤素灯;
2、单反/深度必须在后面,没有顺序要求;
3、必须要有高光谱任务:单反存在唤醒程序和一定反应时间,所以必须依赖前一个任务进行唤醒;
 (1)当单反已经是唤醒状态时,重新上电(先下电后上电)后可马上重新唤醒单反:单反适配器剩余电量马上耗尽,所以才能马上重新唤醒单反;
 (2)当单反在上电的状态下,从唤醒状态自动进入休眠状态时,重新下电后需要等待2分15秒(135秒)后,再重新上电才能唤醒单反:等待135秒的目的是将适配器中电容的剩余电量耗尽;
2026-06-11 15:27:02 +08:00

606 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "TimedDataCollectionDataStructures.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QTextStream>
#include <QDebug>
// ==================== 公共接口实现 ====================
bool TimedDataCollectionDataStructuresReaderWriter::saveTasksToFile(const QString& filePath, const QVector<TimedTask>& tasks)
{
QJsonObject root;
root["version"] = "1.0";
root["taskCount"] = tasks.size();
QJsonArray tasksArray;
for (const auto& task : tasks) {
tasksArray.append(timedTaskToJson(task));
}
root["tasks"] = tasksArray;
QJsonDocument doc(root);
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Failed to open file for writing:" << filePath;
return false;
}
QTextStream out(&file);
//out.setEncoding(QStringConverter::Utf8);
out << doc.toJson(QJsonDocument::Indented);
file.close();
return true;
}
bool TimedDataCollectionDataStructuresReaderWriter::loadTasksFromFile(const QString& filePath, QVector<TimedTask>& tasks)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Failed to open file for reading:" << filePath;
return false;
}
QByteArray jsonData = file.readAll();
file.close();
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "JSON parse error:" << parseError.errorString();
return false;
}
if (!doc.isObject()) {
qWarning() << "Invalid JSON root object";
return false;
}
QJsonObject root = doc.object();
QJsonArray tasksArray = root["tasks"].toArray();
tasks.clear();
tasks.reserve(tasksArray.size());
for (const auto& taskValue : tasksArray) {
if (!taskValue.isObject()) continue;
TimedTask task;
if (jsonToTimedTask(taskValue.toObject(), task)) {
tasks.append(task);
}
}
return true;
}
// ==================== 枚举转换函数 ====================
QString TimedDataCollectionDataStructuresReaderWriter::taskStatusToString(TaskStatus status)
{
switch (status) {
case TaskStatus::Waiting: return "Waiting";
case TaskStatus::Running: return "Running";
case TaskStatus::Finished: return "Finished";
default: return "Waiting";
}
}
TaskStatus TimedDataCollectionDataStructuresReaderWriter::stringToTaskStatus(const QString& str)
{
if (str == "Running") return TaskStatus::Running;
if (str == "Finished") return TaskStatus::Finished;
return TaskStatus::Waiting;
}
QString TimedDataCollectionDataStructuresReaderWriter::subTaskTypeToString(SubTaskType type)
{
switch (type) {
case SubTaskType::HyperSpectual400_1000nm: return "HyperSpectual400_1000nm";
case SubTaskType::HyperSpectual1000_1700nm: return "HyperSpectual1000_1700nm";
case SubTaskType::SingleLensReflex: return "SingleLensReflex";
case SubTaskType::DepthCamera: return "DepthCamera";
default: return "Unknown";
}
}
SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(const QString& str)
{
if (str == "HyperSpectual400_1000nm") return SubTaskType::HyperSpectual400_1000nm;
if (str == "HyperSpectual1000_1700nm") return SubTaskType::HyperSpectual1000_1700nm;
if (str == "SingleLensReflex") return SubTaskType::SingleLensReflex;
if (str == "DepthCamera") return SubTaskType::DepthCamera;
return SubTaskType::SingleLensReflex;
}
// ==================== SubTask序列化 ====================
QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const SubTask& subTask)
{
QJsonObject obj;
obj["type"] = subTaskTypeToString(subTask.type);
obj["startTime"] = subTask.startTime.toString(Qt::ISODate);
obj["endTime"] = subTask.endTime.toString(Qt::ISODate);
obj["durationSeconds"] = subTask.durationSeconds;
obj["estimatedDurationSeconds"] = subTask.estimatedDurationSeconds;
obj["pathLineFilePath"] = subTask.pathLineFilePath;
obj["status"] = taskStatusToString(subTask.status);
obj["frameRate"] = subTask.frameRate;
obj["exposureTime"] = subTask.exposureTime;
obj["defaultRenderBand"] = subTask.defaultRenderBand;
obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds;
return obj;
}
bool TimedDataCollectionDataStructuresReaderWriter::jsonToSubTask(const QJsonObject& json, SubTask& subTask)
{
subTask.type = stringToSubTaskType(json["type"].toString());
subTask.startTime = QDateTime::fromString(json["startTime"].toString(), Qt::ISODate);
subTask.endTime = QDateTime::fromString(json["endTime"].toString(), Qt::ISODate);
subTask.durationSeconds = json["durationSeconds"].toInt();
subTask.estimatedDurationSeconds = json["estimatedDurationSeconds"].toInt();
subTask.pathLineFilePath = json["pathLineFilePath"].toString();
subTask.status = stringToTaskStatus(json["status"].toString());
subTask.frameRate = json["frameRate"].toDouble();
subTask.exposureTime = json["exposureTime"].toDouble();
subTask.defaultRenderBand = json["defaultRenderBand"].toInt();
subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toInt();
return true;
}
// ==================== TimedTask序列化 ====================
QJsonObject TimedDataCollectionDataStructuresReaderWriter::timedTaskToJson(const TimedTask& task)
{
QJsonObject obj;
obj["id"] = task.id;
obj["scheduledTime"] = task.scheduledTime.toString(Qt::ISODate);
obj["startTime"] = task.startTime.toString(Qt::ISODate);
obj["endTime"] = task.endTime.toString(Qt::ISODate);
obj["durationSeconds"] = task.durationSeconds;
obj["savePath"] = task.savePath;
obj["status"] = taskStatusToString(task.status);
obj["HalogenLampPreheatingTime_Minute"] = task.HalogenLampPreheatingTime_Minute;
QJsonArray subTasksArray;
for (const auto& subTask : task.subTasks) {
subTasksArray.append(subTaskToJson(subTask));
}
obj["subTasks"] = subTasksArray;
return obj;
}
bool TimedDataCollectionDataStructuresReaderWriter::jsonToTimedTask(const QJsonObject& json, TimedTask& task)
{
task.id = json["id"].toInt();
task.scheduledTime = QDateTime::fromString(json["scheduledTime"].toString(), Qt::ISODate);
task.startTime = QDateTime::fromString(json["startTime"].toString(), Qt::ISODate);
task.endTime = QDateTime::fromString(json["endTime"].toString(), Qt::ISODate);
task.durationSeconds = json["durationSeconds"].toInt();
task.savePath = json["savePath"].toString();
task.status = stringToTaskStatus(json["status"].toString());
task.HalogenLampPreheatingTime_Minute = json["HalogenLampPreheatingTime_Minute"].toDouble();
QJsonArray subTasksArray = json["subTasks"].toArray();
task.subTasks.clear();
task.subTasks.reserve(subTasksArray.size());
for (const auto& subTaskValue : subTasksArray) {
if (!subTaskValue.isObject()) continue;
SubTask subTask;
if (jsonToSubTask(subTaskValue.toObject(), subTask)) {
task.subTasks.append(subTask);
}
}
return true;
}
// ==================== TaskExecutor 实现 ====================
TaskExecutor::TaskExecutor(QObject* parent)
: QObject(parent)
, m_currentSubTaskIndex(0)
, m_isRunning(false)
{
}
TaskExecutor::~TaskExecutor()
{
stop();
}
void TaskExecutor::execute(const TimedTask& task)
{
if (m_isRunning) {
qWarning() << "TaskExecutor: Already running, ignoring execute request";
return;
}
m_task = task;
m_currentSubTaskIndex = 0;
m_isRunning = true;
qDebug() << "TaskExecutor: Starting task" << task.id;
// 打开卤素灯预热
emit switchHalogenLampSignal(1);
printMsgAndTime("open HalogenLamp");
makeFolder(m_task.savePath);
// 开始执行第一个子任务
double sleepTimeSecond = m_task.HalogenLampPreheatingTime_Minute * 60;
QTimer::singleShot(sleepTimeSecond *1000, this, &TaskExecutor::executeNextSubTask);
}
void TaskExecutor::printMsgAndTime(QString msg)
{
QDateTime now = QDateTime::currentDateTime();
QString timeString = now.toString("yyyy-MM-dd hh:mm:ss.zzz");
qDebug() << msg + " time:" << timeString;
}
void TaskExecutor::stop()
{
if (!m_isRunning) return;
qDebug() << "TaskExecutor: Stopping task" << m_task.id;
m_isRunning = false;
emit finished(false);
}
void TaskExecutor::makeFolder(QString savePath)
{
QDir dir(savePath);
if (!dir.exists()) {
if (dir.mkpath(".")) {
qDebug() << "TaskExecutor: Created data folder:" << savePath;
} else {
qWarning() << "TaskExecutor: Failed to create data folder:" << savePath;
}
} else {
qDebug() << "TaskExecutor: Data folder already exists:" << savePath;
}
}
QString TaskExecutor::makeSubTaskDataFolder(QString suffix)
{
QString dateStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");
QString folderPath = m_task.savePath + QDir::separator() + dateStr + "_" + suffix;
makeFolder(folderPath);
return folderPath;
}
void TaskExecutor::onSequenceComplete(int status)
{
if (!m_isRunning) return;
qDebug() << "TaskExecutor: Sequence complete, status:" << status;
// 更新当前子任务状态
if (m_currentSubTaskIndex < m_task.subTasks.size()) {
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
subTask.status = (status == 0) ? TaskStatus::Finished : TaskStatus::Waiting;
emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0));
}
//
switch (m_task.subTasks[m_currentSubTaskIndex].type)
{
case SubTaskType::SingleLensReflex:
{
emit switchD65LampSignal(0);
emit switchSlrSignal(0);
break;
}
case SubTaskType::DepthCamera:
{
emit switchD65LampSignal(0);
break;
}
}
// 判断下一次的任务是否为高光谱任务,如果不是关闭卤素灯
int nestSubTaskIndex = m_currentSubTaskIndex + 1;
if (nestSubTaskIndex >= m_task.subTasks.size())
{
emit switchHalogenLampSignal(0);
return;
}
switch (m_task.subTasks[nestSubTaskIndex].type)
{
case SubTaskType::SingleLensReflex:
{
emit switchHalogenLampSignal(0);
break;
}
case SubTaskType::DepthCamera:
{
emit switchHalogenLampSignal(0);
break;
}
}
}
void TaskExecutor::onBack2Origin()
{
// 检查是否还有更多子任务
m_currentSubTaskIndex++;
if (m_currentSubTaskIndex < m_task.subTasks.size()) {
// 执行下一个子任务
if(m_task.subTasks[m_currentSubTaskIndex].type== SubTaskType::SingleLensReflex)
{
printMsgAndTime("Slr taskfor weak upplease wait 135 seconds!");
emit switchSlrSignal(0);
QTimer::singleShot(135*1000, this, &TaskExecutor::executeNextSubTask);
}
else
{
QTimer::singleShot(1000, this, &TaskExecutor::executeNextSubTask);
}
}
else {
// 所有子任务完成
m_isRunning = false;
qDebug() << "TaskExecutor: All subtasks completed";
emit finished(true);
}
}
void TaskExecutor::onError(const QString& error)
{
if (!m_isRunning) return;
qWarning() << "TaskExecutor: Error occurred:" << error;
m_isRunning = false;
emit errorOccurred(error);
emit finished(false);
}
void TaskExecutor::executeNextSubTask()
{
if (!m_isRunning || m_currentSubTaskIndex >= m_task.subTasks.size()) {
return;
}
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
subTask.status = TaskStatus::Running;
subTask.startTime = QDateTime::currentDateTime();
QString tmp = "TaskExecutor: Starting subtask" + QString::number(m_currentSubTaskIndex) + "type:" + static_cast<int>(subTask.type);
printMsgAndTime(tmp);
//printMsgAndTime("excute " + QString::number(m_currentSubTaskIndex) + " subTask: ");
//qDebug() << "TaskExecutor: Starting subtask" << m_currentSubTaskIndex
// << "type:" << static_cast<int>(subTask.type);
emit subTaskStarted(m_currentSubTaskIndex, subTask.type);
emit motorParm(subTask.pathLineFilePath);
int camType;
switch (subTask.type)
{
case SubTaskType::HyperSpectual400_1000nm:
{
camType = 0;
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, makeSubTaskDataFolder("L"), "test");
break;
}
case SubTaskType::HyperSpectual1000_1700nm:
{
camType = 1;
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, makeSubTaskDataFolder("NIR"), "test");
break;
}
case SubTaskType::SingleLensReflex:
{
camType = 2;
emit camParm(camType, 3, makeSubTaskDataFolder("SLR"));
emit switchD65LampSignal(1);
emit switchSlrSignal(1);
break;
}
case SubTaskType::DepthCamera:
{
camType = 3;
emit camParm(camType, 3, makeSubTaskDataFolder("DepthCamera"));
emit switchD65LampSignal(1);
break;
}
}
emit startRecordSignal(camType);
}
// ==================== TaskScheduler 实现 ====================
TaskScheduler::TaskScheduler(QObject* parent)
: QObject(parent)
, m_timer(nullptr)
, m_currentExecutor(nullptr)
, m_currentTaskId(-1)
{
}
TaskScheduler::~TaskScheduler()
{
stop();
}
void TaskScheduler::loadTasks(const QVector<TimedTask>& tasks)
{
m_tasks = tasks;
qDebug() << "TaskScheduler: Loaded" << tasks.size() << "tasks";
}
void TaskScheduler::start()
{
if (m_timer) {
qDebug() << "TaskScheduler: Already running";
return;
}
qDebug() << "TaskScheduler: Starting";
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &TaskScheduler::checkTasks);
m_timer->start(1000); // 每秒检查一次
emit schedulerStateChanged(true);
}
void TaskScheduler::stop()
{
if (m_timer) {
m_timer->stop();
delete m_timer;
m_timer = nullptr;
}
if (m_currentExecutor) {
m_currentExecutor->stop();
m_currentExecutor->deleteLater();
m_currentExecutor = nullptr;
}
qDebug() << "TaskScheduler: Stopped";
emit schedulerStateChanged(false);
}
void TaskScheduler::checkTasks()
{
QDateTime now = QDateTime::currentDateTime();
for (auto& task : m_tasks) {
if (task.status != TaskStatus::Waiting) continue;
// 超过计划时间1分钟以上认为任务已过时跳过
if (task.scheduledTime.addSecs(60) < now) {
std::cerr << "TaskScheduler::checkTasks任务已过时跳过:" << task.id << std::endl;
task.status = TaskStatus::Finished;
continue;
}
if (task.scheduledTime > now) continue;
// 到达计划时间,启动任务
std::cerr << "TaskScheduler::checkTasks到达计划时间启动任务" << std::endl;
executeTask(task);
break; // 一次只执行一个任务
}
}
void TaskScheduler::onTaskFinished(bool success)
{
if (m_currentTaskId > 0) {
TaskStatus status = success ? TaskStatus::Finished : TaskStatus::Waiting;
updateTaskStatus(m_currentTaskId, status);
emit taskFinished(m_currentTaskId, success);
}
// 清理执行器
if (m_currentExecutor) {
m_currentExecutor->deleteLater();
m_currentExecutor = nullptr;
}
m_currentTaskId = -1;
}
void TaskScheduler::onSubTaskStarted(int subTaskIndex, SubTaskType type)
{
if (m_currentTaskId > 0) {
emit subTaskStarted(m_currentTaskId, subTaskIndex);
}
}
void TaskScheduler::onSubTaskFinished(int subTaskIndex, SubTaskType type, bool success)
{
if (m_currentTaskId > 0) {
emit subTaskFinished(m_currentTaskId, subTaskIndex);
}
}
void TaskScheduler::onExecutorError(const QString& error)
{
emitError(error);
}
void TaskScheduler::executeTask(TimedTask& task)
{
qDebug() << "TaskScheduler: Executing task" << task.id;
updateTaskStatus(task.id, TaskStatus::Running);
m_currentTaskId = task.id;
emit taskStarted(task.id);
// 创建任务执行器
m_currentExecutor = new TaskExecutor(this);
// 连接信号
connect(m_currentExecutor, &TaskExecutor::finished,
this, &TaskScheduler::onTaskFinished);
connect(m_currentExecutor, &TaskExecutor::subTaskStarted,
this, &TaskScheduler::onSubTaskStarted);
connect(m_currentExecutor, &TaskExecutor::subTaskFinished,
this, &TaskScheduler::onSubTaskFinished);
connect(m_currentExecutor, &TaskExecutor::errorOccurred,
this, &TaskScheduler::onExecutorError);
// 采集相关信号透传
connect(m_currentExecutor, &TaskExecutor::hyperCamParm,
this, &TaskScheduler::hyperCamParm);
connect(m_currentExecutor, &TaskExecutor::camParm,
this, &TaskScheduler::camParm);
connect(m_currentExecutor, &TaskExecutor::motorParm,
this, &TaskScheduler::motorParm);
connect(m_currentExecutor, &TaskExecutor::startRecordSignal,
this, &TaskScheduler::startRecordSignal);
connect(m_currentExecutor, &TaskExecutor::switchHalogenLampSignal, this, &TaskScheduler::switchHalogenLampSignal);
connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal);
connect(m_currentExecutor, &TaskExecutor::switchSlrSignal, this, &TaskScheduler::switchSlrSignal);
connect(this, &TaskScheduler::sequenceCompleteSignal, m_currentExecutor, &TaskExecutor::onSequenceComplete);
connect(this, &TaskScheduler::Back2OriginSignal, m_currentExecutor, &TaskExecutor::onBack2Origin);
// 开始执行
m_currentExecutor->execute(task);
}
void TaskScheduler::updateTaskStatus(int taskId, TaskStatus status)
{
for (auto& task : m_tasks) {
if (task.id == taskId) {
task.status = status;
if (status == TaskStatus::Running) {
task.startTime = QDateTime::currentDateTime();
} else if (status == TaskStatus::Finished) {
task.endTime = QDateTime::currentDateTime();
}
break;
}
}
}
void TaskScheduler::emitError(const QString& error)
{
qWarning() << "TaskScheduler: Error:" << error;
emit errorOccurred(error);
}