GrabBag/BeltTearingServer/BeltTearingPresenter.cpp

483 lines
16 KiB
C++
Raw Normal View History

#include "BeltTearingPresenter.h"
2025-09-10 00:31:27 +08:00
#include "PathManager.h"
#include "version.h"
#include <QUuid>
#include <QDataStream>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDateTime>
#include <iostream>
2025-09-10 00:31:27 +08:00
#include "VrLog.h"
BeltTearingPresenter::BeltTearingPresenter(QObject *parent)
: QObject(parent)
, m_tcpServer(new QTcpServer(this))
2025-09-10 00:31:27 +08:00
, m_cameraInitTimer(new QTimer(this))
, m_port(0)
2025-09-10 00:31:27 +08:00
, m_config(nullptr)
, m_eyeDevice(nullptr)
, m_beltTearingAlgo(new BeltTearingAlgo())
, m_cameraInitialized(false)
, m_cameraDetecting(false)
{
2025-09-10 00:31:27 +08:00
// 打印版本信息
LOG_INFO("Initializing %s %s\n", getProductName().toStdString().c_str(), getVersionString().toStdString().c_str());
LOG_INFO("Build: %s\n", getBuildInfo().toStdString().c_str());
// 连接信号槽
connect(m_tcpServer, &QTcpServer::newConnection, this, &BeltTearingPresenter::onNewConnection);
2025-09-10 00:31:27 +08:00
connect(m_cameraInitTimer, &QTimer::timeout, this, &BeltTearingPresenter::onCameraInitTimer);
// 创建配置实例
IVrBeltTearingConfig::CreateInstance(&m_config);
if (m_config) {
m_config->SetConfigChangeNotify(this);
}
// 初始化相机
initializeCamera();
}
BeltTearingPresenter::~BeltTearingPresenter()
{
stopServer();
2025-09-10 00:31:27 +08:00
stopCamera();
if (m_beltTearingAlgo) {
delete m_beltTearingAlgo;
m_beltTearingAlgo = nullptr;
}
if (m_config) {
delete m_config;
m_config = nullptr;
}
}
bool BeltTearingPresenter::loadConfiguration(const QString& configFilePath)
{
if (!m_config) {
LOG_WARNING("Config instance not created\n");
return false;
}
m_configFilePath = configFilePath;
try {
// 加载配置文件
m_configResult = m_config->LoadConfig(configFilePath.toStdString());
LOG_INFO("Configuration loaded successfully:\n");
LOG_INFO(" Server Port: %d\n", m_configResult.serverPort);
LOG_INFO(" Project Type: %d\n", static_cast<int>(m_configResult.projectType));
LOG_INFO(" Servers count: %d\n", m_configResult.servers.size());
// 应用算法参数
applyAlgorithmParameters(m_configResult.algorithmParams);
// 输出算法参数信息
const auto& params = m_configResult.algorithmParams;
LOG_INFO("Algorithm Parameters:\n");
LOG_INFO(" Tear Threshold: %f\n", params.beltTearingParam.tearThreshold);
LOG_INFO(" Min Tear Length: %f\n", params.beltTearingParam.minTearLength);
LOG_INFO(" Max Tear Width: %f\n", params.beltTearingParam.maxTearWidth);
LOG_INFO(" Blur Size: %d\n", params.imageProcessingParam.blurSize);
LOG_INFO(" Check Interval: %d\n", params.monitoringParam.checkInterval);
return true;
} catch (const std::exception& e) {
LOG_ERROR("Error loading configuration: %s\n", e.what());
return false;
}
}
void BeltTearingPresenter::applyAlgorithmParameters(const BeltTearingAlgorithmParams& params)
{
if (!m_beltTearingAlgo) {
return;
}
// 重置算法参数
m_beltTearingAlgo->ResetParameter();
// 应用算法参数
LOG_DEBUG("Applying algorithm parameters...\n");
LOG_DEBUG(" Tear Threshold: %f\n", params.beltTearingParam.tearThreshold);
LOG_DEBUG(" Min Tear Length: %f\n", params.beltTearingParam.minTearLength);
LOG_DEBUG(" Max Tear Width: %f\n", params.beltTearingParam.maxTearWidth);
LOG_DEBUG(" Blur Size: %d\n", params.imageProcessingParam.blurSize);
LOG_DEBUG(" Canny Threshold 1: %f\n", params.imageProcessingParam.cannyThreshold1);
LOG_DEBUG(" Canny Threshold 2: %f\n", params.imageProcessingParam.cannyThreshold2);
LOG_DEBUG(" Check Interval: %d ms\n", params.monitoringParam.checkInterval);
LOG_DEBUG(" Alert Threshold: %f\n", params.monitoringParam.alertThreshold);
// 调试参数
if (m_configResult.debugParam.enableDebug) {
LOG_DEBUG("Debug mode enabled:\n");
LOG_DEBUG(" Save debug images: %s\n", (m_configResult.debugParam.saveDebugImage ? "Yes" : "No"));
LOG_DEBUG(" Print detail log: %s\n", (m_configResult.debugParam.printDetailLog ? "Yes" : "No"));
}
// TODO: 根据BeltTearingAlgo的实际接口设置参数
// 例如m_beltTearingAlgo->SetTearThreshold(params.beltTearingParam.tearThreshold);
}
void BeltTearingPresenter::OnConfigChanged(const BeltTearingConfigResult& configResult)
{
LOG_INFO("Configuration changed notification received\n");
// 更新配置结果
m_configResult = configResult;
// 重新应用算法参数
applyAlgorithmParameters(configResult.algorithmParams);
// 如果服务器端口改变,可能需要重启服务器
if (m_tcpServer->isListening() && m_tcpServer->serverPort() != configResult.serverPort) {
LOG_INFO("Server port changed, restarting server...\n");
stopServer();
startServer(configResult.serverPort);
}
}
bool BeltTearingPresenter::initializeCamera()
{
if (m_eyeDevice) {
return true; // 已经初始化过
}
int result = IVrEyeDevice::CreateObject(&m_eyeDevice);
if (result != 0 || !m_eyeDevice) {
LOG_ERROR("Failed to create VrEyeDevice object, error code: %d\n", result);
return false;
}
result = m_eyeDevice->InitDevice();
if (result != 0) {
LOG_ERROR("Failed to initialize VrEyeDevice, error code: %d\n", result);
delete m_eyeDevice;
m_eyeDevice = nullptr;
return false;
}
// 设置状态回调
result = m_eyeDevice->SetStatusCallback(OnStatusCallback, this);
if (result != 0) {
LOG_WARNING("Failed to set status callback, error code: %d\n", result);
}
LOG_INFO("VrEyeDevice initialized successfully\n");
return true;
}
void BeltTearingPresenter::startCamera()
{
if (!m_eyeDevice) {
if (!initializeCamera()) {
// 启动定时器持续重试初始化
LOG_WARNING("Camera initialization failed, starting retry timer...\n");
m_cameraInitTimer->start(5000); // 每5秒重试一次
return;
}
}
// 尝试打开设备
int result = m_eyeDevice->OpenDevice(nullptr);
if (result != 0) {
LOG_WARNING("Failed to open camera device, error code: %d, retrying...\n", result);
// 启动定时器持续重试连接
m_cameraInitTimer->start(3000); // 每3秒重试一次
return;
}
// 停止重试定时器
m_cameraInitTimer->stop();
m_cameraInitialized = true;
// 开始检测
result = m_eyeDevice->StartDetect(OnPointCloudCallback, keResultDataType_Position, this);
if (result != 0) {
LOG_ERROR("Failed to start detection, error code: %d\n", result);
return;
}
m_cameraDetecting = true;
}
void BeltTearingPresenter::stopCamera()
{
m_cameraInitTimer->stop();
if (m_eyeDevice) {
if (m_cameraDetecting) {
m_eyeDevice->StopDetect();
m_cameraDetecting = false;
}
if (m_cameraInitialized) {
m_eyeDevice->CloseDevice();
m_cameraInitialized = false;
}
delete m_eyeDevice;
m_eyeDevice = nullptr;
}
LOG_INFO("Camera stopped\n");
}
void BeltTearingPresenter::onCameraInitTimer()
{
LOG_DEBUG("Retrying camera initialization...\n");
// 尝试重新初始化和连接相机
if (!m_eyeDevice) {
if (!initializeCamera()) {
return; // 继续重试
}
}
// 尝试连接相机
int result = m_eyeDevice->OpenDevice(nullptr);
if (result == 0) {
// 连接成功,开始检测
m_cameraInitTimer->stop();
m_cameraInitialized = true;
result = m_eyeDevice->StartDetect(OnPointCloudCallback, keResultDataType_Position, this);
if (result == 0) {
m_cameraDetecting = true;
LOG_INFO("Camera connection restored successfully!\n");
} else {
LOG_ERROR("Failed to start detection after reconnection, error code: %d\n", result);
}
} else {
LOG_WARNING("Still unable to connect to camera, continuing retry...\n");
}
}
void BeltTearingPresenter::OnStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
BeltTearingPresenter* presenter = static_cast<BeltTearingPresenter*>(pInfoParam);
if (!presenter) return;
LOG_DEBUG("Camera status changed: %d\n", static_cast<int>(eStatus));
// 处理相机状态变化
switch (eStatus) {
case keDeviceWorkStatus_Eye_Comming:
LOG_INFO("Camera connected\n");
break;
case keDeviceWorkStatus_Offline:
LOG_WARNING("Camera disconnected, attempting to reconnect...\n");
presenter->m_cameraInitialized = false;
presenter->m_cameraDetecting = false;
// 开始重连尝试
if (!presenter->m_cameraInitTimer->isActive()) {
presenter->m_cameraInitTimer->start(3000);
}
break;
default:
break;
}
}
void BeltTearingPresenter::OnPointCloudCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pParam)
{
if(keResultDataType_Position != eDataType) return;
BeltTearingPresenter* presenter = static_cast<BeltTearingPresenter*>(pParam);
if (!presenter || !pLaserLinePoint) return;
// 处理点云数据
presenter->processPointCloudData(pLaserLinePoint);
}
void BeltTearingPresenter::processPointCloudData(const SVzLaserLineData* pLaserLine)
{
if (!m_beltTearingAlgo || !pLaserLine) return;
try {
SVzNL3DLaserLine sNL3DLaserLine;
sNL3DLaserLine.nTimeStamp = pLaserLine->llTimeStamp;
sNL3DLaserLine.p3DPosition = static_cast<SVzNL3DPosition*>(pLaserLine->p3DPoint);
sNL3DLaserLine.nPositionCnt = pLaserLine->nPointCount;
// 调用算法进行检测
std::vector<SSG_beltTearingInfo> results = m_beltTearingAlgo->Predit(&sNL3DLaserLine, pLaserLine->llFrameIdx);
// 如果有检测结果,发送到网络客户端
if (!results.empty()) {
LOG_INFO("Detected %d belt tearing(s)\n", results.size());
sendTearingResults(results);
}
} catch (const std::exception& e) {
LOG_ERROR("Error in algorithm processing: %s\n", e.what());
}
}
void BeltTearingPresenter::sendTearingResults(const std::vector<SSG_beltTearingInfo>& results)
{
if (results.empty() || m_clients.isEmpty()) {
return;
}
// 将检测结果转换为JSON格式
QJsonArray tearingArray;
for (const auto& result : results) {
QJsonObject tearingObj;
// tearingObj["level"] = QString::number(result.level);
tearingObj["id"] = QString::number(result.tearID);
tearingObj["tearStatus"] = QString::number(static_cast<int>(result.tearStatus));
tearingObj["tearType"] = QString::number(result.tearType);
tearingObj["statLineIdx"] = QString::number(result.statLineIdx);
tearingObj["endLineIdx"] = QString::number(result.endLineIdx);
tearingObj["tearDepth"] = QString::number(result.tearDepth);
tearingObj["tearWidth"] = QString::number(result.tearWidth);
// tearingObj["tearLength"] = QString::number(result.tearLength);
tearingObj["roiLeft"] = QString::number(result.roi.left);
tearingObj["roiRight"] = QString::number(result.roi.right);
tearingObj["roiTop"] = QString::number(result.roi.top);
tearingObj["roiBottom"] = QString::number(result.roi.bottom);
// tearingObj["imageFile"] = QString::fromStdString(result.imageFile);
// tearingObj["older"] = QString::fromStdString(result.older);
tearingObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
tearingArray.append(tearingObj);
}
// 转换为JSON字符串
QJsonDocument doc(tearingArray);
QByteArray message = doc.toJson(QJsonDocument::Compact);
// 创建数据包
QByteArray package;
QDataStream stream(&package, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::BigEndian);
stream << quint8(static_cast<quint8>(ByteDataType::Text)) << quint32(message.size());
package.append(message);
package.append("___END___\r\n");
// 发送到所有连接的客户端
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
QTcpSocket *socket = it.value();
if (socket->state() == QAbstractSocket::ConnectedState) {
socket->write(package);
}
}
LOG_INFO("Sent tearing detection results to %d client(s)\n", m_clients.size());
}
bool BeltTearingPresenter::startServer(quint16 port)
{
if (m_tcpServer->isListening()) {
stopServer();
}
m_port = port;
bool result = m_tcpServer->listen(QHostAddress::Any, port);
if (result) {
2025-09-10 00:31:27 +08:00
LOG_INFO("TCP server started on port %d\n", port);
} else {
2025-09-10 00:31:27 +08:00
LOG_ERROR("Failed to start TCP server: %s\n", m_tcpServer->errorString().toStdString().c_str());
}
return result;
}
void BeltTearingPresenter::stopServer()
{
// 断开所有客户端连接
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
it.value()->disconnectFromHost();
}
m_clients.clear();
// 停止服务器监听
if (m_tcpServer->isListening()) {
m_tcpServer->close();
}
m_port = 0;
}
void BeltTearingPresenter::onNewConnection()
{
while (m_tcpServer->hasPendingConnections()) {
QTcpSocket *socket = m_tcpServer->nextPendingConnection();
// 生成客户端ID
QString clientId = generateClientId(socket);
// 存储客户端连接
m_clients[clientId] = socket;
// 连接客户端信号
connect(socket, &QTcpSocket::disconnected, this, &BeltTearingPresenter::onClientDisconnected);
2025-09-10 00:31:27 +08:00
LOG_INFO("Client connected: %s\n", clientId.toStdString().c_str());
// 发送欢迎消息
QByteArray welcomeMsg = "Welcome to BeltTearing Server!";
socket->write(welcomeMsg);
}
}
void BeltTearingPresenter::onClientDisconnected()
{
QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
if (!socket) {
return;
}
// 查找断开连接的客户端ID
QString clientId;
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
if (it.value() == socket) {
clientId = it.key();
break;
}
}
if (!clientId.isEmpty()) {
m_clients.remove(clientId);
2025-09-10 00:31:27 +08:00
LOG_INFO("Client disconnected: %s\n", clientId.toStdString().c_str());
}
socket->deleteLater();
}
2025-09-10 00:31:27 +08:00
QString BeltTearingPresenter::generateClientId(QTcpSocket *socket)
{
2025-09-10 00:31:27 +08:00
// 使用UUID生成唯一的客户端ID
return QUuid::createUuid().toString();
}
2025-09-10 00:31:27 +08:00
QString BeltTearingPresenter::getVersionString()
{
2025-09-10 00:31:27 +08:00
return QString(BELT_TEARING_SERVER_VERSION_STRING);
}
2025-09-10 00:31:27 +08:00
QString BeltTearingPresenter::getProductName()
2025-08-31 21:08:28 +08:00
{
2025-09-10 00:31:27 +08:00
return QString(BELT_TEARING_SERVER_PRODUCT_NAME);
2025-08-31 21:08:28 +08:00
}
2025-09-10 00:31:27 +08:00
QString BeltTearingPresenter::getBuildInfo()
{
2025-09-10 00:31:27 +08:00
return QString("%1 %2 built on %3 %4 for %5")
.arg(BELT_TEARING_SERVER_BUILD_TYPE)
.arg(BELT_TEARING_SERVER_VERSION_STRING)
.arg(BELT_TEARING_SERVER_BUILD_DATE)
.arg(BELT_TEARING_SERVER_BUILD_TIME)
.arg(BELT_TEARING_SERVER_PLATFORM);
}