GrabBag/GrabBagConfigCmd/ConfigCmdParser.cpp

547 lines
20 KiB
C++
Raw Normal View History

2025-07-23 01:35:14 +08:00
#include "ConfigCmdParser.h"
#include "VrError.h"
#include <iostream>
#include <sstream>
#include <chrono>
#include <iomanip>
#include <cstring>
ConfigCmdParser::ConfigCmdParser()
: m_pShareMem(nullptr)
{
}
ConfigCmdParser::~ConfigCmdParser()
{
CleanupSharedMemory();
}
bool ConfigCmdParser::ParseCommandLine(int argc, char* argv[], ConfigCmdData& configData)
{
if (argc < 2) {
ShowHelp();
return false;
}
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "-h" || arg == "--help") {
ShowHelp();
return false;
}
if (arg == "-v" || arg == "--version") {
ShowVersion();
return false;
}
if (arg == "-c" || arg == "--config") {
if (i + 1 >= argc) {
std::cerr << "错误: -c 参数需要指定配置项" << std::endl;
return false;
}
std::string configType = argv[i + 1];
// 收集剩余的参数
std::vector<std::string> configParams;
for (int j = i + 2; j < argc; ++j) {
configParams.push_back(argv[j]);
}
// 根据参数类型进行解析
if (configType == "expose") {
return ParseCameraExpose(configParams, configData);
}
else if (configType == "gain") {
return ParseCameraGain(configParams, configData);
}
else if (configType == "framerate") {
return ParseCameraFrameRate(configParams, configData);
}
else if (configType == "swing") {
return ParseCameraSwing(configParams, configData);
}
else if (configType == "roi") {
return ParseROISetting(configParams, configData);
}
else if (configType == "algo") {
return ParseAlgoParam(configParams, configData);
}
else if (configType == "calib") {
return ParseCalibParam(configParams, configData);
}
else {
std::cerr << "错误: 未知的配置参数类型: " << configType << std::endl;
return false;
}
}
}
std::cerr << "错误: 未找到有效的配置参数" << std::endl;
return false;
}
bool ConfigCmdParser::SendConfigCommand(const ConfigCmdData& configData)
{
if (!InitializeSharedMemory()) {
std::cerr << "错误: 初始化共享内存失败" << std::endl;
return false;
}
// 准备共享数据
ConfigCmdSharedData sharedData;
sharedData.data = configData;
sharedData.header.checksum = sharedData.CalculateChecksum();
sharedData.header.hasNewData = true;
// 写入共享内存
int ret = m_pShareMem->Lock(5000); // 5秒超时
if (ret != SUCCESS) {
std::cerr << "错误: 锁定共享内存失败, 错误码: " << ret << std::endl;
return false;
}
ret = m_pShareMem->WriteData(0, &sharedData, sizeof(ConfigCmdSharedData));
m_pShareMem->Unlock();
if (ret < 0) {
std::cerr << "错误: 写入共享内存失败, 错误码: " << ret << std::endl;
return false;
}
std::cout << "配置命令发送成功" << std::endl;
return true;
}
bool ConfigCmdParser::ParseCameraExpose(const std::vector<std::string>& params, ConfigCmdData& configData)
{
// 支持格式:
// expose 100 - 设置所有相机曝光时间为100微秒
// expose 1 100 - 设置相机1曝光时间为100微秒
if (params.empty()) {
std::cerr << "错误: expose 命令需要指定曝光时间" << std::endl;
std::cerr << "用法: expose <曝光时间> 或 expose <相机索引> <曝光时间>" << std::endl;
return false;
}
configData.cmdType = CONFIG_CMD_CAMERA_EXPOSE;
configData.cameraParam.cameraIndex = -1; // 默认所有相机
if (params.size() == 1) {
// 格式: expose 100
if (!IsNumber(params[0])) {
std::cerr << "错误: 曝光时间必须是数字: " << params[0] << std::endl;
return false;
}
configData.cameraParam.exposeTime = std::stod(params[0]);
}
else if (params.size() == 2) {
// 格式: expose 1 100
if (!IsNumber(params[0]) || !IsNumber(params[1])) {
std::cerr << "错误: 相机索引和曝光时间都必须是数字" << std::endl;
return false;
}
configData.cameraParam.cameraIndex = std::stoi(params[0]);
configData.cameraParam.exposeTime = std::stod(params[1]);
}
else {
std::cerr << "错误: expose 命令参数过多" << std::endl;
std::cerr << "用法: expose <曝光时间> 或 expose <相机索引> <曝光时间>" << std::endl;
return false;
}
// 参数验证
if (configData.cameraParam.exposeTime <= 0) {
std::cerr << "错误: 曝光时间必须大于0" << std::endl;
return false;
}
// 设置时间戳
std::string timestamp = GetCurrentTimestamp();
strncpy(configData.timestamp, timestamp.c_str(), sizeof(configData.timestamp) - 1);
std::cout << "解析相机曝光参数: 相机" << configData.cameraParam.cameraIndex
<< ", 曝光时间: " << configData.cameraParam.exposeTime << "微秒" << std::endl;
return true;
}
bool ConfigCmdParser::ParseCameraGain(const std::vector<std::string>& params, ConfigCmdData& configData)
{
// 支持格式:
// gain 2.5 - 设置所有相机增益为2.5
// gain 1 2.5 - 设置相机1增益为2.5
if (params.empty()) {
std::cerr << "错误: gain 命令需要指定增益值" << std::endl;
std::cerr << "用法: gain <增益值> 或 gain <相机索引> <增益值>" << std::endl;
return false;
}
configData.cmdType = CONFIG_CMD_CAMERA_GAIN;
configData.cameraParam.cameraIndex = -1; // 默认所有相机
if (params.size() == 1) {
// 格式: gain 2.5
if (!IsNumber(params[0])) {
std::cerr << "错误: 增益值必须是数字: " << params[0] << std::endl;
return false;
}
configData.cameraParam.gain = std::stod(params[0]);
}
else if (params.size() == 2) {
// 格式: gain 1 2.5
if (!IsNumber(params[0]) || !IsNumber(params[1])) {
std::cerr << "错误: 相机索引和增益值都必须是数字" << std::endl;
return false;
}
configData.cameraParam.cameraIndex = std::stoi(params[0]);
configData.cameraParam.gain = std::stod(params[1]);
}
else {
std::cerr << "错误: gain 命令参数过多" << std::endl;
std::cerr << "用法: gain <增益值> 或 gain <相机索引> <增益值>" << std::endl;
return false;
}
// 参数验证
if (configData.cameraParam.gain <= 0) {
std::cerr << "错误: 增益值必须大于0" << std::endl;
return false;
}
std::string timestamp = GetCurrentTimestamp();
strncpy(configData.timestamp, timestamp.c_str(), sizeof(configData.timestamp) - 1);
std::cout << "解析相机增益参数: 相机" << configData.cameraParam.cameraIndex
<< ", 增益: " << configData.cameraParam.gain << std::endl;
return true;
}
bool ConfigCmdParser::ParseAlgoParam(const std::vector<std::string>& params, ConfigCmdData& configData)
{
// 支持格式:
// algo threshold 0.5 - 设置算法参数threshold为0.5
if (params.size() != 2) {
std::cerr << "错误: algo 命令需要2个参数" << std::endl;
std::cerr << "用法: algo <参数名> <参数值>" << std::endl;
return false;
}
if (!IsNumber(params[1])) {
std::cerr << "错误: 算法参数值必须是数字: " << params[1] << std::endl;
return false;
}
configData.cmdType = CONFIG_CMD_ALGO_PARAM;
strncpy(configData.algoParam.paramName, params[0].c_str(), sizeof(configData.algoParam.paramName) - 1);
configData.algoParam.paramValue = std::stod(params[1]);
std::string timestamp = GetCurrentTimestamp();
strncpy(configData.timestamp, timestamp.c_str(), sizeof(configData.timestamp) - 1);
std::cout << "解析算法参数: " << configData.algoParam.paramName
<< " = " << configData.algoParam.paramValue << std::endl;
return true;
}
bool ConfigCmdParser::ParseCalibParam(const std::vector<std::string>& params, ConfigCmdData& configData)
{
// 简化实现,这里可以根据实际需求扩展
// 支持格式:
// calib <相机索引> - 触发指定相机的标定过程
if (params.size() != 1) {
std::cerr << "错误: calib 命令需要1个参数" << std::endl;
std::cerr << "用法: calib <相机索引>" << std::endl;
return false;
}
if (!IsNumber(params[0])) {
std::cerr << "错误: 相机索引必须是数字: " << params[0] << std::endl;
return false;
}
configData.cmdType = CONFIG_CMD_CALIB_PARAM;
configData.calibParam.cameraIndex = std::stoi(params[0]);
std::string timestamp = GetCurrentTimestamp();
strncpy(configData.timestamp, timestamp.c_str(), sizeof(configData.timestamp) - 1);
std::cout << "解析标定参数: 相机" << configData.calibParam.cameraIndex << std::endl;
std::cerr << "警告: 标定参数配置功能尚未完全实现" << std::endl;
return true;
}
bool ConfigCmdParser::ParseCameraFrameRate(const std::vector<std::string>& params, ConfigCmdData& configData)
{
// 支持格式:
// framerate 30 - 设置所有相机帧率为30fps
// framerate 1 30 - 设置相机1帧率为30fps
if (params.empty()) {
std::cerr << "错误: framerate 命令需要指定帧率值" << std::endl;
std::cerr << "用法: framerate <帧率> 或 framerate <相机索引> <帧率>" << std::endl;
return false;
}
configData.cmdType = CONFIG_CMD_CAMERA_FRAMERATE;
configData.cameraParam.cameraIndex = -1; // 默认所有相机
if (params.size() == 1) {
// 格式: framerate 30
if (!IsNumber(params[0])) {
std::cerr << "错误: 帧率值必须是数字: " << params[0] << std::endl;
return false;
}
configData.cameraParam.frameRate = std::stod(params[0]);
}
else if (params.size() == 2) {
// 格式: framerate 1 30
if (!IsNumber(params[0]) || !IsNumber(params[1])) {
std::cerr << "错误: 相机索引和帧率值都必须是数字" << std::endl;
return false;
}
configData.cameraParam.cameraIndex = std::stoi(params[0]);
configData.cameraParam.frameRate = std::stod(params[1]);
}
else {
std::cerr << "错误: framerate 命令参数过多" << std::endl;
std::cerr << "用法: framerate <帧率> 或 framerate <相机索引> <帧率>" << std::endl;
return false;
}
// 参数验证
if (configData.cameraParam.frameRate <= 0) {
std::cerr << "错误: 帧率值必须大于0" << std::endl;
return false;
}
// 设置时间戳
std::string timestamp = GetCurrentTimestamp();
strncpy(configData.timestamp, timestamp.c_str(), sizeof(configData.timestamp) - 1);
std::cout << "解析相机帧率参数: 相机" << configData.cameraParam.cameraIndex
<< ", 帧率: " << configData.cameraParam.frameRate << "fps" << std::endl;
return true;
}
bool ConfigCmdParser::ParseCameraSwing(const std::vector<std::string>& params, ConfigCmdData& configData)
{
// 支持格式:
// swing 10 0 180 - 设置所有相机摆动速度10角度0-180度
// swing 1 10 0 180 - 设置相机1摆动速度10角度0-180度
if (params.size() != 3 && params.size() != 4) {
std::cerr << "错误: swing 命令需要3个或4个参数" << std::endl;
std::cerr << "用法: swing <速度> <开始角度> <结束角度> 或 swing <相机索引> <速度> <开始角度> <结束角度>" << std::endl;
return false;
}
configData.cmdType = CONFIG_CMD_CAMERA_SWING;
configData.swingParam.cameraIndex = -1; // 默认所有相机
std::vector<std::string> swingValues;
if (params.size() == 3) {
// 格式: swing 10 0 180
swingValues = params;
}
else if (params.size() == 4) {
// 格式: swing 1 10 0 180
if (!IsNumber(params[0])) {
std::cerr << "错误: 相机索引必须是数字: " << params[0] << std::endl;
return false;
}
configData.swingParam.cameraIndex = std::stoi(params[0]);
swingValues = std::vector<std::string>(params.begin() + 1, params.end());
}
// 验证所有摆动参数都是数字
for (size_t i = 0; i < swingValues.size(); ++i) {
if (!IsNumber(swingValues[i])) {
std::cerr << "错误: 摆动参数必须是数字: " << swingValues[i] << std::endl;
return false;
}
}
// 解析摆动参数
configData.swingParam.swingSpeed = std::stod(swingValues[0]);
configData.swingParam.startAngle = std::stod(swingValues[1]);
configData.swingParam.stopAngle = std::stod(swingValues[2]);
// 参数验证
if (configData.swingParam.swingSpeed <= 0) {
std::cerr << "错误: 摆动速度必须大于0" << std::endl;
return false;
}
if (configData.swingParam.startAngle >= configData.swingParam.stopAngle) {
std::cerr << "错误: 开始角度必须小于结束角度" << std::endl;
return false;
}
// 设置时间戳
std::string timestamp = GetCurrentTimestamp();
strncpy(configData.timestamp, timestamp.c_str(), sizeof(configData.timestamp) - 1);
std::cout << "解析相机摆动参数: 相机" << configData.swingParam.cameraIndex
<< ", 速度: " << configData.swingParam.swingSpeed
<< ", 角度: " << configData.swingParam.startAngle
<< "-" << configData.swingParam.stopAngle << std::endl;
return true;
}
void ConfigCmdParser::ShowHelp()
{
std::cout << "GrabBag 配置命令行工具" << std::endl;
std::cout << "用法: grabbag [选项] -c <配置类型> <参数...>" << std::endl;
std::cout << std::endl;
std::cout << "选项:" << std::endl;
std::cout << " -h, --help 显示帮助信息" << std::endl;
std::cout << " -v, --version 显示版本信息" << std::endl;
std::cout << " -c, --config 设置配置参数" << std::endl;
std::cout << std::endl;
std::cout << "配置参数格式:" << std::endl;
std::cout << " 相机曝光:" << std::endl;
std::cout << " grabbag -c expose <曝光时间> - 设置所有相机曝光时间(微秒)" << std::endl;
std::cout << " grabbag -c expose <相机索引> <曝光时间> - 设置指定相机曝光时间" << std::endl;
std::cout << " 示例: grabbag -c expose 100" << std::endl;
std::cout << " grabbag -c expose 1 150" << std::endl;
std::cout << std::endl;
std::cout << " 相机增益:" << std::endl;
std::cout << " grabbag -c gain <增益值> - 设置所有相机增益" << std::endl;
std::cout << " grabbag -c gain <相机索引> <增益值> - 设置指定相机增益" << std::endl;
std::cout << " 示例: grabbag -c gain 2.5" << std::endl;
std::cout << " grabbag -c gain 1 3.0" << std::endl;
std::cout << std::endl;
std::cout << " 相机帧率:" << std::endl;
std::cout << " grabbag -c framerate <帧率> - 设置所有相机帧率(fps)" << std::endl;
std::cout << " grabbag -c framerate <相机索引> <帧率> - 设置指定相机帧率" << std::endl;
std::cout << " 示例: grabbag -c framerate 30" << std::endl;
std::cout << " grabbag -c framerate 1 25" << std::endl;
std::cout << std::endl;
std::cout << " 摆动参数:" << std::endl;
std::cout << " grabbag -c swing <速度> <开始角度> <结束角度> - 设置所有相机摆动参数" << std::endl;
std::cout << " grabbag -c swing <相机索引> <速度> <开始角度> <结束角度> - 设置指定相机摆动参数" << std::endl;
std::cout << " 示例: grabbag -c swing 10 0 180" << std::endl;
std::cout << " grabbag -c swing 1 15 -45 45" << std::endl;
std::cout << std::endl;
std::cout << " 算法参数:" << std::endl;
std::cout << " grabbag -c algo <参数名> <值> - 设置算法参数" << std::endl;
std::cout << " 示例: grabbag -c algo threshold 0.5" << std::endl;
std::cout << " grabbag -c algo windowSize 10" << std::endl;
std::cout << std::endl;
std::cout << " 标定参数:" << std::endl;
std::cout << " grabbag -c calib <相机索引> - 触发指定相机标定" << std::endl;
std::cout << " 示例: grabbag -c calib 1" << std::endl;
std::cout << std::endl;
}
void ConfigCmdParser::ShowVersion()
{
std::cout << "GrabBag 配置命令行工具 v1.0.0" << std::endl;
std::cout << "版权所有 (C) 2024" << std::endl;
}
bool ConfigCmdParser::InitializeSharedMemory()
{
if (m_pShareMem) {
return true; // 已经初始化
}
m_pShareMem = CreateShareMemInstance();
if (!m_pShareMem) {
return false;
}
// 尝试打开已存在的共享内存,如果不存在则创建
int ret = m_pShareMem->CreateOrOpen(CONFIG_CMD_SHARED_MEM_NAME, CONFIG_CMD_SHARED_MEM_SIZE, false);
if (ret != SUCCESS) {
// 如果打开失败,尝试创建新的
ret = m_pShareMem->CreateOrOpen(CONFIG_CMD_SHARED_MEM_NAME, CONFIG_CMD_SHARED_MEM_SIZE, true);
if (ret != SUCCESS) {
CleanupSharedMemory();
return false;
}
}
// 映射内存
void* mappedAddr = m_pShareMem->MapView();
if (!mappedAddr) {
CleanupSharedMemory();
return false;
}
return true;
}
void ConfigCmdParser::CleanupSharedMemory()
{
if (m_pShareMem) {
m_pShareMem->UnmapView();
m_pShareMem->Close();
DestroyShareMemInstance(m_pShareMem);
m_pShareMem = nullptr;
}
}
std::vector<std::string> ConfigCmdParser::SplitString(const std::string& str, char delimiter)
{
std::vector<std::string> result;
std::stringstream ss(str);
std::string item;
while (std::getline(ss, item, delimiter)) {
result.push_back(item);
}
return result;
}
bool ConfigCmdParser::IsNumber(const std::string& str)
{
if (str.empty()) return false;
std::string::const_iterator it = str.begin();
// 允许负号
if (*it == '-') ++it;
bool hasDigit = false;
bool hasDot = false;
while (it != str.end()) {
if (std::isdigit(*it)) {
hasDigit = true;
}
else if (*it == '.' && !hasDot) {
hasDot = true;
}
else {
return false;
}
++it;
}
return hasDigit;
}
std::string ConfigCmdParser::GetCurrentTimestamp()
{
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
return ss.str();
}