change - 代码结构整理

master
wenjy 2 months ago
parent ab6c817864
commit 7fb35e2dda

@ -276,5 +276,12 @@ namespace SlnMesnac.Business
}
}
public int GetTrackMotorAddress()
{
int is_arrive_flag = _plc.readInt16ByAddress("VD2005");
return is_arrive_flag;
}
}
}

@ -112,14 +112,14 @@
</Border>
<!--停止-->
<Border Width="80" Height="80" Background="Transparent" CornerRadius="60" MouseLeftButtonDown="btn_auto_MouseLeftButtonDown">
<TextBlock x:Name="btnAuto" Text="Auto" FontSize="20" Foreground="Red" FontWeight="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBlock x:Name="btnAuto" Text="{Binding GimbalAutoRunText}" FontSize="20" Foreground="Red" FontWeight="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="开启预览" FontWeight="Black" FontSize="16" Width="100" Height="30" Foreground="#0050BF" Background="#E5EDF8" BorderBrush="#0050BF" Margin="50,0,0,0" Click="btn_start_preview_Click"/>
<Button Content="关闭预览" FontWeight="Black" FontSize="16" Width="100" Height="30" Foreground="#0050BF" Background="#E5EDF8" BorderBrush="#0050BF" Margin="50,20,0,0" Click="btn_stop_preview_Click"/>
<Button Content="回 零" FontWeight="Black" FontSize="16" Width="100" Height="30" Foreground="#0050BF" Background="#E5EDF8" BorderBrush="#0050BF" Margin="50,20,0,0" Click="btn_ptz_set_Click"/>
<Button Content="回 零" FontWeight="Black" FontSize="16" Width="100" Height="30" Foreground="#0050BF" Background="#E5EDF8" BorderBrush="#0050BF" Margin="50,20,0,0" Command="{Binding GimbalOriginCommand}"/>
</StackPanel>
</StackPanel>
</Grid>
@ -529,13 +529,13 @@ Canvas.Left="175" Canvas.Top="155" Stroke="Transparent" StrokeThickness="1">
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#F4F5FA" CornerRadius="5,0,0,5">
<Border Grid.Column="0" Background="#F4F5FA" CornerRadius="5,0,0,5" MouseDown="btnZoomOut_MouseDown" MouseUp="btnZoomOut_MouseUp">
<TextBlock Text="—" FontSize="16" FontWeight="Black" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<Border Grid.Column="1" Background="#F4F5FA" Margin="5,0,5,0">
<TextBlock Text="变 倍" FontSize="16" FontWeight="Black" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<Border Grid.Column="2" Background="#F4F5FA" CornerRadius="0,5,5,0">
<Border Grid.Column="2" Background="#F4F5FA" CornerRadius="0,5,5,0" MouseDown="btnZoomIn_MouseDown" MouseUp="btnZoomIn_MouseUp">
<TextBlock Text="+" FontSize="22" FontWeight="Black" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</Grid>
@ -547,13 +547,13 @@ Canvas.Left="175" Canvas.Top="155" Stroke="Transparent" StrokeThickness="1">
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#F4F5FA" CornerRadius="5,0,0,5">
<Border Grid.Column="0" Background="#F4F5FA" CornerRadius="5,0,0,5" MouseDown="btnFocusNear_MouseDown" MouseUp="btnFocusNear_MouseUp">
<TextBlock Text="—" FontSize="16" FontWeight="Black" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<Border Grid.Column="1" Background="#F4F5FA" Margin="5,0,5,0">
<TextBlock Text="焦 距" FontSize="16" FontWeight="Black" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<Border Grid.Column="2" Background="#F4F5FA" CornerRadius="0,5,5,0">
<Border Grid.Column="2" Background="#F4F5FA" CornerRadius="0,5,5,0" MouseDown="btnFocusFar_MouseDown" MouseUp="btnFocusFar_MouseUp">
<TextBlock Text="+" FontSize="22" FontWeight="Black" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</Grid>

@ -1,29 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using SlnMesnac.Business;
using SlnMesnac.Config;
using SlnMesnac.Model.dto;
using SlnMesnac.Serilog;
using SlnMesnac.WPF.ViewModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
using SlnMesnac.WPF.ViewModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static SlnMesnac.WPF.CHCNetSDK;
namespace SlnMesnac.WPF.Page
{
@ -32,392 +13,80 @@ namespace SlnMesnac.WPF.Page
/// </summary>
public partial class IndexControl : UserControl
{
private IndexControlViewModel indexControlViewModel = new IndexControlViewModel();
private SerilogHelper serilogHelper = null;
private AppConfig _appConfig = null;
private AutoModeBusiness taskBusiness = null;
private InspModeBusiness inspModeBusiness = null;
private bool m_bInitSDK = false;
private Int32 m_lUserID = -1;
private Int32 m_lRealHandle_1 = -1;
private Int32 m_lRealHandle_2 = -1;
public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;
public CHCNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;
public CHCNetSDK.NET_DVR_PTZPOS m_struPtzCfg;
private bool bAuto = false;
private CHCNetSDK.RemoteConfigCallback _callback;
private CHCNetSDK.MSGCallBack_V31 m_falarmData_V31 = null;
private string DVRIPAddress = "192.168.1.64"; //设备IP地址或者域名 Device IP
private Int16 DVRPortNumber = 8000; //设备服务端口号 Device Port
private string DVRUserName = "admin"; //设备登录用户名 User name to login
private string DVRPassword = "haiwei@2024"; //设备登录密码 Password to login
private IndexControlViewModel indexControlViewModel;
public IndexControl()
{
InitializeComponent();
this.DataContext = indexControlViewModel;
serilogHelper = App.ServiceProvider.GetService<SerilogHelper>();
_appConfig = App.ServiceProvider.GetService<AppConfig>();
taskBusiness = App.ServiceProvider.GetService<AutoModeBusiness>();
inspModeBusiness = App.ServiceProvider.GetService<InspModeBusiness>();
_callback = new CHCNetSDK.RemoteConfigCallback(GetThermInfoCallback);
Open_Device();
taskBusiness.CaptureAlarmPictureEvent += CapturePicture;
}
private void Open_Device()
{
try
{
Task.Run(() =>
{
m_bInitSDK = CHCNetSDK.NET_DVR_Init();
if (m_bInitSDK == false)
{
DebugInfo("热成像双光谱微型云台初始化失败 error!");
return;
}
else
{
//保存SDK日志 To save the SDK log
CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
DebugInfo("热成像双光谱微型云台初始化成功!");
}
m_lUserID = CHCNetSDK.NET_DVR_Login_V30(DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DeviceInfo);
if (m_lUserID < 0)
{
string str = "热成像双光谱微型云台打开失败, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ; //登录失败,输出错误号 Failed to login and output the error code
DebugInfo(str);
}
else
{
//登录成功
DebugInfo("热成像双光谱微型云台打开成功!");
//SceneryPreview();
//ThermalPreview();
///
/// 加载实时温度数据
///
var size = Marshal.SizeOf(typeof(CHCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND));
CHCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND struThermCond = new CHCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND();
struThermCond.dwSize = (uint)size;
struThermCond.byRuleID = 0; //规则ID0代表获取全部规则具体规则ID从1开始
struThermCond.dwChan = 2;// dwChannel; //从1开始0xffffffff代表获取全部通道
IntPtr pCond = Marshal.AllocCoTaskMem(size);
Marshal.StructureToPtr(struThermCond, pCond, false);
var ret = NET_DVR_StartRemoteConfig(m_lUserID, NET_DVR_GET_REALTIME_THERMOMETRY, pCond, size, _callback, IntPtr.Zero);
if (ret < 0)
{
DebugInfo("配置测温失败, 错误代码:" + NET_DVR_GetLastError()); //登录失败,输出错误号
return;
}
}
});
}
catch (Exception ex)
{
DebugInfo($"热成像双光谱微型云台加载异常: {ex.Message}");
}
}
/// <summary>
/// 测温回调函数
/// </summary>
/// <param name="dwType"></param>
/// <param name="lpBuffer"></param>
/// <param name="dwBufLen"></param>
/// <param name="pUserData"></param>
public void GetThermInfoCallback(uint dwType, IntPtr lpBuffer, uint dwBufLen, IntPtr pUserData)
{
var ret = Marshal.PtrToStructure<NET_DVR_THERMOMETRY_UPLOAD>(lpBuffer);
taskBusiness._realTemperatureInfo.fMaxTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMaxTemperature, 1);
taskBusiness._realTemperatureInfo.fMinTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMinTemperature);
taskBusiness._realTemperatureInfo.fAverageTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fAverageTemperature, 1);
taskBusiness._realTemperatureInfo.fTemperatureDiff = (float)Math.Round(ret.struLinePolygonThermCfg.fTemperatureDiff, 1);
var real = new RealTemperatureInfo()
{
fMaxTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMaxTemperature, 1),
fMinTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMinTemperature, 1),
fAverageTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fAverageTemperature, 1),
fTemperatureDiff = (float)Math.Round(ret.struLinePolygonThermCfg.fTemperatureDiff, 1),
};
indexControlViewModel.RefreshRealTemperature(real);
}
/// <summary>
/// 抓拍图像
/// </summary>
/// <param name="sJpegPicFileName"></param>
public void CapturePicture(string sJpegPicFileName)
{
for (int i = 1; i < 3; i++)
{
CHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA();
lpJpegPara.wPicQuality = 0;
lpJpegPara.wPicSize = 0xff;
var path = string.Empty;
if (i == 1)
{
path = $"{_appConfig.visibleRangePath}\\{sJpegPicFileName}";
}
else
{
path = $"{_appConfig.infraredImagePath}\\{sJpegPicFileName}";
}
if (!CHCNetSDK.NET_DVR_CaptureJPEGPicture(m_lUserID, i, ref lpJpegPara, path))
{
var str = "高温报警,图像信息保存失败, error code= " + NET_DVR_GetLastError();
DebugInfo(str);
return;
}
else
{
var str = "高温报警,图像信息保存成功: " + path;
DebugInfo(str);
}
}
}
/// <summary>
/// 可见光预览
/// </summary>
private void SceneryPreview()
{
try
{
App.Current.Dispatcher.Invoke(() =>
{
CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = RealPlayWnd.Handle;//预览窗口 live view window
lpPreviewInfo.lChannel = 1;//预览的设备通道 the device channel number
lpPreviewInfo.dwStreamType = 0;//码流类型0-主码流1-子码流2-码流33-码流4以此类推
lpPreviewInfo.dwLinkMode = 0;//连接方式0- TCP方式1- UDP方式2- 多播方式3- RTP方式4-RTP/RTSP5-RSTP/HTTP
lpPreviewInfo.bBlocked = true; //0- 非阻塞取流1- 阻塞取流
lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数
IntPtr pUser = IntPtr.Zero;//用户数据 user data
m_lRealHandle_1 = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser);
if (m_lRealHandle_1 < 0)
{
var str = "光景图像预览加载失败, error code= " + CHCNetSDK.NET_DVR_GetLastError(); //预览失败,输出错误号 failed to start live view, and output the error code.
DebugInfo(str);
}
else
{
//预览成功
DebugInfo("光景图像预览加载成功!");
}
});
}
catch (Exception ex)
{
serilogHelper.Camera($"光景图像预览加载异常:{ex.Message}");
}
}
/// <summary>
/// 热成像预览
/// </summary>
private void ThermalPreview()
{
try
{
App.Current.Dispatcher.Invoke(() =>
{
CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = RealPlayWnd2.Handle;//预览窗口 live view window
lpPreviewInfo.lChannel = 2;//预览的设备通道 the device channel number
lpPreviewInfo.dwStreamType = 0;//码流类型0-主码流1-子码流2-码流33-码流4以此类推
lpPreviewInfo.dwLinkMode = 0;//连接方式0- TCP方式1- UDP方式2- 多播方式3- RTP方式4-RTP/RTSP5-RSTP/HTTP
lpPreviewInfo.bBlocked = true; //0- 非阻塞取流1- 阻塞取流
lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数
IntPtr pUser = IntPtr.Zero;//用户数据 user data
m_lRealHandle_2 = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser);
if (m_lRealHandle_2 < 0)
{
var str = "热成像预览加载失败, error code= " + CHCNetSDK.NET_DVR_GetLastError(); //预览失败,输出错误号 failed to start live view, and output the error code.
DebugInfo(str);
}
else
{
//预览成功
DebugInfo("热成像预览加载成功!");
}
});
}
catch (Exception ex)
{
serilogHelper.Camera($"热成像图像预览加载异常:{ex.Message}");
}
}
indexControlViewModel = new IndexControlViewModel();
/// <summary>
/// 关闭设备
/// </summary>
private void Close_Device()
{
if (!CHCNetSDK.NET_DVR_Logout(m_lUserID))
{
var str = "NET_DVR_Logout failed, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ;
DebugInfo(str);
return;
}
DebugInfo("NET_DVR_Logout succ!");
}
this.DataContext = indexControlViewModel;
/// <summary>
/// 日志记录
/// </summary>
/// <param name="str"></param>
private void DebugInfo(string str)
{
serilogHelper.Camera(str);
indexControlViewModel.RefreshHighlightStationEvent += HighlightStation;
}
#region 云台控制
private void btnUp_MouseDown(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.TILT_UP, 0, 4);
indexControlViewModel.GimbalOperate("up", true);
}
private void btnUp_MouseUp(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.TILT_UP, 1, 4);
indexControlViewModel.GimbalOperate("up", false);
}
private void btnDown_MouseDown(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.TILT_DOWN, 0, 4);
indexControlViewModel.GimbalOperate("down", true);
}
private void btnDown_MouseUp(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.TILT_DOWN, 1, 4);
indexControlViewModel.GimbalOperate("down", false);
}
private void btnLeft_MouseDown(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, (uint)CHCNetSDK.PAN_LEFT, 0, 4);
indexControlViewModel.GimbalOperate("left", true);
}
private void btnLeft_MouseUp(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.PAN_LEFT, 1, 4);
indexControlViewModel.GimbalOperate("left", false);
}
private void btnRight_MouseDown(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.PAN_RIGHT, 0, 4);
indexControlViewModel.GimbalOperate("right", true);
}
private void btnRight_MouseUp(object sender, MouseButtonEventArgs e)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.PAN_RIGHT, 1, 4);
indexControlViewModel.GimbalOperate("right", false);
}
#endregion
/// <summary>
/// 云台回零点
/// 云台自动运行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_ptz_set_Click(object sender, RoutedEventArgs e)
{
if (bAuto)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.PAN_AUTO, 1, 4);
btnAuto.Text = "Auto";
bAuto = false;
}
float wPanPos, wTiltPos, wZoomPos;
var flag = 0;
m_struPtzCfg.wAction = 1;
m_struPtzCfg.wPanPos = (ushort)(Convert.ToUInt16("20", 16));
m_struPtzCfg.wTiltPos = (ushort)(Convert.ToUInt16("4", 16));
m_struPtzCfg.wZoomPos = (ushort)(Convert.ToUInt16("10", 16));
while (flag == 0)
{
Int32 nSize = Marshal.SizeOf(m_struPtzCfg);
IntPtr ptrPtzCfg = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(m_struPtzCfg, ptrPtzCfg, false);
if (!CHCNetSDK.NET_DVR_SetDVRConfig(m_lUserID, CHCNetSDK.NET_DVR_SET_PTZPOS, 1, ptrPtzCfg, (UInt32)nSize))
{
var str = "云台回零加载异常, error code= " + CHCNetSDK.NET_DVR_GetLastError();
//设置POS参数失败
DebugInfo(str);
return;
}
else
{
DebugInfo("云台回零加载成功!");
break;
}
Marshal.FreeHGlobal(ptrPtzCfg);
}
}
private void btn_auto_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!bAuto)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.PAN_AUTO, 0, 4);
btnAuto.Text = "Stop";
bAuto = true;
}
else
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(m_lRealHandle_1, CHCNetSDK.PAN_AUTO, 1, 4);
btnAuto.Text = "Auto";
bAuto = false;
}
indexControlViewModel.GimbalAutoRun();
}
private bool is_insp_model = false;
/// <summary>
/// 巡检模式
/// 巡检模式切换
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_inspmode_MouseDown(object sender, MouseButtonEventArgs e)
{
if (!is_insp_model)
{
if (is_auto_model)
{
MessageBox.Show("当前处于自动模式中,请先关闭自动模式,再开启巡检模式");
@ -426,80 +95,23 @@ namespace SlnMesnac.WPF.Page
btn_automatic.Background = new SolidColorBrush(Colors.LightBlue);
is_insp_model = true;
string taskCode = DateTime.Now.ToString("yyyyMMddHHmmssffff");
string fileName = $"{taskCode}.mp4";
Task.Run(() =>
{
var url = $"{_appConfig.videoFilePath}\\可见光\\{fileName}";
CHCNetSDK.NET_DVR_MakeKeyFrame(m_lUserID, 1);
if (!CHCNetSDK.NET_DVR_SaveRealData(m_lRealHandle_1, url))
{
var str = "可见光通道开启巡检录像失败, error code= " + NET_DVR_GetLastError();
DebugInfo(str);
return;
}
else
{
DebugInfo($"可见光通道开启巡检录像成功");
}
});
Task.Run(() =>
{
var url = $"{_appConfig.videoFilePath}\\热成像\\{fileName}";
CHCNetSDK.NET_DVR_MakeKeyFrame(m_lUserID, 2);
if (!CHCNetSDK.NET_DVR_SaveRealData(m_lRealHandle_2, url))
{
var str = "热成像通道开启巡检录像失败, error code= " + NET_DVR_GetLastError();
DebugInfo(str);
return;
}
else
{
DebugInfo($"热成像通道开启巡检录像成功");
}
});
inspModeBusiness.Start(taskCode, fileName);
indexControlViewModel.Start_InspMode();
}
else
{
//MessageBox.Show("巡检模式关闭");
btn_automatic.Background = new SolidColorBrush(Colors.Transparent);
is_insp_model = false;
indexControlViewModel.Stop_InspMode();
Task.Run(() =>
{
if (!CHCNetSDK.NET_DVR_StopSaveRealData(m_lRealHandle_1))
{
var str = "可见光通道关闭巡检录像失败, error code= " + NET_DVR_GetLastError();
DebugInfo(str);
return;
}
else
{
DebugInfo($"可见光通道关闭巡检录像成功");
}
});
Task.Run(() =>
{
if (!CHCNetSDK.NET_DVR_StopSaveRealData(m_lRealHandle_2))
{
var str = "热成像通道关闭巡检录像失败, error code= " + NET_DVR_GetLastError();
DebugInfo(str);
return;
}
else
{
DebugInfo($"热成像通道关闭巡检录像成功");
}
});
}
}
private bool is_auto_model = false;
/// <summary>
/// 自动模式切换
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_automode_MouseDown(object sender, MouseButtonEventArgs e)
{
if (!is_auto_model)
@ -510,13 +122,13 @@ namespace SlnMesnac.WPF.Page
}
btn_autotask.Background = new SolidColorBrush(Colors.LightBlue);
is_auto_model = true;
taskBusiness.Start();
indexControlViewModel.Start_AutoMode();
}
else
{
btn_autotask.Background = new SolidColorBrush(Colors.Transparent);
is_auto_model = false;
taskBusiness.Stop();
indexControlViewModel.Stop_AutoMode();
}
}
@ -528,13 +140,7 @@ namespace SlnMesnac.WPF.Page
/// <param name="e"></param>
private void btn_start_preview_Click(object sender, RoutedEventArgs e)
{
if (m_lRealHandle_1 > 0 || m_lRealHandle_2 > 0)
{
MessageBox.Show("实时预览已开启,请勿重复开启");
return;
}
SceneryPreview();
ThermalPreview();
indexControlViewModel.Login(RealPlayWnd, RealPlayWnd2);
}
/// <summary>
@ -544,30 +150,82 @@ namespace SlnMesnac.WPF.Page
/// <param name="e"></param>
private void btn_stop_preview_Click(object sender, RoutedEventArgs e)
{
if (!CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle_1))
{
var str = "NET_DVR_StopRealPlay failed, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ;
DebugInfo(str);
return;
}
else
{
DebugInfo("NET_DVR_StopRealPlay succ!");
RealPlayWnd.Invalidate();//刷新窗口 refresh the window
}
indexControlViewModel.ClosePreview(RealPlayWnd, RealPlayWnd2);
Thread.Sleep(1000);
indexControlViewModel.Logout();
}
private void HighlightStation(int stationNumber)
{
if (!CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle_2))
App.Current.Dispatcher.Invoke(() =>
{
var str = "NET_DVR_StopRealPlay failed, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ;
DebugInfo(str);
return;
}
else
ResetStationColors();
// 根据输入的站点编号高亮对应的站点
if(canvasTrack!= null)
{
Rectangle station = (Rectangle)canvasTrack.FindName($"station{stationNumber}");
if (station != null)
{
station.Fill = Brushes.GreenYellow;
}
}
});
}
private void ResetStationColors()
{
// 重置所有站点的颜色
for (int i = 1; i <= 18; i++)
{
DebugInfo("NET_DVR_StopRealPlay succ!");
RealPlayWnd2.Invalidate();//刷新窗口 refresh the window
m_lRealHandle_2 = 0;
Rectangle station = (Rectangle)canvasTrack.FindName($"station{i}");
if (station != null)
{
station.Fill = Brushes.Gray;
}
}
}
private void btnZoomIn_MouseDown(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("zoomIn", true);
}
private void btnZoomIn_MouseUp(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("zoomIn", false);
}
private void btnZoomOut_MouseDown(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("zoomOut", true);
}
private void btnZoomOut_MouseUp(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("zoomOut", false);
}
private void btnFocusFar_MouseDown(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("focusFar", true);
}
private void btnFocusFar_MouseUp(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("focusFar", false);
}
private void btnFocusNear_MouseDown(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("focusNear", true);
}
private void btnFocusNear_MouseUp(object sender, MouseButtonEventArgs e)
{
indexControlViewModel.GimbalOperate("focusNear", false);
}
}
}

@ -1,10 +1,19 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.DependencyInjection;
using SlnMesnac.Business;
using SlnMesnac.Business.@base;
using SlnMesnac.Config;
using SlnMesnac.Model.dto;
using SlnMesnac.Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static SlnMesnac.WPF.CHCNetSDK;
#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
@ -30,18 +39,575 @@ using System.Threading.Tasks;
#endregion << 版 本 注 释 >>
namespace SlnMesnac.WPF.ViewModel
{
public class IndexControlViewModel : ObservableObject
public partial class IndexControlViewModel : ObservableObject
{
private SerilogHelper _log;
private AutoModeBusiness autoModeBusiness;
private InspModeBusiness inspModeBusiness;
private AppConfig _appConfig;
private CHCNetSDK.RemoteConfigCallback _callback;
public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;
private bool m_bInitSDK = false;
private Int32 m_lUserID = -1;
public Int32 Scenery_RealHandle = -1;
public Int32 Thermal_RealHandle = -1;
private const string DVRIPAddress = "192.168.1.64"; //设备IP地址或者域名 Device IP
private const Int16 DVRPortNumber = 8000; //设备服务端口号 Device Port
private const string DVRUserName = "admin"; //设备登录用户名 User name to login
private const string DVRPassword = "haiwei@2024"; //设备登录密码 Password to login
public IndexControlViewModel()
{
_log = App.ServiceProvider.GetService<SerilogHelper>();
_callback = new CHCNetSDK.RemoteConfigCallback(GetThermInfoCallback);
_appConfig = App.ServiceProvider.GetService<AppConfig>();
autoModeBusiness = App.ServiceProvider.GetService<AutoModeBusiness>();
inspModeBusiness = App.ServiceProvider.GetService<InspModeBusiness>();
autoModeBusiness.CaptureAlarmPictureEvent += CapturePicture;
RefreshTrackMotorAddress();
}
#region 参数定义
private string _gimbalAutoRunText = "Auto";
public string GimbalAutoRunText
{
get => _gimbalAutoRunText;
set => SetProperty(ref _gimbalAutoRunText, value);
}
public RealTemperatureInfo _realTemperature;
public RealTemperatureInfo RealTemperature
{
get => _realTemperature;
set => SetProperty(ref _realTemperature, value);
}
#endregion
#region 事件定义
public delegate void RefreshHighlightStation(int cabinetCode);
public event RefreshHighlightStation RefreshHighlightStationEvent;
#endregion
public void Login(PictureBox SceneryPreviewWnd, PictureBox ThermalPreviewWnd)
{
try
{
Task.Run(() =>
{
m_bInitSDK = CHCNetSDK.NET_DVR_Init();
if (m_bInitSDK == false)
{
_log.Info("热成像双光谱微型云台初始化失败 error!");
return;
}
else
{
//保存SDK日志 To save the SDK log
CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
_log.Info("热成像双光谱微型云台初始化成功!");
}
m_lUserID = CHCNetSDK.NET_DVR_Login_V30(DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DeviceInfo);
if (m_lUserID < 0)
{
string str = "热成像双光谱微型云台打开失败, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ; //登录失败,输出错误号 Failed to login and output the error code
_log.Info(str);
}
else
{
//登录成功
_log.Info("热成像双光谱微型云台打开成功!");
SceneryPreview(SceneryPreviewWnd);
ThermalPreview(ThermalPreviewWnd);
///
/// 加载实时温度数据
///
var size = Marshal.SizeOf(typeof(CHCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND));
CHCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND struThermCond = new CHCNetSDK.NET_DVR_REALTIME_THERMOMETRY_COND();
struThermCond.dwSize = (uint)size;
struThermCond.byRuleID = 0; //规则ID0代表获取全部规则具体规则ID从1开始
struThermCond.dwChan = 2;// dwChannel; //从1开始0xffffffff代表获取全部通道
IntPtr pCond = Marshal.AllocCoTaskMem(size);
Marshal.StructureToPtr(struThermCond, pCond, false);
var ret = CHCNetSDK.NET_DVR_StartRemoteConfig(m_lUserID, CHCNetSDK.NET_DVR_GET_REALTIME_THERMOMETRY, pCond, size, _callback, IntPtr.Zero);
if (ret < 0)
{
_log.Info("配置测温失败, 错误代码:" + CHCNetSDK.NET_DVR_GetLastError()); //登录失败,输出错误号
return;
}
}
});
}
catch (Exception ex)
{
_log.Info($"热成像双光谱微型云台加载异常: {ex.Message}");
}
}
/// <summary>
/// 测温回调函数
/// </summary>
/// <param name="dwType"></param>
/// <param name="lpBuffer"></param>
/// <param name="dwBufLen"></param>
/// <param name="pUserData"></param>
public void GetThermInfoCallback(uint dwType, IntPtr lpBuffer, uint dwBufLen, IntPtr pUserData)
{
var ret = Marshal.PtrToStructure<CHCNetSDK.NET_DVR_THERMOMETRY_UPLOAD>(lpBuffer);
autoModeBusiness._realTemperatureInfo.fMaxTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMaxTemperature, 1);
autoModeBusiness._realTemperatureInfo.fMinTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMinTemperature);
autoModeBusiness._realTemperatureInfo.fAverageTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fAverageTemperature, 1);
autoModeBusiness._realTemperatureInfo.fTemperatureDiff = (float)Math.Round(ret.struLinePolygonThermCfg.fTemperatureDiff, 1);
this.RealTemperature = new RealTemperatureInfo()
{
fMaxTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMaxTemperature, 1),
fMinTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fMinTemperature, 1),
fAverageTemperature = (float)Math.Round(ret.struLinePolygonThermCfg.fAverageTemperature, 1),
fTemperatureDiff = (float)Math.Round(ret.struLinePolygonThermCfg.fTemperatureDiff, 1),
};
}
/// <summary>
/// 抓拍图像
/// </summary>
/// <param name="sJpegPicFileName"></param>
public void CapturePicture(string sJpegPicFileName)
{
for (int i = 1; i < 3; i++)
{
CHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA();
lpJpegPara.wPicQuality = 0;
lpJpegPara.wPicSize = 0xff;
var path = string.Empty;
if (i == 1)
{
path = $"{_appConfig.visibleRangePath}\\{sJpegPicFileName}";
}
else
{
path = $"{_appConfig.infraredImagePath}\\{sJpegPicFileName}";
}
if (!CHCNetSDK.NET_DVR_CaptureJPEGPicture(m_lUserID, i, ref lpJpegPara, path))
{
_log.Info("高温报警,图像信息保存失败, error code= " + NET_DVR_GetLastError());
return;
}
else
{
_log.Info("高温报警,图像信息保存成功: " + path);
}
}
}
public void RefreshRealTemperature(RealTemperatureInfo realTemperature)
/// <summary>
/// 可见光景预览加载
/// </summary>
/// <param name="SceneryPreviewWnd"></param>
public void SceneryPreview(PictureBox SceneryPreviewWnd)
{
this.RealTemperature = realTemperature;
try
{
App.Current.Dispatcher.Invoke(() =>
{
CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = SceneryPreviewWnd.Handle;//预览窗口 live view window
lpPreviewInfo.lChannel = 1;//预览的设备通道 the device channel number
lpPreviewInfo.dwStreamType = 0;//码流类型0-主码流1-子码流2-码流33-码流4以此类推
lpPreviewInfo.dwLinkMode = 0;//连接方式0- TCP方式1- UDP方式2- 多播方式3- RTP方式4-RTP/RTSP5-RSTP/HTTP
lpPreviewInfo.bBlocked = true; //0- 非阻塞取流1- 阻塞取流
lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数
IntPtr pUser = IntPtr.Zero;//用户数据 user data
Scenery_RealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser);
if (Scenery_RealHandle < 0)
{
_log.Info("光景图像预览加载失败, error code= " + CHCNetSDK.NET_DVR_GetLastError());
}
else
{
//预览成功
_log.Info("光景图像预览加载成功 ");
}
});
}
catch (Exception ex)
{
_log.Camera($"光景图像预览加载异常:{ex.Message}");
}
}
/// <summary>
/// 热成像预览加载
/// </summary>
/// <param name="ThermalPreviewWnd"></param>
public void ThermalPreview(PictureBox ThermalPreviewWnd)
{
try
{
App.Current.Dispatcher.Invoke(() =>
{
CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = ThermalPreviewWnd.Handle;//预览窗口 live view window
lpPreviewInfo.lChannel = 2;//预览的设备通道 the device channel number
lpPreviewInfo.dwStreamType = 0;//码流类型0-主码流1-子码流2-码流33-码流4以此类推
lpPreviewInfo.dwLinkMode = 0;//连接方式0- TCP方式1- UDP方式2- 多播方式3- RTP方式4-RTP/RTSP5-RSTP/HTTP
lpPreviewInfo.bBlocked = true; //0- 非阻塞取流1- 阻塞取流
lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数
IntPtr pUser = IntPtr.Zero;//用户数据 user data
Thermal_RealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser);
if (Thermal_RealHandle < 0)
{
_log.Info("热成像预览加载失败, error code= " + CHCNetSDK.NET_DVR_GetLastError());
}
else
{
//预览成功
_log.Info("热成像预览加载成功");
}
});
}
catch (Exception ex)
{
_log.Camera($"热成像图像预览加载异常:{ex.Message}");
}
}
/// <summary>
/// 关闭预览
/// </summary>
/// <param name="SceneryPreviewWnd"></param>
/// <param name="ThermalPreviewWnd"></param>
public void ClosePreview(PictureBox SceneryPreviewWnd, PictureBox ThermalPreviewWnd)
{
if (!CHCNetSDK.NET_DVR_StopRealPlay(Scenery_RealHandle))
{
var str = "NET_DVR_StopRealPlay failed, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ;
_log.Info(str);
return;
}
else
{
_log.Info("NET_DVR_StopRealPlay succ!");
SceneryPreviewWnd.Invalidate();//刷新窗口 refresh the window
}
if (!CHCNetSDK.NET_DVR_StopRealPlay(Thermal_RealHandle))
{
var str = "NET_DVR_StopRealPlay failed, error code= " + CHCNetSDK.NET_DVR_GetLastError(); ;
_log.Info(str);
return;
}
else
{
_log.Info("NET_DVR_StopRealPlay succ!");
ThermalPreviewWnd.Invalidate();//刷新窗口 refresh the window
Thermal_RealHandle = 0;
}
}
/// <summary>
/// 退出设备
/// </summary>
public void Logout()
{
if (!CHCNetSDK.NET_DVR_Logout(m_lUserID))
{
_log.Info("NET_DVR_Logout failed, error code= " + CHCNetSDK.NET_DVR_GetLastError());
return;
}
if (!CHCNetSDK.NET_DVR_Cleanup())
{
_log.Info("NET_DVR_Cleanup failed, error code= " + CHCNetSDK.NET_DVR_GetLastError());
return;
}
else
{
this.RealTemperature = new RealTemperatureInfo()
{
fMaxTemperature = 0,
fMinTemperature = 0,
fAverageTemperature = 0,
fTemperatureDiff = 0,
};
}
_log.Info("NET_DVR_Logout succ!");
}
/// <summary>
/// 云台控制
/// </summary>
/// <param name="direction"></param>
/// <param name="is_MouseDown"></param>
public void GimbalOperate(string direction, bool is_MouseDown)
{
if (is_MouseDown)
{
switch (direction)
{
case "left":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, (uint)CHCNetSDK.PAN_LEFT, 0, 4);
break;
case "right":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.PAN_RIGHT, 0, 4);
break;
case "up":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.TILT_UP, 0, 4);
break;
case "down":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.TILT_DOWN, 0, 4);
break;
case "zoomIn":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.ZOOM_IN, 0);
break;
case "zoomOut":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.ZOOM_OUT, 0);
break;
case "focusNear":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.FOCUS_NEAR, 0);
break;
case "focusFar":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.FOCUS_FAR, 0);
break;
default:
break;
}
}
else
{
switch (direction)
{
case "left":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.PAN_LEFT, 1, 4);
break;
case "right":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.PAN_RIGHT, 1, 4);
break;
case "up":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.TILT_UP, 1, 4);
break;
case "down":
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.TILT_DOWN, 1, 4);
break;
case "zoomIn":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.ZOOM_IN, 1);
break;
case "zoomOut":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.ZOOM_OUT, 1);
break;
case "focusNear":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.FOCUS_NEAR, 1);
break;
case "focusFar":
CHCNetSDK.NET_DVR_PTZControl(Scenery_RealHandle, CHCNetSDK.FOCUS_FAR, 1);
break;
default:
break;
}
}
}
private bool gimbalAuto = false;
public CHCNetSDK.NET_DVR_PTZPOS m_struPtzCfg;
/// <summary>
/// 云台回原点
/// </summary>
[RelayCommand]
private void GimbalOrigin()
{
if (gimbalAuto)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.PAN_AUTO, 1, 4);
this.GimbalAutoRunText = "Auto";
gimbalAuto = false;
}
float wPanPos, wTiltPos, wZoomPos;
var flag = 0;
m_struPtzCfg.wAction = 1;
m_struPtzCfg.wPanPos = (ushort)(Convert.ToUInt16("20", 16));
m_struPtzCfg.wTiltPos = (ushort)(Convert.ToUInt16("4", 16));
m_struPtzCfg.wZoomPos = (ushort)(Convert.ToUInt16("10", 16));
while (flag == 0)
{
Int32 nSize = Marshal.SizeOf(m_struPtzCfg);
IntPtr ptrPtzCfg = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(m_struPtzCfg, ptrPtzCfg, false);
if (!CHCNetSDK.NET_DVR_SetDVRConfig(m_lUserID, CHCNetSDK.NET_DVR_SET_PTZPOS, 1, ptrPtzCfg, (UInt32)nSize))
{
var str = "云台回零加载异常, error code= " + CHCNetSDK.NET_DVR_GetLastError();
//设置POS参数失败
_log.Info(str);
return;
}
else
{
_log.Info("云台回零加载成功!");
break;
}
Marshal.FreeHGlobal(ptrPtzCfg);
}
}
/// <summary>
/// 云台自动运行模式
/// </summary>
public void GimbalAutoRun()
{
if (!gimbalAuto)
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.PAN_AUTO, 0, 4);
this.GimbalAutoRunText = "Stop";
gimbalAuto = true;
}
else
{
CHCNetSDK.NET_DVR_PTZControlWithSpeed(Scenery_RealHandle, CHCNetSDK.PAN_AUTO, 1, 4);
this.GimbalAutoRunText = "Auto";
gimbalAuto = false;
}
}
/// <summary>
/// 开启自动模式
/// </summary>
public void Start_AutoMode()
{
autoModeBusiness.Start();
}
/// <summary>
/// 关闭自动模式
/// </summary>
public void Stop_AutoMode()
{
autoModeBusiness.Stop();
}
/// <summary>
/// 开启巡检模式
/// </summary>
public void Start_InspMode()
{
string taskCode = DateTime.Now.ToString("yyyyMMddHHmmssffff");
string fileName = $"{taskCode}.mp4";
Task.Run(() =>
{
var url = $"{_appConfig.videoFilePath}\\可见光\\{fileName}";
CHCNetSDK.NET_DVR_MakeKeyFrame(m_lUserID, 1);
if (!CHCNetSDK.NET_DVR_SaveRealData(Scenery_RealHandle, url))
{
var str = "可见光通道开启巡检录像失败, error code= " + NET_DVR_GetLastError();
_log.Info(str);
return;
}
else
{
_log.Info($"可见光通道开启巡检录像成功");
}
});
Task.Run(() =>
{
var url = $"{_appConfig.videoFilePath}\\热成像\\{fileName}";
CHCNetSDK.NET_DVR_MakeKeyFrame(m_lUserID, 2);
if (!CHCNetSDK.NET_DVR_SaveRealData(Thermal_RealHandle, url))
{
var str = "热成像通道开启巡检录像失败, error code= " + NET_DVR_GetLastError();
_log.Info(str);
return;
}
else
{
_log.Info($"热成像通道开启巡检录像成功");
}
});
inspModeBusiness.Start(taskCode, fileName);
}
/// <summary>
/// 关闭巡检模式
/// </summary>
public void Stop_InspMode()
{
Task.Run(() =>
{
if (!CHCNetSDK.NET_DVR_StopSaveRealData(Scenery_RealHandle))
{
var str = "可见光通道关闭巡检录像失败, error code= " + NET_DVR_GetLastError();
_log.Info(str);
return;
}
else
{
_log.Info($"可见光通道关闭巡检录像成功");
}
});
Task.Run(() =>
{
if (!CHCNetSDK.NET_DVR_StopSaveRealData(Thermal_RealHandle))
{
var str = "热成像通道关闭巡检录像失败, error code= " + NET_DVR_GetLastError();
_log.Info(str);
return;
}
else
{
_log.Info($"热成像通道关闭巡检录像成功");
}
});
}
private int lastTrackMotorAddress = 0;
private void RefreshTrackMotorAddress()
{
Task.Run(() =>
{
while (true)
{
int trackMotorAddress = autoModeBusiness.GetTrackMotorAddress();
if (trackMotorAddress != lastTrackMotorAddress)
{
RefreshHighlightStationEvent?.Invoke(trackMotorAddress);
}
Task.Delay(1000).Wait();
}
});
}
}
}

Loading…
Cancel
Save