994 lines
30 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 "ParkingSpaceGuidePresenter.h"
#include <algorithm>
#include <chrono>
#include <cstring>
#include <exception>
#include <fstream>
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include "DetectPresenter.h"
#include "IYUDPClient.h"
#include "ParkingStatusHttpServer.h"
#include "PathManager.h"
#include "Version.h"
#include "VrLog.h"
namespace {
constexpr int kMvsPixelTypeMono8 = 0x01080001;
constexpr int kMvsPixelTypeBGR8 = 0x02180014;
constexpr int kMvsAcqModeContinuous = 2;
constexpr int kDetectionIntervalMs = 100;
QString ConfigText(const std::string& value, const QString& fallback)
{
const QString text = QString::fromStdString(value).trimmed();
return text.isEmpty() ? fallback : text;
}
QString ResultText(const QString& value, const QString& fallback)
{
const QString text = value.trimmed();
return text.isEmpty() ? fallback : text;
}
ParkingSpaceGuideInfo FallbackGuideInfo(const UdpBroadcastConfig& config)
{
ParkingSpaceGuideInfo info;
info.targetId = ConfigText(config.targetId, QStringLiteral("T001"));
info.parkId = ConfigText(config.parkId, QStringLiteral("P01"));
info.modelType = QStringLiteral("未知");
return info;
}
bool IsExceptionGuideState(int guideStateCode)
{
switch (guideStateCode) {
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
return true;
default:
return false;
}
}
QJsonObject BuildGuideInfoJson(const ParkingSpaceGuideInfo& info,
const UdpBroadcastConfig& config)
{
const ParkingSpaceGuideInfo fallback = FallbackGuideInfo(config);
QJsonObject object;
object["targetId"] = ResultText(info.targetId, fallback.targetId);
object["parkId"] = ResultText(info.parkId, fallback.parkId);
object["modelType"] = ResultText(info.modelType, fallback.modelType);
object["guideStateCode"] = info.guideStateCode;
object["distanceToStop"] = info.distance;
object["bodyYawAngle"] = info.angle;
object["lateralOffset"] = info.lateralOffset;
object["aircraftSpeed"] = info.aircraftSpeed;
object["hasException"] = info.hasException || IsExceptionGuideState(info.guideStateCode);
object["guideText"] = info.guideText;
return object;
}
QJsonObject BuildDetectionResultPayload(const DetectionResult& result,
const UdpBroadcastConfig& config)
{
const bool hasResult = !result.parkingSpaceInfoList.empty();
const bool success = result.errorCode == 0 && hasResult;
const ParkingSpaceGuideInfo firstInfo = hasResult
? result.parkingSpaceInfoList.front()
: FallbackGuideInfo(config);
const QJsonObject firstResult = BuildGuideInfoJson(firstInfo, config);
QJsonObject payload;
payload["protocol"] = QStringLiteral("ParkingSpaceGuideResult");
payload["version"] = QStringLiteral("1.0");
payload["success"] = success;
payload["hasResult"] = hasResult;
payload["targetId"] = firstResult["targetId"];
payload["parkId"] = firstResult["parkId"];
payload["modelType"] = firstResult["modelType"];
payload["guideStateCode"] = firstResult["guideStateCode"];
payload["distanceToStop"] = firstResult["distanceToStop"];
payload["bodyYawAngle"] = firstResult["bodyYawAngle"];
payload["lateralOffset"] = firstResult["lateralOffset"];
payload["aircraftSpeed"] = firstResult["aircraftSpeed"];
payload["hasException"] = result.errorCode != 0 || firstResult["hasException"].toBool();
payload["guideText"] = firstResult["guideText"];
payload["message"] = result.message;
payload["errorCode"] = result.errorCode;
payload["timestamp"] = QDateTime::currentMSecsSinceEpoch();
return payload;
}
} // namespace
ParkingSpaceGuidePresenter::ParkingSpaceGuidePresenter(QObject* parent)
: QObject(parent)
{
}
ParkingSpaceGuidePresenter::~ParkingSpaceGuidePresenter()
{
DeinitApp();
}
int ParkingSpaceGuidePresenter::Init()
{
m_reconfiguring.store(false);
NotifyWorkStatus(WorkStatus::InitIng);
NotifyStatus("停车引导初始化中");
int ret = InitConfig();
if (ret != 0) {
NotifyWorkStatus(WorkStatus::Error);
return ret;
}
const ConfigResult config = m_configManager->GetConfigResult();
m_cameraList.clear();
DetectionResult initialStatus;
initialStatus.errorCode = -1;
initialStatus.message = QStringLiteral("暂无检测结果");
UpdateCurrentStatus(initialStatus);
m_detectPresenter = new DetectPresenter();
ret = InitMvsCamera(config.mvsCamera);
if (ret != 0) {
NotifyStatus("平面相机初始化失败,继续使用预留算法模式");
}
if (m_cameraList.empty()) {
const std::string cameraName = config.mvsCamera.serialNumber.empty()
? std::string("平面相机")
: config.mvsCamera.serialNumber;
m_cameraList.push_back(std::make_pair(cameraName, static_cast<void*>(m_mvsDevice)));
}
ret = InitRsLidar(config.lidarConfig);
if (ret != 0) {
NotifyStatus("雷达初始化失败,继续使用预留算法模式");
}
ret = InitLedDisplay(config.ledDisplayConfig);
if (ret != 0) {
NotifyStatus("显示屏初始化失败");
}
ret = InitUdpBroadcast(config.udpBroadcastConfig);
if (ret != 0) {
NotifyStatus("组播初始化失败");
}
ret = InitHttpServer(config.httpServerConfig);
if (ret != 0) {
NotifyStatus("HTTP状态服务初始化失败");
}
if (StatusCallback()) {
StatusCallback()->OnCameraCountChanged(1);
}
m_initialized = true;
NotifyWorkStatus(WorkStatus::Ready);
NotifyStatus("停车引导初始化完成");
return 0;
}
void ParkingSpaceGuidePresenter::DeinitApp()
{
m_initialized.store(false);
{
std::lock_guard<std::mutex> reconfigurationLock(m_reconfigurationMutex);
m_reconfiguring.store(true);
StopDetection();
CloseDevices();
delete m_detectPresenter;
m_detectPresenter = nullptr;
}
if (m_configManager) {
m_configManager->Shutdown();
delete m_configManager;
m_configManager = nullptr;
}
}
bool ParkingSpaceGuidePresenter::StartDetection(int cameraIndex)
{
std::lock_guard<std::mutex> threadLock(m_detectionThreadMutex);
if (!m_initialized || m_reconfiguring.load() || !m_detectPresenter || !m_configManager) {
NotifyStatus("系统未初始化");
return false;
}
if (m_detectionRunning.load()) {
NotifyStatus("停车引导实时检测已在运行");
return true;
}
if (m_detectionThread.joinable()) {
m_detectionThread.join();
}
if (cameraIndex > 0) {
m_detectIndex = cameraIndex;
} else {
m_detectIndex = m_currentCameraIndex;
}
m_stopDetectionRequested.store(false);
m_detectionRunning.store(true);
try {
m_detectionThread = std::thread(&ParkingSpaceGuidePresenter::DetectionLoop, this);
} catch (...) {
m_detectionRunning.store(false);
m_stopDetectionRequested.store(true);
NotifyWorkStatus(WorkStatus::Error);
NotifyStatus("启动停车引导实时检测线程失败");
return false;
}
NotifyWorkStatus(WorkStatus::Working);
NotifyStatus("停车引导实时检测已开始");
return true;
}
bool ParkingSpaceGuidePresenter::TriggerDetection(int cameraIndex)
{
std::lock_guard<std::mutex> threadLock(m_detectionThreadMutex);
if (!m_initialized || m_reconfiguring.load() || !m_detectPresenter || !m_configManager) {
NotifyStatus("系统未初始化");
return false;
}
if (m_detectionRunning.load()) {
NotifyStatus("实时检测运行中,无法执行单次检测");
return false;
}
if (cameraIndex > 0) {
m_detectIndex = cameraIndex;
} else {
m_detectIndex = m_currentCameraIndex;
}
NotifyWorkStatus(WorkStatus::Detecting);
NotifyStatus("停车引导单次检测已开始");
bool success = false;
try {
success = DetectOnce();
} catch (const std::exception& e) {
NotifyStatus(std::string("停车引导单次检测异常:") + e.what());
} catch (...) {
NotifyStatus("停车引导单次检测发生未知异常");
}
NotifyWorkStatus(success ? WorkStatus::Completed : WorkStatus::Error);
NotifyStatus(success ? "停车引导单次检测完成"
: "停车引导单次检测失败");
return success;
}
bool ParkingSpaceGuidePresenter::DetectOnce()
{
std::lock_guard<std::mutex> executionLock(m_detectionExecutionMutex);
if (!m_detectPresenter || !m_configManager) {
return false;
}
QImage frame;
RsCloudData cloud;
{
std::lock_guard<std::mutex> lock(m_dataMutex);
frame = BuildPreviewImage();
cloud = m_latestCloud;
}
DetectionResult result;
result.cameraIndex = m_detectIndex;
const int ret = m_detectPresenter->DetectParkingSpaceGuide(frame,
cloud,
m_configManager->GetAlgorithmParams(),
result);
result.cameraIndex = m_detectIndex;
EnrichDetectionResult(result);
if (ret != 0) {
result.errorCode = ret;
if (result.message.isEmpty()) {
result.message = QStringLiteral("停车引导检测失败");
}
} else {
if (result.parkingSpaceInfoList.empty() && result.message.isEmpty()) {
result.message = QStringLiteral("无停车引导结果");
}
}
if (StatusCallback()) {
StatusCallback()->OnDetectionResult(result);
}
UpdateCurrentStatus(result);
if (ret == 0 && m_ledDisplay) {
m_ledDisplay->SendResult(ConvertLedResult(result));
}
BroadcastDetectionResult(result);
return ret == 0;
}
void ParkingSpaceGuidePresenter::DetectionLoop()
{
const std::chrono::milliseconds interval(kDetectionIntervalMs);
while (!m_stopDetectionRequested.load()) {
const std::chrono::steady_clock::time_point cycleStart = std::chrono::steady_clock::now();
try {
DetectOnce();
} catch (const std::exception& e) {
const bool stopping = m_stopDetectionRequested.exchange(true);
m_detectionRunning.store(false);
if (!stopping) {
NotifyStatus(std::string("停车引导实时检测异常:") + e.what());
NotifyWorkStatus(WorkStatus::Error);
}
} catch (...) {
const bool stopping = m_stopDetectionRequested.exchange(true);
m_detectionRunning.store(false);
if (!stopping) {
NotifyStatus("停车引导实时检测发生未知异常");
NotifyWorkStatus(WorkStatus::Error);
}
}
std::unique_lock<std::mutex> waitLock(m_detectionWaitMutex);
m_detectionCondition.wait_until(
waitLock,
cycleStart + interval,
[this]() { return m_stopDetectionRequested.load(); });
}
m_detectionRunning.store(false);
}
int ParkingSpaceGuidePresenter::StopDetection()
{
std::lock_guard<std::mutex> threadLock(m_detectionThreadMutex);
const bool wasRunning = m_detectionRunning.load();
m_stopDetectionRequested.store(true);
m_detectionCondition.notify_all();
if (m_detectionThread.joinable() &&
m_detectionThread.get_id() != std::this_thread::get_id()) {
m_detectionThread.join();
}
m_detectionRunning.store(false);
if (wasRunning) {
NotifyWorkStatus(WorkStatus::Ready);
NotifyStatus("停车引导实时检测已停止");
}
return 0;
}
bool ParkingSpaceGuidePresenter::IsDetectionRunning() const
{
return m_detectionRunning.load();
}
int ParkingSpaceGuidePresenter::LoadAndDetect(const QString& fileName)
{
Q_UNUSED(fileName);
return TriggerDetection(m_currentCameraIndex) ? 0 : -1;
}
int ParkingSpaceGuidePresenter::SaveDetectionDataToFile(const std::string& filePath)
{
std::lock_guard<std::mutex> lock(m_dataMutex);
std::ofstream file(filePath.c_str(), std::ios::out | std::ios::trunc);
if (!file.is_open()) {
return -1;
}
file << "ParkingSpaceGuide cached data\n";
file << "hasFrame=" << (m_hasFrame ? 1 : 0) << "\n";
file << "frameWidth=" << m_latestFrameInfo.width << "\n";
file << "frameHeight=" << m_latestFrameInfo.height << "\n";
file << "hasCloud=" << (m_hasCloud ? 1 : 0) << "\n";
file << "cloudLines=" << m_latestCloud.size() << "\n";
return 0;
}
int ParkingSpaceGuidePresenter::GetDetectionDataCacheSize() const
{
std::lock_guard<std::mutex> lock(m_dataMutex);
return (m_hasFrame ? 1 : 0) + (m_hasCloud ? 1 : 0);
}
void ParkingSpaceGuidePresenter::SetDefaultCameraIndex(int cameraIndex)
{
m_currentCameraIndex = (std::max)(1, cameraIndex);
}
int ParkingSpaceGuidePresenter::GetDetectIndex() const
{
return m_detectIndex;
}
QString ParkingSpaceGuidePresenter::GetAlgoVersion() const
{
return DetectPresenter::GetAlgoVersion();
}
ConfigManager* ParkingSpaceGuidePresenter::GetConfigManager()
{
return m_configManager;
}
std::vector<std::pair<std::string, void*>> ParkingSpaceGuidePresenter::GetCameraList() const
{
return m_cameraList;
}
void ParkingSpaceGuidePresenter::OnConfigChanged(const ConfigResult& configResult)
{
std::lock_guard<std::mutex> reconfigurationLock(m_reconfigurationMutex);
if (!m_initialized) {
return;
}
m_reconfiguring.store(true);
const bool restartDetection = m_detectionRunning.load();
const int detectIndex = m_detectIndex;
StopDetection();
NotifyStatus("配置已变更,正在重新连接设备");
InitMvsCamera(configResult.mvsCamera);
InitRsLidar(configResult.lidarConfig);
InitLedDisplay(configResult.ledDisplayConfig);
InitUdpBroadcast(configResult.udpBroadcastConfig);
InitHttpServer(configResult.httpServerConfig);
m_reconfiguring.store(false);
if (restartDetection) {
StartDetection(detectIndex);
}
}
IYParkingSpaceGuideStatus* ParkingSpaceGuidePresenter::StatusCallback() const
{
return static_cast<IYParkingSpaceGuideStatus*>(m_statusCallback);
}
int ParkingSpaceGuidePresenter::InitConfig()
{
if (!m_configManager) {
m_configManager = new ConfigManager();
}
if (!m_configManager->Initialize(PathManager::GetInstance().GetConfigFilePath().toStdString())) {
NotifyStatus("初始化配置管理器失败");
return -1;
}
ConfigResult config = m_configManager->GetConfigResult();
config.Normalize();
SystemConfig systemConfig = m_configManager->GetConfig();
systemConfig.configResult = config;
m_configManager->UpdateFullConfig(systemConfig);
return 0;
}
int ParkingSpaceGuidePresenter::InitMvsCamera(const MvsCameraConfig& config)
{
auto closeMvsDevice = [this]() {
if (!m_mvsDevice) {
return;
}
m_mvsDevice->StopAcquisition();
m_mvsDevice->UnregisterImageCallback();
m_mvsDevice->CloseDevice();
m_mvsDevice->UninitSDK();
delete m_mvsDevice;
m_mvsDevice = nullptr;
};
closeMvsDevice();
m_cameraList.clear();
{
std::lock_guard<std::mutex> lock(m_dataMutex);
m_latestFrame.clear();
m_latestFrameInfo = CameraFrameInfo();
m_hasFrame = false;
}
if (!config.enabled) {
NotifyCameraStatus(false);
NotifyStatus("平面相机未启用");
m_cameraList.push_back(std::make_pair(std::string("平面相机"), static_cast<void*>(nullptr)));
return 0;
}
if (IMvsDevice::CreateObject(&m_mvsDevice) != 0 || !m_mvsDevice) {
NotifyCameraStatus(false);
NotifyStatus("创建平面相机设备失败");
return -1;
}
int ret = m_mvsDevice->InitSDK();
if (ret != 0) {
NotifyCameraStatus(false);
NotifyStatus("平面相机SDK初始化失败" + std::to_string(ret));
closeMvsDevice();
return ret;
}
std::vector<MvsDeviceInfo> devices;
ret = m_mvsDevice->EnumerateDevices(devices);
if (ret != 0 || devices.empty()) {
NotifyCameraStatus(false);
NotifyStatus(ret != 0
? "搜索平面相机失败:" + std::to_string(ret)
: "未搜索到平面相机");
closeMvsDevice();
return ret != 0 ? ret : -1;
}
NotifyStatus("搜索到平面相机数量:" + std::to_string(devices.size()));
if (!config.serialNumber.empty()) {
ret = m_mvsDevice->OpenDevice(config.serialNumber);
} else {
unsigned int deviceIndex = static_cast<unsigned int>((std::max)(0, config.deviceIndex));
if (deviceIndex >= devices.size()) {
NotifyStatus("相机设备序号超出范围使用第0台设备");
deviceIndex = 0;
}
ret = m_mvsDevice->OpenDeviceByIndex(deviceIndex);
}
if (ret != 0) {
NotifyCameraStatus(false);
NotifyStatus("打开平面相机失败:" + std::to_string(ret));
closeMvsDevice();
return ret;
}
MvsDeviceInfo openedInfo;
std::string cameraName = config.serialNumber.empty() ? std::string("平面相机") : config.serialNumber;
if (m_mvsDevice->GetDeviceInfo(openedInfo) == 0) {
if (!openedInfo.displayName.empty()) {
cameraName = openedInfo.displayName;
} else if (!openedInfo.serialNumber.empty()) {
cameraName = openedInfo.serialNumber;
}
}
ret = m_mvsDevice->SetEnumFeature("AcquisitionMode", kMvsAcqModeContinuous);
if (ret != 0) {
NotifyStatus("设置平面相机连续采集模式失败,继续使用当前模式:" + std::to_string(ret));
}
ret = m_mvsDevice->SetEnumFeature("PixelFormat", kMvsPixelTypeMono8);
if (ret != 0) {
NotifyStatus("设置平面相机灰度格式失败,继续使用当前格式:" + std::to_string(ret));
}
ret = m_mvsDevice->SetTriggerMode(false);
if (ret != 0) {
NotifyStatus("关闭平面相机触发模式失败,继续启动采集:" + std::to_string(ret));
}
ret = m_mvsDevice->RegisterImageCallback([this](const MvsImageData& image) {
OnMvsFrame(image);
});
if (ret != 0) {
NotifyCameraStatus(false);
NotifyStatus("注册平面相机图像回调失败:" + std::to_string(ret));
closeMvsDevice();
return ret;
}
ret = m_mvsDevice->StartAcquisition();
if (ret != 0) {
NotifyCameraStatus(false);
NotifyStatus("启动平面相机采集失败:" + std::to_string(ret));
closeMvsDevice();
return ret;
}
NotifyCameraStatus(true);
m_cameraList.push_back(std::make_pair(cameraName, static_cast<void*>(m_mvsDevice)));
NotifyStatus("平面相机已连接:" + cameraName);
return 0;
}
int ParkingSpaceGuidePresenter::InitRsLidar(const RsLidarConfig& config)
{
if (m_lidarDevice) {
m_lidarDevice->Stop();
m_lidarDevice->CloseDevice();
delete m_lidarDevice;
m_lidarDevice = nullptr;
}
if (IRsLidarDevice::CreateObject(&m_lidarDevice) != 0 || !m_lidarDevice) {
NotifyLidarStatus(false);
return -1;
}
m_lidarDevice->SetPointCloudCallback([this](const RsCloudData& cloud, const RsFrameInfo& info) {
std::lock_guard<std::mutex> lock(m_dataMutex);
m_latestCloud = cloud;
m_latestCloudInfo = info;
m_hasCloud = true;
});
m_lidarDevice->SetExceptionCallback([this](const RsExceptionInfo& info) {
Q_UNUSED(info);
NotifyStatus("雷达异常");
NotifyLidarStatus(false);
});
int ret = m_lidarDevice->InitDevice();
if (ret != 0) {
NotifyLidarStatus(false);
return ret;
}
ret = m_lidarDevice->OpenDevice(config);
if (ret != 0) {
NotifyLidarStatus(false);
return ret;
}
ret = m_lidarDevice->Start();
NotifyLidarStatus(ret == 0);
return ret;
}
int ParkingSpaceGuidePresenter::InitLedDisplay(const LedDisplayConfig& config)
{
if (m_ledDisplay) {
m_ledDisplay->Close();
delete m_ledDisplay;
m_ledDisplay = nullptr;
}
if (ILedDisplayDevice::CreateObject(&m_ledDisplay) != 0 || !m_ledDisplay) {
NotifyLedStatus(false);
return -1;
}
m_ledDisplay->SetStatusCallback([](ELedDisplayStatus status,
const std::string& message,
void* user) {
auto* self = static_cast<ParkingSpaceGuidePresenter*>(user);
if (!self) {
return;
}
self->NotifyLedStatus(status == ELedDisplayStatus::Connected);
if (!message.empty()) {
self->NotifyStatus(std::string("显示屏:") + message);
}
}, this);
const int ret = m_ledDisplay->Open(config);
NotifyLedStatus(config.enabled && ret == 0 && m_ledDisplay->IsConnected());
return ret;
}
int ParkingSpaceGuidePresenter::InitUdpBroadcast(const UdpBroadcastConfig& config)
{
std::lock_guard<std::mutex> lock(m_udpMutex);
if (m_udpClient) {
m_udpClient->StopUDPClient();
delete m_udpClient;
m_udpClient = nullptr;
}
m_udpBroadcastConfig = config;
if (!config.enabled) {
NotifyStatus("组播未启用");
return 0;
}
if (config.address.empty() || config.port <= 0 || config.port > 65535) {
NotifyStatus("组播配置无效");
return -1;
}
if (!IYUDPClient::CreateUDPClient(&m_udpClient) || !m_udpClient) {
NotifyStatus("创建组播客户端失败");
return -1;
}
const int ret = m_udpClient->Init(false);
if (ret != 0) {
NotifyStatus("初始化组播客户端失败:" + std::to_string(ret));
m_udpClient->StopUDPClient();
delete m_udpClient;
m_udpClient = nullptr;
return ret;
}
NotifyStatus("组播客户端已初始化");
return 0;
}
int ParkingSpaceGuidePresenter::InitHttpServer(const HttpServerConfig& config)
{
CloseHttpServer();
m_httpServer = new ParkingStatusHttpServer();
const int ret = m_httpServer->Start(
config,
[this]() {
return CurrentStatusJson();
});
if (ret != 0) {
const std::string error = m_httpServer->LastError();
delete m_httpServer;
m_httpServer = nullptr;
NotifyStatus(error.empty() ? "HTTP状态服务启动失败" : "HTTP状态服务启动失败" + error);
return ret;
}
if (config.enabled) {
NotifyStatus("HTTP状态服务已启动" + config.address + ":" + std::to_string(config.port));
} else {
NotifyStatus("HTTP状态服务未启用");
}
return 0;
}
void ParkingSpaceGuidePresenter::CloseUdpBroadcast()
{
std::lock_guard<std::mutex> lock(m_udpMutex);
if (!m_udpClient) {
return;
}
m_udpClient->StopUDPClient();
delete m_udpClient;
m_udpClient = nullptr;
}
void ParkingSpaceGuidePresenter::CloseHttpServer()
{
if (!m_httpServer) {
return;
}
m_httpServer->Stop();
delete m_httpServer;
m_httpServer = nullptr;
}
void ParkingSpaceGuidePresenter::CloseDevices()
{
CloseHttpServer();
CloseUdpBroadcast();
if (m_mvsDevice) {
m_mvsDevice->StopAcquisition();
m_mvsDevice->UnregisterImageCallback();
m_mvsDevice->CloseDevice();
m_mvsDevice->UninitSDK();
delete m_mvsDevice;
m_mvsDevice = nullptr;
}
if (m_lidarDevice) {
m_lidarDevice->Stop();
m_lidarDevice->CloseDevice();
delete m_lidarDevice;
m_lidarDevice = nullptr;
}
if (m_ledDisplay) {
m_ledDisplay->Close();
delete m_ledDisplay;
m_ledDisplay = nullptr;
}
}
void ParkingSpaceGuidePresenter::EnrichDetectionResult(DetectionResult& result) const
{
const UdpBroadcastConfig config = m_configManager
? m_configManager->GetConfigResult().udpBroadcastConfig
: m_udpBroadcastConfig;
for (ParkingSpaceGuideInfo& info : result.parkingSpaceInfoList) {
if (info.targetId.trimmed().isEmpty()) {
info.targetId = ConfigText(config.targetId, QStringLiteral("T001"));
}
if (info.parkId.trimmed().isEmpty()) {
info.parkId = ConfigText(config.parkId, QStringLiteral("P01"));
}
if (info.modelType.trimmed().isEmpty()) {
info.modelType = QStringLiteral("未知");
}
}
}
void ParkingSpaceGuidePresenter::UpdateCurrentStatus(const DetectionResult& result)
{
const UdpBroadcastConfig config = m_configManager
? m_configManager->GetConfigResult().udpBroadcastConfig
: m_udpBroadcastConfig;
const QByteArray data = QJsonDocument(BuildDetectionResultPayload(result, config))
.toJson(QJsonDocument::Compact);
std::lock_guard<std::mutex> lock(m_statusMutex);
m_currentStatusJson.assign(data.constData(), static_cast<size_t>(data.size()));
}
std::string ParkingSpaceGuidePresenter::CurrentStatusJson() const
{
std::lock_guard<std::mutex> lock(m_statusMutex);
if (!m_currentStatusJson.empty()) {
return m_currentStatusJson;
}
return "{\"success\":false,\"hasResult\":false,\"message\":\"暂无检测结果\",\"errorCode\":-1}";
}
bool ParkingSpaceGuidePresenter::BroadcastDetectionResult(const DetectionResult& result)
{
Q_UNUSED(result);
std::lock_guard<std::mutex> lock(m_udpMutex);
if (!m_udpClient || !m_udpBroadcastConfig.enabled) {
return false;
}
const std::string currentStatus = CurrentStatusJson();
const QByteArray data(currentStatus.data(), static_cast<int>(currentStatus.size()));
const int ret = m_udpClient->SendData(m_udpBroadcastConfig.port,
m_udpBroadcastConfig.address.c_str(),
data.constData(),
data.size());
if (ret != 0) {
NotifyStatus("组播发送失败:" + std::to_string(ret));
return false;
}
return true;
}
void ParkingSpaceGuidePresenter::NotifyStatus(const std::string& message)
{
LOG_INFO("%s\n", message.c_str());
if (StatusCallback()) {
StatusCallback()->OnStatusUpdate(message);
}
}
void ParkingSpaceGuidePresenter::NotifyWorkStatus(WorkStatus status)
{
if (StatusCallback()) {
StatusCallback()->OnWorkStatusChanged(status);
}
}
void ParkingSpaceGuidePresenter::NotifyCameraStatus(bool connected)
{
if (StatusCallback()) {
StatusCallback()->OnCamera1StatusChanged(connected);
}
}
void ParkingSpaceGuidePresenter::NotifyLidarStatus(bool connected)
{
if (StatusCallback()) {
StatusCallback()->OnCamera2StatusChanged(connected);
}
}
void ParkingSpaceGuidePresenter::NotifyLedStatus(bool connected)
{
if (StatusCallback()) {
StatusCallback()->OnSerialConnectionChanged(connected);
}
}
QImage ParkingSpaceGuidePresenter::BuildPreviewImage() const
{
if (!m_hasFrame || m_latestFrame.empty() || m_latestFrameInfo.width <= 0 || m_latestFrameInfo.height <= 0) {
return QImage();
}
QImage image(m_latestFrame.data(),
m_latestFrameInfo.width,
m_latestFrameInfo.height,
m_latestFrameInfo.width * 3,
QImage::Format_RGB888);
return image.copy();
}
LedDisplayResult ParkingSpaceGuidePresenter::ConvertLedResult(const DetectionResult& result) const
{
LedDisplayResult output;
output.valid = result.errorCode == 0 && !result.parkingSpaceInfoList.empty();
if (!output.valid) {
return output;
}
const ParkingSpaceGuideInfo& info = result.parkingSpaceInfoList.front();
output.guideCode = (info.hasException || IsExceptionGuideState(info.guideStateCode)) ? 2 : 1;
output.distance = static_cast<float>(info.distance);
output.lateralOffset = static_cast<float>(info.lateralOffset);
output.angle = static_cast<float>(info.angle);
return output;
}
void ParkingSpaceGuidePresenter::OnMvsFrame(const MvsImageData& image)
{
if (!image.pData || image.width == 0 || image.height == 0 || image.dataSize == 0) {
return;
}
const int width = static_cast<int>(image.width);
const int height = static_cast<int>(image.height);
const size_t pixelCount = static_cast<size_t>(width) * static_cast<size_t>(height);
if (pixelCount == 0) {
return;
}
QImage rgbImage;
if (image.dataSize >= pixelCount * 3) {
QImage src(image.pData, width, height, width * 3, QImage::Format_RGB888);
rgbImage = image.pixelFormat == kMvsPixelTypeBGR8 ? src.rgbSwapped() : src.copy();
} else if (image.dataSize >= pixelCount) {
QImage src(image.pData, width, height, width, QImage::Format_Grayscale8);
rgbImage = src.convertToFormat(QImage::Format_RGB888);
} else {
return;
}
if (rgbImage.isNull()) {
return;
}
std::vector<unsigned char> compact(pixelCount * 3);
for (int row = 0; row < height; ++row) {
std::memcpy(compact.data() + static_cast<size_t>(row) * static_cast<size_t>(width) * 3,
rgbImage.constScanLine(row),
static_cast<size_t>(width) * 3);
}
CameraFrameInfo frameInfo;
frameInfo.width = width;
frameInfo.height = height;
frameInfo.pixelFormat = image.pixelFormat;
frameInfo.frameId = image.frameID;
frameInfo.timestamp = image.timestamp;
std::lock_guard<std::mutex> lock(m_dataMutex);
m_latestFrame.swap(compact);
m_latestFrameInfo = frameInfo;
m_hasFrame = true;
}