GrabBag/GrabBagConfigCmd/ConfigCmdParser.cpp

547 lines
19 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 "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();
}