diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs b/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs index a040455..7f577ba 100644 --- a/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs @@ -43,6 +43,9 @@ namespace Test this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel(); this.groupBox1 = new System.Windows.Forms.GroupBox(); this.txtLog = new System.Windows.Forms.TextBox(); + this.lblIpAddress = new System.Windows.Forms.Label(); + this.txtIpAddress = new System.Windows.Forms.TextBox(); + this.btnSetIP = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.LedImage)).BeginInit(); this.statusStrip1.SuspendLayout(); this.groupBox1.SuspendLayout(); @@ -79,82 +82,109 @@ namespace Test this.btnSetConfigFile.UseVisualStyleBackColor = true; this.btnSetConfigFile.Click += new System.EventHandler(this.btnSetConfigFile_Click); // + // lblIpAddress + // + this.lblIpAddress.AutoSize = true; + this.lblIpAddress.Location = new System.Drawing.Point(608, 125); + this.lblIpAddress.Name = "lblIpAddress"; + this.lblIpAddress.Size = new System.Drawing.Size(65, 12); + this.lblIpAddress.TabIndex = 3; + this.lblIpAddress.Text = "IP地址:"; + // + // txtIpAddress + // + this.txtIpAddress.Location = new System.Drawing.Point(675, 122); + this.txtIpAddress.Name = "txtIpAddress"; + this.txtIpAddress.Size = new System.Drawing.Size(100, 21); + this.txtIpAddress.TabIndex = 4; + this.txtIpAddress.Text = "192.168.100.10"; + // + // btnSetIP + // + this.btnSetIP.Location = new System.Drawing.Point(608, 140); + this.btnSetIP.Name = "btnSetIP"; + this.btnSetIP.Size = new System.Drawing.Size(111, 31); + this.btnSetIP.TabIndex = 5; + this.btnSetIP.Text = "3. 设置IP地址"; + this.btnSetIP.UseVisualStyleBackColor = true; + this.btnSetIP.Click += new System.EventHandler(this.btnSetIP_Click); + // // btnStartCamera // - this.btnStartCamera.Location = new System.Drawing.Point(608, 140); + this.btnStartCamera.Location = new System.Drawing.Point(608, 177); this.btnStartCamera.Name = "btnStartCamera"; this.btnStartCamera.Size = new System.Drawing.Size(111, 31); - this.btnStartCamera.TabIndex = 3; - this.btnStartCamera.Text = "3. 启动摄像头"; + this.btnStartCamera.TabIndex = 6; + this.btnStartCamera.Text = "4. 启动摄像头"; this.btnStartCamera.UseVisualStyleBackColor = true; this.btnStartCamera.Click += new System.EventHandler(this.btnStartCamera_Click); // // btnStartCapture // - this.btnStartCapture.Location = new System.Drawing.Point(608, 191); + this.btnStartCapture.Location = new System.Drawing.Point(608, 228); this.btnStartCapture.Name = "btnStartCapture"; this.btnStartCapture.Size = new System.Drawing.Size(111, 31); - this.btnStartCapture.TabIndex = 4; - this.btnStartCapture.Text = "4. 开始捕获"; + this.btnStartCapture.TabIndex = 7; + this.btnStartCapture.Text = "5. 开始捕获"; this.btnStartCapture.UseVisualStyleBackColor = true; this.btnStartCapture.Click += new System.EventHandler(this.btnStartCapture_Click); // // btnDetectLeds // - this.btnDetectLeds.Location = new System.Drawing.Point(608, 242); + this.btnDetectLeds.Location = new System.Drawing.Point(608, 279); this.btnDetectLeds.Name = "btnDetectLeds"; this.btnDetectLeds.Size = new System.Drawing.Size(111, 31); - this.btnDetectLeds.TabIndex = 5; - this.btnDetectLeds.Text = "5. LED识别"; + this.btnDetectLeds.TabIndex = 8; + this.btnDetectLeds.Text = "6. LED识别"; this.btnDetectLeds.UseVisualStyleBackColor = true; this.btnDetectLeds.Click += new System.EventHandler(this.btnDetectLeds_Click); // // btnGetLedStatuses // - this.btnGetLedStatuses.Location = new System.Drawing.Point(608, 293); + this.btnGetLedStatuses.Location = new System.Drawing.Point(608, 330); this.btnGetLedStatuses.Name = "btnGetLedStatuses"; this.btnGetLedStatuses.Size = new System.Drawing.Size(111, 31); - this.btnGetLedStatuses.TabIndex = 6; - this.btnGetLedStatuses.Text = "6. 状态查询"; + this.btnGetLedStatuses.TabIndex = 9; + this.btnGetLedStatuses.Text = "7. 状态查询"; this.btnGetLedStatuses.UseVisualStyleBackColor = true; this.btnGetLedStatuses.Click += new System.EventHandler(this.btnGetLedStatuses_Click); // // btnShowRegionEditor // - this.btnShowRegionEditor.Location = new System.Drawing.Point(608, 344); + this.btnShowRegionEditor.Location = new System.Drawing.Point(608, 381); this.btnShowRegionEditor.Name = "btnShowRegionEditor"; this.btnShowRegionEditor.Size = new System.Drawing.Size(111, 31); - this.btnShowRegionEditor.TabIndex = 7; - this.btnShowRegionEditor.Text = "7. 区域编辑器"; + this.btnShowRegionEditor.TabIndex = 10; + this.btnShowRegionEditor.Text = "8. 区域编辑器"; this.btnShowRegionEditor.UseVisualStyleBackColor = true; this.btnShowRegionEditor.Click += new System.EventHandler(this.btnShowRegionEditor_Click); // // btnShutdown // - this.btnShutdown.Location = new System.Drawing.Point(608, 395); + this.btnShutdown.Location = new System.Drawing.Point(608, 432); this.btnShutdown.Name = "btnShutdown"; this.btnShutdown.Size = new System.Drawing.Size(111, 31); - this.btnShutdown.TabIndex = 8; - this.btnShutdown.Text = "8. 关闭"; + this.btnShutdown.TabIndex = 11; + this.btnShutdown.Text = "9. 关闭"; this.btnShutdown.UseVisualStyleBackColor = true; this.btnShutdown.Click += new System.EventHandler(this.btnShutdown_Click); // // btnStopCapture // - this.btnStopCapture.Location = new System.Drawing.Point(725, 191); + this.btnStopCapture.Location = new System.Drawing.Point(725, 228); this.btnStopCapture.Name = "btnStopCapture"; this.btnStopCapture.Size = new System.Drawing.Size(63, 31); - this.btnStopCapture.TabIndex = 9; + this.btnStopCapture.TabIndex = 12; this.btnStopCapture.Text = "停止"; this.btnStopCapture.UseVisualStyleBackColor = true; this.btnStopCapture.Click += new System.EventHandler(this.btnStopCapture_Click); // // btnStopCamera // - this.btnStopCamera.Location = new System.Drawing.Point(725, 140); + this.btnStopCamera.Location = new System.Drawing.Point(725, 177); this.btnStopCamera.Name = "btnStopCamera"; this.btnStopCamera.Size = new System.Drawing.Size(63, 31); - this.btnStopCamera.TabIndex = 10; + this.btnStopCamera.TabIndex = 13; this.btnStopCamera.Text = "停止"; this.btnStopCamera.UseVisualStyleBackColor = true; this.btnStopCamera.Click += new System.EventHandler(this.btnStopCamera_Click); @@ -210,6 +240,9 @@ namespace Test this.Controls.Add(this.btnDetectLeds); this.Controls.Add(this.btnStartCapture); this.Controls.Add(this.btnStartCamera); + this.Controls.Add(this.btnSetIP); + this.Controls.Add(this.txtIpAddress); + this.Controls.Add(this.lblIpAddress); this.Controls.Add(this.btnSetConfigFile); this.Controls.Add(this.btnInitialize); this.Controls.Add(this.LedImage); @@ -243,5 +276,8 @@ namespace Test private System.Windows.Forms.ToolStripStatusLabel lblStatus; private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.TextBox txtLog; + private System.Windows.Forms.Label lblIpAddress; + private System.Windows.Forms.TextBox txtIpAddress; + private System.Windows.Forms.Button btnSetIP; } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.cs b/Windows/CS/Framework4.0/XCamera/Test/Form1.cs index 7400e9e..8eeb1a5 100644 --- a/Windows/CS/Framework4.0/XCamera/Test/Form1.cs +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.cs @@ -3,10 +3,13 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; +using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Windows.Forms; +using ErrorEventArgs = XCamera.Models.ErrorEventArgs; +using InfoEventArgs = XCamera.Models.InfoEventArgs; using XCamera.Models; namespace Test @@ -16,6 +19,7 @@ namespace Test private bool _isInitialized = false; private bool _isConnected = false; private bool _isCapturing = false; + private string _cameraIpAddress = "192.168.100.10"; // 默认IP地址 public Form1() { @@ -44,6 +48,8 @@ namespace Test global::XCamera.XCamera.ConnectionStateChanged += OnConnectionStateChanged; global::XCamera.XCamera.CaptureStateChanged += OnCaptureStateChanged; global::XCamera.XCamera.ErrorOccurred += OnErrorOccurred; + global::XCamera.XCamera.InfoOccurred += OnInfoOccurred; + global::XCamera.XCamera.ImageCaptured += OnImageCaptured; } /// @@ -53,28 +59,18 @@ namespace Test { try { - LogMessage("正在初始化..."); + LogMessage("正在初始化SDK..."); - // 使用默认配置文件路径 - string configPath = System.IO.Path.Combine(Application.StartupPath, "config", "sample_config.json"); - - if (global::XCamera.XCamera.Initialize(configPath)) + // 初始化SDK(不加载配置文件) + if (global::XCamera.XCamera.Initialize()) { _isInitialized = true; - LogMessage("初始化成功!"); - - // 显示配置信息 - var config = global::XCamera.XCamera.GetCurrentConfig(); - if (config != null) - { - LogMessage($"摄像头IP: {config.IpAddress}"); - LogMessage($"TCP端口: {config.TcpPort}"); - LogMessage($"LED区域数: {config.LedRegions.Count}"); - } + LogMessage("SDK初始化成功!"); + LogMessage("现在可以设置配置文件或启动摄像头"); } else { - LogMessage("初始化失败!"); + LogMessage("SDK初始化失败!"); } } catch (Exception ex) @@ -92,42 +88,91 @@ namespace Test { try { - using (OpenFileDialog openFileDialog = new OpenFileDialog()) + using (FolderBrowserDialog folderDialog = new FolderBrowserDialog()) { - openFileDialog.Filter = "JSON文件|*.json|所有文件|*.*"; - openFileDialog.Title = "选择配置文件"; - - if (openFileDialog.ShowDialog() == DialogResult.OK) + // 设置默认路径为程序目录下的config文件夹 + string defaultConfigPath = Path.Combine(Application.StartupPath, "config"); + if (Directory.Exists(defaultConfigPath)) { - LogMessage($"正在加载配置文件: {openFileDialog.FileName}"); + folderDialog.SelectedPath = defaultConfigPath; + } + else + { + folderDialog.SelectedPath = Application.StartupPath; + } + + folderDialog.Description = "选择配置目录"; + folderDialog.ShowNewFolderButton = false; + + if (folderDialog.ShowDialog() == DialogResult.OK) + { + LogMessage($"正在设置配置目录: {folderDialog.SelectedPath}"); - if (global::XCamera.XCamera.SetConfigFile(openFileDialog.FileName)) + if (global::XCamera.XCamera.SetConfigPath(folderDialog.SelectedPath)) { - LogMessage("配置文件加载成功!"); + LogMessage("配置目录设置成功!"); // 显示配置信息 var config = global::XCamera.XCamera.GetCurrentConfig(); if (config != null) { - LogMessage($"摄像头IP: {config.IpAddress}"); LogMessage($"LED区域数: {config.LedRegions.Count}"); + LogMessage($"TCP端口: {config.TcpPort}"); + LogMessage($"用户名: {config.Username}"); + LogMessage($"通道: {config.Channel}"); } } else { - LogMessage("配置文件加载失败!"); + LogMessage("配置目录设置失败!"); } } } } catch (Exception ex) { - LogMessage($"配置文件加载错误: {ex.Message}"); + LogMessage($"配置目录设置错误: {ex.Message}"); } } /// - /// 3. 启动摄像头 + /// 3. 设置IP地址 + /// + private void btnSetIP_Click(object sender, EventArgs e) + { + try + { + if (!_isInitialized) + { + LogMessage("请先初始化!"); + return; + } + + string ipAddress = txtIpAddress.Text.Trim(); + if (string.IsNullOrEmpty(ipAddress)) + { + LogMessage("IP地址不能为空!"); + return; + } + + if (global::XCamera.XCamera.SetIP(ipAddress)) + { + _cameraIpAddress = ipAddress; + LogMessage($"IP地址设置成功: {ipAddress}"); + } + else + { + LogMessage($"IP地址设置失败: {ipAddress}"); + } + } + catch (Exception ex) + { + LogMessage($"设置IP地址错误: {ex.Message}"); + } + } + + /// + /// 5. 启动摄像头 /// private void btnStartCamera_Click(object sender, EventArgs e) { @@ -159,7 +204,7 @@ namespace Test } /// - /// 4. 开始捕获图像 + /// 6. 开始捕获图像 /// private void btnStartCapture_Click(object sender, EventArgs e) { @@ -197,7 +242,7 @@ namespace Test } /// - /// 5. LED灯识别 + /// 7. LED灯识别 /// private void btnDetectLeds_Click(object sender, EventArgs e) { @@ -229,7 +274,7 @@ namespace Test } /// - /// 6. 状态查询 + /// 8. 状态查询 /// private void btnGetLedStatuses_Click(object sender, EventArgs e) { @@ -250,6 +295,9 @@ namespace Test { LogMessage($" {status.GetStatusDescription()}"); } + + // 显示图像 + DisplayLedImage(statuses); } catch (Exception ex) { @@ -258,7 +306,7 @@ namespace Test } /// - /// 7. 区域设置窗口 + /// 9. 区域编辑器 /// private void btnShowRegionEditor_Click(object sender, EventArgs e) { @@ -275,37 +323,47 @@ namespace Test } /// - /// 8. 资源释放 + /// 9. 关闭 /// private void btnShutdown_Click(object sender, EventArgs e) { try { - LogMessage("正在释放资源..."); + LogMessage("正在关闭..."); + // 停止捕获 if (_isCapturing) { global::XCamera.XCamera.StopCapture(); + LogMessage("捕获已停止"); } + // 停止摄像头 if (_isConnected) { global::XCamera.XCamera.StopCamera(); + LogMessage("摄像头已停止"); } - global::XCamera.XCamera.Shutdown(); + // 关闭SDK + if (_isInitialized) + { + global::XCamera.XCamera.Shutdown(); + LogMessage("SDK已关闭"); + } - _isInitialized = false; - _isConnected = false; - _isCapturing = false; - - LogMessage("资源已释放"); + LogMessage("关闭完成!"); } catch (Exception ex) { - LogMessage($"资源释放错误: {ex.Message}"); + LogMessage($"关闭错误: {ex.Message}"); } + // 重置状态 + _isInitialized = false; + _isConnected = false; + _isCapturing = false; + UpdateUI(); } @@ -318,13 +376,14 @@ namespace Test { if (!_isCapturing) { - LogMessage("当前未在捕获中!"); + LogMessage("当前未在捕获状态!"); return; } LogMessage("正在停止捕获..."); + global::XCamera.XCamera.StopCapture(); - LogMessage("捕获已停止"); + LogMessage("停止捕获成功!"); } catch (Exception ex) { @@ -343,19 +402,14 @@ namespace Test { if (!_isConnected) { - LogMessage("摄像头未连接!"); + LogMessage("当前未连接摄像头!"); return; } LogMessage("正在停止摄像头..."); - if (_isCapturing) - { - global::XCamera.XCamera.StopCapture(); - } - global::XCamera.XCamera.StopCamera(); - LogMessage("摄像头已停止"); + LogMessage("停止摄像头成功!"); } catch (Exception ex) { @@ -376,10 +430,23 @@ namespace Test return; } - LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] LED状态更新:"); - foreach (var status in e.Statuses) + // 更新状态 + _isConnected = global::XCamera.XCamera.IsConnected; + _isCapturing = global::XCamera.XCamera.IsCapturing; + + UpdateUI(); + + // 显示LED状态 + if (e.Statuses.Count > 0) { - LogMessage($" {status.GetStatusDescription()}"); + LogMessage($"LED状态更新 ({e.Statuses.Count} 个):"); + foreach (var status in e.Statuses) + { + LogMessage($" {status.GetStatusDescription()}"); + } + + // 显示图像 + DisplayLedImage(e.Statuses); } } @@ -395,8 +462,16 @@ namespace Test } _isConnected = e.IsConnected; - LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] 摄像头连接状态: {(e.IsConnected ? "已连接" : "已断开")}"); UpdateUI(); + + if (e.IsConnected) + { + LogMessage("摄像头已连接"); + } + else + { + LogMessage("摄像头已断开"); + } } /// @@ -411,8 +486,16 @@ namespace Test } _isCapturing = e.IsCapturing; - LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] 图像捕获状态: {(e.IsCapturing ? "开始捕获" : "停止捕获")}"); UpdateUI(); + + if (e.IsCapturing) + { + LogMessage("开始捕获图像"); + } + else + { + LogMessage("停止捕获图像"); + } } /// @@ -430,19 +513,123 @@ namespace Test } /// - /// 日志消息 + /// 信息事件处理 /// - private void LogMessage(string message) + private void OnInfoOccurred(object sender, InfoEventArgs e) { if (InvokeRequired) { - BeginInvoke(new Action(LogMessage), message); + BeginInvoke(new Action(OnInfoOccurred), sender, e); return; } - string timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); - txtLog.AppendText($"[{timestamp}] {message}" + Environment.NewLine); - txtLog.ScrollToCaret(); + LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] {e.InfoMessage}"); + } + + /// + /// 图像捕获事件处理 + /// + private void OnImageCaptured(object sender, ImageCapturedEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new Action(OnImageCaptured), sender, e); + return; + } + + try + { + // 显示捕获的图像 + if (e.Image != null) + { + // 清理之前的图像 + if (LedImage.Image != null) + { + var oldImage = LedImage.Image; + LedImage.Image = null; + oldImage.Dispose(); + } + + // 如果LED状态为空,直接显示原图 + if (e.LedStatuses == null || e.LedStatuses.Count == 0) + { + LedImage.Image = (System.Drawing.Image)e.Image.Clone(); + } + else + { + // 创建带LED区域标注的图像 + var annotatedImage = CreateAnnotatedImage(e.Image, e.LedStatuses); + LedImage.Image = annotatedImage; + } + + // 调整显示模式 + LedImage.SizeMode = PictureBoxSizeMode.Zoom; + } + } + catch (Exception ex) + { + LogMessage($"显示图像失败: {ex.Message}"); + } + } + + /// + /// 创建带LED区域标注的图像 + /// + private System.Drawing.Image CreateAnnotatedImage(System.Drawing.Image originalImage, List ledStatuses) + { + // 创建位图副本 + var bitmap = new Bitmap(originalImage.Width, originalImage.Height); + using (var g = Graphics.FromImage(bitmap)) + { + // 绘制原始图像 + g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height); + + // 绘制LED状态信息 + for (int i = 0; i < ledStatuses.Count; i++) + { + var status = ledStatuses[i]; + + // 根据状态设置颜色 + Color ledColor = GetLedColor(status); + + // 计算LED显示位置 + int ledSize = 40; + int spacing = 60; + int startX = 20; + int startY = 20; + + int x = startX + (i % 5) * spacing; + int y = startY + (i / 5) * spacing; + + // 绘制LED圆形 + Rectangle ledRect = new Rectangle(x, y, ledSize, ledSize); + using (var ledBrush = new SolidBrush(ledColor)) + { + g.FillEllipse(ledBrush, ledRect); + } + + // 绘制LED边框 + using (var borderPen = new Pen(Color.Black, 2)) + { + g.DrawEllipse(borderPen, ledRect); + } + + // 绘制标签 + using (var font = new Font("Arial", 8)) + using (var textBrush = new SolidBrush(Color.White)) + { + string label = status.RegionName; + g.DrawString(label, font, textBrush, x, y + ledSize + 2); + + string stateText = status.State.ToString(); + if (status.IsBlinking) + stateText = "Blinking"; + g.DrawString(stateText, font, textBrush, x, y + ledSize + 15); + } + } + } + + return bitmap; } /// @@ -552,11 +739,7 @@ namespace Test { try { - // 避免在设计模式下执行外部代码 - if (DesignMode) - return; - - // 确保释放资源 + // 确保在关闭时清理资源 if (_isCapturing) { global::XCamera.XCamera.StopCapture(); @@ -572,10 +755,27 @@ namespace Test global::XCamera.XCamera.Shutdown(); } } - catch + catch (Exception ex) { // 忽略关闭时的错误 + System.Diagnostics.Debug.WriteLine($"关闭错误: {ex.Message}"); } } + + /// + /// 日志消息 + /// + private void LogMessage(string message) + { + if (InvokeRequired) + { + BeginInvoke(new Action(LogMessage), message); + return; + } + + string timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); + txtLog.AppendText($"[{timestamp}] {message}" + Environment.NewLine); + txtLog.ScrollToCaret(); + } } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Test.csproj b/Windows/CS/Framework4.0/XCamera/Test/Test.csproj index 7a019ee..99a0f1b 100644 --- a/Windows/CS/Framework4.0/XCamera/Test/Test.csproj +++ b/Windows/CS/Framework4.0/XCamera/Test/Test.csproj @@ -42,6 +42,7 @@ + diff --git a/Windows/CS/Framework4.0/XCamera/Test/XCloudSDK.ini b/Windows/CS/Framework4.0/XCamera/Test/XCloudSDK.ini new file mode 100644 index 0000000..0b1ae5a --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/XCloudSDK.ini @@ -0,0 +1,14 @@ +{ + "Server": { + "SID": "98FE3E132FD026031709254777EA-XCloudSDK" + }, + "Log": { + "UIEnbale": 0, + "FileEnbale": 1, + "NetEnbale": 0, + "ServerIP": "", + "Port": 0, + "LogLevel": 8, + "BackupDays": 7 + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs index 8ad8c0a..bed5e32 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs @@ -85,9 +85,15 @@ namespace XCamera.Core /// 是否成功初始化 public bool Initialize(CameraConfig config) { - if (config == null || !config.IsValid) + if (config == null) { - throw new ArgumentException("摄像头配置无效"); + throw new ArgumentException("摄像头配置为空"); + } + + if (!config.IsValid) + { + string validationErrors = GetConfigValidationErrors(config); + throw new ArgumentException($"摄像头配置无效: {validationErrors}"); } lock (_lockObject) @@ -98,6 +104,34 @@ namespace XCamera.Core return true; } + /// + /// 获取配置验证错误信息 + /// + private string GetConfigValidationErrors(CameraConfig config) + { + var errors = new System.Collections.Generic.List(); + + if (config.TcpPort <= 0 || config.TcpPort > 65535) + errors.Add($"TCP端口无效: {config.TcpPort}"); + + if (config.HttpPort <= 0 || config.HttpPort > 65535) + errors.Add($"HTTP端口无效: {config.HttpPort}"); + + if (config.OnvifPort <= 0 || config.OnvifPort > 65535) + errors.Add($"ONVIF端口无效: {config.OnvifPort}"); + + if (string.IsNullOrEmpty(config.Username)) + errors.Add("用户名为空"); + + if (config.Channel < 0) + errors.Add($"通道号无效: {config.Channel}"); + + if (config.LedRegions == null) + errors.Add("LED区域列表为空"); + + return string.Join(", ", errors); + } + /// /// 连接到摄像头 /// diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs index 114a412..a0466bf 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs @@ -31,7 +31,6 @@ namespace XCamera.Core { return _config != null ? new CameraConfig { - IpAddress = _config.IpAddress, TcpPort = _config.TcpPort, HttpPort = _config.HttpPort, OnvifPort = _config.OnvifPort, @@ -181,10 +180,7 @@ namespace XCamera.Core lock (_lockObject) { - if (_config != null) - { - _config.IpAddress = ipAddress; - } + // IP地址现在存储在XCameraManager中,不在配置里 } OnConfigChanged(); @@ -309,10 +305,6 @@ namespace XCamera.Core // 简单的JSON解析实现 // 这里使用基本的字符串解析,实际项目中建议使用Newtonsoft.Json - // 提取IP地址 - var ipMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""IpAddress""\s*:\s*""([^""]+)"""); - if (ipMatch.Success) config.IpAddress = ipMatch.Groups[1].Value; - // 提取端口 var tcpPortMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""TcpPort""\s*:\s*(\d+)"); if (tcpPortMatch.Success) config.TcpPort = int.Parse(tcpPortMatch.Groups[1].Value); @@ -421,7 +413,6 @@ namespace XCamera.Core { var sb = new StringBuilder(); sb.AppendLine("{"); - sb.AppendLine($" \"IpAddress\": \"{config.IpAddress}\","); sb.AppendLine($" \"TcpPort\": {config.TcpPort},"); sb.AppendLine($" \"HttpPort\": {config.HttpPort},"); sb.AppendLine($" \"OnvifPort\": {config.OnvifPort},"); @@ -457,13 +448,12 @@ namespace XCamera.Core /// /// 创建默认配置 /// - private bool CreateDefaultConfig(string configFilePath) + public bool CreateDefaultConfig(string configFilePath) { try { var defaultConfig = new CameraConfig { - IpAddress = "192.168.100.10", TcpPort = 34567, HttpPort = 8888, OnvifPort = 8899, diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs index 8d5838a..3331e24 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/XCloudSdkWrapper.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Runtime.InteropServices; namespace XCamera.Core @@ -8,6 +9,30 @@ namespace XCamera.Core /// public static class XCloudSdkWrapper { + // Windows API - 设置DLL搜索路径 + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool SetDllDirectory(string lpPathName); + + /// + /// 设置XCloudSDK.dll的搜索路径 + /// + /// DLL所在目录路径 + /// 是否成功 + public static bool SetDllSearchPath(string dllPath) + { + try + { + if (Directory.Exists(dllPath)) + { + return SetDllDirectory(dllPath); + } + return false; + } + catch + { + return false; + } + } // 回调函数委托 public delegate int XCloudSdkMessageCallback( int hObject, diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/CameraConfig.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/CameraConfig.cs index 12a2515..2d65ce6 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/CameraConfig.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/CameraConfig.cs @@ -8,11 +8,6 @@ namespace XCamera.Models /// public class CameraConfig { - /// - /// IP地址 - /// - public string IpAddress { get; set; } - /// /// TCP端口(固定34567) /// @@ -55,13 +50,10 @@ namespace XCamera.Models { get { - return !string.IsNullOrEmpty(IpAddress) && - IsValidIpAddress(IpAddress) && - TcpPort > 0 && TcpPort <= 65535 && + return TcpPort > 0 && TcpPort <= 65535 && HttpPort > 0 && HttpPort <= 65535 && OnvifPort > 0 && OnvifPort <= 65535 && !string.IsNullOrEmpty(Username) && - !string.IsNullOrEmpty(Password) && Channel >= 0 && LedRegions != null; } @@ -72,7 +64,6 @@ namespace XCamera.Models /// public CameraConfig() { - IpAddress = "192.168.100.10"; TcpPort = 34567; HttpPort = 8888; OnvifPort = 8899; @@ -104,11 +95,11 @@ namespace XCamera.Models } /// - /// 获取设备ID(基于IP地址) + /// 获取设备ID(基于配置信息) /// public string GetDeviceId() { - return $"DEV_{IpAddress.Replace(".", "_")}"; + return $"DEV_{TcpPort}_{Channel}"; } /// @@ -116,7 +107,7 @@ namespace XCamera.Models /// public string GetConnectionString() { - return $"{{\"IP\":\"{IpAddress}\",\"Port\":{TcpPort}}}"; + return $"{{\"Port\":{TcpPort}}}"; } } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs index 64a807a..cec3eaf 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs @@ -59,6 +59,25 @@ namespace XCamera.Models } } + /// + /// 信息事件参数 + /// + public class InfoEventArgs : EventArgs + { + /// + /// 信息消息 + /// + public string InfoMessage { get; set; } + + /// + /// 构造函数 + /// + public InfoEventArgs(string infoMessage) + { + InfoMessage = infoMessage; + } + } + /// /// 错误事件参数 /// @@ -77,4 +96,49 @@ namespace XCamera.Models ErrorMessage = errorMessage; } } + + /// + /// 图像捕获事件参数 + /// + public class ImageCapturedEventArgs : EventArgs + { + /// + /// 捕获的图像 + /// + public System.Drawing.Image Image { get; set; } + + /// + /// 图像文件名(临时文件) + /// + public string ImageFilePath { get; set; } + + /// + /// 捕获时间 + /// + public DateTime CaptureTime { get; set; } + + /// + /// LED状态列表(可选) + /// + public System.Collections.Generic.List LedStatuses { get; set; } + + /// + /// 构造函数 + /// + public ImageCapturedEventArgs(System.Drawing.Image image, string imageFilePath) + { + Image = image; + ImageFilePath = imageFilePath; + CaptureTime = DateTime.Now; + LedStatuses = new System.Collections.Generic.List(); + } + + /// + /// 带LED状态的构造函数 + /// + public ImageCapturedEventArgs(System.Drawing.Image image, string imageFilePath, System.Collections.Generic.List ledStatuses) : this(image, imageFilePath) + { + LedStatuses = ledStatuses ?? new System.Collections.Generic.List(); + } + } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs index 9af7e5c..6f18209 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs @@ -60,6 +60,24 @@ namespace XCamera remove { Manager.CaptureStateChanged -= value; } } + /// + /// 图像捕获事件 + /// + public static event EventHandler ImageCaptured + { + add { Manager.ImageCaptured += value; } + remove { Manager.ImageCaptured -= value; } + } + + /// + /// 信息事件 + /// + public static event EventHandler InfoOccurred + { + add { Manager.InfoOccurred += value; } + remove { Manager.InfoOccurred -= value; } + } + /// /// 错误事件 /// @@ -104,13 +122,23 @@ namespace XCamera } /// - /// 2. 设置配置文件路径 + /// 2. 设置配置目录路径 /// - /// 配置文件路径 + /// 配置目录路径 /// 是否成功设置 - public static bool SetConfigFile(string configFilePath) + public static bool SetConfigPath(string configPath) { - return Manager.SetConfigFile(configFilePath); + return Manager.SetConfigPath(configPath); + } + + /// + /// 2.1 设置摄像头IP地址 + /// + /// IP地址 + /// 是否成功设置 + public static bool SetIP(string ipAddress) + { + return Manager.UpdateIpAddress(ipAddress); } /// diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs index a06b77e..c851258 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Windows.Forms; using XCamera.Models; using XCamera.Core; using XCamera.Vision; +using ErrorEventArgs = XCamera.Models.ErrorEventArgs; namespace XCamera { @@ -23,6 +25,7 @@ namespace XCamera private bool _shouldStopCapture = false; private readonly object _lockObject = new object(); private int _captureInterval = 1000; + private string _cameraIpAddress = "192.168.100.10"; // 摄像头IP地址 /// /// LED状态更新事件 @@ -39,6 +42,16 @@ namespace XCamera /// public event EventHandler CaptureStateChanged; + /// + /// 图像捕获事件 + /// + public event EventHandler ImageCaptured; + + /// + /// 信息事件(用于显示正常信息) + /// + public event EventHandler InfoOccurred; + /// /// 错误事件 /// @@ -87,9 +100,21 @@ namespace XCamera /// /// 1. 初始化 /// - /// 配置文件路径 + /// + /// 初始化管理器(仅初始化SDK和基础功能,不加载配置) + /// /// 是否成功初始化 - public bool Initialize(string configFilePath = null) + public bool Initialize() + { + return Initialize(null); + } + + /// + /// 初始化管理器(带配置文件路径) + /// + /// 配置文件路径,为null则不加载配置 + /// 是否成功初始化 + public bool Initialize(string configFilePath) { try { @@ -99,6 +124,14 @@ namespace XCamera Cleanup(); } + // 设置DLL搜索路径 + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + string dllPath = System.IO.Path.Combine(baseDirectory, "lib", "XCloudSDK"); + if (System.IO.Directory.Exists(dllPath)) + { + XCloudSdkWrapper.SetDllSearchPath(dllPath); + } + // 初始化SDK string initParam = "{\"LogLevel\":8,\"TempPath\":\"\",\"ConfigPath\":\"\",\"PlatUUID\":\"\",\"PlatAppKey\":\"\",\"PlatAppSecret\":\"\",\"PlatMovedCard\":0,\"ServerIP\":\"\",\"ServerPort\":34567,\"InitType\":0}"; int result = XCloudSdkWrapper.XCloudSDK_Init(initParam); @@ -115,7 +148,7 @@ namespace XCamera throw new Exception($"注册回调函数失败,错误码: {userHandle}"); } - // 加载配置 + // 仅在提供了配置文件路径时加载配置 if (!string.IsNullOrEmpty(configFilePath)) { _configManager.LoadFromFile(configFilePath); @@ -137,11 +170,11 @@ namespace XCamera } /// - /// 2. 设置配置文件路径 + /// 2. 设置配置目录路径 /// - /// 配置文件路径 + /// 配置目录路径 /// 是否成功设置 - public bool SetConfigFile(string configFilePath) + public bool SetConfigPath(string configPath) { if (!_isInitialized) { @@ -151,12 +184,38 @@ namespace XCamera try { - _configManager.LoadFromFile(configFilePath); + if (string.IsNullOrEmpty(configPath)) + { + OnErrorOccurred("配置目录路径不能为空"); + return false; + } + + // 查找目录中的配置文件 + if (!Directory.Exists(configPath)) + { + OnErrorOccurred($"配置目录不存在: {configPath}"); + return false; + } + + // 查找LedArea.json配置文件 + string ledAreaConfigFile = Path.Combine(configPath, "LedArea.json"); + if (!File.Exists(ledAreaConfigFile)) + { + // 如果没有LedArea.json,创建默认配置 + _configManager.CreateDefaultConfig(ledAreaConfigFile); + OnInfoOccurred($"配置目录中没有找到LedArea.json,已创建默认配置文件: {ledAreaConfigFile}"); + } + else + { + // 加载LedArea.json配置文件 + _configManager.LoadFromFile(ledAreaConfigFile); + OnInfoOccurred($"成功加载配置文件: {ledAreaConfigFile}"); + } return true; } catch (Exception ex) { - OnErrorOccurred($"设置配置文件失败: {ex.Message}"); + OnErrorOccurred($"设置配置目录失败: {ex.Message}"); return false; } } @@ -289,13 +348,42 @@ namespace XCamera return new List(); } + // 加载图像并触发图像捕获事件 + try + { + using (var image = System.Drawing.Image.FromFile(tempFile)) + { + // 触发图像捕获事件 + OnImageCaptured((System.Drawing.Image)image.Clone(), tempFile); + } + } + catch (Exception imgEx) + { + OnErrorOccurred($"图像加载失败: {imgEx.Message}"); + } + try { // 加载图像到处理器 _imageProcessor.LoadImage(tempFile); // 检测LED状态 - return _ledDetector.DetectLedStates(CurrentConfig.LedRegions); + var ledStatuses = _ledDetector.DetectLedStates(CurrentConfig.LedRegions); + + // 更新图像事件,包含LED状态信息 + try + { + using (var image = System.Drawing.Image.FromFile(tempFile)) + { + OnImageCaptured((System.Drawing.Image)image.Clone(), tempFile, ledStatuses); + } + } + catch (Exception imgEx) + { + OnErrorOccurred($"图像加载失败: {imgEx.Message}"); + } + + return ledStatuses; } finally { @@ -425,7 +513,33 @@ namespace XCamera try { - _configManager.UpdateIpAddress(ipAddress); + if (string.IsNullOrEmpty(ipAddress)) + { + throw new ArgumentException("IP地址不能为空"); + } + + // 验证IP地址格式 + var parts = ipAddress.Split('.'); + if (parts.Length != 4) + { + throw new ArgumentException("IP地址格式不正确"); + } + + foreach (var part in parts) + { + if (!int.TryParse(part, out int num) || num < 0 || num > 255) + { + throw new ArgumentException("IP地址格式不正确"); + } + } + + lock (_lockObject) + { + _cameraIpAddress = ipAddress; + } + + // 使用信息事件而不是错误事件 + OnInfoOccurred($"IP地址已更新: {ipAddress}"); return true; } catch (Exception ex) @@ -644,6 +758,30 @@ namespace XCamera ErrorOccurred?.Invoke(this, new ErrorEventArgs(error)); } + /// + /// 触发信息事件 + /// + private void OnInfoOccurred(string info) + { + InfoOccurred?.Invoke(this, new InfoEventArgs(info)); + } + + /// + /// 触发图像捕获事件 + /// + private void OnImageCaptured(System.Drawing.Image image, string imageFilePath) + { + OnImageCaptured(image, imageFilePath, new List()); + } + + /// + /// 触发图像捕获事件(带LED状态) + /// + private void OnImageCaptured(System.Drawing.Image image, string imageFilePath, List ledStatuses) + { + ImageCaptured?.Invoke(this, new ImageCapturedEventArgs(image, imageFilePath, ledStatuses)); + } + /// /// 释放资源 ///