fajiao
2 years ago
69 changed files with 6458 additions and 0 deletions
@ -0,0 +1,59 @@ |
|||||
|
using System.Text; |
||||
|
|
||||
|
namespace EC.Util.CameraSDK; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 相机异常
|
||||
|
/// </summary>
|
||||
|
public class CameraException : Exception |
||||
|
{ |
||||
|
public CameraException() : base() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public CameraException(string? message) : base(message) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public CameraException(string? message, Exception? innerException) : base(message, innerException) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected class CameraExceptionObj |
||||
|
{ |
||||
|
public CameraManufactor Manufactor { get; set; } |
||||
|
|
||||
|
public int Code { get; set; } |
||||
|
|
||||
|
public string? Msg { get; set; } |
||||
|
|
||||
|
public override string? ToString() |
||||
|
{ |
||||
|
StringBuilder builder = new(); |
||||
|
builder.Append($"Manufactor:{Manufactor}, Code:{Code}"); |
||||
|
if (!string.IsNullOrEmpty(Msg)) builder.Append($", Msg:{Msg}"); |
||||
|
return builder.ToString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static CameraException New(CameraManufactor manufactor, int code) |
||||
|
{ |
||||
|
CameraExceptionObj obj = new() |
||||
|
{ |
||||
|
Manufactor = manufactor, |
||||
|
Code = code |
||||
|
}; |
||||
|
return new CameraException(obj.ToString()); |
||||
|
} |
||||
|
|
||||
|
public static CameraException New(CameraManufactor manufactor, int code, string msg) |
||||
|
{ |
||||
|
CameraExceptionObj obj = new() |
||||
|
{ |
||||
|
Manufactor = manufactor, |
||||
|
Code = code, |
||||
|
Msg = msg |
||||
|
}; |
||||
|
return new CameraException(obj.ToString()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
namespace EC.Util.CameraSDK; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 相机信息
|
||||
|
/// </summary>
|
||||
|
public class CameraInfo |
||||
|
{ |
||||
|
#region Attr
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 相机厂商
|
||||
|
/// </summary>
|
||||
|
public int Manufactor { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// ip 地址
|
||||
|
/// </summary>
|
||||
|
public string Ip { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 端口
|
||||
|
/// </summary>
|
||||
|
public int Port { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 账号
|
||||
|
/// </summary>
|
||||
|
public string UserName { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 密码
|
||||
|
/// </summary>
|
||||
|
public string Password { get; set; } = string.Empty; |
||||
|
|
||||
|
#endregion Attr
|
||||
|
|
||||
|
public static CameraInfo New(int manufactor, string ip, int port, string userName, string password) |
||||
|
{ |
||||
|
CameraInfo info = new() { Manufactor = manufactor, Ip = ip, Port = port, UserName = userName, Password = password }; |
||||
|
if (port <= 0) |
||||
|
throw new Exception("Camera manufactor not support."); |
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
public static CameraInfo New(int manufactor, string ip, string userName, string password) |
||||
|
{ |
||||
|
CameraInfo info = new() { Manufactor = manufactor, Ip = ip, UserName = userName, Password = password }; |
||||
|
int port = (CameraManufactor)manufactor switch |
||||
|
{ |
||||
|
CameraManufactor.HiK => (int)CameraPort.HiK, |
||||
|
CameraManufactor.DaHua => (int)CameraPort.DaHua, |
||||
|
CameraManufactor.YuShi => (int)CameraPort.YuShi, |
||||
|
_ => -1, |
||||
|
}; |
||||
|
info.Port = port; |
||||
|
if (port <= 0) |
||||
|
throw new Exception("Camera manufactor not support."); |
||||
|
return info; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 相机厂商
|
||||
|
/// </summary>
|
||||
|
public enum CameraManufactor : int |
||||
|
{ |
||||
|
HiK = 1, |
||||
|
DaHua, |
||||
|
YuShi, |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 相机默认连接端口
|
||||
|
/// </summary>
|
||||
|
public enum CameraPort : int |
||||
|
{ |
||||
|
HiK = 8000, |
||||
|
DaHua = 37777, |
||||
|
YuShi = 8800, |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Ptz 信息
|
||||
|
/// </summary>
|
||||
|
public class PtzInfo |
||||
|
{ |
||||
|
#region Attr
|
||||
|
|
||||
|
public double Pan { get; set; } |
||||
|
public double Tilt { get; set; } |
||||
|
public double Zoom { get; set; } |
||||
|
|
||||
|
#endregion Attr
|
||||
|
|
||||
|
public PtzInfo(double pan, double tilt, double zoom) |
||||
|
{ |
||||
|
Pan = pan; |
||||
|
Tilt = tilt; |
||||
|
Zoom = zoom; |
||||
|
} |
||||
|
|
||||
|
public static PtzInfo Default |
||||
|
{ |
||||
|
get { return new(0, 0, 0); } |
||||
|
} |
||||
|
|
||||
|
public static PtzInfo New(double pan, double tilt, double zoom) |
||||
|
{ |
||||
|
return new PtzInfo(pan, tilt, zoom); |
||||
|
} |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
namespace EC.Util.CameraSDK; |
||||
|
|
||||
|
public abstract class ICameraSDK |
||||
|
{ |
||||
|
#region Attr
|
||||
|
|
||||
|
protected CameraInfo CameraInfo { get; set; } |
||||
|
|
||||
|
#endregion Attr
|
||||
|
|
||||
|
public ICameraSDK(CameraInfo cameraInfo) |
||||
|
{ |
||||
|
CameraInfo = cameraInfo; |
||||
|
} |
||||
|
|
||||
|
#region Base Method
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 初始化资源
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public abstract bool Init(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 释放资源
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public abstract bool Destory(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 连接是否成功
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public abstract bool ConnectSuccess(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 构建异常
|
||||
|
/// </summary>
|
||||
|
public abstract void BuildException(); |
||||
|
|
||||
|
#endregion Base Method
|
||||
|
|
||||
|
#region Main Method
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取 ptz
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public abstract PtzInfo GetPtzInfo(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取 ptz
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public abstract bool TryGetPtzInfo(out PtzInfo ptzInfo); |
||||
|
|
||||
|
#endregion Main Method
|
||||
|
} |
@ -0,0 +1,245 @@ |
|||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace EC.Util.CameraSDK; |
||||
|
|
||||
|
public static class HiKOriSDK |
||||
|
{ |
||||
|
#region Lib Attr
|
||||
|
|
||||
|
public const string LibHcNetSDK = @"./libs/hik-win64/HCNetSDK.dll"; |
||||
|
|
||||
|
#endregion Lib Attr
|
||||
|
|
||||
|
static HiKOriSDK() |
||||
|
{ |
||||
|
GlobalInit(); |
||||
|
} |
||||
|
|
||||
|
#region Global
|
||||
|
|
||||
|
public static bool InitSuccess { get; private set; } |
||||
|
|
||||
|
public static bool GlobalInit() |
||||
|
{ |
||||
|
if (InitSuccess) return true; |
||||
|
bool ret = NET_DVR_Init(); |
||||
|
InitSuccess = ret; |
||||
|
if (!ret) throw new Exception("HiKOriSDK global init failure."); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
public static bool GlobalDestory() |
||||
|
{ |
||||
|
if (!InitSuccess) return true; |
||||
|
bool ret = NET_DVR_Cleanup(); |
||||
|
if (ret) InitSuccess = false; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
#endregion Global
|
||||
|
|
||||
|
#region SDK Const
|
||||
|
|
||||
|
public const int SERIALNO_LEN = 48; //序列号长度
|
||||
|
|
||||
|
#region 用于 NET_DVR_SetDVRConfig 和 NET_DVR_GetDVRConfig
|
||||
|
|
||||
|
public const int NET_DVR_SET_PTZPOS = 292; //云台设置PTZ位置
|
||||
|
public const int NET_DVR_GET_PTZPOS = 293; //云台获取PTZ位置
|
||||
|
public const int NET_DVR_GET_PTZSCOPE = 294; //云台获取PTZ范围
|
||||
|
|
||||
|
#endregion 用于 NET_DVR_SetDVRConfig 和 NET_DVR_GetDVRConfig
|
||||
|
|
||||
|
#region PtzMove
|
||||
|
|
||||
|
public const int TILT_UP = 21; /* 云台以SS的速度上仰 */ |
||||
|
public const int TILT_DOWN = 22; /* 云台以SS的速度下俯 */ |
||||
|
public const int PAN_LEFT = 23; /* 云台以SS的速度左转 */ |
||||
|
public const int PAN_RIGHT = 24; /* 云台以SS的速度右转 */ |
||||
|
public const int UP_LEFT = 25; /* 云台以SS的速度上仰和左转 */ |
||||
|
public const int UP_RIGHT = 26; /* 云台以SS的速度上仰和右转 */ |
||||
|
public const int DOWN_LEFT = 27; /* 云台以SS的速度下俯和左转 */ |
||||
|
public const int DOWN_RIGHT = 28; /* 云台以SS的速度下俯和右转 */ |
||||
|
public const int PAN_AUTO = 29; /* 云台以SS的速度左右自动扫描 */ |
||||
|
public const int GOTO_PRESET = 39; /* 快球转到预置点 */ |
||||
|
|
||||
|
#endregion PtzMove
|
||||
|
|
||||
|
#endregion SDK Const
|
||||
|
|
||||
|
#region SDK Struct
|
||||
|
|
||||
|
//NET_DVR_Login()参数结构
|
||||
|
[StructLayoutAttribute(LayoutKind.Sequential)] |
||||
|
public struct NET_DVR_DEVICEINFO |
||||
|
{ |
||||
|
[MarshalAsAttribute( |
||||
|
UnmanagedType.ByValArray, |
||||
|
SizeConst = SERIALNO_LEN, |
||||
|
ArraySubType = UnmanagedType.I1 |
||||
|
)] |
||||
|
public byte[] sSerialNumber; //序列号
|
||||
|
|
||||
|
public byte byAlarmInPortNum; //DVR报警输入个数
|
||||
|
public byte byAlarmOutPortNum; //DVR报警输出个数
|
||||
|
public byte byDiskNum; //DVR硬盘个数
|
||||
|
public byte byDVRType; //DVR类型, 1:DVR 2:ATM DVR 3:DVS ......
|
||||
|
public byte byChanNum; //DVR 通道个数
|
||||
|
public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1
|
||||
|
} |
||||
|
|
||||
|
//NET_DVR_Login_V30()参数结构
|
||||
|
[StructLayoutAttribute(LayoutKind.Sequential)] |
||||
|
public struct NET_DVR_DEVICEINFO_V30 |
||||
|
{ |
||||
|
[MarshalAsAttribute( |
||||
|
UnmanagedType.ByValArray, |
||||
|
SizeConst = SERIALNO_LEN, |
||||
|
ArraySubType = UnmanagedType.I1 |
||||
|
)] |
||||
|
public byte[] sSerialNumber; //序列号
|
||||
|
|
||||
|
public byte byAlarmInPortNum; //报警输入个数
|
||||
|
public byte byAlarmOutPortNum; //报警输出个数
|
||||
|
public byte byDiskNum; //硬盘个数
|
||||
|
public byte byDVRType; //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
|
||||
|
public byte byChanNum; //模拟通道个数
|
||||
|
public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1
|
||||
|
public byte byAudioChanNum; //语音通道数
|
||||
|
public byte byIPChanNum; //最大数字通道个数,低位
|
||||
|
public byte byZeroChanNum; //零通道编码个数 //2010-01-16
|
||||
|
public byte byMainProto; //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp
|
||||
|
public byte bySubProto; //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp
|
||||
|
public byte bySupport; //能力,位与结果为0表示不支持,1表示支持,
|
||||
|
|
||||
|
//bySupport & 0x1, 表示是否支持智能搜索
|
||||
|
//bySupport & 0x2, 表示是否支持备份
|
||||
|
//bySupport & 0x4, 表示是否支持压缩参数能力获取
|
||||
|
//bySupport & 0x8, 表示是否支持多网卡
|
||||
|
//bySupport & 0x10, 表示支持远程SADP
|
||||
|
//bySupport & 0x20, 表示支持Raid卡功能
|
||||
|
//bySupport & 0x40, 表示支持IPSAN 目录查找
|
||||
|
//bySupport & 0x80, 表示支持rtp over rtsp
|
||||
|
public byte bySupport1; // 能力集扩充,位与结果为0表示不支持,1表示支持
|
||||
|
|
||||
|
//bySupport1 & 0x1, 表示是否支持snmp v30
|
||||
|
//bySupport1 & 0x2, 支持区分回放和下载
|
||||
|
//bySupport1 & 0x4, 是否支持布防优先级
|
||||
|
//bySupport1 & 0x8, 智能设备是否支持布防时间段扩展
|
||||
|
//bySupport1 & 0x10, 表示是否支持多磁盘数(超过33个)
|
||||
|
//bySupport1 & 0x20, 表示是否支持rtsp over http
|
||||
|
//bySupport1 & 0x80, 表示是否支持车牌新报警信息2012-9-28, 且还表示是否支持NET_DVR_IPPARACFG_V40结构体
|
||||
|
public byte bySupport2; /*能力,位与结果为0表示不支持,非0表示支持 |
||||
|
|
||||
|
bySupport2 & 0x1, 表示解码器是否支持通过URL取流解码 |
||||
|
bySupport2 & 0x2, 表示支持FTPV40 |
||||
|
bySupport2 & 0x4, 表示支持ANR |
||||
|
bySupport2 & 0x8, 表示支持CCD的通道参数配置 |
||||
|
bySupport2 & 0x10, 表示支持布防报警回传信息(仅支持抓拍机报警 新老报警结构) |
||||
|
bySupport2 & 0x20, 表示是否支持单独获取设备状态子项 |
||||
|
bySupport2 & 0x40, 表示是否是码流加密设备*/ |
||||
|
public ushort wDevType; //设备型号
|
||||
|
public byte bySupport3; //能力集扩展,位与结果为0表示不支持,1表示支持
|
||||
|
|
||||
|
//bySupport3 & 0x1, 表示是否多码流
|
||||
|
// bySupport3 & 0x4 表示支持按组配置, 具体包含 通道图像参数、报警输入参数、IP报警输入、输出接入参数、
|
||||
|
// 用户参数、设备工作状态、JPEG抓图、定时和时间抓图、硬盘盘组管理
|
||||
|
//bySupport3 & 0x8为1 表示支持使用TCP预览、UDP预览、多播预览中的"延时预览"字段来请求延时预览(后续都将使用这种方式请求延时预览)。而当bySupport3 & 0x8为0时,将使用 "私有延时预览"协议。
|
||||
|
//bySupport3 & 0x10 表示支持"获取报警主机主要状态(V40)"。
|
||||
|
//bySupport3 & 0x20 表示是否支持通过DDNS域名解析取流
|
||||
|
|
||||
|
public byte byMultiStreamProto; //是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流
|
||||
|
public byte byStartDChan; //起始数字通道号,0表示无效
|
||||
|
public byte byStartDTalkChan; //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效
|
||||
|
public byte byHighDChanNum; //数字通道个数,高位
|
||||
|
public byte bySupport4; |
||||
|
public byte byLanguageType; // 支持语种能力,按位表示,每一位0-不支持,1-支持
|
||||
|
|
||||
|
// byLanguageType 等于0 表示 老设备
|
||||
|
// byLanguageType & 0x1表示支持中文
|
||||
|
// byLanguageType & 0x2表示支持英文
|
||||
|
[MarshalAsAttribute( |
||||
|
UnmanagedType.ByValArray, |
||||
|
SizeConst = 9, |
||||
|
ArraySubType = UnmanagedType.I1 |
||||
|
)] |
||||
|
public byte[] byRes2; //保留
|
||||
|
} |
||||
|
|
||||
|
//球机位置信息
|
||||
|
[StructLayoutAttribute(LayoutKind.Sequential)] |
||||
|
public struct NET_DVR_PTZPOS |
||||
|
{ |
||||
|
public ushort wAction; //获取时该字段无效
|
||||
|
public ushort wPanPos; //水平参数
|
||||
|
public ushort wTiltPos; //垂直参数
|
||||
|
public ushort wZoomPos; //变倍参数
|
||||
|
} |
||||
|
|
||||
|
//球机范围信息
|
||||
|
[StructLayoutAttribute(LayoutKind.Sequential)] |
||||
|
public struct NET_DVR_PTZSCOPE |
||||
|
{ |
||||
|
public ushort wPanPosMin; //水平参数min
|
||||
|
public ushort wPanPosMax; //水平参数max
|
||||
|
public ushort wTiltPosMin; //垂直参数min
|
||||
|
public ushort wTiltPosMax; //垂直参数max
|
||||
|
public ushort wZoomPosMin; //变倍参数min
|
||||
|
public ushort wZoomPosMax; //变倍参数max
|
||||
|
} |
||||
|
|
||||
|
#endregion SDK Struct
|
||||
|
|
||||
|
#region Common Method
|
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern bool NET_DVR_Init(); |
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern bool NET_DVR_Cleanup(); |
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern uint NET_DVR_GetLastError(); |
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern int NET_DVR_Login_V30( |
||||
|
string sDVRIP, |
||||
|
int wDVRPort, |
||||
|
string sUserName, |
||||
|
string sPassword, |
||||
|
ref NET_DVR_DEVICEINFO_V30 lpDeviceInfo |
||||
|
); |
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern bool NET_DVR_Logout(int iUserID); |
||||
|
|
||||
|
//参数配置 begin
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern bool NET_DVR_GetDVRConfig( |
||||
|
int lUserID, |
||||
|
uint dwCommand, |
||||
|
int lChannel, |
||||
|
IntPtr lpOutBuffer, |
||||
|
uint dwOutBufferSize, |
||||
|
ref uint lpBytesReturned |
||||
|
); |
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern bool NET_DVR_PTZControlWithSpeed_Other( |
||||
|
int lUserID, |
||||
|
int lChannel, |
||||
|
uint dwPTZCommand, |
||||
|
uint dwStop, |
||||
|
uint dwSpeed |
||||
|
); |
||||
|
|
||||
|
[DllImport(LibHcNetSDK)] |
||||
|
public static extern bool NET_DVR_PTZPreset_Other( |
||||
|
int lUserID, |
||||
|
int lChannel, |
||||
|
uint dwPTZPresetCmd, |
||||
|
uint dwPresetIndex |
||||
|
); |
||||
|
|
||||
|
#endregion Common Method
|
||||
|
} |
@ -0,0 +1,143 @@ |
|||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace EC.Util.CameraSDK; |
||||
|
|
||||
|
public class HiKSDK : ICameraSDK |
||||
|
{ |
||||
|
#region Attr
|
||||
|
|
||||
|
private int LoginId { get; set; } = -1; |
||||
|
|
||||
|
#endregion Attr
|
||||
|
|
||||
|
public HiKSDK(CameraInfo cameraInfo) : base(cameraInfo) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
#region Base Method
|
||||
|
|
||||
|
public override bool Init() |
||||
|
{ |
||||
|
bool ret = ConnectSuccess(); |
||||
|
if (ret) return true; |
||||
|
|
||||
|
HiKOriSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new(); |
||||
|
LoginId = HiKOriSDK.NET_DVR_Login_V30(CameraInfo.Ip, CameraInfo.Port, CameraInfo.UserName, CameraInfo.Password, ref deviceInfo); |
||||
|
ret = ConnectSuccess(); |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
public override bool Destory() |
||||
|
{ |
||||
|
bool ret = ConnectSuccess(); |
||||
|
if (!ret) return true; |
||||
|
|
||||
|
ret = HiKOriSDK.NET_DVR_Logout(LoginId); |
||||
|
if (ret) LoginId = -1; |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
public override bool ConnectSuccess() |
||||
|
{ |
||||
|
return LoginId >= 0; |
||||
|
} |
||||
|
|
||||
|
public override void BuildException() |
||||
|
{ |
||||
|
uint errCode = HiKOriSDK.NET_DVR_GetLastError(); |
||||
|
if (errCode == 0) return; |
||||
|
throw CameraException.New(CameraManufactor.HiK, (int)errCode); |
||||
|
} |
||||
|
|
||||
|
#endregion Base Method
|
||||
|
|
||||
|
#region Main Method
|
||||
|
|
||||
|
private static class GPIParams |
||||
|
{ |
||||
|
public static int Size { get; private set; } |
||||
|
public static Type Type { get; private set; } |
||||
|
|
||||
|
static GPIParams() |
||||
|
{ |
||||
|
HiKOriSDK.NET_DVR_PTZPOS ptzPos = new(); |
||||
|
Size = Marshal.SizeOf(ptzPos); |
||||
|
Type = ptzPos.GetType(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override PtzInfo GetPtzInfo() |
||||
|
{ |
||||
|
bool ret = ConnectSuccess(); |
||||
|
if (!ret) return PtzInfo.Default; |
||||
|
|
||||
|
HiKOriSDK.NET_DVR_PTZPOS entity = new(); |
||||
|
int dwSize = GPIParams.Size; |
||||
|
uint dwReturned = 0; |
||||
|
IntPtr ptrBuf = Marshal.AllocHGlobal(dwSize); |
||||
|
Marshal.StructureToPtr(entity, ptrBuf, true); |
||||
|
try |
||||
|
{ |
||||
|
ret = HiKOriSDK.NET_DVR_GetDVRConfig(LoginId, HiKOriSDK.NET_DVR_GET_PTZPOS, 0, ptrBuf, (uint)dwSize, ref dwReturned); |
||||
|
if (!ret) { BuildException(); return PtzInfo.Default; } |
||||
|
object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type); |
||||
|
if (objBuf == null) return PtzInfo.Default; |
||||
|
entity = (HiKOriSDK.NET_DVR_PTZPOS)objBuf; |
||||
|
return PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos); |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
Marshal.FreeHGlobal(ptrBuf); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override bool TryGetPtzInfo(out PtzInfo ptzInfo) |
||||
|
{ |
||||
|
bool ret = ConnectSuccess(); |
||||
|
if (!ret) { ptzInfo = PtzInfo.Default; return false; } |
||||
|
|
||||
|
HiKOriSDK.NET_DVR_PTZPOS entity = new(); |
||||
|
int dwSize = GPIParams.Size; |
||||
|
uint dwReturned = 0; |
||||
|
IntPtr ptrBuf = Marshal.AllocHGlobal(dwSize); |
||||
|
Marshal.StructureToPtr(entity, ptrBuf, true); |
||||
|
try |
||||
|
{ |
||||
|
ret = HiKOriSDK.NET_DVR_GetDVRConfig(LoginId, HiKOriSDK.NET_DVR_GET_PTZPOS, 0, ptrBuf, (uint)dwSize, ref dwReturned); |
||||
|
if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; } |
||||
|
object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type); |
||||
|
if (objBuf == null) { ptzInfo = PtzInfo.Default; return false; } |
||||
|
entity = (HiKOriSDK.NET_DVR_PTZPOS)objBuf; |
||||
|
ptzInfo = PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos); |
||||
|
return true; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
Marshal.FreeHGlobal(ptrBuf); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Main Method
|
||||
|
|
||||
|
#region Ptz Method
|
||||
|
|
||||
|
public void PtzMove(uint[] args) |
||||
|
{ |
||||
|
bool ret = ConnectSuccess(); |
||||
|
if (!ret || args == null || args.Length < 3) return; |
||||
|
int lChannel = 1; |
||||
|
HiKOriSDK.NET_DVR_PTZControlWithSpeed_Other(LoginId, lChannel, args[0], args[1], args[2]); |
||||
|
} |
||||
|
|
||||
|
public void PtzPreset(uint[] args) |
||||
|
{ |
||||
|
bool ret = ConnectSuccess(); |
||||
|
if (!ret || args == null || args.Length < 2) return; |
||||
|
int lChannel = 1; |
||||
|
HiKOriSDK.NET_DVR_PTZPreset_Other(LoginId, lChannel, args[0], args[1]); |
||||
|
} |
||||
|
|
||||
|
#endregion Ptz Method
|
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Converters; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
|
||||
|
namespace EC.Util.Common; |
||||
|
|
||||
|
public static class JsonUtil |
||||
|
{ |
||||
|
public static object ToJson(string Json) |
||||
|
{ |
||||
|
object? obj = JsonConvert.DeserializeObject(Json); |
||||
|
return obj ?? new(); |
||||
|
} |
||||
|
|
||||
|
public static string ToJson(object obj) |
||||
|
{ |
||||
|
IsoDateTimeConverter timeConverter = new() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }; |
||||
|
return JsonConvert.SerializeObject(obj, timeConverter); |
||||
|
} |
||||
|
|
||||
|
public static string ToJson(object obj, string datetimeformats) |
||||
|
{ |
||||
|
IsoDateTimeConverter timeConverter = new() { DateTimeFormat = datetimeformats }; |
||||
|
return JsonConvert.SerializeObject(obj, timeConverter); |
||||
|
} |
||||
|
|
||||
|
public static T ToObject<T>(string Json) |
||||
|
{ |
||||
|
T? obj = JsonConvert.DeserializeObject<T>(Json); |
||||
|
return obj ?? Activator.CreateInstance<T>(); |
||||
|
} |
||||
|
|
||||
|
public static List<T> ToList<T>(string Json) |
||||
|
{ |
||||
|
List<T>? list = JsonConvert.DeserializeObject<List<T>>(Json); |
||||
|
return list ?? new List<T>(); |
||||
|
} |
||||
|
|
||||
|
public static JObject ToJObject(string Json) |
||||
|
{ |
||||
|
return Json != null ? JObject.Parse(Json.Replace(" ", "")) : JObject.Parse("{}"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace EC.Util.Common; |
||||
|
|
||||
|
public static class SystemUtil |
||||
|
{ |
||||
|
[DllImport("Kernel32")] |
||||
|
public static extern void AllocConsole(); |
||||
|
|
||||
|
[DllImport("Kernel32")] |
||||
|
public static extern void FreeConsole(); |
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net6.0</TargetFramework> |
||||
|
<ImplicitUsings>enable</ImplicitUsings> |
||||
|
<Nullable>enable</Nullable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="libs\hik-win64\HCCore.dll" /> |
||||
|
<None Remove="libs\hik-win64\HCNetSDK.dll" /> |
||||
|
<None Remove="libs\hik-win64\HCNetSDKCom\HCCoreDevCfg.dll" /> |
||||
|
<None Remove="libs\hik-win64\HCNetSDKCom\HCPreview.dll" /> |
||||
|
<None Remove="libs\hik-win64\libcrypto-1_1-x64.dll" /> |
||||
|
<None Remove="libs\hik-win64\libssl-1_1-x64.dll" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Content Include="libs\hik-win64\HCCore.dll"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
<Content Include="libs\hik-win64\HCNetSDK.dll"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
<Content Include="libs\hik-win64\HCNetSDKCom\HCCoreDevCfg.dll"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
<Content Include="libs\hik-win64\HCNetSDKCom\HCPreview.dll"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
<Content Include="libs\hik-win64\libcrypto-1_1-x64.dll"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
<Content Include="libs\hik-win64\libssl-1_1-x64.dll"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="NetMQ" Version="4.0.1.11" /> |
||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
||||
|
<PackageReference Include="System.IO.Ports" Version="7.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
@ -0,0 +1,60 @@ |
|||||
|
namespace EC.Util.Port; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 串口构建类
|
||||
|
/// </summary>
|
||||
|
public class SerialPortBuilder |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// </summary>
|
||||
|
/// <param name="param"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static YcSerialPort CreateSerialPort(SerialPortParam param) |
||||
|
{ |
||||
|
return new YcSerialPort(param); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// </summary>
|
||||
|
/// <param name="comName"></param>
|
||||
|
public static YcSerialPort CreateSerialPort(string comName) |
||||
|
{ |
||||
|
var param = new SerialPortParam |
||||
|
{ |
||||
|
ComName = comName |
||||
|
}; |
||||
|
return new YcSerialPort(param); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// </summary>
|
||||
|
/// <param name="comName"></param>
|
||||
|
/// <param name="baudRate"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static YcSerialPort CreateSerialPort(string comName, int baudRate) |
||||
|
{ |
||||
|
var param = new SerialPortParam |
||||
|
{ |
||||
|
ComName = comName, |
||||
|
BaudRate = baudRate |
||||
|
}; |
||||
|
return new YcSerialPort(param); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// </summary>
|
||||
|
/// <param name="comName"></param>
|
||||
|
/// <param name="baudRate"></param>
|
||||
|
/// <param name="receivedBytesThreshold"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static YcSerialPort CreateSerialPort(string comName, int baudRate, int receivedBytesThreshold) |
||||
|
{ |
||||
|
var param = new SerialPortParam |
||||
|
{ |
||||
|
ComName = comName, |
||||
|
BaudRate = baudRate, |
||||
|
ReceivedBytesThreshold = receivedBytesThreshold |
||||
|
}; |
||||
|
return new YcSerialPort(param); |
||||
|
} |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
namespace EC.Util.Port; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 串口参数类
|
||||
|
/// </summary>
|
||||
|
public class SerialPortParam |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 串口名称
|
||||
|
/// </summary>
|
||||
|
public string ComName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
///波特率
|
||||
|
/// </summary>
|
||||
|
public int BaudRate { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 奇偶校验0-4=no,odd,even,mark,space
|
||||
|
/// </summary>
|
||||
|
public int Parity { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 校验位对应值
|
||||
|
/// </summary>
|
||||
|
public int ParityValue { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
///数据位 默认
|
||||
|
/// </summary>
|
||||
|
public int DataBits { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 停止位
|
||||
|
/// </summary>
|
||||
|
public int StopBits { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// ?Byte时,触发一次事件。设置为1时,易造成线程死锁
|
||||
|
/// </summary>
|
||||
|
public int ReceivedBytesThreshold { get; set; } |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public SerialPortParam() |
||||
|
{ |
||||
|
ComName = string.Empty; |
||||
|
BaudRate = 9600; |
||||
|
Parity = 0; |
||||
|
DataBits = 8; |
||||
|
StopBits = 1; |
||||
|
ReceivedBytesThreshold = 128; |
||||
|
} |
||||
|
} |
@ -0,0 +1,166 @@ |
|||||
|
using System.IO.Ports; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
namespace EC.Util.Port; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 串口类
|
||||
|
/// </summary>
|
||||
|
public class YcSerialPort |
||||
|
{ |
||||
|
private SerialPort _port;//声明一个串口
|
||||
|
private readonly SerialPortParam _param; |
||||
|
|
||||
|
public long RecCount { get; set; }//接收计数
|
||||
|
|
||||
|
public long SendCount { get; set; }//发送计数
|
||||
|
|
||||
|
public YcSerialPort() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public YcSerialPort(SerialPortParam param) |
||||
|
{ |
||||
|
_param = param; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 打开串口
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public bool OpenCom() |
||||
|
{ |
||||
|
if (IsOpen()) |
||||
|
CloseCom(); |
||||
|
if (string.IsNullOrEmpty(_param.ComName)) |
||||
|
throw new Exception("请插入串口设备!"); |
||||
|
|
||||
|
_port = new SerialPort |
||||
|
{ |
||||
|
PortName = _param.ComName,//串口名
|
||||
|
BaudRate = _param.BaudRate,//波特率
|
||||
|
DataBits = _param.DataBits,//数据位
|
||||
|
Parity = (Parity)_param.Parity,//奇偶校验0-4=no,odd,even,mark,space
|
||||
|
StopBits = (StopBits)Convert.ToInt32(_param.StopBits),//停止位
|
||||
|
ReadTimeout = 500,//读超时
|
||||
|
WriteTimeout = 2000,//写超时
|
||||
|
//ReadBufferSize = 1024,
|
||||
|
//WriteBufferSize = 1024,
|
||||
|
ReceivedBytesThreshold = _param.ReceivedBytesThreshold,//128Byte时触发一次事件,设置为1时易造成线程死锁。
|
||||
|
RtsEnable = true, |
||||
|
DtrEnable = true, |
||||
|
}; |
||||
|
_port.DataReceived += RecData; |
||||
|
//port.DataReceived += new SerialDataReceivedEventHandler(Comm_DataReceived);
|
||||
|
_port.Open(); |
||||
|
return IsOpen(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 关闭串口
|
||||
|
/// </summary>
|
||||
|
public bool CloseCom() |
||||
|
{ |
||||
|
if (IsOpen()) |
||||
|
{ |
||||
|
_port.Close(); |
||||
|
_port = null; |
||||
|
} |
||||
|
return !IsOpen(); |
||||
|
} |
||||
|
|
||||
|
public bool IsOpen() |
||||
|
{ |
||||
|
if (_port == null) |
||||
|
return false; |
||||
|
if (!_port.IsOpen) |
||||
|
return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public event EventHandler<byte[]> OnRecData; //定义一个委托类型的事件
|
||||
|
|
||||
|
private void RecData(object sender, EventArgs e) |
||||
|
{ |
||||
|
var count = _port.BytesToRead;//获取缓存区字节数
|
||||
|
var buf = new byte[count];//存储串口数据用
|
||||
|
_port.Read(buf, 0, count);//读取缓冲数据
|
||||
|
RecCount += count;//接收计数
|
||||
|
OnRecData?.Invoke(this, buf); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送 Ascii
|
||||
|
/// </summary>
|
||||
|
/// <param name="text"></param>
|
||||
|
/// <param name="newLine"></param>
|
||||
|
public void SendAscii(string text, bool newLine = false) |
||||
|
{ |
||||
|
//定义一个变量,记录发送了几个字节
|
||||
|
int count; |
||||
|
|
||||
|
if (newLine) |
||||
|
{ |
||||
|
_port.Write(text + "\r\n"); |
||||
|
count = text.Length + 2; |
||||
|
} |
||||
|
else//不包含换行符
|
||||
|
{ |
||||
|
_port.Write(text); |
||||
|
count = text.Length; |
||||
|
} |
||||
|
|
||||
|
SendCount += count;//累加发送字节数
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送 Hex
|
||||
|
/// </summary>
|
||||
|
/// <param name="text"></param>
|
||||
|
/// <param name="newLine"></param>
|
||||
|
public void SendHex(string text, bool newLine = false) |
||||
|
{ |
||||
|
int count;//定义一个变量,记录发送了几个字节
|
||||
|
var mc = Regex.Matches(text, @"(?i)[\da-f]{2}");//正则得到有效的十六进制数(?i)对大小写不敏感,[/da-f],{2}连续出现2次
|
||||
|
var buf = new List<byte>();//填充到这个临时列表中
|
||||
|
foreach (Match m in mc) |
||||
|
{ |
||||
|
buf.Add(byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber));//依次添加到列表中
|
||||
|
} |
||||
|
_port.Write(buf.ToArray(), 0, buf.Count);//转换列表为数组后发送
|
||||
|
if (newLine) |
||||
|
{ |
||||
|
_port.Write("\r\n"); |
||||
|
count = buf.Count + 2; |
||||
|
} |
||||
|
else//不包含换行符
|
||||
|
{ |
||||
|
count = buf.Count; |
||||
|
} |
||||
|
|
||||
|
SendCount += count;//累加发送字节数
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送 Hex
|
||||
|
/// </summary>
|
||||
|
/// <param name="buf"></param>
|
||||
|
/// <param name="newline"></param>
|
||||
|
public void SendHex(byte[] buf, bool newline = false) |
||||
|
{ |
||||
|
int count;//定义一个变量,记录发送了几个字节
|
||||
|
var bufLen = buf.Count(); |
||||
|
_port.Write(buf, 0, bufLen); |
||||
|
if (newline) |
||||
|
{ //记录发送的字节数
|
||||
|
_port.WriteLine("\n"); |
||||
|
count = bufLen + 2; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
count = bufLen; |
||||
|
} |
||||
|
|
||||
|
SendCount += count;//累加发送字节数
|
||||
|
} |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
namespace EC.Util.Zmq; |
||||
|
|
||||
|
internal class ZmqUtil |
||||
|
{ |
||||
|
//#region fields
|
||||
|
|
||||
|
//private SubscriberSocket SubSocket { get; set; }
|
||||
|
//private PublisherSocket PubSocket { get; set; }
|
||||
|
|
||||
|
//#endregion fields
|
||||
|
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,31 @@ |
|||||
|
|
||||
|
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
|
# Visual Studio Version 17 |
||||
|
VisualStudioVersion = 17.4.33205.214 |
||||
|
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiLinApp", "JiLinApp\JiLinApp.csproj", "{273E34C9-ED30-460E-BA9A-66A8F27CC5FE}" |
||||
|
EndProject |
||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EC.Util", "EC.Util\EC.Util.csproj", "{A41E47C9-1930-4FF0-955E-B91EC859D262}" |
||||
|
EndProject |
||||
|
Global |
||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
|
Debug|Any CPU = Debug|Any CPU |
||||
|
Release|Any CPU = Release|Any CPU |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
|
{273E34C9-ED30-460E-BA9A-66A8F27CC5FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{273E34C9-ED30-460E-BA9A-66A8F27CC5FE}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{273E34C9-ED30-460E-BA9A-66A8F27CC5FE}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{273E34C9-ED30-460E-BA9A-66A8F27CC5FE}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{A41E47C9-1930-4FF0-955E-B91EC859D262}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{A41E47C9-1930-4FF0-955E-B91EC859D262}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{A41E47C9-1930-4FF0-955E-B91EC859D262}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{A41E47C9-1930-4FF0-955E-B91EC859D262}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
EndGlobalSection |
||||
|
GlobalSection(SolutionProperties) = preSolution |
||||
|
HideSolutionNode = FALSE |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
|
SolutionGuid = {18952E5F-487C-4B42-92A5-5EBBE87AFF1F} |
||||
|
EndGlobalSection |
||||
|
EndGlobal |
@ -0,0 +1,20 @@ |
|||||
|
<prism:PrismApplication x:Class="JiLinApp.App" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" |
||||
|
xmlns:prism="http://prismlibrary.com/" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
||||
|
<Application.Resources> |
||||
|
<ResourceDictionary> |
||||
|
<ResourceDictionary.MergedDictionaries> |
||||
|
<!-- This is the current way to setup your app's initial theme --> |
||||
|
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Blue" SecondaryColor="Lime" ColorAdjustment="{materialDesign:ColorAdjustment}" /> |
||||
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" /> |
||||
|
<!--<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Dark.xaml" />--> |
||||
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> |
||||
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Blue.xaml" /> |
||||
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" /> |
||||
|
</ResourceDictionary.MergedDictionaries> |
||||
|
<SolidColorBrush x:Key="PrimaryBodyBrush" Color="#44494f" /> |
||||
|
</ResourceDictionary> |
||||
|
</Application.Resources> |
||||
|
</prism:PrismApplication> |
@ -0,0 +1,79 @@ |
|||||
|
using JiLinApp.Core; |
||||
|
using JiLinApp.Pages.Main; |
||||
|
using NewLife.Log; |
||||
|
using Prism.Ioc; |
||||
|
using Prism.Modularity; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Threading; |
||||
|
|
||||
|
namespace JiLinApp; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Interaction logic for App.xaml
|
||||
|
/// </summary>
|
||||
|
public partial class App |
||||
|
{ |
||||
|
public App() : base() |
||||
|
{ |
||||
|
RegisterEvents(); |
||||
|
Global.Init(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnStartup(StartupEventArgs e) |
||||
|
{ |
||||
|
base.OnStartup(e); |
||||
|
} |
||||
|
|
||||
|
protected override Window CreateShell() |
||||
|
{ |
||||
|
return Container.Resolve<MainWindow>(); |
||||
|
} |
||||
|
|
||||
|
protected override void RegisterTypes(IContainerRegistry containerRegistry) |
||||
|
{ |
||||
|
//containerRegistry.RegisterSingleton<IMessageService, MessageService>();
|
||||
|
} |
||||
|
|
||||
|
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) |
||||
|
{ |
||||
|
//moduleCatalog.AddModule<ModuleNameModule>();
|
||||
|
} |
||||
|
|
||||
|
protected override void OnInitialized() |
||||
|
{ |
||||
|
base.OnInitialized(); |
||||
|
} |
||||
|
|
||||
|
#region Bind
|
||||
|
|
||||
|
private void RegisterEvents() |
||||
|
{ |
||||
|
//UI线程未捕获异常处理事件(UI主线程)
|
||||
|
DispatcherUnhandledException += App_DispatcherUnhandledException; |
||||
|
|
||||
|
//Task线程内未捕获异常处理事件
|
||||
|
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; |
||||
|
|
||||
|
//非UI线程未捕获异常处理事件(例如自己创建的一个子线程)
|
||||
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; |
||||
|
} |
||||
|
|
||||
|
private static void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) |
||||
|
{ |
||||
|
XTrace.Log.Error("{0}", e.Exception.Message); |
||||
|
} |
||||
|
|
||||
|
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) |
||||
|
{ |
||||
|
XTrace.Log.Error("{0}", e.Exception.Message); |
||||
|
} |
||||
|
|
||||
|
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) |
||||
|
{ |
||||
|
XTrace.Log.Error("{0}", ((Exception)e.ExceptionObject).Message); |
||||
|
} |
||||
|
|
||||
|
#endregion Bind
|
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
using EC.Util.CameraSDK; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace JiLinApp.Core; |
||||
|
|
||||
|
public class AppConfig |
||||
|
{ |
||||
|
public ZmqConfig Zmq { get; set; } |
||||
|
|
||||
|
public List<CameraInfo> CameraList { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class ZmqConfig |
||||
|
{ |
||||
|
public string AlarmPubAddr { get; set; } |
||||
|
public string AlarmPubTopic { get; set; } |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
using NetMQ.Sockets; |
||||
|
using NewLife.Configuration; |
||||
|
using System; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace JiLinApp.Core; |
||||
|
|
||||
|
public static class Global |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
public static readonly JsonConfigProvider ConfigProvider; |
||||
|
public static readonly AppConfig AppConfig; |
||||
|
|
||||
|
public static readonly PublisherSocket AlarmPubSocket; |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
static Global() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// Config
|
||||
|
ConfigProvider = new() { FileName = "config.json" }; |
||||
|
AppConfig = new AppConfig(); |
||||
|
ConfigProvider.Bind(AppConfig); |
||||
|
|
||||
|
// Zmq
|
||||
|
AlarmPubSocket = new(); |
||||
|
AlarmPubSocket.Connect(AppConfig.Zmq.AlarmPubAddr); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
MessageBox.Show(ex.ToString()); |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void Init() |
||||
|
{ |
||||
|
} |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
using NewLife.Log; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Core; |
||||
|
|
||||
|
public static class TaskUtil |
||||
|
{ |
||||
|
public static Task Run(Action action) |
||||
|
{ |
||||
|
return Task.Run(() => |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
action(); |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
XTrace.Log.Error("{0}", e.Message); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,64 @@ |
|||||
|
using JiLinApp.Pages.FenceServerManage; |
||||
|
using JiLinApp.Pages.ShakeServerManage; |
||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Docking; |
||||
|
|
||||
|
public class AlarmMessage |
||||
|
{ |
||||
|
/** (必填)传感器设备编码*/ |
||||
|
public string labelCode; |
||||
|
/** (必填)报警类型((1-视频报警,2-雷达报警;3-微振动警报,4-电子围网警报,9-其他报警))*/ |
||||
|
public int warnType; |
||||
|
/** (必填)报警级别(1-5)*/ |
||||
|
public int warnLevel; |
||||
|
/** (必填)报警内容*/ |
||||
|
public string warnContent; |
||||
|
/** 处置方式*/ |
||||
|
public int dealWay; |
||||
|
/** (必填)处置状态(1-未处理,2-已处理)*/ |
||||
|
public int dealStatus; |
||||
|
/** (必填)发生地点*/ |
||||
|
public string cameraLoc; |
||||
|
/** (必填)发生时间*/ |
||||
|
public DateTime createTime; |
||||
|
/** 负责人*/ |
||||
|
public string director; |
||||
|
/** (必填)类型(1-预警,2-报警)*/ |
||||
|
public int kind; |
||||
|
/** 现场照片*/ |
||||
|
public string imgUrl; |
||||
|
} |
||||
|
|
||||
|
public static class AlarmMessageHelper |
||||
|
{ |
||||
|
public static AlarmMessage ToAlarmMessage(this TcpAlarmHostMessage msg) |
||||
|
{ |
||||
|
AlarmMessage obj = new() |
||||
|
{ |
||||
|
labelCode = Convert.ToString(msg.Id), |
||||
|
warnType = 3, |
||||
|
warnLevel = 1, |
||||
|
warnContent = msg.AlarmId, |
||||
|
dealStatus = 1, |
||||
|
createTime = Convert.ToDateTime(msg.AlarmTime), |
||||
|
kind = 1, |
||||
|
}; |
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
public static AlarmMessage ToAlarmMessage(this UdpAlarmHostMessage msg) |
||||
|
{ |
||||
|
AlarmMessage obj = new() |
||||
|
{ |
||||
|
labelCode = Convert.ToString(msg.Id), |
||||
|
warnType = 4, |
||||
|
warnLevel = 1, |
||||
|
warnContent = msg.CID, |
||||
|
dealStatus = 1, |
||||
|
createTime = Convert.ToDateTime(msg.AlarmTime), |
||||
|
kind = 1, |
||||
|
}; |
||||
|
return obj; |
||||
|
} |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<OutputType>WinExe</OutputType> |
||||
|
<TargetFramework>net6.0-windows</TargetFramework> |
||||
|
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages> |
||||
|
<UseWPF>true</UseWPF> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="MaterialDesignColors" Version="2.1.2" /> |
||||
|
<PackageReference Include="MaterialDesignThemes" Version="4.8.0" /> |
||||
|
<PackageReference Include="NewLife.Core" Version="10.2.2023.301" /> |
||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
||||
|
<PackageReference Include="Prism.DryIoc" Version="8.1.97" /> |
||||
|
<PackageReference Include="System.IO.Ports" Version="7.0.0" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\EC.Util\EC.Util.csproj" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<None Update="config.json"> |
||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
</ItemGroup> |
||||
|
</Project> |
@ -0,0 +1,30 @@ |
|||||
|
using Prism.Events; |
||||
|
using Prism.Regions; |
||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Mvvm; |
||||
|
|
||||
|
public class RegionViewModelBase : ViewModelBase, INavigationAware, IConfirmNavigationRequest |
||||
|
{ |
||||
|
public RegionViewModelBase(IRegionManager region, IEventAggregator ea) : base(region, ea) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) |
||||
|
{ |
||||
|
continuationCallback(true); |
||||
|
} |
||||
|
|
||||
|
public virtual bool IsNavigationTarget(NavigationContext navigationContext) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public virtual void OnNavigatedFrom(NavigationContext navigationContext) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual void OnNavigatedTo(NavigationContext navigationContext) |
||||
|
{ |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
using Prism.Events; |
||||
|
using Prism.Mvvm; |
||||
|
using Prism.Regions; |
||||
|
|
||||
|
namespace JiLinApp.Mvvm; |
||||
|
|
||||
|
public abstract class AbstractViewModelBase : BindableBase |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
protected IRegionManager _region { get; set; } |
||||
|
protected IEventAggregator _ea { get; set; } |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public AbstractViewModelBase(IRegionManager region, IEventAggregator ea) |
||||
|
{ |
||||
|
_region = region; |
||||
|
_ea = ea; |
||||
|
} |
||||
|
|
||||
|
public abstract void SetView(object view); |
||||
|
} |
||||
|
|
||||
|
public class ViewModelBase : AbstractViewModelBase |
||||
|
{ |
||||
|
public ViewModelBase(IRegionManager region, IEventAggregator ea) : base(region, ea) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override void SetView(object view) |
||||
|
{ |
||||
|
} |
||||
|
} |
@ -0,0 +1,141 @@ |
|||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class AlarmEncode |
||||
|
{ |
||||
|
private static byte[] TEA_key = new byte[16] { |
||||
|
0x08,0x01,0x08,0x06,0x07,0x08,0x07,0x08, |
||||
|
0x08,0x90,0xC5,0x04,0x0D,0x0E,0x0F,0x10 |
||||
|
}; |
||||
|
|
||||
|
public static byte[] encodeMessage(byte[] msg) |
||||
|
{ |
||||
|
if (!checkMessage(msg)) return null; |
||||
|
return getMessage(msg[0], btea_encrypt(getContent(msg, msg[0] - 1))); |
||||
|
} |
||||
|
|
||||
|
public static byte[] decodeMessage(byte[] msg) |
||||
|
{ |
||||
|
if (!checkMessage(msg)) return null; |
||||
|
return getMessage(msg[0], btea_decrpyt(getContent(msg, msg[0] - 1))); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CRC16(byte[] data) |
||||
|
{ |
||||
|
int len = data.Length; |
||||
|
if (len > 0) |
||||
|
{ |
||||
|
ushort crc = 0xFFFF; |
||||
|
|
||||
|
for (int i = 0; i < len; i++) |
||||
|
{ |
||||
|
crc = (ushort)(crc ^ (data[i])); |
||||
|
for (int j = 0; j < 8; j++) |
||||
|
{ |
||||
|
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); |
||||
|
} |
||||
|
} |
||||
|
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
|
||||
|
byte lo = (byte)(crc & 0x00FF); //低位置
|
||||
|
|
||||
|
return new byte[] { hi, lo }; |
||||
|
} |
||||
|
return new byte[] { 0, 0 }; |
||||
|
} |
||||
|
|
||||
|
private static byte version = 0x12; |
||||
|
private static byte[] head = new byte[] { 0xF0, 0xFA }; |
||||
|
private static byte end = 0x0D; |
||||
|
|
||||
|
public static byte[] getSendMessage(byte command, byte[] data) |
||||
|
{ |
||||
|
byte[] msg = null; |
||||
|
if (data == null) |
||||
|
{ |
||||
|
msg = new byte[8]; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
msg = new byte[data.Length + 8]; |
||||
|
} |
||||
|
msg[0] = (byte)msg.Length; |
||||
|
msg[1] = version; |
||||
|
msg[2] = head[0]; |
||||
|
msg[3] = head[1]; |
||||
|
msg[4] = command; |
||||
|
if (data != null) |
||||
|
{ |
||||
|
for (int i = 0; i < data.Length; i++) |
||||
|
{ |
||||
|
msg[i + 5] = data[i]; |
||||
|
} |
||||
|
} |
||||
|
byte[] subMsg = null; |
||||
|
if (data == null) |
||||
|
{ |
||||
|
subMsg = new byte[4]; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
subMsg = new byte[4 + data.Length]; |
||||
|
} |
||||
|
for (int i = 0; i < subMsg.Length; i++) |
||||
|
{ |
||||
|
subMsg[i] = msg[i + 1]; |
||||
|
} |
||||
|
byte[] crc = CRC16(subMsg); |
||||
|
msg[msg.Length - 3] = crc[1]; |
||||
|
msg[msg.Length - 2] = crc[0]; |
||||
|
msg[msg.Length - 1] = end; |
||||
|
return msg; |
||||
|
} |
||||
|
|
||||
|
private static bool checkMessage(byte[] msg) |
||||
|
{ |
||||
|
if (msg == null) return false; |
||||
|
if (msg[0] > msg.Length) return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private static byte[] getContent(byte[] msg, int len) |
||||
|
{ |
||||
|
byte[] bytes = new byte[len]; |
||||
|
for (int i = 0; i < len; i++) |
||||
|
{ |
||||
|
bytes[i] = msg[i + 1]; |
||||
|
} |
||||
|
return bytes; |
||||
|
} |
||||
|
|
||||
|
private static byte[] getMessage(byte msgLen, byte[] msg) |
||||
|
{ |
||||
|
byte[] out_msg = new byte[msg.Length + 1]; |
||||
|
out_msg[0] = msgLen; |
||||
|
for (int i = 0; i < msg.Length; i++) |
||||
|
{ |
||||
|
out_msg[i + 1] = msg[i]; |
||||
|
} |
||||
|
return out_msg; |
||||
|
} |
||||
|
|
||||
|
private static byte[] btea_encrypt(byte[] bytes) |
||||
|
{ |
||||
|
byte[] output = new byte[bytes.Length]; |
||||
|
for (int i = 0; i < bytes.Length; i++) |
||||
|
{ |
||||
|
byte abyte = (byte)(bytes[i] ^ TEA_key[i % 16]); |
||||
|
output[i] = (byte)(((byte)(abyte >> 3)) | ((byte)(abyte << 5))); |
||||
|
} |
||||
|
return output; |
||||
|
} |
||||
|
|
||||
|
private static byte[] btea_decrpyt(byte[] bytes) |
||||
|
{ |
||||
|
byte[] output = new byte[bytes.Length]; |
||||
|
for (int i = 0; i < bytes.Length; i++) |
||||
|
{ |
||||
|
byte abyte = (byte)(((byte)(bytes[i] << 3)) | ((byte)(bytes[i] >> 5))); |
||||
|
output[i] = (byte)(abyte ^ TEA_key[i % 16]); |
||||
|
} |
||||
|
return output; |
||||
|
} |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class DeviceStateMessage |
||||
|
{ |
||||
|
public int deviceID { get; set; }//设备唯一ID
|
||||
|
public string StatusTime { get; set; }//时间
|
||||
|
public int channel { get; set; }//防区
|
||||
|
public int StatusType { get; set; }//状态
|
||||
|
|
||||
|
public DeviceStateMessage(int id, DateTime time, int Channel, int statusType) |
||||
|
{ |
||||
|
this.deviceID = id; |
||||
|
this.StatusTime = time.ToString("yyyy-MM-dd HH:mm:ss"); |
||||
|
this.channel = Channel; |
||||
|
this.StatusType = statusType; |
||||
|
} |
||||
|
|
||||
|
public DeviceStateMessage() |
||||
|
{ |
||||
|
this.deviceID = -1; |
||||
|
this.StatusTime = ""; |
||||
|
this.channel = -1; |
||||
|
this.StatusType = -1; |
||||
|
} |
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class SectorState |
||||
|
{ |
||||
|
public int id { get; set; }//防区号
|
||||
|
/*0:防区未使用 |
||||
|
1:防区撤防 |
||||
|
2:防区布防 |
||||
|
3:防区旁路 |
||||
|
4:防区报警 |
||||
|
5:无线防区欠压 |
||||
|
6:防区掉线(与主线总线脱离) |
||||
|
*/ |
||||
|
public int state { get; set; }//防区状态
|
||||
|
|
||||
|
public string stateStr |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
switch (state) |
||||
|
{ |
||||
|
case 0: return "防区未使用"; |
||||
|
case 1: return "防区撤防"; |
||||
|
case 2: return "防区布防"; |
||||
|
case 3: return "防区旁路"; |
||||
|
case 4: return "防区报警"; |
||||
|
case 5: return "无线防区欠压"; |
||||
|
case 6: return "防区掉线"; |
||||
|
default: return "未知状态:" + state; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
0:普通防区,无特殊参数 |
||||
|
1:张力防区需要单独查询因为这个防区显示张力线值每条线状态 |
||||
|
2:脉冲围栏 |
||||
|
3:振动光纤 |
||||
|
4:泄漏电缆 |
||||
|
5:网络或总线多子防区模块 |
||||
|
*/ |
||||
|
public int type { get; set; }//防区类型,特殊参数需单独查询
|
||||
|
|
||||
|
public string typeStr |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
switch (type) |
||||
|
{ |
||||
|
case 0: return "普通防区"; |
||||
|
case 1: return "张力防区"; |
||||
|
case 2: return "脉冲围栏"; |
||||
|
case 3: return "振动光纤"; |
||||
|
case 4: return "泄漏电缆"; |
||||
|
case 5: return "网络或总线多子防区模块"; |
||||
|
default: return "未知类型:" + type; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public SectorState(int id, byte data) |
||||
|
{ |
||||
|
this.id = id; |
||||
|
this.state = data & 0x0F; |
||||
|
this.type = data >> 4; |
||||
|
} |
||||
|
} |
@ -0,0 +1,172 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class UdpAlarmHostDevice |
||||
|
{ |
||||
|
public int deviceID { get; set; }//设备唯一ID
|
||||
|
|
||||
|
public string IP { get; set; }//设备IP
|
||||
|
|
||||
|
public int groupID { get; set; }//分组号,报警主机可划入不同组
|
||||
|
|
||||
|
public int userID { get; set; }//用户ID,指主机名称,有多台主机可以通过此名称区分
|
||||
|
/*0x00: 撤防状态 |
||||
|
0x04: 在家布防(留守布防有些防区可能是在旁路状态) |
||||
|
0x02:即时布防(所有防区没有延时) |
||||
|
0x08 :即时留守布防(有些防区可能旁路,但是没有旁路防区没有延时) |
||||
|
0x01:外出布防(普通布防最常用) |
||||
|
0x09:部分防区布防部分防区撤防 |
||||
|
*/ |
||||
|
public int deviceState { get; set; }//主机布撤状态,
|
||||
|
|
||||
|
public string deviceStateStr |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
switch (deviceState) |
||||
|
{ |
||||
|
case 0x00: |
||||
|
return "撤防状态"; |
||||
|
|
||||
|
case 0x01: |
||||
|
return "外出布防"; |
||||
|
|
||||
|
case 0x02: |
||||
|
return "即时布防"; |
||||
|
|
||||
|
case 0x04: |
||||
|
return "在家布防"; |
||||
|
|
||||
|
case 0x08: |
||||
|
return "即时留守布防"; |
||||
|
|
||||
|
case 0x09: |
||||
|
return "部分防区布防"; |
||||
|
|
||||
|
default: |
||||
|
return "未知状态号:" + deviceState; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*0x00:此设备处于常规工作状态,正常报警 |
||||
|
0x01:工作在设置模式,不会处理报警,用户这进行设置,设置完一般很快退出 |
||||
|
0x02:用户正在查询当前报警信息 |
||||
|
0x03:用户正在设置时钟 |
||||
|
0x04:工作在用户密码修改模式下 |
||||
|
*/ |
||||
|
public int deviceWorkState { get; set; }//设备工作状态
|
||||
|
|
||||
|
public string deviceWorkStateStr |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
switch (deviceState) |
||||
|
{ |
||||
|
case 0x00: |
||||
|
return "常规工作状态"; |
||||
|
|
||||
|
case 0x01: |
||||
|
return "在设置模式"; |
||||
|
|
||||
|
case 0x02: |
||||
|
return "用户正在查询报警"; |
||||
|
|
||||
|
case 0x03: |
||||
|
return "用户正在设置时钟"; |
||||
|
|
||||
|
case 0x04: |
||||
|
return "用户密码修改模式"; |
||||
|
|
||||
|
default: |
||||
|
return "未知状态号:" + deviceWorkState; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public int cellState { get; set; }//电池状态 1=电池故障 0=电池正常
|
||||
|
public int electricityState { get; set; }//交流状态 1=交流掉电 0=交流正常
|
||||
|
public int fuseState { get; set; }//警保险丝状态 1=外接警号断了0=正常
|
||||
|
public int sectorState { get; set; }//有线防区触发了 1=其中有线防区触发了 0=所有有线防区准备好
|
||||
|
public int cellTestState { get; set; }//正在电池载能测试 1=主机正在进行电池载能测试 0=无(主机会降低电压到电池12V以下,来测试电池负载特性需要2分钟)
|
||||
|
public int deviceElectricityState { get; set; }//设备交流电状态1=交流掉电,目前电池供电0=正常 这是即时状态
|
||||
|
public int soundState { get; set; }//设备声音输出状态(=0关闭声音) =1 输出声音) 用于布防和报警延时
|
||||
|
public int testState { get; set; }//主机本地测试状态1=主机在本地测试(用于测试探测好坏是没有报警记录的)0=无
|
||||
|
|
||||
|
public int criticalAlarmState { get; set; }//软防区紧急报警状态1=有紧急报警(用户通过手动按下主机自带装置报警) 0=无
|
||||
|
public int fireAlarmState { get; set; }//软防区火警报警状态1=有火警报警(用户通过手动按下主机自带装置报警) 0=无
|
||||
|
public int stealAlarmState { get; set; }//软防区盗警报警状态1=有盗警报警(用户通过手动按下主机自带装置报警) 0=无
|
||||
|
public int deviceFireAlarmState { get; set; }//设备中有火警报警状态 1=其中有火警防区触发了 0=无 整体状态
|
||||
|
public int deviceAlarmState { get; set; }//设备有报警发生 1=指设备有报警状态,任一一种0=无报警
|
||||
|
public int deviceBywayState { get; set; }//设备有旁路防区1=指设备某些防区有旁路了(这时软件可以要求上传具体旁路的防区) 2=无防区旁路
|
||||
|
public int busOfflineState { get; set; }//有总线防区掉线状态1=指某些总线防区掉线了0=无
|
||||
|
public int netOfflineState { get; set; }//有网络防区掉线状态1=指某些网络防区掉线了0=无
|
||||
|
|
||||
|
/*00:通用设备兼容没有设置或未知设备 |
||||
|
01:EH508报警主机 |
||||
|
02:EH508NP网络模块 |
||||
|
03: NETLINKBOARD32路网络模块 |
||||
|
04: EH508NETCILENT网络终端 |
||||
|
05: EH800 8路光纤主机 |
||||
|
06: EH508NP_UDP 私有服务器网络模块 |
||||
|
07: EH508CILENT_UDP 私有服务器接警终端 |
||||
|
08: EH508SEVER_UDP 私有服务器主机 |
||||
|
09: EH508MAP_UDP 私有服务器电子地图 |
||||
|
0A: EH508_UDP 私有服务器用EH508主机 |
||||
|
0x32: H768_IP系列网络模块 |
||||
|
0x33: D238C_IP网络模块 |
||||
|
0x34: H778S+ 系列报警主机 |
||||
|
0x35: H778S系列报警主机 |
||||
|
0x36:N201 N202网络模块 |
||||
|
*/ |
||||
|
public int devideType { get; set; }//设备类型:区分不同的设备类型 增强可控,防止混乱,具体的设备类型见附加说明表格
|
||||
|
|
||||
|
public int signalIntensity { get; set; }//31:信号最强,如果设备类型不是这种不需要显示 指主要带有GPRS模块设备跟据设备类型来的
|
||||
|
|
||||
|
public int channelNum { get; set; }//分区数量
|
||||
|
|
||||
|
public List<int> channelState { get; set; }//分区布防撤防状态,0为撤防,1为布防
|
||||
|
public List<int> channelAlarmState { get; set; }//分区报警状态,0为报警中,1为未报警
|
||||
|
|
||||
|
//-------------------------------防区信息-----------------------------//
|
||||
|
public int maxSectorNum { get; set; }//最大防区号
|
||||
|
|
||||
|
public List<SectorState> sectorList { get; set; } |
||||
|
|
||||
|
public int deviceOnlineState { get; set; }//设备在线状态
|
||||
|
|
||||
|
public int keep_live { get; set; }//设备在线状态
|
||||
|
|
||||
|
public UdpAlarmHostDevice() |
||||
|
{ |
||||
|
deviceID = 0; |
||||
|
groupID = 0; |
||||
|
userID = 0; |
||||
|
deviceState = -1; |
||||
|
deviceWorkState = 0; |
||||
|
cellState = 0; |
||||
|
electricityState = 0; |
||||
|
fuseState = 0; |
||||
|
sectorState = 0; |
||||
|
cellTestState = 0; |
||||
|
deviceElectricityState = 0; |
||||
|
soundState = 0; |
||||
|
testState = 0; |
||||
|
criticalAlarmState = 0; |
||||
|
fireAlarmState = 0; |
||||
|
stealAlarmState = 0; |
||||
|
deviceFireAlarmState = 0; |
||||
|
deviceAlarmState = 0; |
||||
|
deviceBywayState = 0; |
||||
|
busOfflineState = 0; |
||||
|
netOfflineState = 0; |
||||
|
devideType = 0; |
||||
|
signalIntensity = 0; |
||||
|
channelNum = 0; |
||||
|
channelState = null; |
||||
|
channelAlarmState = null; |
||||
|
sectorList = null; |
||||
|
deviceOnlineState = 0; |
||||
|
} |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
using Newtonsoft.Json.Linq; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class UdpAlarmHostMessage |
||||
|
{ |
||||
|
public int Id { get; set; } |
||||
|
public string AlarmTime { get; set; }//报警时间
|
||||
|
public string CID { get; set; }//CID代码
|
||||
|
|
||||
|
/*设备信息*/ |
||||
|
public int DeviceID { get; set; }//设备唯一ID
|
||||
|
public int ChannelNum { get; set; }//防区号
|
||||
|
public int SubChannelNum { get; set; }//子防区号
|
||||
|
public string Ip { get; set; }//设备IP
|
||||
|
public int GroupID { get; set; }//分组号,报警主机可划入不同组
|
||||
|
public int UserID { get; set; }//用户ID,指主机名称,有多台主机可以通过此名称区分
|
||||
|
public int LinkOut { get; set; }//联动输出
|
||||
|
public string ExtendArgs { get; set; }//扩展参数
|
||||
|
|
||||
|
/*CID信息*/ |
||||
|
public string AlarmLevel { get; set; }//报警级别
|
||||
|
public string AlarmContent { get; set; }//报警内容
|
||||
|
public string AlarmRemarks { get; set; }//报警备注
|
||||
|
public string AlarmType { get; set; }//报警类型
|
||||
|
|
||||
|
/*联动信息*/ |
||||
|
public bool IsLinked { get; set; }//是否有联动信息
|
||||
|
public JArray Linklist { get; set; } |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class UdpManagerConfig |
||||
|
{ |
||||
|
public string ServerIp { get; set; } |
||||
|
|
||||
|
public int ServerPort { get; set; } |
||||
|
|
||||
|
public int DevicePort { get; set; } |
||||
|
|
||||
|
public int DeviceHeartKeep { get; set; } |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
using System.ComponentModel; |
||||
|
using System.Net; |
||||
|
using System.Net.Sockets; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class Udp |
||||
|
{ |
||||
|
private BackgroundWorker back = null; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 用于UDP发送的网络服务类
|
||||
|
/// </summary>
|
||||
|
private UdpClient udpcSend = null; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 用于UDP接收的网络服务类
|
||||
|
/// </summary>
|
||||
|
private UdpClient udpcRecv; |
||||
|
|
||||
|
public delegate void UDPReceive(string IP, byte[] str);//
|
||||
|
|
||||
|
public event UDPReceive myUDPReceive;//
|
||||
|
|
||||
|
public Udp(string ip, int port) |
||||
|
{ |
||||
|
IPEndPoint localIpep = new IPEndPoint( |
||||
|
IPAddress.Parse(ip), port); // 本机IP和监听端口号
|
||||
|
|
||||
|
udpcRecv = new UdpClient(localIpep); |
||||
|
udpcSend = new UdpClient(); |
||||
|
back = new BackgroundWorker(); |
||||
|
back.WorkerSupportsCancellation = true; |
||||
|
back.DoWork += back_DoWork; |
||||
|
back.RunWorkerAsync(); |
||||
|
} |
||||
|
|
||||
|
~Udp() |
||||
|
{ |
||||
|
if (back != null) |
||||
|
back.CancelAsync(); |
||||
|
if (udpcRecv != null) |
||||
|
udpcRecv.Close(); |
||||
|
if (udpcSend != null) |
||||
|
udpcSend.Close(); |
||||
|
} |
||||
|
|
||||
|
public bool SendMessage(byte[] sendbytes, string IP, int port) |
||||
|
{ |
||||
|
IPEndPoint remoteIpep = new IPEndPoint( |
||||
|
IPAddress.Parse(IP), port); // 发送到的IP地址和端口号
|
||||
|
int result = udpcSend.Send(sendbytes, sendbytes.Length, remoteIpep); |
||||
|
return result >= sendbytes.Length; |
||||
|
} |
||||
|
|
||||
|
private void back_DoWork(object sender, DoWorkEventArgs e) |
||||
|
{ |
||||
|
IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Any, 0); |
||||
|
while (!back.CancellationPending) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
byte[] bytRecv = udpcRecv.Receive(ref remoteIpep); |
||||
|
myUDPReceive(remoteIpep.Address.ToString(), bytRecv); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,885 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Data; |
||||
|
using System.Timers; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class UdpManager |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
private Udp myUdp = null; |
||||
|
private int udp_sendPort = -1; |
||||
|
private int udp_ReceivePort = -1; |
||||
|
private int keep_alive = -1; |
||||
|
private Timer PtzCheckTimer = new(); |
||||
|
|
||||
|
private List<UdpAlarmHostDevice> deviceList = new(); |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public UdpManager() |
||||
|
{ |
||||
|
PtzCheckTimer.Interval = 1000; |
||||
|
PtzCheckTimer.Elapsed += PTZCheckTimer_Elapsed; |
||||
|
} |
||||
|
|
||||
|
//计时判断设备是否在线,若超过规定时间没有新消息发来,则设备离线
|
||||
|
private void PTZCheckTimer_Elapsed(object sender, ElapsedEventArgs e) |
||||
|
{ |
||||
|
foreach (UdpAlarmHostDevice p1 in deviceList) |
||||
|
{ |
||||
|
if (p1.keep_live >= 0) |
||||
|
{ |
||||
|
p1.keep_live--; |
||||
|
} |
||||
|
if (p1.keep_live < 0) |
||||
|
{ |
||||
|
p1.deviceOnlineState = 0; |
||||
|
if (OnUdpAlarmDeviceState != null) |
||||
|
{ |
||||
|
OnUdpAlarmDeviceState(p1.deviceID, "设备离线"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public List<UdpAlarmHostDevice> getDeviceAll() |
||||
|
{ |
||||
|
return deviceList; |
||||
|
} |
||||
|
|
||||
|
public UdpAlarmHostDevice getDevice(int deviceID) |
||||
|
{ |
||||
|
foreach (UdpAlarmHostDevice p1 in deviceList) |
||||
|
{ |
||||
|
if (p1.deviceID == deviceID) return p1; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public List<SectorState> getDeviceChannelAll(int deviceID) |
||||
|
{ |
||||
|
foreach (UdpAlarmHostDevice p1 in deviceList) |
||||
|
{ |
||||
|
if (p1.deviceID == deviceID) return p1.sectorList; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public SectorState getDeviceChannel(int deviceID, int channel) |
||||
|
{ |
||||
|
UdpAlarmHostDevice state = getDevice(deviceID); |
||||
|
if (state == null || state.sectorList == null) return null; |
||||
|
foreach (SectorState p1 in state.sectorList) |
||||
|
{ |
||||
|
if (p1.id == channel) return p1; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
#region BaseMethod
|
||||
|
|
||||
|
public bool StartServer(UdpManagerConfig config) |
||||
|
{ |
||||
|
string s_IP = config.ServerIp; |
||||
|
int s_Port = config.ServerPort; |
||||
|
int d_Port = config.DevicePort; |
||||
|
int d_Keep = config.DeviceHeartKeep; |
||||
|
|
||||
|
return AlarmHostLogin(s_IP, s_Port, d_Port, d_Keep); |
||||
|
} |
||||
|
|
||||
|
public bool StopServer() |
||||
|
{ |
||||
|
return AlarmHostLoginOut(); |
||||
|
} |
||||
|
|
||||
|
private bool AlarmHostLogin(string IP, int Port, int device_port, int keep_alive) |
||||
|
{ |
||||
|
if (myUdp != null) AlarmHostLoginOut(); |
||||
|
|
||||
|
this.udp_sendPort = device_port; |
||||
|
this.udp_ReceivePort = Port; |
||||
|
this.keep_alive = keep_alive; |
||||
|
try |
||||
|
{ |
||||
|
//启动UDP协议
|
||||
|
myUdp = new Udp(IP, udp_ReceivePort); |
||||
|
myUdp.myUDPReceive += myUDPReceive; |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
myUdp = null; |
||||
|
MessageBox.Show(ex.ToString()); |
||||
|
return false; |
||||
|
} |
||||
|
if (keep_alive > 0) |
||||
|
{ |
||||
|
PtzCheckTimer.Enabled = true; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private bool AlarmHostLoginOut() |
||||
|
{ |
||||
|
PtzCheckTimer.Enabled = false; |
||||
|
if (myUdp != null) |
||||
|
{ |
||||
|
myUdp.myUDPReceive -= myUDPReceive; |
||||
|
myUdp = null; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
#endregion BaseMethod
|
||||
|
|
||||
|
public delegate void UDPAlarmDeviceStateEvent(int deviceId, string state); |
||||
|
|
||||
|
public event UDPAlarmDeviceStateEvent OnUdpAlarmDeviceState; |
||||
|
|
||||
|
public delegate void UDPAlarmSectionStateEvent(int deviceId, int channel, string state); |
||||
|
|
||||
|
public event UDPAlarmSectionStateEvent OnUdpAlarmSectionState; |
||||
|
|
||||
|
public delegate void UDPAlarmEvent(UdpAlarmHostMessage msg); |
||||
|
|
||||
|
public event UDPAlarmEvent OnUdpAlarmEvent; |
||||
|
|
||||
|
public delegate void UDPAlarmCancelEvent(int deviceId, int channel); |
||||
|
|
||||
|
public event UDPAlarmCancelEvent OnUdpAlarmCancel; |
||||
|
|
||||
|
private void myUDPReceive(string Ip, byte[] str) |
||||
|
{ |
||||
|
//解码
|
||||
|
byte[] msg = AlarmEncode.decodeMessage(str); |
||||
|
//解析
|
||||
|
switch (msg[4]) |
||||
|
{ |
||||
|
case 0x01: //心跳数据
|
||||
|
analysisHeartMessage(Ip, msg); |
||||
|
break; |
||||
|
|
||||
|
case 0x02://报警信息
|
||||
|
AnalysisAlarmMessage(Ip, msg); |
||||
|
break; |
||||
|
|
||||
|
case 0x03://防区信息
|
||||
|
analysisAllSectorMessage(Ip, msg); |
||||
|
break; |
||||
|
|
||||
|
case 0x04://张力防区信息
|
||||
|
analysisSectorMessage(Ip, msg); |
||||
|
break; |
||||
|
|
||||
|
case 0x05://报警主机最大防区信息
|
||||
|
analysisMaxSectorMessage(Ip, msg); |
||||
|
break; |
||||
|
|
||||
|
case 0x08://返回报警主机设置参数回服务器,无需解析
|
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
Console.WriteLine("消息类型:" + msg[4]); |
||||
|
sendOK(Ip); |
||||
|
} |
||||
|
|
||||
|
private void sendOK(string IP) |
||||
|
{ |
||||
|
if (myUdp == null) return; |
||||
|
//byte[] bytes = new byte[] { 0x08, 0x12, 0xF0, 0xFA, 0x8F, 0x7F, 0x2E, 0x0D };
|
||||
|
byte[] bytes = new byte[] { 0x08, 0x12, 0xF0, 0xFA, 0x8F, 0x06, 0x6B, 0x0D }; |
||||
|
myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), IP, udp_sendPort); |
||||
|
} |
||||
|
|
||||
|
private void analysisHeartMessage(string IP, byte[] msg) |
||||
|
{ |
||||
|
int deviceID = ByteToInt(msg, 5); |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (device == null) |
||||
|
{ |
||||
|
device = new UdpAlarmHostDevice(); |
||||
|
device.deviceID = deviceID; |
||||
|
device.userID = ByteToInt(msg, 13); |
||||
|
device.IP = IP; |
||||
|
device.deviceOnlineState = 1; |
||||
|
device.keep_live = keep_alive; |
||||
|
deviceList.Add(device); |
||||
|
} |
||||
|
device.deviceID = deviceID; |
||||
|
device.IP = IP; |
||||
|
device.groupID = ByteToInt(msg, 9); |
||||
|
device.userID = ByteToInt(msg, 13); |
||||
|
if (device.deviceState != msg[17]) |
||||
|
{ |
||||
|
if (OnUdpAlarmDeviceState != null) |
||||
|
{ |
||||
|
switch (msg[17]) |
||||
|
{ |
||||
|
case 0x00://撤防状态
|
||||
|
OnUdpAlarmDeviceState(device.deviceID, "撤防状态"); |
||||
|
break; |
||||
|
|
||||
|
case 0x01://外出布防
|
||||
|
OnUdpAlarmDeviceState(device.deviceID, "外出布防(普通布防最常用)"); |
||||
|
break; |
||||
|
|
||||
|
case 0x02://即时布防(所有防区没有延时)
|
||||
|
OnUdpAlarmDeviceState(device.deviceID, "即时布防(所有防区没有延时)"); |
||||
|
break; |
||||
|
|
||||
|
case 0x04://在家布防(留守布防有些防区可能是在旁路状态)
|
||||
|
OnUdpAlarmDeviceState(device.deviceID, "在家布防(留守布防有些防区可能是在旁路状态)"); |
||||
|
break; |
||||
|
|
||||
|
case 0x08://即时留守布防(有些防区可能旁路,但是没有旁路防区没有延时)
|
||||
|
OnUdpAlarmDeviceState(device.deviceID, "即时留守布防(有些防区可能旁路,但是没有旁路防区没有延时)"); |
||||
|
break; |
||||
|
|
||||
|
case 0x09://部分防区布防部分防区撤防
|
||||
|
OnUdpAlarmDeviceState(device.deviceID, "部分防区布防部分防区撤防"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
device.deviceState = msg[17]; |
||||
|
device.deviceWorkState = msg[18]; |
||||
|
//设备状态1
|
||||
|
device.cellState = getBit(msg[19], 0); |
||||
|
device.electricityState = getBit(msg[19], 1); |
||||
|
device.fuseState = getBit(msg[19], 2); |
||||
|
device.sectorState = getBit(msg[19], 3); |
||||
|
device.cellTestState = getBit(msg[19], 4); |
||||
|
device.deviceElectricityState = getBit(msg[19], 5); |
||||
|
device.soundState = getBit(msg[19], 6); |
||||
|
device.testState = getBit(msg[19], 7); |
||||
|
//设备状态2
|
||||
|
device.criticalAlarmState = getBit(msg[20], 0); |
||||
|
device.fireAlarmState = getBit(msg[20], 1); |
||||
|
device.stealAlarmState = getBit(msg[20], 2); |
||||
|
device.deviceFireAlarmState = getBit(msg[20], 3); |
||||
|
device.deviceAlarmState = getBit(msg[20], 4); |
||||
|
device.deviceBywayState = getBit(msg[20], 5); |
||||
|
device.busOfflineState = getBit(msg[20], 6); |
||||
|
device.netOfflineState = getBit(msg[20], 7); |
||||
|
//设备状态3,4暂不使用
|
||||
|
|
||||
|
device.devideType = msg[23]; |
||||
|
device.signalIntensity = msg[24]; |
||||
|
device.channelNum = msg[25]; |
||||
|
if (device.channelNum > 0) |
||||
|
{ |
||||
|
device.channelState = new List<int>(); |
||||
|
device.channelAlarmState = new List<int>(); |
||||
|
for (int i = 0; i < device.channelNum; i++) |
||||
|
{ |
||||
|
device.channelState.Add(getBit(msg[26], i)); |
||||
|
device.channelAlarmState.Add(getBit(msg[27], i)); |
||||
|
} |
||||
|
} |
||||
|
//在线状态
|
||||
|
device.keep_live = keep_alive; |
||||
|
if (device.deviceOnlineState == 0) |
||||
|
{ |
||||
|
if (OnUdpAlarmDeviceState != null) |
||||
|
{ |
||||
|
OnUdpAlarmDeviceState(device.deviceID, "设备上线"); |
||||
|
} |
||||
|
} |
||||
|
device.deviceOnlineState = 1; |
||||
|
} |
||||
|
|
||||
|
private int getBit(byte bytes, int index) |
||||
|
{ |
||||
|
switch (index) |
||||
|
{ |
||||
|
case 0: |
||||
|
return bytes & 0x01; |
||||
|
|
||||
|
case 1: |
||||
|
return (bytes & 0x02) >> 1; |
||||
|
|
||||
|
case 2: |
||||
|
return (bytes & 0x04) >> 2; |
||||
|
|
||||
|
case 3: |
||||
|
return (bytes & 0x08) >> 3; |
||||
|
|
||||
|
case 4: |
||||
|
return (bytes & 0x10) >> 4; |
||||
|
|
||||
|
case 5: |
||||
|
return (bytes & 0x20) >> 5; |
||||
|
|
||||
|
case 6: |
||||
|
return (bytes & 0x40) >> 6; |
||||
|
|
||||
|
case 7: |
||||
|
return (bytes & 0x80) >> 7; |
||||
|
|
||||
|
default: |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private int ByteToInt(byte[] msg, int start) |
||||
|
{ |
||||
|
byte[] bytes = new byte[] { msg[start + 3], msg[start + 2], msg[start + 1], msg[start] }; |
||||
|
return BitConverter.ToInt32(bytes, 0); |
||||
|
} |
||||
|
|
||||
|
private byte[] IntToByte(int num) |
||||
|
{ |
||||
|
byte[] bytes = BitConverter.GetBytes(num); |
||||
|
return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; |
||||
|
} |
||||
|
|
||||
|
public void testAlarm(string devideId, string channel) |
||||
|
{ |
||||
|
byte[] bytes = BitConverter.GetBytes(int.Parse(devideId)); |
||||
|
byte[] bytes2 = BitConverter.GetBytes(int.Parse(channel)); |
||||
|
byte[] msg = new byte[36]{ |
||||
|
0x24,0x12,0xF0,0xFA, |
||||
|
0x02,bytes[3],bytes[2],bytes[1], |
||||
|
bytes[0],0x00,0x00,0x00, |
||||
|
0x00,bytes[3],bytes[2],bytes[1], |
||||
|
bytes[0],0x22,0x12,0x23, |
||||
|
0x10,0x10,0x10,0x01, |
||||
|
0x01,0x03,0x01,0x00, |
||||
|
0x02,bytes2[0],bytes2[1],0x00, |
||||
|
0x00,0x04,0x03,0x01 |
||||
|
}; |
||||
|
AnalysisAlarmMessage("127.0.0.1", msg); |
||||
|
} |
||||
|
|
||||
|
private void AnalysisAlarmMessage(string IP, byte[] msg) |
||||
|
{ |
||||
|
string CID = getCID(msg[23]) + getCID(msg[24]) + getCID(msg[25]) + getCID(msg[26]); |
||||
|
int deviceID = ByteToInt(msg, 5); |
||||
|
int channelNum = msg[29] + msg[30] * 256; |
||||
|
string alarmTime = "20" + getBCD(msg[17]) + "-" + getBCD(msg[18]) + "-" + getBCD(msg[19]) |
||||
|
+ " " + getBCD(msg[20]) + ":" + getBCD(msg[21]) + ":" + getBCD(msg[22]); |
||||
|
if (CID.StartsWith("3")) |
||||
|
{ |
||||
|
DataTable arrlist2 = new(); |
||||
|
//DataTable arrlist2 = DBCenter.center.SearchByCondition("table_SectorAlarmMessage", "CID2='" + CID + "'");
|
||||
|
if (arrlist2 == null || arrlist2.Rows.Count == 0) |
||||
|
{ |
||||
|
//不是想要的消除警报信息
|
||||
|
Console.WriteLine("不是想要的消除警报信息,设备号:" + deviceID + ",CID:" + CID); |
||||
|
return; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (OnUdpAlarmCancel != null) |
||||
|
{ |
||||
|
OnUdpAlarmCancel(deviceID, channelNum); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
//查询CID
|
||||
|
DataTable arrlist = new(); |
||||
|
//DataTable arrlist = DBCenter.center.SearchByCondition("table_SectorAlarmMessage", "CID='" + CID + "'");
|
||||
|
if (arrlist == null || arrlist.Rows.Count == 0) |
||||
|
{ |
||||
|
//查询不到的CID码的不需要处理
|
||||
|
Console.WriteLine("不是想要的警报信息,设备号:" + deviceID + ",CID:" + CID); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
UdpAlarmHostMessage alarm = new() |
||||
|
{ |
||||
|
DeviceID = deviceID, |
||||
|
Ip = IP, |
||||
|
GroupID = ByteToInt(msg, 9), |
||||
|
UserID = ByteToInt(msg, 13), |
||||
|
AlarmTime = alarmTime, |
||||
|
//CID暂定
|
||||
|
CID = CID, |
||||
|
LinkOut = msg[27] + msg[28] * 256, |
||||
|
ChannelNum = channelNum, |
||||
|
SubChannelNum = msg[31] + msg[32] * 256, |
||||
|
ExtendArgs = msg[33].ToString("X2") + " " + msg[34].ToString("X2") + " " + msg[35].ToString("X2"), |
||||
|
|
||||
|
AlarmLevel = arrlist.Rows[0]["level"].ToString(), |
||||
|
AlarmContent = arrlist.Rows[0]["content"].ToString(), |
||||
|
AlarmRemarks = arrlist.Rows[0]["remarks"].ToString(), |
||||
|
AlarmType = arrlist.Rows[0]["type"].ToString(), |
||||
|
|
||||
|
Linklist = new() |
||||
|
}; |
||||
|
//string error = "";
|
||||
|
//alarm.linklist = DBCenter.center.SearchByConditionJArray("table_UDPLink", "deviceID=" + alarm.deviceID + "/channel='" + alarm.channelNum + "'", ref error);
|
||||
|
if (alarm.Linklist == null || alarm.Linklist.Count == 0) |
||||
|
{ |
||||
|
alarm.IsLinked = false; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
alarm.IsLinked = true; |
||||
|
} |
||||
|
|
||||
|
ProcessAlarm(alarm); |
||||
|
} |
||||
|
|
||||
|
//处理报警事件
|
||||
|
private void ProcessAlarm(UdpAlarmHostMessage msg) |
||||
|
{ |
||||
|
OnUdpAlarmEvent(msg); |
||||
|
|
||||
|
////报警信息放入数据库
|
||||
|
//JObject obj = new()
|
||||
|
//{
|
||||
|
// { "alarmTime", msg.AlarmTime },
|
||||
|
// { "CID", msg.CID },
|
||||
|
|
||||
|
// { "deviceID", msg.DeviceID },
|
||||
|
// { "channelNum", msg.ChannelNum },
|
||||
|
// { "subChannelNum", msg.SubChannelNum },
|
||||
|
|
||||
|
// { "IP", msg.Ip },
|
||||
|
// { "groupID", msg.GroupID },
|
||||
|
// { "userID", msg.UserID },
|
||||
|
// { "linkOut", msg.LinkOut },
|
||||
|
// { "extendArgs", msg.ExtendArgs },
|
||||
|
|
||||
|
// { "alarm_level", msg.AlarmLevel },
|
||||
|
// { "alarm_content", msg.AlarmContent },
|
||||
|
// { "alarm_remarks", msg.AlarmRemarks },
|
||||
|
// { "alarm_type", msg.AlarmType },
|
||||
|
|
||||
|
// { "IsLinked", msg.IsLinked },
|
||||
|
// { "linklist", msg.Linklist }
|
||||
|
//};
|
||||
|
//string error = "";
|
||||
|
//DBCenter.center.InsertResult("table_UDPAlarmMessage", obj, ref error);
|
||||
|
////打开预览窗口
|
||||
|
//if (msg.IsLinked)
|
||||
|
//{
|
||||
|
// if (OnUdpAlarmEvent != null)
|
||||
|
// {
|
||||
|
// OnUdpAlarmEvent(msg);
|
||||
|
// }
|
||||
|
// //联动预置位
|
||||
|
// for (int i = 0; i < msg.Linklist.Count; i++)
|
||||
|
// {
|
||||
|
// if (msg.Linklist[i]["needPreset"].ToString() == "true")
|
||||
|
// {
|
||||
|
// //int camID = int.Parse(msg.linklist[i]["camID"].ToString());
|
||||
|
// //string camType = msg.linklist[i]["camType"].ToString();
|
||||
|
// //CamType device_type = CamType.Table;
|
||||
|
// //if (camType == "摄像机") device_type = CamType.Camera;
|
||||
|
// //int presetId = int.Parse(msg.linklist[i]["presetID"].ToString());
|
||||
|
// //RequestToService.center.NET_SDK_PTZPreset_Other(camID, device_type, (int)WMPTZPresetCommand.WMPTZPreset_GOTO, presetId, ref error);
|
||||
|
// }
|
||||
|
// }
|
||||
|
//}
|
||||
|
} |
||||
|
|
||||
|
private string getCID(byte bytes) |
||||
|
{ |
||||
|
switch (bytes) |
||||
|
{ |
||||
|
case 0x00: |
||||
|
return "0"; |
||||
|
|
||||
|
case 0x01: |
||||
|
return "1"; |
||||
|
|
||||
|
case 0x02: |
||||
|
return "2"; |
||||
|
|
||||
|
case 0x03: |
||||
|
return "3"; |
||||
|
|
||||
|
case 0x04: |
||||
|
return "4"; |
||||
|
|
||||
|
case 0x05: |
||||
|
return "5"; |
||||
|
|
||||
|
case 0x06: |
||||
|
return "6"; |
||||
|
|
||||
|
case 0x07: |
||||
|
return "7"; |
||||
|
|
||||
|
case 0x08: |
||||
|
return "8"; |
||||
|
|
||||
|
case 0x09: |
||||
|
return "9"; |
||||
|
|
||||
|
case 0x0A: |
||||
|
return "A"; |
||||
|
|
||||
|
case 0x0B: |
||||
|
return "B"; |
||||
|
|
||||
|
case 0x0C: |
||||
|
return "C"; |
||||
|
|
||||
|
case 0x0D: |
||||
|
return "D"; |
||||
|
|
||||
|
case 0x0E: |
||||
|
return "E"; |
||||
|
|
||||
|
case 0x0F: |
||||
|
return "F"; |
||||
|
|
||||
|
default: |
||||
|
return "0"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private string getBCD(byte bytes) |
||||
|
{ |
||||
|
int num = (bytes >> 4) * 10 + (bytes & 0x0F); |
||||
|
return num.ToString(); |
||||
|
} |
||||
|
|
||||
|
private byte getBCDByte(int num) |
||||
|
{ |
||||
|
if (num >= 100) num = num % 100; |
||||
|
int hex = num / 10; |
||||
|
int lex = num % 10; |
||||
|
return (byte)(hex * 16 + lex); |
||||
|
} |
||||
|
|
||||
|
private byte[] getBCDTime(DateTime time) |
||||
|
{ |
||||
|
return new byte[] { getBCDByte(time.Year),getBCDByte((int)time.DayOfWeek),getBCDByte(time.Month),getBCDByte(time.Day), |
||||
|
|
||||
|
getBCDByte(time.Hour),getBCDByte(time.Minute),getBCDByte(time.Second) }; |
||||
|
} |
||||
|
|
||||
|
private string getBCD2(byte bytes) |
||||
|
{ |
||||
|
int num1 = bytes / 16; |
||||
|
int num2 = bytes % 16; |
||||
|
return (num1 * 10 + num2).ToString(); |
||||
|
} |
||||
|
|
||||
|
private void analysisAllSectorMessage(string IP, byte[] msg) |
||||
|
{ |
||||
|
int deviceID = ByteToInt(msg, 5); |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (device == null) |
||||
|
{ |
||||
|
device = new UdpAlarmHostDevice(); |
||||
|
device.deviceID = deviceID; |
||||
|
device.IP = IP; |
||||
|
device.deviceOnlineState = 1; |
||||
|
device.keep_live = keep_alive; |
||||
|
deviceList.Add(device); |
||||
|
} |
||||
|
device.IP = IP; |
||||
|
device.groupID = ByteToInt(msg, 9); |
||||
|
device.userID = ByteToInt(msg, 13); |
||||
|
|
||||
|
if (device.sectorList == null) |
||||
|
{ |
||||
|
device.sectorList = new List<SectorState>(); |
||||
|
} |
||||
|
int count = msg[19]; |
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
int index = i + msg[20];//防区序号
|
||||
|
int pos = 21 + i;//防区信息所在byte数组未知
|
||||
|
SectorState state = new SectorState(index, msg[pos]); |
||||
|
updateSector(state, device.sectorList, device.deviceID); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void updateSector(SectorState state, List<SectorState> list, int deviceId) |
||||
|
{ |
||||
|
for (int i = 0; i < list.Count; i++) |
||||
|
{ |
||||
|
if (list[i].id == state.id) |
||||
|
{ |
||||
|
//设备离线
|
||||
|
if (list[i].state != state.state) |
||||
|
{ |
||||
|
reportSectorState(deviceId, state.id, state.state); |
||||
|
} |
||||
|
list[i] = state; //防区存在,更新
|
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
list.Add(state);//防区不存在,添加
|
||||
|
reportSectorState(deviceId, state.id, state.state); |
||||
|
} |
||||
|
|
||||
|
private void reportSectorState(int deviceId, int channel, int state) |
||||
|
{ |
||||
|
if (OnUdpAlarmSectionState != null) |
||||
|
{ |
||||
|
switch (state) |
||||
|
{ |
||||
|
case 0: |
||||
|
OnUdpAlarmSectionState(deviceId, channel, "防区未使用"); |
||||
|
break; |
||||
|
|
||||
|
case 1://撤防
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "防区撤防"); |
||||
|
break; |
||||
|
|
||||
|
case 2://布防
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "防区布防"); |
||||
|
break; |
||||
|
|
||||
|
case 3://旁路
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "防区旁路"); |
||||
|
break; |
||||
|
|
||||
|
case 4://报警
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "防区报警"); |
||||
|
break; |
||||
|
|
||||
|
case 5://无线防区欠压
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "无线防区欠压"); |
||||
|
break; |
||||
|
|
||||
|
case 6://防区掉线
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "防区掉线(与主线总线脱离)"); |
||||
|
break; |
||||
|
|
||||
|
case 7://未准备就绪
|
||||
|
OnUdpAlarmSectionState(deviceId, channel, "未准备就绪"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void analysisSectorMessage(string IP, byte[] msg) |
||||
|
{ |
||||
|
//东北没有张力防区,暂不解析
|
||||
|
} |
||||
|
|
||||
|
private void analysisMaxSectorMessage(string IP, byte[] msg) |
||||
|
{ |
||||
|
int deviceID = ByteToInt(msg, 5); |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (device == null) |
||||
|
{ |
||||
|
device = new UdpAlarmHostDevice(); |
||||
|
device.deviceID = deviceID; |
||||
|
device.IP = IP; |
||||
|
device.deviceOnlineState = 1; |
||||
|
device.keep_live = keep_alive; |
||||
|
deviceList.Add(device); |
||||
|
} |
||||
|
device.IP = IP; |
||||
|
device.groupID = ByteToInt(msg, 9); |
||||
|
device.userID = ByteToInt(msg, 13); |
||||
|
device.maxSectorNum = msg[17] * 256 + msg[18]; |
||||
|
} |
||||
|
|
||||
|
private bool checkDevice(UdpAlarmHostDevice device, ref string error) |
||||
|
{ |
||||
|
if (device == null) |
||||
|
{ |
||||
|
error = "没有此报警主机的记录"; |
||||
|
return false; |
||||
|
} |
||||
|
if (device.deviceOnlineState == 0) |
||||
|
{ |
||||
|
error = "此报警主机离线"; |
||||
|
return false; |
||||
|
} |
||||
|
if (myUdp == null) |
||||
|
{ |
||||
|
error = "UDP故障"; |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
//外出布防或者布防
|
||||
|
public bool setDeviceDefence(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x80, new byte[] { 0x60 }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//立即布防
|
||||
|
public bool setDeviceDefenceImmediately(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x80, new byte[] { 0x62 }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//在家布防留守布防
|
||||
|
public bool setDeviceDefenceHome(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x80, new byte[] { 0x63 }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//即时留守布防
|
||||
|
public bool setDeviceDefenceHomeImmediately(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x80, new byte[] { 0x64 }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//撤防
|
||||
|
public bool withdrawDeviceDefence(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x80, new byte[] { 0x61 }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//清除报警记忆(复位)
|
||||
|
public bool clearDeviceDefence(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x80, new byte[] { 0x65 }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//校对系统时间
|
||||
|
public bool setDeviceTime(int deviceID, DateTime time, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] content = getBCDTime(time); |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0x8D, content); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//设备重启
|
||||
|
public bool rebootDevice(int deviceID, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0xA0, null); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//单防区布防
|
||||
|
public bool setDeviceChannelDefence(int deviceID, int channel, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0xC0, new byte[] { (byte)(channel / 256), (byte)(channel % 256) }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//单防区撤防
|
||||
|
public bool withdrawDeviceChannelDefence(int deviceID, int channel, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0xC1, new byte[] { (byte)(channel / 256), (byte)(channel % 256) }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//单防区旁路
|
||||
|
public bool setDeviceChannelByway(int deviceID, int channel, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0xC2, new byte[] { (byte)(channel / 256), (byte)(channel % 256) }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//单防区旁路恢复
|
||||
|
public bool withdrawDeviceChannelByway(int deviceID, int channel, ref string error) |
||||
|
{ |
||||
|
UdpAlarmHostDevice device = getDevice(deviceID); |
||||
|
if (checkDevice(device, ref error)) |
||||
|
{ |
||||
|
byte[] bytes = AlarmEncode.getSendMessage(0xC3, new byte[] { (byte)(channel / 256), (byte)(channel % 256) }); |
||||
|
return myUdp.SendMessage(AlarmEncode.encodeMessage(bytes), device.IP, udp_sendPort); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
<UserControl x:Class="JiLinApp.Pages.FenceServerManage.Main" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" |
||||
|
xmlns:prism="http://prismlibrary.com/" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" |
||||
|
prism:ViewModelLocator.AutoWireViewModel="True" |
||||
|
d:DesignHeight="450" d:DesignWidth="800"> |
||||
|
<materialDesign:Card> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="250" /> |
||||
|
<RowDefinition /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<GroupBox Header="优周围网服务器设置(UDP)" Grid.Row="0"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0" Margin="5"> |
||||
|
<TextBox Name="ServerIp" materialDesign:HintAssist.Hint="服务地址" Text="127.0.0.1" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1" Margin="5"> |
||||
|
<TextBox Name="ServerPort" materialDesign:HintAssist.Hint="服务端口" Text="5080" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="0" Margin="5"> |
||||
|
<TextBox Name="DevicePort" materialDesign:HintAssist.Hint="设备端口" Text="5080" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5"> |
||||
|
<TextBox Name="DeviceHeartKeep" materialDesign:HintAssist.Hint="设备心跳间隔" Text="10" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1"> |
||||
|
</StackPanel> |
||||
|
<WrapPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<Button Name="OpenBtn" Content="开启服务" Width="100" Margin="5" Click="OpenBtn_Click" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
<Button Name="StopBtn" Content="关闭服务" Width="100" Margin="5" Click="StopBtn_Click" IsEnabled="False" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
</WrapPanel> |
||||
|
</Grid> |
||||
|
</GroupBox> |
||||
|
<!--<GroupBox Name="MsgBox" Header="消息窗口" Grid.Row="1" Margin="0 6 0 0"> |
||||
|
<TextBox VerticalAlignment="Top" AcceptsReturn="True" Style="{StaticResource MaterialDesignOutlinedTextBox}" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" /> |
||||
|
</GroupBox>--> |
||||
|
</Grid> |
||||
|
</materialDesign:Card> |
||||
|
</UserControl> |
@ -0,0 +1,93 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Main.xaml 的交互逻辑
|
||||
|
/// </summary>
|
||||
|
public partial class Main : UserControl |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private UdpManager Manager { get; } = new(); |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
public Main() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Init(); |
||||
|
} |
||||
|
|
||||
|
#region Init
|
||||
|
|
||||
|
private void Init() |
||||
|
{ |
||||
|
if (DataContext != null) |
||||
|
{ |
||||
|
MainViewModel vm = DataContext as MainViewModel; |
||||
|
vm.SetView(this); |
||||
|
|
||||
|
Manager.OnUdpAlarmDeviceState += vm.OnUdpAlarmDeviceState; |
||||
|
Manager.OnUdpAlarmSectionState += vm.OnUdpAlarmSectionState; |
||||
|
Manager.OnUdpAlarmEvent += vm.OnUdpAlarmEvent; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ChangeState(bool openState) |
||||
|
{ |
||||
|
if (openState) |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = false; |
||||
|
StopBtn.IsEnabled = true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = true; |
||||
|
StopBtn.IsEnabled = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Init
|
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void OpenBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
UdpManagerConfig config = new() |
||||
|
{ |
||||
|
ServerIp = ServerIp.Text, |
||||
|
ServerPort = int.Parse(ServerPort.Text), |
||||
|
DevicePort = int.Parse(DevicePort.Text), |
||||
|
DeviceHeartKeep = int.Parse(DeviceHeartKeep.Text) |
||||
|
}; |
||||
|
Manager.StartServer(config); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
MessageBox.Show(ex.ToString()); |
||||
|
return; |
||||
|
} |
||||
|
ChangeState(true); |
||||
|
} |
||||
|
|
||||
|
private void StopBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
Manager.StopServer(); |
||||
|
ChangeState(false); |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
|
||||
|
#region InvokeEvent
|
||||
|
|
||||
|
public void Test() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
#endregion InvokeEvent
|
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
using JiLinApp.Mvvm; |
||||
|
using JiLinApp.Pages.Main; |
||||
|
using Prism.Events; |
||||
|
using Prism.Regions; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServerManage; |
||||
|
|
||||
|
public class MainViewModel : ViewModelBase |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
private Main View { get; set; } |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public MainViewModel(IRegionManager region, IEventAggregator ea) : base(region, ea) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override void SetView(object view) |
||||
|
{ |
||||
|
View = (Main)view; |
||||
|
View.Test(); |
||||
|
} |
||||
|
|
||||
|
#region ConnEvent
|
||||
|
|
||||
|
internal void OnUdpAlarmDeviceState(int deviceId, string state) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
internal void OnUdpAlarmSectionState(int deviceId, int channel, string state) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
internal void OnUdpAlarmEvent(UdpAlarmHostMessage msg) |
||||
|
{ |
||||
|
_ea.GetEvent<FenceUdpAlarmSendEvent>().Publish(msg); |
||||
|
} |
||||
|
|
||||
|
#endregion ConnEvent
|
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
using JiLinApp.Pages.FenceServerManage; |
||||
|
using JiLinApp.Pages.ShakeServerManage; |
||||
|
using Prism.Events; |
||||
|
|
||||
|
namespace JiLinApp.Pages.Main; |
||||
|
|
||||
|
public class MessageSentEvent : PubSubEvent<string> |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public class ShakeTcpAlarmSendEvent : PubSubEvent<TcpAlarmHostMessage> |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public class FenceUdpAlarmSendEvent : PubSubEvent<UdpAlarmHostMessage> |
||||
|
{ |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
namespace JiLinApp.Pages.Main; |
||||
|
|
||||
|
public static class PageNames |
||||
|
{ |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
namespace JiLinApp.Pages.Main; |
||||
|
|
||||
|
public static class RegionNames |
||||
|
{ |
||||
|
public static string ContentRegion { get; } = "ContentRegion"; |
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
<Window x:Class="JiLinApp.Pages.Main.MainWindow" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:fenceManage="clr-namespace:JiLinApp.Pages.FenceServerManage" |
||||
|
xmlns:ptzManage="clr-namespace:JiLinApp.Pages.PtzManage" |
||||
|
xmlns:shakeManage="clr-namespace:JiLinApp.Pages.ShakeServerManage" |
||||
|
Title="{Binding Title}" Width="1000" Height="700"> |
||||
|
<materialDesign:Card materialDesign:ColorZoneAssist.Mode="PrimaryMid"> |
||||
|
<TabControl Style="{StaticResource MaterialDesignNavigationRailTabControl}" TabStripPlacement="Top"> |
||||
|
<TabItem Width="auto" Margin="5 0 5 0"> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel Width="auto" Height="auto"> |
||||
|
<materialDesign:PackIcon Width="24" Height="24" HorizontalAlignment="Center" Kind="CogOutline" /> |
||||
|
<TextBlock HorizontalAlignment="Center" Text="Ptz 配置" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
<ptzManage:Main materialDesign:ColorZoneAssist.Mode="PrimaryLight" Margin="10"></ptzManage:Main> |
||||
|
</TabItem> |
||||
|
<TabItem Width="auto" Margin="5 0 5 0"> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel Width="auto" Height="auto"> |
||||
|
<materialDesign:PackIcon Width="24" Height="24" HorizontalAlignment="Center" Kind="Server" /> |
||||
|
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="震动报警服务" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
<shakeManage:Main materialDesign:ColorZoneAssist.Mode="PrimaryLight" Margin="10"></shakeManage:Main> |
||||
|
</TabItem> |
||||
|
<TabItem Width="auto" Margin="5 0 5 0"> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel Width="auto" Height="auto"> |
||||
|
<materialDesign:PackIcon Width="24" Height="24" HorizontalAlignment="Center" Kind="Server" /> |
||||
|
<TextBlock HorizontalAlignment="Center" Text="优周围网服务" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
<fenceManage:Main materialDesign:ColorZoneAssist.Mode="PrimaryLight" Margin="10"></fenceManage:Main> |
||||
|
</TabItem> |
||||
|
<TabItem Width="auto" Margin="5 0 5 0" IsEnabled="False"> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel Width="auto" Height="auto"> |
||||
|
<materialDesign:PackIcon Width="24" Height="24" HorizontalAlignment="Center" Kind="CogOutline" /> |
||||
|
<TextBlock HorizontalAlignment="Center" Text="其它设置" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
|
||||
|
<WrapPanel Width="auto" Height="auto" Margin="10"> |
||||
|
<StackPanel> |
||||
|
<ToggleButton ToolTip="控制台开关" IsChecked="False" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Checked" Style="{StaticResource MaterialDesignSwitchSecondaryToggleButton}" /> |
||||
|
<TextBlock HorizontalAlignment="Center" Text="控制台开关" /> |
||||
|
</StackPanel> |
||||
|
</WrapPanel> |
||||
|
</TabItem> |
||||
|
</TabControl> |
||||
|
</materialDesign:Card> |
||||
|
</Window> |
@ -0,0 +1,47 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls.Primitives; |
||||
|
|
||||
|
namespace JiLinApp.Pages.Main; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Interaction logic for MainWindow.xaml
|
||||
|
/// </summary>
|
||||
|
public partial class MainWindow : Window |
||||
|
{ |
||||
|
public MainWindow() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void ToggleButton_Checked(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
ToggleButton btn = (ToggleButton)sender; |
||||
|
bool isChecked = btn.IsChecked ?? false; |
||||
|
if (isChecked) { AllocConsole(); AttachConsole(-1); } |
||||
|
else FreeConsole(); |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
|
||||
|
#region
|
||||
|
|
||||
|
[DllImport("Kernel32")] |
||||
|
private static extern void AllocConsole(); |
||||
|
|
||||
|
[DllImport("Kernel32")] |
||||
|
private static extern void FreeConsole(); |
||||
|
|
||||
|
[DllImport("kernel32")] |
||||
|
private static extern bool AttachConsole(int dwProcessId); |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
private void Button_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
Console.WriteLine("test"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,242 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzManage; |
||||
|
|
||||
|
public class PelcoD |
||||
|
{ |
||||
|
private string watchdir = ""; //监控方向
|
||||
|
private static readonly byte STX = 0xFF; //同步字节
|
||||
|
|
||||
|
#region 监控方向和定时监控实体
|
||||
|
|
||||
|
public string WatchDir |
||||
|
{ |
||||
|
get { return watchdir; } |
||||
|
set { watchdir = value; } |
||||
|
} |
||||
|
|
||||
|
#endregion 监控方向和定时监控实体
|
||||
|
|
||||
|
#region 基本指令定义
|
||||
|
|
||||
|
#region 指令码1
|
||||
|
|
||||
|
private const byte FocusNear = 0x01; //增加聚焦
|
||||
|
private const byte IrisOpen = 0x02; //减小光圈
|
||||
|
private const byte IrisClose = 0x04; //增加光圈
|
||||
|
private const byte CameraOnOff = 0x08; //摄像机打开和关闭
|
||||
|
private const byte AutoManualScan = 0x10; //自动和手动扫描
|
||||
|
private const byte Sense = 0x80; //Sence码
|
||||
|
|
||||
|
#endregion 指令码1
|
||||
|
|
||||
|
#region 指令码2
|
||||
|
|
||||
|
private const byte PanRight = 0x02; //右
|
||||
|
private const byte PanLeft = 0x04; //左
|
||||
|
|
||||
|
private const byte TiltUp = 0x08; //上
|
||||
|
private const byte TiltDown = 0x10; //下
|
||||
|
private const byte ZoomTele = 0x20; //增加对焦
|
||||
|
private const byte ZoomWide = 0x40; //减小对焦
|
||||
|
private const byte FocusFar = 0x80; //减小聚焦
|
||||
|
|
||||
|
#endregion 指令码2
|
||||
|
|
||||
|
#region 镜头左右平移的速度
|
||||
|
|
||||
|
public static byte PanSpeedMin = 0x00; //停止
|
||||
|
public static byte PanSpeedMax = 0x3F; //最高速
|
||||
|
|
||||
|
#endregion 镜头左右平移的速度
|
||||
|
|
||||
|
#region 镜头上下移动的速度
|
||||
|
|
||||
|
public static byte TiltSpeedMin = 0x00; //停止
|
||||
|
public static byte TiltSpeedMax = 0x3F; //最高速
|
||||
|
|
||||
|
#endregion 镜头上下移动的速度
|
||||
|
|
||||
|
#endregion 基本指令定义
|
||||
|
|
||||
|
private const byte PanRightUp = 0xa; //右上
|
||||
|
private const byte PanLeftUp = 0x0c; //左上
|
||||
|
|
||||
|
private const byte PanRightDown = 0x12; //右下
|
||||
|
private const byte PanLeftDown = 0x14; //左下
|
||||
|
|
||||
|
#region 云台控制枚举
|
||||
|
|
||||
|
public enum Switch |
||||
|
{ |
||||
|
On = 0x01, |
||||
|
Off = 0x02 |
||||
|
} //雨刷控制
|
||||
|
|
||||
|
public enum Focus |
||||
|
{ |
||||
|
Near = FocusNear, |
||||
|
Far = FocusFar |
||||
|
} //聚焦控制
|
||||
|
|
||||
|
public enum Zoom |
||||
|
{ |
||||
|
Wide = ZoomWide, |
||||
|
Tele = ZoomTele |
||||
|
} //对焦控制
|
||||
|
|
||||
|
public enum Tilt |
||||
|
{ |
||||
|
Up = TiltUp, |
||||
|
Down = TiltDown |
||||
|
} //上下控制
|
||||
|
|
||||
|
public enum Pan |
||||
|
{ |
||||
|
Left = PanLeft, |
||||
|
Right = PanRight, |
||||
|
LeftUp = PanLeftUp, |
||||
|
LeftDown = PanLeftDown, |
||||
|
RightUp = PanRightUp, |
||||
|
RightDown = PanRightDown |
||||
|
} //左右控制
|
||||
|
|
||||
|
public enum Scan |
||||
|
{ |
||||
|
Auto, |
||||
|
Manual |
||||
|
} //自动和手动控制
|
||||
|
|
||||
|
public enum Iris |
||||
|
{ |
||||
|
Open = IrisOpen, |
||||
|
Close = IrisClose |
||||
|
} //光圈控制
|
||||
|
|
||||
|
public enum PresetAction |
||||
|
{ |
||||
|
Set = 0x03, |
||||
|
Clear = 0x05, |
||||
|
Goto = 0x07 |
||||
|
} |
||||
|
|
||||
|
#endregion 云台控制枚举
|
||||
|
|
||||
|
#region 云台控制方法
|
||||
|
|
||||
|
//雨刷控制
|
||||
|
public static byte[] CameraSwitch(uint deviceAddress, Switch action) |
||||
|
{ |
||||
|
byte m_action = CameraOnOff; |
||||
|
if (action == Switch.On) |
||||
|
m_action = CameraOnOff + Sense; |
||||
|
return Message.GetMessage(deviceAddress, m_action, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
//光圈控制
|
||||
|
public static byte[] CameraIrisSwitch(uint deviceAddress, Iris action) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, (byte)action, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
//聚焦控制
|
||||
|
public static byte[] CameraFocus(uint deviceAddress, Focus action) |
||||
|
{ |
||||
|
if (action == Focus.Near) |
||||
|
return Message.GetMessage(deviceAddress, (byte)action, 0x00, 0x00, 0x00); |
||||
|
else |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
//对焦控制
|
||||
|
public static byte[] CameraZoom(uint deviceAddress, Zoom action) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 上下控制
|
||||
|
/// </summary>
|
||||
|
/// <param name="deviceAddress"></param>
|
||||
|
/// <param name="action"></param>
|
||||
|
/// <param name="speed"></param>
|
||||
|
/// <returns></returns>
|
||||
|
|
||||
|
public static byte[] CameraTilt(uint deviceAddress, Tilt action, uint speed) |
||||
|
{ |
||||
|
if (speed < TiltSpeedMin) |
||||
|
speed = TiltSpeedMin; |
||||
|
if (speed > TiltSpeedMax) |
||||
|
speed = TiltSpeedMax; |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, (byte)speed); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 左右控制
|
||||
|
/// </summary>
|
||||
|
/// <param name="deviceAddress"></param>
|
||||
|
/// <param name="action"></param>
|
||||
|
/// <param name="speed"></param>
|
||||
|
/// <returns></returns>
|
||||
|
|
||||
|
public static byte[] CameraPan(uint deviceAddress, Pan action, uint speed) |
||||
|
{ |
||||
|
if (speed < PanSpeedMin) |
||||
|
speed = PanSpeedMin; |
||||
|
if (speed > PanSpeedMax) |
||||
|
speed = PanSpeedMax; |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, (byte)speed, 0x00); |
||||
|
} |
||||
|
|
||||
|
//停止云台的移动
|
||||
|
public static byte[] CameraStop(uint deviceAddress) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
//自动和手动控制
|
||||
|
public static byte[] CameraScan(uint deviceAddress, Scan scan) |
||||
|
{ |
||||
|
byte m_byte = AutoManualScan; |
||||
|
if (scan == Scan.Auto) |
||||
|
m_byte = AutoManualScan + Sense; |
||||
|
return Message.GetMessage(deviceAddress, m_byte, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] Preset(uint deviceAddress, PresetAction action, byte presetId) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, presetId); |
||||
|
} |
||||
|
|
||||
|
#endregion 云台控制方法
|
||||
|
|
||||
|
public struct Message |
||||
|
{ |
||||
|
public static byte Address; |
||||
|
public static byte CheckSum; |
||||
|
|
||||
|
public static byte Command1, |
||||
|
Command2, |
||||
|
Data1, |
||||
|
Data2; |
||||
|
|
||||
|
public static byte[] GetMessage( |
||||
|
uint address, |
||||
|
byte command1, |
||||
|
byte command2, |
||||
|
byte data1, |
||||
|
byte data2 |
||||
|
) |
||||
|
{ |
||||
|
if (address < 1 & address > 256) |
||||
|
throw new Exception("Pelco D协议只支持256设备"); |
||||
|
Address = byte.Parse(address.ToString()); |
||||
|
Command1 = command1; |
||||
|
Command2 = command2; |
||||
|
Data1 = data1; |
||||
|
Data2 = data2; |
||||
|
CheckSum = (byte)(Address + Command1 + Command2 + Data1 + Data2); |
||||
|
return new byte[] { STX, Address, Command1, Command2, Data1, Data2, CheckSum }; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,364 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// dot.NET Implementation of Pelco P Protocol
|
||||
|
/// </summary>
|
||||
|
public class PelcoP |
||||
|
{ |
||||
|
private const byte STX = 0xA0; |
||||
|
private const byte ETX = 0xAF; |
||||
|
|
||||
|
#region Pan and Tilt Commands
|
||||
|
|
||||
|
#region Data1
|
||||
|
|
||||
|
private const byte FocusFar = 0x01; |
||||
|
private const byte FocusNear = 0x02; |
||||
|
private const byte IrisOpen = 0x04; |
||||
|
private const byte IrisClose = 0x08; |
||||
|
private const byte CameraOnOff = 0x10; |
||||
|
private const byte AutoscanOn = 0x20; |
||||
|
private const byte CameraOn = 0x40; |
||||
|
|
||||
|
#endregion Data1
|
||||
|
|
||||
|
#region Data2
|
||||
|
|
||||
|
private const byte PanRight = 0x02; |
||||
|
private const byte PanLeft = 0x04; |
||||
|
private const byte TiltUp = 0x08; |
||||
|
private const byte TiltDown = 0x10; |
||||
|
private const byte ZoomTele = 0x20; |
||||
|
private const byte ZoomWide = 0x40; |
||||
|
|
||||
|
#endregion Data2
|
||||
|
|
||||
|
#region Data3
|
||||
|
|
||||
|
public static byte PanSpeedMin = 0x00; |
||||
|
public static byte PanSpeedMax = 0x3F; |
||||
|
|
||||
|
#endregion Data3
|
||||
|
|
||||
|
#region Data4
|
||||
|
|
||||
|
public static byte TiltSpeedMin = 0x00; |
||||
|
public static byte TiltSpeedMax = 0x3F; |
||||
|
|
||||
|
#endregion Data4
|
||||
|
|
||||
|
#endregion Pan and Tilt Commands
|
||||
|
|
||||
|
#region Enums
|
||||
|
|
||||
|
public enum PatternAction |
||||
|
{ |
||||
|
Start, |
||||
|
Stop, |
||||
|
Run |
||||
|
} |
||||
|
|
||||
|
public enum Action |
||||
|
{ |
||||
|
Start, |
||||
|
Stop |
||||
|
} |
||||
|
|
||||
|
public enum LensSpeed |
||||
|
{ |
||||
|
Low = 0x00, |
||||
|
Medium = 0x01, |
||||
|
High = 0x02, |
||||
|
Turbo = 0x03 |
||||
|
} |
||||
|
|
||||
|
public enum Pan |
||||
|
{ |
||||
|
Left = PanLeft, |
||||
|
Right = PanRight |
||||
|
} |
||||
|
|
||||
|
public enum Tilt |
||||
|
{ |
||||
|
Up = TiltUp, |
||||
|
Down = TiltDown |
||||
|
} |
||||
|
|
||||
|
public enum Iris |
||||
|
{ |
||||
|
Open = IrisOpen, |
||||
|
Close = IrisClose |
||||
|
} |
||||
|
|
||||
|
public enum Zoom |
||||
|
{ |
||||
|
Wide = ZoomWide, |
||||
|
Tele = ZoomTele |
||||
|
} |
||||
|
|
||||
|
public enum Switch |
||||
|
{ |
||||
|
On, |
||||
|
Off |
||||
|
} |
||||
|
|
||||
|
public enum Focus |
||||
|
{ |
||||
|
Near = FocusNear, |
||||
|
Far = FocusFar |
||||
|
} |
||||
|
|
||||
|
public enum PresetAction |
||||
|
{ |
||||
|
Set = 0x03, |
||||
|
Clear = 0x05, |
||||
|
Goto = 0x07 |
||||
|
} |
||||
|
|
||||
|
#endregion Enums
|
||||
|
|
||||
|
#region Extended Command Set
|
||||
|
|
||||
|
public static byte[] Preset(uint deviceAddress, PresetAction action, byte presetId) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, presetId); |
||||
|
} |
||||
|
|
||||
|
public static byte[] Flip(uint deviceAddress) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x07, 0x00, 0x21); |
||||
|
} |
||||
|
|
||||
|
public static byte[] ZeroPanPosition(uint deviceAddress) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x07, 0x00, 0x22); |
||||
|
} |
||||
|
|
||||
|
public static byte[] AutoScan(uint deviceAddress, Action action) |
||||
|
{ |
||||
|
byte m_action; |
||||
|
if (action == Action.Start) |
||||
|
m_action = 0x09; |
||||
|
else |
||||
|
m_action = 0x0B; |
||||
|
return Message.GetMessage(deviceAddress, 0x00, m_action, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] RemoteReset(uint deviceAddress) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x0F, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] Zone(uint deviceAddress, byte zone, Action action) |
||||
|
{ |
||||
|
if (zone < 0x01 & zone > 0x08) |
||||
|
throw new Exception("Zone value should be between 0x01 and 0x08 include"); |
||||
|
byte m_action; |
||||
|
if (action == Action.Start) |
||||
|
m_action = 0x11; |
||||
|
else |
||||
|
m_action = 0x13; |
||||
|
|
||||
|
return Message.GetMessage(deviceAddress, 0x00, m_action, 0x00, zone); |
||||
|
} |
||||
|
|
||||
|
public static byte[] WriteToScreen(uint deviceAddress, string text) |
||||
|
{ |
||||
|
if (text.Length > 40) |
||||
|
text = text.Remove(40, text.Length - 40); |
||||
|
System.Text.Encoding encoding = System.Text.Encoding.ASCII; |
||||
|
byte[] m_bytes = new byte[encoding.GetByteCount(text) * 8]; |
||||
|
int i = 0; |
||||
|
byte m_scrPosition; |
||||
|
byte m_ASCIIchr; |
||||
|
|
||||
|
foreach (char ch in text) |
||||
|
{ |
||||
|
m_scrPosition = Convert.ToByte(i / 8); |
||||
|
m_ASCIIchr = Convert.ToByte(ch); |
||||
|
Array.Copy( |
||||
|
Message.GetMessage(deviceAddress, 0x00, 0x15, m_scrPosition, m_ASCIIchr), |
||||
|
0, |
||||
|
m_bytes, |
||||
|
i, |
||||
|
8 |
||||
|
); |
||||
|
i = i + 8; |
||||
|
} |
||||
|
|
||||
|
return m_bytes; |
||||
|
} |
||||
|
|
||||
|
public static byte[] ClearScreen(uint deviceAddress) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x17, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] AlarmAcknowledge(uint deviceAddress, uint alarmID) |
||||
|
{ |
||||
|
if (alarmID < 1 & alarmID > 8) |
||||
|
throw new Exception("Only 8 alarms allowed for Pelco P implementation"); |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x19, 0x00, Convert.ToByte(alarmID)); |
||||
|
} |
||||
|
|
||||
|
public static byte[] ZoneScan(uint deviceAddress, Action action) |
||||
|
{ |
||||
|
byte m_action; |
||||
|
if (action == Action.Start) |
||||
|
m_action = 0x1B; |
||||
|
else |
||||
|
m_action = 0x1D; |
||||
|
return Message.GetMessage(deviceAddress, 0x00, m_action, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] Pattern(uint deviceAddress, PatternAction action) |
||||
|
{ |
||||
|
byte m_action; |
||||
|
switch (action) |
||||
|
{ |
||||
|
case PatternAction.Start: |
||||
|
m_action = 0x1F; |
||||
|
break; |
||||
|
|
||||
|
case PatternAction.Stop: |
||||
|
m_action = 0x21; |
||||
|
break; |
||||
|
|
||||
|
case PatternAction.Run: |
||||
|
m_action = 0x23; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
m_action = 0x23; |
||||
|
break; |
||||
|
} |
||||
|
return Message.GetMessage(deviceAddress, 0x00, m_action, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] SetZoomLensSpeed(uint deviceAddress, LensSpeed speed) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x25, 0x00, (byte)speed); |
||||
|
} |
||||
|
|
||||
|
public static byte[] SetFocusLensSpeed(uint deviceAddress, LensSpeed speed) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x27, 0x00, (byte)speed); |
||||
|
} |
||||
|
|
||||
|
#endregion Extended Command Set
|
||||
|
|
||||
|
#region Base Command Set
|
||||
|
|
||||
|
public static byte[] CameraSwitch(uint deviceAddress, Switch action) |
||||
|
{ |
||||
|
byte m_action = CameraOnOff; |
||||
|
if (action == Switch.On) |
||||
|
m_action += CameraOnOff; //Maybe wrong !!!
|
||||
|
return Message.GetMessage(deviceAddress, m_action, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraIrisSwitch(uint deviceAddress, Iris action) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, (byte)action, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraFocus(uint deviceAddress, Focus action) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, (byte)action, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraZoom(uint deviceAddress, Zoom action) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraTilt(uint deviceAddress, Tilt action, uint speed) |
||||
|
{ |
||||
|
if (speed < TiltSpeedMin) |
||||
|
speed = TiltSpeedMin; |
||||
|
if (speed > TiltSpeedMax) |
||||
|
speed = TiltSpeedMax; |
||||
|
|
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, 0x00, (byte)speed); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraPan(uint deviceAddress, Pan action, uint speed) |
||||
|
{ |
||||
|
if (speed < PanSpeedMin) |
||||
|
speed = PanSpeedMin; |
||||
|
if (speed > PanSpeedMax) |
||||
|
speed = PanSpeedMax; |
||||
|
|
||||
|
return Message.GetMessage(deviceAddress, 0x00, (byte)action, (byte)speed, 0x00); |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraPanTilt( |
||||
|
uint deviceAddress, |
||||
|
Pan panAction, |
||||
|
uint panSpeed, |
||||
|
Tilt tiltAction, |
||||
|
uint tiltSpeed |
||||
|
) |
||||
|
{ |
||||
|
byte[] m_bytes = new byte[8]; |
||||
|
byte[] m_tiltMessage = CameraTilt(deviceAddress, tiltAction, tiltSpeed); |
||||
|
byte[] m_panMessage = CameraPan(deviceAddress, panAction, panSpeed); |
||||
|
//m_tiltMessage.CopyTo(m_bytes,0);
|
||||
|
//m_panMessage.CopyTo(m_bytes,9);
|
||||
|
/*m_bytes[0] = m_tiltMessage[0]; |
||||
|
m_bytes[1] = m_tiltMessage[1]; |
||||
|
m_bytes[2] = m_tiltMessage[2]; |
||||
|
m_bytes[3] = (byte)(m_tiltMessage[3]+m_panMessage[3]); |
||||
|
m_bytes[4] = (byte)(+m_panMessage[4]); |
||||
|
m_bytes[5] = (byte)(+m_panMessage[5]); |
||||
|
m_bytes[6] = m_tiltMessage[6]; |
||||
|
m_bytes[7] = m_tiltMessage[7];*/ |
||||
|
m_bytes = Message.GetMessage( |
||||
|
deviceAddress, |
||||
|
0x00, |
||||
|
(byte)(m_tiltMessage[3] + m_panMessage[3]), |
||||
|
m_panMessage[4], |
||||
|
m_tiltMessage[5] |
||||
|
); |
||||
|
return m_bytes; |
||||
|
} |
||||
|
|
||||
|
public static byte[] CameraStop(uint deviceAddress) |
||||
|
{ |
||||
|
return Message.GetMessage(deviceAddress, 0x00, 0x00, 0x00, 0x00); |
||||
|
} |
||||
|
|
||||
|
#endregion Base Command Set
|
||||
|
|
||||
|
public struct Message |
||||
|
{ |
||||
|
public static byte Address; |
||||
|
public static byte CheckSum; |
||||
|
|
||||
|
public static byte Data1, |
||||
|
Data2, |
||||
|
Data3, |
||||
|
Data4; |
||||
|
|
||||
|
public static byte[] GetMessage( |
||||
|
uint address, |
||||
|
byte data1, |
||||
|
byte data2, |
||||
|
byte data3, |
||||
|
byte data4 |
||||
|
) |
||||
|
{ |
||||
|
if (address < 0 & address > 32) |
||||
|
throw new Exception("Protocol Pelco P support 32 devices only"); |
||||
|
Address = byte.Parse((address - 1).ToString()); |
||||
|
Data1 = data1; |
||||
|
Data2 = data2; |
||||
|
Data3 = data3; |
||||
|
Data4 = data4; |
||||
|
CheckSum = (byte)(STX ^ Address ^ Data1 ^ Data2 ^ Data3 ^ Data4 ^ ETX); |
||||
|
return new byte[] { STX, Address, Data1, Data2, Data3, Data4, ETX, CheckSum }; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,191 @@ |
|||||
|
using EC.Util.CameraSDK; |
||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzManage; |
||||
|
|
||||
|
public class PtzCmd |
||||
|
{ |
||||
|
public static PtzControlType GetControlType(string ctrlStr) |
||||
|
{ |
||||
|
return ctrlStr switch |
||||
|
{ |
||||
|
"PelcoD" => PtzControlType.PelcoD, |
||||
|
"PelcoP" => PtzControlType.PelcoP, |
||||
|
"HikSdk" => PtzControlType.HikSdk, |
||||
|
_ => PtzControlType.None |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public static PtzCmdType GetCmdType(string cmdStr) |
||||
|
{ |
||||
|
return cmdStr switch |
||||
|
{ |
||||
|
"Top" => PtzCmdType.Top, |
||||
|
"Down" => PtzCmdType.Down, |
||||
|
"Left" => PtzCmdType.Left, |
||||
|
"Right" => PtzCmdType.Right, |
||||
|
"TopLeft" => PtzCmdType.TopLeft, |
||||
|
"TopRight" => PtzCmdType.TopRight, |
||||
|
"DownLeft" => PtzCmdType.DownLeft, |
||||
|
"DownRight" => PtzCmdType.DownRight, |
||||
|
"Stop" => PtzCmdType.Stop, |
||||
|
"AutoStart" => PtzCmdType.AutoStart, |
||||
|
"AutoStop" => PtzCmdType.AutoStop, |
||||
|
"PresetSet" => PtzCmdType.PresetSet, |
||||
|
"PresetClear" => PtzCmdType.PresetClear, |
||||
|
"PresetGoto" => PtzCmdType.PresetGoto, |
||||
|
_ => PtzCmdType.None |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public static byte[] GetCmd(PtzControlType ctrlType, PtzCmdType cmdType, byte[] args = null) |
||||
|
{ |
||||
|
args ??= new byte[] { 1, 1, 1 }; |
||||
|
byte[] cmd = ctrlType switch |
||||
|
{ |
||||
|
PtzControlType.PelcoD => GetPelcoDCmd(cmdType, args), |
||||
|
PtzControlType.PelcoP => GetPelcoPCmd(cmdType, args), |
||||
|
_ => Array.Empty<byte>(), |
||||
|
}; |
||||
|
return cmd; |
||||
|
} |
||||
|
|
||||
|
public static byte[] GetPelcoDCmd(PtzCmdType cmdType, byte[] args) |
||||
|
{ |
||||
|
uint addr = args[0]; |
||||
|
uint panSpeed = 0x2f; |
||||
|
uint tiltSpeed = (uint)(PelcoD.TiltSpeedMax + PelcoD.TiltSpeedMin) / 2; |
||||
|
byte[] cmd = cmdType switch |
||||
|
{ |
||||
|
PtzCmdType.Top => PelcoD.CameraTilt(addr, PelcoD.Tilt.Up, tiltSpeed), |
||||
|
PtzCmdType.Down => PelcoD.CameraTilt(addr, PelcoD.Tilt.Down, tiltSpeed), |
||||
|
PtzCmdType.Left => PelcoD.CameraPan(addr, PelcoD.Pan.Left, panSpeed), |
||||
|
PtzCmdType.Right => PelcoD.CameraPan(addr, PelcoD.Pan.Right, panSpeed), |
||||
|
PtzCmdType.TopLeft => PelcoD.CameraPan(addr, PelcoD.Pan.LeftUp, panSpeed), |
||||
|
PtzCmdType.TopRight => PelcoD.CameraPan(addr, PelcoD.Pan.RightUp, panSpeed), |
||||
|
PtzCmdType.DownLeft => PelcoD.CameraPan(addr, PelcoD.Pan.LeftDown, panSpeed), |
||||
|
PtzCmdType.DownRight => PelcoD.CameraPan(addr, PelcoD.Pan.RightDown, panSpeed), |
||||
|
PtzCmdType.Stop => PelcoD.CameraStop(addr), |
||||
|
PtzCmdType.AutoStart => PelcoD.CameraScan(addr, PelcoD.Scan.Auto), |
||||
|
PtzCmdType.AutoStop => PelcoD.CameraScan(addr, PelcoD.Scan.Manual), |
||||
|
PtzCmdType.PresetGoto => PelcoD.Preset(addr, PelcoD.PresetAction.Goto, args[1]), |
||||
|
PtzCmdType.None => Array.Empty<byte>(), |
||||
|
_ => Array.Empty<byte>(), |
||||
|
}; |
||||
|
return cmd; |
||||
|
} |
||||
|
|
||||
|
public static byte[] GetPelcoPCmd(PtzCmdType cmdType, byte[] args) |
||||
|
{ |
||||
|
uint addr = args[0]; |
||||
|
uint panSpeed = (uint)(PelcoP.PanSpeedMax + PelcoP.PanSpeedMin) / 2; |
||||
|
uint tiltSpeed = (uint)(PelcoP.TiltSpeedMax + PelcoP.TiltSpeedMin) / 2; |
||||
|
byte[] cmd = cmdType switch |
||||
|
{ |
||||
|
PtzCmdType.Top => PelcoP.CameraTilt(addr, PelcoP.Tilt.Up, tiltSpeed), |
||||
|
PtzCmdType.Down => PelcoP.CameraTilt(addr, PelcoP.Tilt.Down, tiltSpeed), |
||||
|
PtzCmdType.Left => PelcoP.CameraPan(addr, PelcoP.Pan.Left, panSpeed), |
||||
|
PtzCmdType.Right => PelcoP.CameraPan(addr, PelcoP.Pan.Right, panSpeed), |
||||
|
PtzCmdType.TopLeft => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Left, panSpeed, PelcoP.Tilt.Up, tiltSpeed), |
||||
|
PtzCmdType.TopRight => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Right, panSpeed, PelcoP.Tilt.Up, tiltSpeed), |
||||
|
PtzCmdType.DownLeft => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Left, panSpeed, PelcoP.Tilt.Down, tiltSpeed), |
||||
|
PtzCmdType.DownRight => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Right, panSpeed, PelcoP.Tilt.Down, tiltSpeed), |
||||
|
PtzCmdType.Stop => PelcoP.CameraStop(addr), |
||||
|
PtzCmdType.AutoStart => PelcoP.AutoScan(addr, PelcoP.Action.Start), |
||||
|
PtzCmdType.AutoStop => PelcoP.AutoScan(addr, PelcoP.Action.Stop), |
||||
|
PtzCmdType.PresetGoto => PelcoP.Preset(addr, PelcoP.PresetAction.Goto, args[1]), |
||||
|
PtzCmdType.None => Array.Empty<byte>(), |
||||
|
_ => Array.Empty<byte>(), |
||||
|
}; |
||||
|
return cmd; |
||||
|
} |
||||
|
|
||||
|
public static void HikPtzMove(ref HiKSDK sdk, PtzCmdType cmdType, uint[] args) |
||||
|
{ |
||||
|
if (sdk == null || args == null) return; |
||||
|
uint[] arr = new uint[args.Length + 1]; |
||||
|
args.CopyTo(arr, 1); |
||||
|
switch (cmdType) |
||||
|
{ |
||||
|
case PtzCmdType.Top: |
||||
|
arr[0] = HiKOriSDK.TILT_UP; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.Down: |
||||
|
arr[0] = HiKOriSDK.TILT_DOWN; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.Left: |
||||
|
arr[0] = HiKOriSDK.PAN_LEFT; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.Right: |
||||
|
arr[0] = HiKOriSDK.PAN_RIGHT; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.TopLeft: |
||||
|
arr[0] = HiKOriSDK.UP_LEFT; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.TopRight: |
||||
|
arr[0] = HiKOriSDK.UP_RIGHT; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.DownLeft: |
||||
|
arr[0] = HiKOriSDK.DOWN_LEFT; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.DownRight: |
||||
|
arr[0] = HiKOriSDK.DOWN_RIGHT; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.AutoStart: |
||||
|
arr[0] = HiKOriSDK.PAN_AUTO; |
||||
|
sdk.PtzMove(arr); |
||||
|
break; |
||||
|
|
||||
|
case PtzCmdType.PresetGoto: |
||||
|
arr[0] = HiKOriSDK.GOTO_PRESET; |
||||
|
sdk.PtzPreset(arr); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public enum PtzControlType |
||||
|
{ |
||||
|
PelcoD, |
||||
|
PelcoP, |
||||
|
HikSdk, |
||||
|
None |
||||
|
} |
||||
|
|
||||
|
public enum PtzCmdType |
||||
|
{ |
||||
|
Top, |
||||
|
Down, |
||||
|
Left, |
||||
|
Right, |
||||
|
TopLeft, |
||||
|
TopRight, |
||||
|
DownLeft, |
||||
|
DownRight, |
||||
|
Stop, |
||||
|
AutoStart, |
||||
|
AutoStop, |
||||
|
PresetSet, |
||||
|
PresetClear, |
||||
|
PresetGoto, |
||||
|
None |
||||
|
} |
@ -0,0 +1,176 @@ |
|||||
|
<UserControl x:Class="JiLinApp.Pages.PtzManage.Main" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" |
||||
|
xmlns:prism="http://prismlibrary.com/" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
prism:ViewModelLocator.AutoWireViewModel="True" |
||||
|
mc:Ignorable="d" |
||||
|
d:DesignHeight="550" d:DesignWidth="800"> |
||||
|
<materialDesign:Card> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="300" /> |
||||
|
<RowDefinition Height="250" /> |
||||
|
<RowDefinition /> |
||||
|
</Grid.RowDefinitions> |
||||
|
|
||||
|
<Grid Grid.Row="0"> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="2*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<GroupBox Header="串口设置" Grid.Column="0" Margin="0 0 6 0"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<StackPanel Grid.Row="0" Grid.Column="0" Margin="5"> |
||||
|
<ComboBox Name="ComName" materialDesign:HintAssist.Hint="COM端口" Width="200" Style="{StaticResource MaterialDesignOutlinedComboBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1" Margin="5"> |
||||
|
<ComboBox Name="BaudRate" materialDesign:HintAssist.Hint="波特率" Width="200" SelectedIndex="3" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
<ComboBoxItem Content="1200" /> |
||||
|
<ComboBoxItem Content="2400" /> |
||||
|
<ComboBoxItem Content="4800" /> |
||||
|
<ComboBoxItem Content="9600" /> |
||||
|
<ComboBoxItem Content="19200" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="0" Margin="5"> |
||||
|
<ComboBox Name="Parity" materialDesign:HintAssist.Hint="校验位" Width="200" SelectedIndex="0" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
<ComboBoxItem Content="无" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5"> |
||||
|
<ComboBox Name="DataBits" materialDesign:HintAssist.Hint="数据位" Width="200" SelectedIndex="4" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
<ComboBoxItem Content="4" /> |
||||
|
<ComboBoxItem Content="5" /> |
||||
|
<ComboBoxItem Content="6" /> |
||||
|
<ComboBoxItem Content="7" /> |
||||
|
<ComboBoxItem Content="8" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="2" Grid.Column="0" Margin="5"> |
||||
|
<ComboBox Name="StopBits" materialDesign:HintAssist.Hint="停止位" Width="200" SelectedIndex="0" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
<ComboBoxItem Content="1" /> |
||||
|
<ComboBoxItem Content="1.5" /> |
||||
|
<ComboBoxItem Content="2" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
<WrapPanel Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<Button Name="OpenBtn" Content="连接" Width="100" Margin="5" Click="OpenBtn_Click" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
<Button Name="StopBtn" Content="关闭" Width="100" Margin="5" Click="StopBtn_Click" IsEnabled="False" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
</WrapPanel> |
||||
|
</Grid> |
||||
|
</GroupBox> |
||||
|
|
||||
|
<GroupBox Header="设备设置" Grid.Column="1"> |
||||
|
<StackPanel> |
||||
|
<ComboBox Name="CameraIp" materialDesign:HintAssist.Hint="相机Ip" Width="200" SelectedIndex="0" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
</GroupBox> |
||||
|
</Grid> |
||||
|
|
||||
|
<GroupBox Header="云台控制" Grid.Row="1" Margin="0 6 0 0"> |
||||
|
<Grid> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<StackPanel Grid.Column="0"> |
||||
|
<ComboBox Name="ControlType" materialDesign:HintAssist.Hint="控制类型" Width="200" SelectionChanged="ControlType_SelectionChanged" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
<ComboBoxItem Content="PelcoD" /> |
||||
|
<ComboBoxItem Content="PelcoP" /> |
||||
|
<ComboBoxItem Content="HikSdk" /> |
||||
|
</ComboBox> |
||||
|
<ComboBox Name="CameraId" materialDesign:HintAssist.Hint="相机Id" Width="200" Margin="0 10 0 0" SelectedIndex="0" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Grid Name="PtzPanel" Grid.Column="1" HorizontalAlignment="Center"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="55" /> |
||||
|
<RowDefinition Height="55" /> |
||||
|
<RowDefinition Height="55" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="55" /> |
||||
|
<ColumnDefinition Width="55" /> |
||||
|
<ColumnDefinition Width="55" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<Button Name="TopLeftBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowTopLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1"> |
||||
|
<Button Name="TopBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowTop" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="2"> |
||||
|
<Button Name="TopRightBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowTopRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<Button Name="LeftBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1"> |
||||
|
<Button Name="AutoStartBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="Circle" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="2"> |
||||
|
<Button Name="RightBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="2" Grid.Column="0"> |
||||
|
<Button Name="DownLeftBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowBottomLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="1"> |
||||
|
<Button Name="DownBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowBottom" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="2"> |
||||
|
<Button Name="DownRightBtn" Width="50" Height="50" Style="{StaticResource MaterialDesignOutlinedLightButton}"> |
||||
|
<materialDesign:PackIcon Kind="ArrowBottomRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<StackPanel Grid.Column="2"> |
||||
|
<ComboBox Name="PresetId" materialDesign:HintAssist.Hint="预置点Id" Width="200" SelectedIndex="0" Style="{StaticResource MaterialDesignOutlinedComboBox}"> |
||||
|
</ComboBox> |
||||
|
<Button Name="GotoBtn" Content="前往预置点" Width="120" Margin="0 10 0 0" Click="GotoBtn_Click" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</GroupBox> |
||||
|
</Grid> |
||||
|
</materialDesign:Card> |
||||
|
</UserControl> |
@ -0,0 +1,315 @@ |
|||||
|
using EC.Util.CameraSDK; |
||||
|
using EC.Util.Port; |
||||
|
using ImTools; |
||||
|
using JiLinApp.Core; |
||||
|
using NewLife.Reflection; |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO.Ports; |
||||
|
using System.Linq; |
||||
|
using System.Text.RegularExpressions; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Input; |
||||
|
using System.Windows.Media; |
||||
|
using System.Windows.Threading; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Main.xaml 的交互逻辑
|
||||
|
/// </summary>
|
||||
|
public partial class Main : UserControl |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
private YcSerialPort Port { get; set; } |
||||
|
|
||||
|
private ConcurrentDictionary<string, HiKSDK> HikMap { get; } = new(); |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public Main() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Init(); |
||||
|
} |
||||
|
|
||||
|
#region Init
|
||||
|
|
||||
|
private void Init() |
||||
|
{ |
||||
|
// 初始化串口
|
||||
|
string[] ports = SerialPort.GetPortNames(); |
||||
|
ports = ports.OrderBy(s => int.Parse(Regex.Match(s, @"\d+").Value)).ToArray(); |
||||
|
foreach (string port in ports) |
||||
|
{ |
||||
|
ComName.Items.Add(new ComboBoxItem { Content = port }); |
||||
|
} |
||||
|
|
||||
|
// 初始化下拉框 Id
|
||||
|
for (int i = 1; i <= 10; i++) |
||||
|
{ |
||||
|
CameraId.Items.Add(new ComboBoxItem { Content = i }); |
||||
|
PresetId.Items.Add(new ComboBoxItem { Content = i }); |
||||
|
} |
||||
|
|
||||
|
// 绑定云台响应事件
|
||||
|
List<Button> btnList = new(); |
||||
|
FindVisualChild<Button>(PtzPanel, ref btnList); |
||||
|
foreach (var btn in btnList) |
||||
|
{ |
||||
|
btn.AddHandler(Button.MouseDownEvent, new MouseButtonEventHandler(PtzBtn_MouseDown), true); |
||||
|
btn.AddHandler(Button.MouseUpEvent, new MouseButtonEventHandler(PtzBtn_MouseUp), true); |
||||
|
} |
||||
|
|
||||
|
// 解析海康相机
|
||||
|
TaskUtil.Run(() => Dispatcher.Invoke(LoadHikCamera)); |
||||
|
//Task.Factory.StartNew(() => Dispatcher.Invoke(LoadHikCamera), TaskCreationOptions.LongRunning);
|
||||
|
|
||||
|
// 刷新控件状态
|
||||
|
ControlType.SelectedIndex = 0; |
||||
|
} |
||||
|
|
||||
|
private bool IsConnect() |
||||
|
{ |
||||
|
return Port != null && Port.IsOpen(); |
||||
|
} |
||||
|
|
||||
|
private void ChangeState(bool openState) |
||||
|
{ |
||||
|
if (openState) |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = false; |
||||
|
StopBtn.IsEnabled = true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = true; |
||||
|
StopBtn.IsEnabled = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Init
|
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void OpenBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!IsConnect()) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
SerialPortParam param = new() |
||||
|
{ |
||||
|
ComName = ComName.Text, |
||||
|
BaudRate = int.Parse(BaudRate.Text), |
||||
|
Parity = 0, |
||||
|
DataBits = int.Parse(DataBits.Text), |
||||
|
StopBits = int.Parse(StopBits.Text), |
||||
|
}; |
||||
|
Port = new YcSerialPort(param); |
||||
|
Port.OpenCom(); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Port = null; |
||||
|
MessageBox.Show(ex.ToString()); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
ChangeState(true); |
||||
|
} |
||||
|
|
||||
|
private void StopBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (IsConnect()) |
||||
|
{ |
||||
|
Port.CloseCom(); |
||||
|
Port = null; |
||||
|
} |
||||
|
ChangeState(false); |
||||
|
} |
||||
|
|
||||
|
private void PtzBtn_MouseDown(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
PtzControlType ctrlType = PtzCmd.GetControlType(ControlType.Text); |
||||
|
PtzCmdType cmdType = PtzCmd.GetCmdType(((Button)sender).Name.Replace("Btn", "")); |
||||
|
|
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
if (!IsConnect()) break; |
||||
|
byte cameraId = byte.Parse(CameraId.Text); |
||||
|
byte[] cmd = PtzCmd.GetCmd(ctrlType, cmdType, new byte[] { cameraId }); |
||||
|
Port.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.HikSdk: |
||||
|
string cameraIp = CameraIp.Text; |
||||
|
HikMap.TryGetValue(cameraIp, out HiKSDK hikSdk); |
||||
|
if (hikSdk == null) break; |
||||
|
uint stop = 0, speed = 4; |
||||
|
PtzCmd.HikPtzMove(ref hikSdk, cmdType, new uint[] { stop, speed }); |
||||
|
break; |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void PtzBtn_MouseUp(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
PtzControlType ctrlType = PtzCmd.GetControlType(ControlType.Text); |
||||
|
PtzCmdType cmdType; |
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
if (!IsConnect()) break; |
||||
|
cmdType = PtzCmd.GetCmdType("Stop"); |
||||
|
byte cameraId = byte.Parse(CameraId.Text); |
||||
|
byte[] cmd = PtzCmd.GetCmd(ctrlType, cmdType, new byte[] { cameraId }); |
||||
|
Port.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.HikSdk: |
||||
|
string cameraIp = CameraIp.Text; |
||||
|
HikMap.TryGetValue(cameraIp, out HiKSDK hikSdk); |
||||
|
if (hikSdk == null) break; |
||||
|
cmdType = PtzCmd.GetCmdType(((Button)sender).Name.Replace("Btn", "")); |
||||
|
uint stop = 1, speed = 4; |
||||
|
PtzCmd.HikPtzMove(ref hikSdk, cmdType, new uint[] { stop, speed }); |
||||
|
break; |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void GotoBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
PtzControlType ctrlType = PtzCmd.GetControlType(ControlType.Text); |
||||
|
PtzCmdType cmdType = PtzCmdType.PresetGoto; |
||||
|
byte presetId = byte.Parse(PresetId.Text); |
||||
|
|
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
if (!IsConnect()) break; |
||||
|
byte cameraId = byte.Parse(CameraId.Text); |
||||
|
byte[] cmd = PtzCmd.GetCmd(ctrlType, cmdType, new byte[] { cameraId, presetId }); |
||||
|
Port.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.HikSdk: |
||||
|
string cameraIp = CameraIp.Text; |
||||
|
HikMap.TryGetValue(cameraIp, out HiKSDK hikSdk); |
||||
|
if (hikSdk == null) break; |
||||
|
PtzCmd.HikPtzMove(ref hikSdk, cmdType, new uint[] { presetId }); |
||||
|
break; |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ControlType_SelectionChanged(object sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (CameraId == null || CameraIp == null) return; |
||||
|
string ctrlTypeStr = ((ComboBoxItem)e.AddedItems[0]).Content.ToString(); |
||||
|
PtzControlType ctrlType = PtzCmd.GetControlType(ctrlTypeStr); |
||||
|
|
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
CameraId.IsEnabled = true; |
||||
|
CameraIp.IsEnabled = false; |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.HikSdk: |
||||
|
CameraId.IsEnabled = false; |
||||
|
CameraIp.IsEnabled = true; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
CameraId.IsEnabled = false; |
||||
|
CameraIp.IsEnabled = false; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
|
||||
|
#region InvokeEvent
|
||||
|
|
||||
|
public void GotoPreset() |
||||
|
{ |
||||
|
GotoBtn_Click(null, null); |
||||
|
} |
||||
|
|
||||
|
#endregion InvokeEvent
|
||||
|
|
||||
|
#region HikMap
|
||||
|
|
||||
|
private void LoadHikCamera() |
||||
|
{ |
||||
|
List<CameraInfo> cameraList = Global.AppConfig.CameraList; |
||||
|
foreach (var item in cameraList) |
||||
|
{ |
||||
|
string ip = item.Ip; |
||||
|
if (HikMap.ContainsKey(ip)) continue; |
||||
|
HikMap[ip] = null; |
||||
|
CameraIp.Items.Add(new ComboBoxItem { Content = ip }); |
||||
|
CameraInfo info = new(); |
||||
|
info.Copy(item); |
||||
|
Task.Run(() => |
||||
|
{ |
||||
|
HiKSDK sdk = new(info); |
||||
|
try |
||||
|
{ |
||||
|
bool ret = sdk.Init(); |
||||
|
if (!ret) sdk.BuildException(); |
||||
|
HikMap[ip] = sdk; |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
MessageBox.Show(ex.Message); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion HikMap
|
||||
|
|
||||
|
#region Util
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 查找子控件
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">控件类型</typeparam>
|
||||
|
/// <param name="parent">父控件依赖对象</param>
|
||||
|
/// <param name="list">子控件列表</param>
|
||||
|
public static void FindVisualChild<T>(DependencyObject parent, ref List<T> list) where T : DependencyObject |
||||
|
{ |
||||
|
if (parent != null) |
||||
|
{ |
||||
|
T child = default(T); |
||||
|
int numVisuals = VisualTreeHelper.GetChildrenCount(parent); |
||||
|
for (int i = 0; i < numVisuals; i++) |
||||
|
{ |
||||
|
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); |
||||
|
child = v as T; |
||||
|
if (child != null) |
||||
|
{ |
||||
|
list.Add(child); |
||||
|
} |
||||
|
FindVisualChild<T>(v, ref list); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Util
|
||||
|
} |
@ -0,0 +1,78 @@ |
|||||
|
using JiLinApp.Core; |
||||
|
using JiLinApp.Docking; |
||||
|
using JiLinApp.Mvvm; |
||||
|
using JiLinApp.Pages.FenceServerManage; |
||||
|
using JiLinApp.Pages.Main; |
||||
|
using JiLinApp.Pages.ShakeServerManage; |
||||
|
using NetMQ; |
||||
|
using NetMQ.Sockets; |
||||
|
using NewLife.Serialization; |
||||
|
using Prism.Events; |
||||
|
using Prism.Regions; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzManage; |
||||
|
|
||||
|
public class MainViewModel : ViewModelBase |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
private Main View { get; set; } |
||||
|
|
||||
|
private readonly AppConfig AppConfig; |
||||
|
|
||||
|
private readonly PublisherSocket AlarmPubSocket; |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public MainViewModel(IRegionManager region, IEventAggregator ea) : base(region, ea) |
||||
|
{ |
||||
|
// Bind global fields
|
||||
|
AppConfig = Global.AppConfig; |
||||
|
AlarmPubSocket = Global.AlarmPubSocket; |
||||
|
|
||||
|
// Bind invoke event
|
||||
|
ea.GetEvent<ShakeTcpAlarmSendEvent>().Subscribe(ShakeTcpAlarmReact); |
||||
|
ea.GetEvent<FenceUdpAlarmSendEvent>().Subscribe(FenceUdpAlarmReact); |
||||
|
} |
||||
|
|
||||
|
public override void SetView(object view) |
||||
|
{ |
||||
|
View = (Main)view; |
||||
|
} |
||||
|
|
||||
|
#region Send
|
||||
|
|
||||
|
private void SendAlarmToZmq(string msg) |
||||
|
{ |
||||
|
AlarmPubSocket.SendMoreFrame(AppConfig.Zmq.AlarmPubTopic).SendFrame(msg); |
||||
|
} |
||||
|
|
||||
|
private void SendAlarmToZmq(object obj) |
||||
|
{ |
||||
|
AlarmPubSocket.SendMoreFrame(AppConfig.Zmq.AlarmPubTopic).SendFrame(obj.ToJson()); |
||||
|
} |
||||
|
|
||||
|
#endregion Send
|
||||
|
|
||||
|
#region InvokeEvent
|
||||
|
|
||||
|
internal void ShakeTcpAlarmReact(TcpAlarmHostMessage msg) |
||||
|
{ |
||||
|
TaskUtil.Run(() => |
||||
|
{ |
||||
|
SendAlarmToZmq(msg.ToAlarmMessage()); |
||||
|
View.GotoPreset(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
internal void FenceUdpAlarmReact(UdpAlarmHostMessage msg) |
||||
|
{ |
||||
|
TaskUtil.Run(() => |
||||
|
{ |
||||
|
SendAlarmToZmq(msg.ToAlarmMessage()); |
||||
|
View.GotoPreset(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
#endregion InvokeEvent
|
||||
|
} |
@ -0,0 +1,525 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Net; |
||||
|
using System.Net.Sockets; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class AsyncTcpServer : IDisposable |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private TcpListener _listener; |
||||
|
private ConcurrentDictionary<string, TcpClientState> _clients; |
||||
|
private bool _disposed = false; |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
#region Ctors
|
||||
|
|
||||
|
private byte[] inOptionValues; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="listenPort">监听的端口</param>
|
||||
|
public AsyncTcpServer(int listenPort) |
||||
|
: this(IPAddress.Any, listenPort) |
||||
|
{ |
||||
|
uint dummy = 0; |
||||
|
inOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; |
||||
|
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0); |
||||
|
BitConverter.GetBytes((uint)1000).CopyTo(inOptionValues, Marshal.SizeOf(dummy)); |
||||
|
BitConverter.GetBytes((uint)1000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="localEP">监听的终结点</param>
|
||||
|
public AsyncTcpServer(IPEndPoint localEP) |
||||
|
: this(localEP.Address, localEP.Port) |
||||
|
{ |
||||
|
uint dummy = 0; |
||||
|
inOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; |
||||
|
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0); |
||||
|
BitConverter.GetBytes((uint)1000).CopyTo(inOptionValues, Marshal.SizeOf(dummy)); |
||||
|
BitConverter.GetBytes((uint)1000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="localIPAddress">监听的IP地址</param>
|
||||
|
/// <param name="listenPort">监听的端口</param>
|
||||
|
public AsyncTcpServer(IPAddress localIPAddress, int listenPort) |
||||
|
{ |
||||
|
uint dummy = 0; |
||||
|
inOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; |
||||
|
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0); |
||||
|
BitConverter.GetBytes((uint)1000).CopyTo(inOptionValues, Marshal.SizeOf(dummy)); |
||||
|
BitConverter.GetBytes((uint)1000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2); |
||||
|
Address = localIPAddress; |
||||
|
Port = listenPort; |
||||
|
Encoding = Encoding.Default; |
||||
|
|
||||
|
_clients = new ConcurrentDictionary<string, TcpClientState>(); |
||||
|
|
||||
|
_listener = new TcpListener(Address, Port); |
||||
|
_listener.AllowNatTraversal(true); |
||||
|
} |
||||
|
|
||||
|
#endregion Ctors
|
||||
|
|
||||
|
#region Properties
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 服务器是否正在运行
|
||||
|
/// </summary>
|
||||
|
public bool IsRunning { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 监听的IP地址
|
||||
|
/// </summary>
|
||||
|
public IPAddress Address { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 监听的端口
|
||||
|
/// </summary>
|
||||
|
public int Port { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 通信使用的编码
|
||||
|
/// </summary>
|
||||
|
public Encoding Encoding { get; set; } |
||||
|
|
||||
|
#endregion Properties
|
||||
|
|
||||
|
#region Server
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 启动服务器
|
||||
|
/// </summary>
|
||||
|
/// <returns>异步TCP服务器</returns>
|
||||
|
public AsyncTcpServer Start() |
||||
|
{ |
||||
|
return Start(30); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 启动服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="backlog">服务器所允许的挂起连接序列的最大长度</param>
|
||||
|
/// <returns>异步TCP服务器</returns>
|
||||
|
public AsyncTcpServer Start(int backlog) |
||||
|
{ |
||||
|
if (IsRunning) return this; |
||||
|
|
||||
|
IsRunning = true; |
||||
|
_listener.Start(backlog); |
||||
|
ContinueAcceptTcpClient(_listener); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 停止服务器
|
||||
|
/// </summary>
|
||||
|
/// <returns>异步TCP服务器</returns>
|
||||
|
public AsyncTcpServer Stop() |
||||
|
{ |
||||
|
if (!IsRunning) return this; |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
_listener.Stop(); |
||||
|
|
||||
|
foreach (var client in _clients.Values) |
||||
|
{ |
||||
|
client.TcpClient.Client.Disconnect(false); |
||||
|
} |
||||
|
_clients.Clear(); |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
} |
||||
|
catch (SocketException ex) |
||||
|
{ |
||||
|
Console.WriteLine("socket错误:" + ex.Message); |
||||
|
} |
||||
|
IsRunning = false; |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
private void ContinueAcceptTcpClient(TcpListener tcpListener) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
tcpListener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), tcpListener); |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
} |
||||
|
catch (SocketException ex) |
||||
|
{ |
||||
|
Console.WriteLine("socket错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Server
|
||||
|
|
||||
|
#region Receive
|
||||
|
|
||||
|
private void HandleTcpClientAccepted(IAsyncResult ar) |
||||
|
{ |
||||
|
if (!IsRunning) return; |
||||
|
|
||||
|
TcpListener tcpListener; |
||||
|
TcpClient tcpClient; |
||||
|
try |
||||
|
{ |
||||
|
tcpListener = (TcpListener)ar.AsyncState; |
||||
|
tcpClient = tcpListener.EndAcceptTcpClient(ar); |
||||
|
tcpClient.Client.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null); |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
return; |
||||
|
} |
||||
|
if (!tcpClient.Connected) return; |
||||
|
|
||||
|
byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; |
||||
|
TcpClientState internalClient = new TcpClientState(tcpClient, buffer); |
||||
|
|
||||
|
// add client connection to cache
|
||||
|
string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString(); |
||||
|
_clients.AddOrUpdate(tcpClientKey, internalClient, (n, o) => { return internalClient; }); |
||||
|
RaiseClientConnected(tcpClient); |
||||
|
|
||||
|
// begin to read data
|
||||
|
NetworkStream networkStream = internalClient.NetworkStream; |
||||
|
ContinueReadBuffer(internalClient, networkStream); |
||||
|
|
||||
|
// keep listening to accept next connection
|
||||
|
ContinueAcceptTcpClient(tcpListener); |
||||
|
} |
||||
|
|
||||
|
private void HandleDatagramReceived(IAsyncResult ar) |
||||
|
{ |
||||
|
if (!IsRunning) return; |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
TcpClientState internalClient = (TcpClientState)ar.AsyncState; |
||||
|
if (!internalClient.TcpClient.Connected) return; |
||||
|
|
||||
|
NetworkStream networkStream = internalClient.NetworkStream; |
||||
|
|
||||
|
int numberOfReadBytes = 0; |
||||
|
try |
||||
|
{ |
||||
|
// if the remote host has shutdown its connection,
|
||||
|
// read will immediately return with zero bytes.
|
||||
|
numberOfReadBytes = networkStream.EndRead(ar); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Console.WriteLine("错误:" + ex.Message); |
||||
|
numberOfReadBytes = 0; |
||||
|
} |
||||
|
|
||||
|
if (numberOfReadBytes == 0) |
||||
|
{ |
||||
|
// connection has been closed
|
||||
|
TcpClientState internalClientToBeThrowAway; |
||||
|
string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString(); |
||||
|
_clients.TryRemove(tcpClientKey, out internalClientToBeThrowAway); |
||||
|
RaiseClientDisconnected(internalClient.TcpClient); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// received byte and trigger event notification
|
||||
|
byte[] receivedBytes = new byte[numberOfReadBytes]; |
||||
|
Buffer.BlockCopy(internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes); |
||||
|
RaiseDatagramReceived(internalClient, receivedBytes); |
||||
|
|
||||
|
// continue listening for tcp datagram packets
|
||||
|
ContinueReadBuffer(internalClient, networkStream); |
||||
|
} |
||||
|
catch (InvalidOperationException ex) |
||||
|
{ |
||||
|
Console.WriteLine("错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ContinueReadBuffer(TcpClientState internalClient, NetworkStream networkStream) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient); |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Receive
|
||||
|
|
||||
|
#region Events
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 接收到数据报文事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived; |
||||
|
|
||||
|
private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) |
||||
|
{ |
||||
|
if (DatagramReceived != null) |
||||
|
{ |
||||
|
DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已建立事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpClientConnectedEventArgs> ClientConnected; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已断开事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected; |
||||
|
|
||||
|
private void RaiseClientConnected(TcpClient tcpClient) |
||||
|
{ |
||||
|
if (ClientConnected != null) |
||||
|
{ |
||||
|
ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void RaiseClientDisconnected(TcpClient tcpClient) |
||||
|
{ |
||||
|
if (ClientDisconnected != null) |
||||
|
{ |
||||
|
ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Events
|
||||
|
|
||||
|
#region Send
|
||||
|
|
||||
|
private void GuardRunning() |
||||
|
{ |
||||
|
if (!IsRunning) |
||||
|
throw new InvalidProgramException("This TCP server has not been started yet."); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至指定的客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void Send(TcpClient tcpClient, byte[] datagram) |
||||
|
{ |
||||
|
GuardRunning(); |
||||
|
|
||||
|
if (tcpClient == null) |
||||
|
throw new ArgumentNullException("tcpClient"); |
||||
|
|
||||
|
if (datagram == null) |
||||
|
throw new ArgumentNullException("datagram"); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
NetworkStream stream = tcpClient.GetStream(); |
||||
|
if (stream.CanWrite) |
||||
|
{ |
||||
|
stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); |
||||
|
} |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至指定的客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void Send(TcpClient tcpClient, string datagram) |
||||
|
{ |
||||
|
Send(tcpClient, Encoding.GetBytes(datagram)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至所有客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SendToAll(byte[] datagram) |
||||
|
{ |
||||
|
GuardRunning(); |
||||
|
|
||||
|
foreach (var client in _clients.Values) |
||||
|
{ |
||||
|
Send(client.TcpClient, datagram); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ICollection<TcpClientState> GetAllClient() |
||||
|
{ |
||||
|
return _clients.Values; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至所有客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SendToAll(string datagram) |
||||
|
{ |
||||
|
GuardRunning(); |
||||
|
|
||||
|
SendToAll(Encoding.GetBytes(datagram)); |
||||
|
} |
||||
|
|
||||
|
private void HandleDatagramWritten(IAsyncResult ar) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
} |
||||
|
catch (InvalidOperationException ex) |
||||
|
{ |
||||
|
Console.WriteLine("错误:" + ex.Message); |
||||
|
} |
||||
|
catch (IOException ex) |
||||
|
{ |
||||
|
Console.WriteLine("错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至指定的客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SyncSend(TcpClient tcpClient, byte[] datagram) |
||||
|
{ |
||||
|
GuardRunning(); |
||||
|
|
||||
|
if (tcpClient == null) |
||||
|
throw new ArgumentNullException("tcpClient"); |
||||
|
|
||||
|
if (datagram == null) |
||||
|
throw new ArgumentNullException("datagram"); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
NetworkStream stream = tcpClient.GetStream(); |
||||
|
if (stream.CanWrite) |
||||
|
{ |
||||
|
stream.Write(datagram, 0, datagram.Length); |
||||
|
} |
||||
|
} |
||||
|
catch (ObjectDisposedException ex) |
||||
|
{ |
||||
|
Console.WriteLine("对象注销错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至指定的客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SyncSend(TcpClient tcpClient, string datagram) |
||||
|
{ |
||||
|
SyncSend(tcpClient, Encoding.GetBytes(datagram)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至所有客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SyncSendToAll(byte[] datagram) |
||||
|
{ |
||||
|
GuardRunning(); |
||||
|
|
||||
|
foreach (var client in _clients.Values) |
||||
|
{ |
||||
|
SyncSend(client.TcpClient, datagram); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至所有客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SyncSendToAll(string datagram) |
||||
|
{ |
||||
|
GuardRunning(); |
||||
|
|
||||
|
SyncSendToAll(Encoding.GetBytes(datagram)); |
||||
|
} |
||||
|
|
||||
|
#endregion Send
|
||||
|
|
||||
|
#region IDisposable Members
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
Dispose(true); |
||||
|
GC.SuppressFinalize(this); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Releases unmanaged and - optionally - managed resources
|
||||
|
/// </summary>
|
||||
|
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
|
||||
|
/// <c>false</c> to release only unmanaged resources.</param>
|
||||
|
protected virtual void Dispose(bool disposing) |
||||
|
{ |
||||
|
if (!_disposed) |
||||
|
{ |
||||
|
if (disposing) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
Stop(); |
||||
|
|
||||
|
if (_listener != null) |
||||
|
{ |
||||
|
_listener = null; |
||||
|
} |
||||
|
} |
||||
|
catch (SocketException ex) |
||||
|
{ |
||||
|
Console.WriteLine("socket错误:" + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
_disposed = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion IDisposable Members
|
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class CRC8 |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// CRC8位校验表
|
||||
|
/// </summary>
|
||||
|
private static byte[] CRC8Table = new byte[] { |
||||
|
0,94,188,226,97,63,221,131,194,156,126,32,163,253,31,65, |
||||
|
157,195,33,127,252,162,64,30, 95,1,227,189,62,96,130,220, |
||||
|
35,125,159,193,66,28,254,160,225,191,93,3,128,222,60,98, |
||||
|
190,224,2,92,223,129,99,61,124,34,192,158,29,67,161,255, |
||||
|
70,24,250,164,39,121,155,197,132,218,56,102,229,187,89,7, |
||||
|
219,133,103,57,186,228,6,88,25,71,165,251,120,38,196,154, |
||||
|
101,59,217,135,4,90,184,230,167,249,27,69,198,152,122,36, |
||||
|
248,166,68,26,153,199,37,123,58,100,134,216,91,5,231,185, |
||||
|
140,210,48,110,237,179,81,15,78,16,242,172,47,113,147,205, |
||||
|
17,79,173,243,112,46,204,146,211,141,111,49,178,236,14,80, |
||||
|
175,241,19,77,206,144,114,44,109,51,209,143,12,82,176,238, |
||||
|
50,108,142,208,83,13,239,177,240,174,76,18,145,207,45,115, |
||||
|
202,148,118,40,171,245,23,73,8,86,180,234,105,55,213,139, |
||||
|
87,9,235,181,54,104,138,212,149,203, 41,119,244,170,72,22, |
||||
|
233,183,85,11,136,214,52,106,43,117,151,201,74,20,246,168, |
||||
|
116,42,200,150,21,75,169,247,182,232,10,84,215,137,107,53 }; |
||||
|
|
||||
|
public static byte CRC(byte[] buffer) |
||||
|
{ |
||||
|
return CRC(buffer, 0, buffer.Length); |
||||
|
} |
||||
|
|
||||
|
public static byte CRC(byte[] buffer, int off, int len) |
||||
|
{ |
||||
|
byte crc = 0; |
||||
|
if (buffer == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException("buffer"); |
||||
|
} |
||||
|
if (off < 0 || len < 0 || off + len > buffer.Length) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException(); |
||||
|
} |
||||
|
|
||||
|
for (int i = off; i < len; i++) |
||||
|
{ |
||||
|
crc = CRC8Table[crc ^ buffer[i]]; |
||||
|
} |
||||
|
return crc; |
||||
|
} |
||||
|
} |
@ -0,0 +1,74 @@ |
|||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net.Sockets; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class ClientMessage |
||||
|
{ |
||||
|
public TcpClient client { get; set; } |
||||
|
|
||||
|
public TcpAlarmHostTable host { get; set; } |
||||
|
|
||||
|
public string IP |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (host != null) return host.ip; |
||||
|
if (client != null) return client.Client.RemoteEndPoint.ToString().Split(':')[0]; |
||||
|
return ""; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public string Port |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (host != null) return host.port; |
||||
|
if (client != null) return client.Client.RemoteEndPoint.ToString().Split(':')[1]; |
||||
|
return "-1"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public List<byte> list { get; set; } |
||||
|
|
||||
|
public Hashtable sectioTable { get; set; } |
||||
|
|
||||
|
public ClientMessage() |
||||
|
{ |
||||
|
list = new List<byte>(); |
||||
|
host = null; |
||||
|
sectioTable = new Hashtable(); |
||||
|
} |
||||
|
|
||||
|
public List<byte[]> getMessageList() |
||||
|
{ |
||||
|
List<byte[]> msglist = new List<byte[]>(); |
||||
|
while (list.Count >= 19) |
||||
|
{ |
||||
|
if (list[0] == 0xAA && list[1] == 0xAA) |
||||
|
{ |
||||
|
int num = list[17]; |
||||
|
if (list.Count < 19 + num) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
byte[] bytes = new byte[num + 19]; |
||||
|
for (int i = 0; i < bytes.Length; i++) |
||||
|
{ |
||||
|
bytes[i] = list[i]; |
||||
|
} |
||||
|
msglist.Add(bytes); |
||||
|
list.RemoveRange(0, num + 19); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
list.RemoveAt(0); |
||||
|
} |
||||
|
} |
||||
|
return msglist; |
||||
|
} |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
using System; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class DataMessage |
||||
|
{ |
||||
|
private byte headA = 0xAA; |
||||
|
private byte headB = 0xAA; //(1)帧头
|
||||
|
public int deviceID { get; set; } //(2)设备ID
|
||||
|
|
||||
|
public string sendIP { get; set; } //(3)原地址
|
||||
|
public int sendPort { get; set; }//(3)原地址
|
||||
|
public string receiveIP { get; set; }//(4)目标地址
|
||||
|
public int receivePort { get; set; }//(4)目标地址
|
||||
|
public byte frameNum { get; set; }//(5)帧编号
|
||||
|
public byte functionNum { get; set; }//(6)功能码
|
||||
|
public byte dataLen { get; set; }//(7)传输数据长度
|
||||
|
public byte[] data { get; set; }//(8)传输数据
|
||||
|
public byte CRC { get; set; }//(9)CRC8
|
||||
|
|
||||
|
public void decode(byte[] bytes) |
||||
|
{ |
||||
|
deviceID = bytes[2]; |
||||
|
sendIP = bytes[3].ToString() + "." + bytes[4].ToString() + "." + bytes[5].ToString() + "." + bytes[6].ToString(); |
||||
|
sendPort = bytes[8] * 256 + bytes[7]; |
||||
|
receiveIP = bytes[9].ToString() + "." + bytes[10].ToString() + "." + bytes[11].ToString() + "." + bytes[12].ToString(); |
||||
|
receivePort = bytes[13] * 256 + bytes[14]; |
||||
|
frameNum = bytes[15]; |
||||
|
functionNum = bytes[16]; |
||||
|
dataLen = bytes[17]; |
||||
|
data = new byte[dataLen]; |
||||
|
for (int i = 0; i < dataLen; i++) |
||||
|
{ |
||||
|
data[i] = bytes[18 + i]; |
||||
|
} |
||||
|
CRC = bytes[18 + dataLen]; |
||||
|
} |
||||
|
|
||||
|
public byte[] encode() |
||||
|
{ |
||||
|
byte[] bytes = new byte[19 + dataLen]; |
||||
|
bytes[0] = bytes[1] = 0xAA; |
||||
|
bytes[2] = (byte)deviceID; |
||||
|
|
||||
|
string[] strs = sendIP.Split('.'); |
||||
|
bytes[3] = byte.Parse(strs[0]); |
||||
|
bytes[4] = byte.Parse(strs[1]); |
||||
|
bytes[5] = byte.Parse(strs[2]); |
||||
|
bytes[6] = byte.Parse(strs[3]); |
||||
|
bytes[7] = (byte)(sendPort % 256); |
||||
|
bytes[8] = (byte)(sendPort / 256); |
||||
|
|
||||
|
string[] strs2 = receiveIP.Split('.'); |
||||
|
bytes[9] = byte.Parse(strs2[0]); |
||||
|
bytes[10] = byte.Parse(strs2[1]); |
||||
|
bytes[11] = byte.Parse(strs2[2]); |
||||
|
bytes[12] = byte.Parse(strs2[3]); |
||||
|
bytes[13] = (byte)(receivePort % 256); |
||||
|
bytes[14] = (byte)(receivePort / 256); |
||||
|
bytes[15] = frameNum; |
||||
|
bytes[16] = functionNum; |
||||
|
bytes[17] = dataLen; |
||||
|
for (int i = 0; i < dataLen; i++) |
||||
|
{ |
||||
|
bytes[18 + i] = data[i]; |
||||
|
} |
||||
|
bytes[bytes.Length - 1] = CRC8.CRC(bytes, 0, bytes.Length - 1); |
||||
|
Console.WriteLine("发送指令:" + ToHexString(bytes)); |
||||
|
return bytes; |
||||
|
} |
||||
|
|
||||
|
private string ToHexString(byte[] bytes) |
||||
|
{ |
||||
|
string hexString = string.Empty; |
||||
|
|
||||
|
if (bytes != null) |
||||
|
{ |
||||
|
StringBuilder strB = new StringBuilder(); |
||||
|
|
||||
|
for (int i = 0; i < bytes.Length; i++) |
||||
|
{ |
||||
|
strB.Append(bytes[i].ToString("X2") + " "); |
||||
|
} |
||||
|
|
||||
|
hexString = strB.ToString(); |
||||
|
} |
||||
|
return hexString; |
||||
|
} |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class DataRequest |
||||
|
{ |
||||
|
public DataMessage request { get; set; } |
||||
|
|
||||
|
public DataMessage responce { get; set; } |
||||
|
|
||||
|
public DataRequest() |
||||
|
{ |
||||
|
responce = null; |
||||
|
request = null; |
||||
|
} |
||||
|
} |
@ -0,0 +1,57 @@ |
|||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class SectionState |
||||
|
{ |
||||
|
public int deviceID { get; set; } |
||||
|
|
||||
|
public string channel { get; set; } |
||||
|
public int online { get; set; } |
||||
|
|
||||
|
public string onLine_str |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (online == 0) |
||||
|
{ |
||||
|
return "在线"; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return "离线"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public int alarm { get; set; } |
||||
|
|
||||
|
public string alarm_str |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (alarm == 0) |
||||
|
{ |
||||
|
return "消警"; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return "报警"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public SectionState(int id, int chan, int state) |
||||
|
{ |
||||
|
deviceID = id; |
||||
|
channel = chan.ToString(); |
||||
|
online = state % 2; |
||||
|
alarm = state / 2 % 2; |
||||
|
} |
||||
|
|
||||
|
public SectionState(int id, int chan, int on, int a) |
||||
|
{ |
||||
|
deviceID = id; |
||||
|
channel = chan.ToString(); |
||||
|
online = on; |
||||
|
alarm = a; |
||||
|
} |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
using Newtonsoft.Json.Linq; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class TcpAlarmHostMessage |
||||
|
{ |
||||
|
public int Id { get; set; } |
||||
|
public string AlarmId { get; set; }//CID代码
|
||||
|
public string AlarmTime { get; set; }//报警时间
|
||||
|
|
||||
|
/*设备信息*/ |
||||
|
public int DeviceID { get; set; }//设备唯一ID
|
||||
|
public string ChannelNum { get; set; }//防区号
|
||||
|
public string Mode { get; set; } |
||||
|
public string Sensitivity { get; set; } |
||||
|
|
||||
|
/*联动信息*/ |
||||
|
public bool IsLinked { get; set; }//是否有联动信息
|
||||
|
public JArray Linklist { get; set; } |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class TcpAlarmHostTable |
||||
|
{ |
||||
|
public int id { get; set; } |
||||
|
|
||||
|
public string name { get; set; } |
||||
|
|
||||
|
public string lat { get; set; } |
||||
|
|
||||
|
public string lng { get; set; } |
||||
|
|
||||
|
public string ip { get; set; } |
||||
|
|
||||
|
public string port { get; set; } |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class TcpManagerConfig |
||||
|
{ |
||||
|
public string ServerIp { get; set; } |
||||
|
|
||||
|
public int ServerPort { get; set; } |
||||
|
|
||||
|
public int DeviceHeartKeep { get; set; } |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class TcpSectionTable |
||||
|
{ |
||||
|
public int id { get; set; } |
||||
|
public int deviceID { get; set; } |
||||
|
|
||||
|
public string name { get; set; } |
||||
|
public string lat { get; set; } |
||||
|
|
||||
|
public string lng { get; set; } |
||||
|
|
||||
|
public string channel { get; set; } |
||||
|
|
||||
|
public string mode { get; set; } |
||||
|
public string sensitivity { get; set; } |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net.Sockets; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已建立事件参数
|
||||
|
/// </summary>
|
||||
|
public class TcpClientConnectedEventArgs : EventArgs |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已建立事件参数
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
public TcpClientConnectedEventArgs(TcpClient tcpClient) |
||||
|
{ |
||||
|
if (tcpClient == null) |
||||
|
throw new ArgumentNullException("tcpClient"); |
||||
|
|
||||
|
TcpClient = tcpClient; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 客户端
|
||||
|
/// </summary>
|
||||
|
public TcpClient TcpClient { get; private set; } |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net.Sockets; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已断开事件参数
|
||||
|
/// </summary>
|
||||
|
public class TcpClientDisconnectedEventArgs : EventArgs |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已断开事件参数
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
public TcpClientDisconnectedEventArgs(TcpClient tcpClient) |
||||
|
{ |
||||
|
if (tcpClient == null) |
||||
|
throw new ArgumentNullException("tcpClient"); |
||||
|
|
||||
|
TcpClient = tcpClient; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 客户端
|
||||
|
/// </summary>
|
||||
|
public TcpClient TcpClient { get; private set; } |
||||
|
} |
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using System.Net.Sockets; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class TcpClientState |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Constructor for a new Client
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">The TCP client</param>
|
||||
|
/// <param name="buffer">The byte array buffer</param>
|
||||
|
public TcpClientState(TcpClient tcpClient, byte[] buffer) |
||||
|
{ |
||||
|
if (tcpClient == null) throw new ArgumentNullException("tcpClient"); |
||||
|
if (buffer == null) throw new ArgumentNullException("buffer"); |
||||
|
|
||||
|
TcpClient = tcpClient; |
||||
|
Buffer = buffer; |
||||
|
temp = string.Empty; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the TCP Client
|
||||
|
/// </summary>
|
||||
|
public TcpClient TcpClient { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the Buffer.
|
||||
|
/// </summary>
|
||||
|
public byte[] Buffer { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// TCP接收到但未处理的数据
|
||||
|
/// </summary>
|
||||
|
public string temp { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the network stream
|
||||
|
/// </summary>
|
||||
|
public NetworkStream NetworkStream |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
return TcpClient.GetStream(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 接收到数据报文事件参数
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">报文类型</typeparam>
|
||||
|
public class TcpDatagramReceivedEventArgs<T> : EventArgs |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 接收到数据报文事件参数
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public TcpDatagramReceivedEventArgs(TcpClientState tcpClient, T datagram) |
||||
|
{ |
||||
|
TcpClient = tcpClient; |
||||
|
Datagram = datagram; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 客户端
|
||||
|
/// </summary>
|
||||
|
public TcpClientState TcpClient { get; private set; } |
||||
|
/// <summary>
|
||||
|
/// 报文
|
||||
|
/// </summary>
|
||||
|
public T Datagram { get; private set; } |
||||
|
} |
@ -0,0 +1,753 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net; |
||||
|
using System.Net.Sockets; |
||||
|
using System.Text; |
||||
|
using System.Timers; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class TcpManager |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
private JsonSerializerSettings jSetting { get; } = new(); |
||||
|
|
||||
|
private AsyncTcpServer server { get; set; } = null; |
||||
|
|
||||
|
private Timer stateSpanTimer { get; } = new(); |
||||
|
|
||||
|
private Timer heartTimer { get; } = new(); |
||||
|
|
||||
|
private List<ClientMessage> list { get; } = new(); |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public TcpManager() |
||||
|
{ |
||||
|
jSetting.NullValueHandling = NullValueHandling.Ignore; |
||||
|
jSetting.DefaultValueHandling = DefaultValueHandling.Ignore; |
||||
|
} |
||||
|
|
||||
|
#region BaseMethod
|
||||
|
|
||||
|
public void StartServer(TcpManagerConfig config) |
||||
|
{ |
||||
|
if (IsRunning()) return; |
||||
|
IPAddress address = IPAddress.Any; |
||||
|
_ = IPAddress.TryParse(config.ServerIp, out address); |
||||
|
|
||||
|
server = new AsyncTcpServer(address, config.ServerPort); |
||||
|
server.ClientConnected += server_ClientConnected; |
||||
|
server.ClientDisconnected += server_ClientDisconnected; |
||||
|
server.DatagramReceived += server_DatagramReceived; |
||||
|
server.Start(); |
||||
|
|
||||
|
heartTimer.Close(); |
||||
|
heartTimer.Interval = 1000 * config.DeviceHeartKeep; |
||||
|
heartTimer.Elapsed += HeartTimer_Elapsed; |
||||
|
heartTimer.Enabled = true; |
||||
|
heartTimer.Start(); |
||||
|
} |
||||
|
|
||||
|
public void StopServer() |
||||
|
{ |
||||
|
heartTimer.Enabled = false; |
||||
|
if (IsRunning()) |
||||
|
{ |
||||
|
server.Stop(); |
||||
|
server = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool IsRunning() |
||||
|
{ |
||||
|
return server != null && server.IsRunning; |
||||
|
} |
||||
|
|
||||
|
public bool StartScan(ref string error) |
||||
|
{ |
||||
|
if (server == null) |
||||
|
{ |
||||
|
error = "服务未创建"; |
||||
|
return false; |
||||
|
} |
||||
|
if (!server.IsRunning) |
||||
|
{ |
||||
|
error = "服务未运行"; |
||||
|
return false; |
||||
|
} |
||||
|
stateSpanTimer.Enabled = true; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public void StopScan() |
||||
|
{ |
||||
|
stateSpanTimer.Enabled = false; |
||||
|
} |
||||
|
|
||||
|
#endregion BaseMethod
|
||||
|
|
||||
|
private void StateSpanTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) |
||||
|
{ |
||||
|
string error = ""; |
||||
|
for (int i = 0; i < list.Count; i++) |
||||
|
{ |
||||
|
sendState(list[i], ref error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void HeartTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) |
||||
|
{ |
||||
|
string error = ""; |
||||
|
for (int i = 0; i < list.Count; i++) |
||||
|
{ |
||||
|
sendHeart(list[i], ref error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private ClientMessage GetClientMessage(TcpClient client) |
||||
|
{ |
||||
|
string clientIP = client.Client.RemoteEndPoint.ToString().Split(':')[0]; |
||||
|
for (int i = 0; i < list.Count; i++) |
||||
|
{ |
||||
|
if (list[i].IP == clientIP) |
||||
|
{ |
||||
|
return list[i]; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private ClientMessage GetClientMessageIP(string clientIP) |
||||
|
{ |
||||
|
for (int i = 0; i < list.Count; i++) |
||||
|
{ |
||||
|
if (list[i].IP == clientIP) |
||||
|
{ |
||||
|
return list[i]; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private ClientMessage GetClientMessageDeviceID(int deviceId) |
||||
|
{ |
||||
|
for (int i = 0; i < list.Count; i++) |
||||
|
{ |
||||
|
if (list[i].host != null && list[i].host.id == deviceId) |
||||
|
{ |
||||
|
return list[i]; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public delegate void TCPSectionAlarmOnEvent(TcpAlarmHostMessage msg); |
||||
|
|
||||
|
public event TCPSectionAlarmOnEvent OnTcpSectionAlarmOn; |
||||
|
|
||||
|
public delegate void TCPSectionStateChangeEvent(SectionState state); |
||||
|
|
||||
|
public event TCPSectionStateChangeEvent OnTcpSectionStateChange; |
||||
|
|
||||
|
public delegate void TCPDeviceMessageEvent(TcpAlarmHostTable host, string msg); |
||||
|
|
||||
|
public event TCPDeviceMessageEvent OnTcpDeviceMessage; |
||||
|
|
||||
|
public delegate void TCPSectionMessageEvent(TcpAlarmHostTable host, TcpSectionTable section, string msg); |
||||
|
|
||||
|
public event TCPSectionMessageEvent OnTcpSectionMessage; |
||||
|
|
||||
|
private void server_DatagramReceived(object sender, TcpDatagramReceivedEventArgs<byte[]> e) |
||||
|
{ |
||||
|
string clientIP = e.TcpClient.TcpClient.Client.RemoteEndPoint.ToString().Split(':')[0]; |
||||
|
ClientMessage client = GetClientMessage(e.TcpClient.TcpClient); |
||||
|
if (client != null) |
||||
|
{ |
||||
|
AnalysisClientMessage(client, e.Datagram); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void TestAlarm(string devideId, string channel) |
||||
|
{ |
||||
|
ClientMessage message = new ClientMessage(); |
||||
|
message.client = new TcpClient("127.0.0.1", 5090); |
||||
|
|
||||
|
list.Add(message); |
||||
|
byte[] bytes1 = BitConverter.GetBytes(int.Parse(devideId)); |
||||
|
byte[] bytes2 = BitConverter.GetBytes(int.Parse(channel)); |
||||
|
byte[] bytes = new byte[24]{ |
||||
|
0xAA,0xAA,bytes1[0],bytes1[1], |
||||
|
127,0,0,1, |
||||
|
0x00,0x00,127,0, |
||||
|
0,1,0x00,0x00, |
||||
|
1,0x14,0x04,bytes2[0], |
||||
|
bytes2[1],0x02,0x00,0x00 |
||||
|
}; |
||||
|
AnalysisClientMessage(message, bytes); |
||||
|
} |
||||
|
|
||||
|
private string ToHexString(byte[] bytes) |
||||
|
{ |
||||
|
string hexString = string.Empty; |
||||
|
|
||||
|
if (bytes != null) |
||||
|
{ |
||||
|
StringBuilder strB = new StringBuilder(); |
||||
|
|
||||
|
for (int i = 0; i < bytes.Length; i++) |
||||
|
{ |
||||
|
strB.Append(bytes[i].ToString("X2") + " "); |
||||
|
} |
||||
|
|
||||
|
hexString = strB.ToString(); |
||||
|
} |
||||
|
return hexString; |
||||
|
} |
||||
|
|
||||
|
private void AnalysisClientMessage(ClientMessage client, byte[] bytes) |
||||
|
{ |
||||
|
client.list.AddRange(bytes); |
||||
|
|
||||
|
List<byte[]> msglist = client.getMessageList(); |
||||
|
if (msglist != null && msglist.Count > 0) |
||||
|
{ |
||||
|
for (int i = 0; i < msglist.Count; i++) |
||||
|
{ |
||||
|
Console.WriteLine(client.IP + " 收到数据:" + ToHexString(msglist[i])); |
||||
|
DataMessage mm = new DataMessage(); |
||||
|
mm.decode(msglist[i]); |
||||
|
switch (mm.functionNum) |
||||
|
{ |
||||
|
case 0x00: |
||||
|
Console.WriteLine(client.IP + " 登录"); |
||||
|
if (client.host == null || client.host.id != mm.deviceID) |
||||
|
{ |
||||
|
//string error = "";
|
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPAlarmHost", "id=" + mm.deviceID, ref error);
|
||||
|
JArray arr = new(); |
||||
|
if (arr != null && arr.Count > 0) |
||||
|
{ |
||||
|
client.host = JsonConvert.DeserializeObject<TcpAlarmHostTable>(arr[0].ToString(), jSetting); |
||||
|
client.host.ip = mm.sendIP; |
||||
|
client.host.port = mm.sendPort.ToString(); |
||||
|
} |
||||
|
} |
||||
|
if (OnTcpDeviceMessage != null) |
||||
|
{ |
||||
|
if (client.host != null) |
||||
|
{ |
||||
|
OnTcpDeviceMessage(client.host, "报警主机登录"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
OnTcpDeviceMessage(new TcpAlarmHostTable() { id = mm.deviceID, ip = mm.sendIP, port = mm.sendPort.ToString(), name = "未知设备" }, "报警主机登录"); |
||||
|
} |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case 0x01: |
||||
|
Console.WriteLine(client.IP + " 心跳"); |
||||
|
break; |
||||
|
|
||||
|
case 0x12: |
||||
|
Console.WriteLine(client.IP + "传感器地址设置响应"); |
||||
|
SetDataRequest(mm, 0x02); |
||||
|
break; |
||||
|
|
||||
|
case 0x13: |
||||
|
Console.WriteLine(client.IP + "传感器模式设置响应"); |
||||
|
SetDataRequest(mm, 0x03); |
||||
|
break; |
||||
|
|
||||
|
case 0x14: |
||||
|
Console.WriteLine(client.IP + "传感器状态响应"); |
||||
|
int channel = mm.data[0] + mm.data[1] * 256; |
||||
|
int state = mm.data[2] + mm.data[3] * 256; |
||||
|
int online = state % 2; |
||||
|
int alarm = state / 2 % 2; |
||||
|
TcpAlarmHostTable host = new() { id = mm.deviceID, ip = mm.sendIP, port = mm.sendPort.ToString(), name = "未知设备" }; |
||||
|
ProcessOnlineEvent(client, host, mm, channel, online); |
||||
|
ProcessAlarmEvent(client, host, mm, channel, alarm); |
||||
|
UpdateOnLineAlarm(client, host, channel, online, alarm); |
||||
|
SetDataRequest(mm, 0x04); |
||||
|
break; |
||||
|
|
||||
|
case 0x15: |
||||
|
Console.WriteLine(client.IP + "传感器复位响应"); |
||||
|
SetDataRequest(mm, 0x05); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ProcessOnlineEvent(ClientMessage client, TcpAlarmHostTable host, DataMessage mm, int channel, int online) |
||||
|
{ |
||||
|
if (client.sectioTable.ContainsKey(channel)) |
||||
|
{ |
||||
|
SectionState oldState = client.sectioTable[channel] as SectionState; |
||||
|
if (oldState.online == online) return; |
||||
|
} |
||||
|
TcpAlarmHostTable host1 = client.host == null ? host : client.host; |
||||
|
string error = ""; |
||||
|
TcpSectionTable section = new TcpSectionTable() { deviceID = host.id, name = "未知传感器", channel = channel.ToString() }; |
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPSection", "deviceID=" + mm.deviceID + "/channel='" + channel + "'", ref error);
|
||||
|
JArray arr = new(); |
||||
|
if (arr != null && arr.Count > 0) section = JsonConvert.DeserializeObject<TcpSectionTable>(arr[0].ToString(), jSetting); |
||||
|
if (OnTcpSectionMessage != null) |
||||
|
{ |
||||
|
OnTcpSectionMessage(host1, section, online == 0 ? "传感器上线" : "传感器离线"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ProcessAlarmEvent(ClientMessage client, TcpAlarmHostTable host, DataMessage mm, int channel, int alarm) |
||||
|
{ |
||||
|
if (client.sectioTable.ContainsKey(channel)) |
||||
|
{ |
||||
|
SectionState oldState = client.sectioTable[channel] as SectionState; |
||||
|
if (oldState.alarm == alarm) return; |
||||
|
} |
||||
|
TcpAlarmHostTable host1 = client.host == null ? host : client.host; |
||||
|
TcpSectionTable section = new() { deviceID = host.id, name = "未知传感器", channel = channel.ToString() }; |
||||
|
JArray arr = new(); |
||||
|
//string error = "";
|
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPSection", "deviceID=" + mm.deviceID + "/channel='" + channel + "'", ref error);
|
||||
|
if (arr != null && arr.Count > 0) section = JsonConvert.DeserializeObject<TcpSectionTable>(arr[0].ToString(), jSetting); |
||||
|
|
||||
|
if (OnTcpSectionMessage != null) |
||||
|
{ |
||||
|
OnTcpSectionMessage(host1, section, alarm == 0 ? "传感器消除警" : "传感器报警"); |
||||
|
} |
||||
|
if (alarm == 1) |
||||
|
{ |
||||
|
ProcessAlarm(host1.id, channel, alarm); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void UpdateOnLineAlarm(ClientMessage client, TcpAlarmHostTable host, int channel, int online, int alarm) |
||||
|
{ |
||||
|
if (client.sectioTable.ContainsKey(channel)) |
||||
|
{ |
||||
|
SectionState oldState = client.sectioTable[channel] as SectionState; |
||||
|
oldState.online = online; |
||||
|
oldState.alarm = alarm; |
||||
|
if (OnTcpSectionStateChange != null) |
||||
|
{ |
||||
|
OnTcpSectionStateChange(oldState); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
TcpAlarmHostTable host1 = client.host == null ? host : client.host; |
||||
|
SectionState state = new SectionState(host1.id, channel, online, alarm); |
||||
|
client.sectioTable[channel] = state; |
||||
|
if (OnTcpSectionStateChange != null) |
||||
|
{ |
||||
|
OnTcpSectionStateChange(state); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ProcessAlarm(int deviceId, int channel, int alarmId) |
||||
|
{ |
||||
|
TcpAlarmHostMessage alarm = new() |
||||
|
{ |
||||
|
AlarmId = Convert.ToString(alarmId), |
||||
|
AlarmTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), |
||||
|
DeviceID = deviceId, |
||||
|
ChannelNum = channel.ToString() |
||||
|
}; |
||||
|
JArray arr = new(); |
||||
|
//string error = "";
|
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPSection", "deviceID=" + deviceId + "/channel='" + channel + "'", ref error);
|
||||
|
if (arr != null && arr.Count > 0) |
||||
|
{ |
||||
|
alarm.Mode = arr[0]["mode"].ToString(); |
||||
|
alarm.Sensitivity = arr[0]["sensitivity"].ToString(); |
||||
|
} |
||||
|
|
||||
|
alarm.Linklist = new(); |
||||
|
//alarm.Linklist = DBCenter.center.SearchByConditionJArray("table_TCPLink", "deviceID=" + alarm.deviceID + "/channel='" + channel + "'", ref error);
|
||||
|
if (alarm.Linklist == null || alarm.Linklist.Count == 0) |
||||
|
{ |
||||
|
alarm.IsLinked = false; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
alarm.IsLinked = true; |
||||
|
} |
||||
|
ProcessAlarmDB(alarm); |
||||
|
} |
||||
|
|
||||
|
//处理报警事件
|
||||
|
private void ProcessAlarmDB(TcpAlarmHostMessage msg) |
||||
|
{ |
||||
|
OnTcpSectionAlarmOn(msg); |
||||
|
|
||||
|
////报警信息放入数据库
|
||||
|
//JObject obj = new JObject
|
||||
|
//{
|
||||
|
// { "alarmTime", msg.AlarmTime },
|
||||
|
|
||||
|
// { "deviceID", msg.DeviceID },
|
||||
|
// { "channelNum", msg.ChannelNum },
|
||||
|
// { "mode", msg.Mode },
|
||||
|
// { "sensitivity", msg.Sensitivity },
|
||||
|
|
||||
|
// { "IsLinked", msg.IsLinked },
|
||||
|
// { "linklist", msg.Linklist }
|
||||
|
//};
|
||||
|
//string error = "";
|
||||
|
//DBCenter.center.InsertResult("table_TCPAlarmMessage", obj, ref error);
|
||||
|
////打开预览窗口
|
||||
|
//if (msg.IsLinked)
|
||||
|
//{
|
||||
|
// if (OnTCPSectionAlarmOn != null)
|
||||
|
// {
|
||||
|
// OnTCPSectionAlarmOn(msg);
|
||||
|
// }
|
||||
|
// //联动预置位
|
||||
|
// for (int i = 0; i < msg.linklist.Count; i++)
|
||||
|
// {
|
||||
|
// if (msg.linklist[i]["needPreset"].ToString() == "true")
|
||||
|
// {
|
||||
|
// int camID = int.Parse(msg.linklist[i]["camID"].ToString());
|
||||
|
// string camType = msg.linklist[i]["camType"].ToString();
|
||||
|
// CamType device_type = CamType.Table;
|
||||
|
// if (camType == "摄像机") device_type = CamType.Camera;
|
||||
|
// int presetId = int.Parse(msg.linklist[i]["presetID"].ToString());
|
||||
|
// RequestToService.center.NET_SDK_PTZPreset_Other(camID, device_type, (int)WMPTZPresetCommand.WMPTZPreset_GOTO, presetId, ref error);
|
||||
|
// }
|
||||
|
// }
|
||||
|
//}
|
||||
|
} |
||||
|
|
||||
|
public void SetDataRequest(DataMessage msg, byte functionNum) |
||||
|
{ |
||||
|
lock (this) |
||||
|
{ |
||||
|
for (int i = 0; i < reqlist.Count; i++) |
||||
|
{ |
||||
|
if (reqlist[i].request.functionNum == functionNum && reqlist[i].request.frameNum == msg.frameNum) |
||||
|
{ |
||||
|
reqlist[i].responce = msg; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool SendMessage(string IP, byte[] bytes, ref string error) |
||||
|
{ |
||||
|
if (server == null) |
||||
|
{ |
||||
|
error = "服务未创建"; |
||||
|
return false; |
||||
|
} |
||||
|
if (!server.IsRunning) |
||||
|
{ |
||||
|
error = "服务未运行"; |
||||
|
return false; |
||||
|
} |
||||
|
ClientMessage client = GetClientMessageIP(IP); |
||||
|
if (client != null) |
||||
|
{ |
||||
|
server.Send(client.client, bytes); |
||||
|
return true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
error = "主机未连接"; |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private List<DataRequest> reqlist = new List<DataRequest>(); |
||||
|
private byte frameNumber = 0; |
||||
|
|
||||
|
public bool sendRequest(ref DataRequest request, ref string error) |
||||
|
{ |
||||
|
if (request.request == null) |
||||
|
{ |
||||
|
error = "请求信息未填写"; |
||||
|
return false; |
||||
|
} |
||||
|
//int waitTime = int.Parse(DBCenter.center.GetConfig("WW_TCP_DeviceTimeOut")) * 10;
|
||||
|
int waitTime = 100; |
||||
|
request.request.frameNum = frameNumber; |
||||
|
frameNumber++; |
||||
|
bool send = SendMessage(request.request.receiveIP, request.request.encode(), ref error); |
||||
|
if (!send) return false; |
||||
|
reqlist.Add(request); |
||||
|
for (int i = 0; i < waitTime; i++) |
||||
|
{ |
||||
|
if (request.responce != null) |
||||
|
{ |
||||
|
reqlist.Remove(request); |
||||
|
return true; |
||||
|
} |
||||
|
System.Threading.Thread.Sleep(100); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public bool sendNoRequest(DataMessage msg, ref string error) |
||||
|
{ |
||||
|
msg.frameNum = frameNumber; |
||||
|
frameNumber++; |
||||
|
return SendMessage(msg.receiveIP, msg.encode(), ref error); |
||||
|
} |
||||
|
|
||||
|
public bool sendHeart(ClientMessage client, ref string error) |
||||
|
{ |
||||
|
if (client.host == null) |
||||
|
{ |
||||
|
error = "报警主机信息缺失"; |
||||
|
return false; |
||||
|
} |
||||
|
DataMessage msg = getSendMessageHead(client.host.id, client, 0x01, 1); |
||||
|
msg.data = new byte[] { 0xFF }; |
||||
|
|
||||
|
return sendNoRequest(msg, ref error); |
||||
|
} |
||||
|
|
||||
|
public bool SetSectionAddress(int deviceId, string channel_str, int address, ref string error) |
||||
|
{ |
||||
|
ClientMessage client = GetClientMessageDeviceID(deviceId); |
||||
|
if (client == null) |
||||
|
{ |
||||
|
error = "此主机号不在线"; |
||||
|
return false; |
||||
|
} |
||||
|
DataMessage msg = getSendMessageHead(deviceId, client, 0x02, 4); |
||||
|
int channel = int.Parse(channel_str); |
||||
|
msg.data = new byte[] { (byte)(channel % 256), (byte)(channel / 256), (byte)(address % 256), (byte)(address / 256) }; |
||||
|
DataRequest request = new DataRequest(); |
||||
|
request.request = msg; |
||||
|
bool result = sendRequest(ref request, ref error); |
||||
|
if (result) |
||||
|
{ |
||||
|
JObject conlist = new JObject(); |
||||
|
conlist.Add("deviceID", deviceId); |
||||
|
conlist.Add("channel", channel_str); |
||||
|
JObject valuelist = new JObject(); |
||||
|
valuelist.Add("channel", address.ToString()); |
||||
|
//DBCenter.center.UpdateResult("table_TCPSection", valuelist, conlist, ref error);
|
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public bool SetSectionMode(int deviceId, string channel_str, byte mode, byte sensitivity, ref string error) |
||||
|
{ |
||||
|
ClientMessage client = GetClientMessageDeviceID(deviceId); |
||||
|
if (client == null) |
||||
|
{ |
||||
|
error = "此主机号不在线"; |
||||
|
return false; |
||||
|
} |
||||
|
DataMessage msg = getSendMessageHead(deviceId, client, 0x03, 3); |
||||
|
int channel = int.Parse(channel_str); |
||||
|
msg.data = new byte[] { (byte)(channel % 256), (byte)(channel / 256), (byte)(mode + sensitivity * 8) }; |
||||
|
DataRequest request = new DataRequest(); |
||||
|
request.request = msg; |
||||
|
bool result = sendRequest(ref request, ref error); |
||||
|
if (result) |
||||
|
{ |
||||
|
JObject conlist = new JObject(); |
||||
|
conlist.Add("deviceID", deviceId); |
||||
|
conlist.Add("channel", channel_str); |
||||
|
JObject valuelist = new JObject(); |
||||
|
valuelist.Add("mode", mode.ToString()); |
||||
|
valuelist.Add("sensitivity", sensitivity.ToString()); |
||||
|
//DBCenter.center.UpdateResult("table_TCPSection", valuelist, conlist, ref error);
|
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public bool SetSectionReset(int deviceId, string channel_str, ref string error) |
||||
|
{ |
||||
|
ClientMessage client = GetClientMessageDeviceID(deviceId); |
||||
|
if (client == null) |
||||
|
{ |
||||
|
error = "此主机号不在线"; |
||||
|
return false; |
||||
|
} |
||||
|
DataMessage msg = getSendMessageHead(deviceId, client, 0x05, 2); |
||||
|
int channel = int.Parse(channel_str); |
||||
|
msg.data = new byte[] { (byte)(channel % 256), (byte)(channel / 256) }; |
||||
|
DataRequest request = new DataRequest(); |
||||
|
request.request = msg; |
||||
|
return sendRequest(ref request, ref error); |
||||
|
} |
||||
|
|
||||
|
public SectionState SetSectionCheck(int deviceId, string channel_str, ref string error) |
||||
|
{ |
||||
|
ClientMessage client = GetClientMessageDeviceID(deviceId); |
||||
|
if (client == null) |
||||
|
{ |
||||
|
error = "此主机号不在线"; |
||||
|
return null; |
||||
|
} |
||||
|
DataMessage msg = getSendMessageHead(deviceId, client, 0x04, 2); |
||||
|
int channel = int.Parse(channel_str); |
||||
|
msg.data = new byte[] { (byte)(channel % 256), (byte)(channel / 256) }; |
||||
|
DataRequest request = new DataRequest(); |
||||
|
request.request = msg; |
||||
|
bool result = sendRequest(ref request, ref error); |
||||
|
if (result) |
||||
|
{ |
||||
|
int channel2 = request.responce.data[0] + request.responce.data[1] * 256; |
||||
|
int state2 = request.responce.data[2] + request.responce.data[3] * 256; |
||||
|
return new SectionState(deviceId, channel2, state2); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public List<SectionState> SetDeviceCheck(int deviceId, ref string error) |
||||
|
{ |
||||
|
List<SectionState> list = new List<SectionState>(); |
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPSection", "deviceID=" + deviceId, ref error);
|
||||
|
JArray arr = new(); |
||||
|
if (arr != null && arr.Count > 0) |
||||
|
{ |
||||
|
for (int i = 0; i < arr.Count; i++) |
||||
|
{ |
||||
|
string channel = arr[i]["channel"].ToString(); |
||||
|
SectionState state = SetSectionCheck(deviceId, channel, ref error); |
||||
|
if (state == null) |
||||
|
{ |
||||
|
state = new SectionState(deviceId, int.Parse(channel), -1, -1); |
||||
|
} |
||||
|
list.Add(state); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
error = "数据库中没有防区信息"; |
||||
|
} |
||||
|
return list; |
||||
|
} |
||||
|
|
||||
|
public List<SectionState> SetAllCheck(ref string error) |
||||
|
{ |
||||
|
List<SectionState> list = new List<SectionState>(); |
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPAlarmHost", "", ref error);
|
||||
|
JArray arr = new(); |
||||
|
if (arr != null && arr.Count > 0) |
||||
|
{ |
||||
|
for (int i = 0; i < arr.Count; i++) |
||||
|
{ |
||||
|
int deviceId = int.Parse(arr[i]["id"].ToString()); |
||||
|
list.AddRange(SetDeviceCheck(deviceId, ref error)); |
||||
|
} |
||||
|
} |
||||
|
return list; |
||||
|
} |
||||
|
|
||||
|
private DataMessage getSendMessageHead(int deviceId, ClientMessage client, byte fun_num, byte datalen) |
||||
|
{ |
||||
|
//DataMessage msg = new DataMessage();
|
||||
|
//msg.deviceID = deviceId;
|
||||
|
//msg.sendIP = DBCenter.center.GetConfig("WW_TCP_ServeIP");
|
||||
|
//msg.sendPort = int.Parse(DBCenter.center.GetConfig("WW_TCP_ServePort"));
|
||||
|
//msg.receiveIP = client.IP;
|
||||
|
//msg.receivePort = int.Parse(client.Port);
|
||||
|
//msg.functionNum = fun_num;
|
||||
|
//msg.dataLen = datalen;
|
||||
|
//return msg;
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public void sendState(ClientMessage client, ref string error) |
||||
|
{ |
||||
|
//if (client.host == null)
|
||||
|
//{
|
||||
|
// error = "报警主机信息缺失";
|
||||
|
// return;
|
||||
|
//}
|
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPSection", "deviceID='" + client.host.id + "'", ref error);
|
||||
|
//if (arr != null && arr.Count > 0)
|
||||
|
//{
|
||||
|
// for (int i = 0; i < arr.Count; i++)
|
||||
|
// {
|
||||
|
// DataMessage msg = getSendMessageHead(client.host.id, client, 0x04, 2);
|
||||
|
// int channel = int.Parse(arr[i]["channel"].ToString());
|
||||
|
// msg.data = new byte[] { (byte)(channel % 256), (byte)(channel / 256) };
|
||||
|
// sendNoRequest(msg, ref error);
|
||||
|
// }
|
||||
|
//}
|
||||
|
} |
||||
|
|
||||
|
private void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e) |
||||
|
{ |
||||
|
string clientIP = e.TcpClient.Client.RemoteEndPoint.ToString().Split(':')[0]; |
||||
|
Console.WriteLine(clientIP + "下线"); |
||||
|
ClientMessage client = GetClientMessage(e.TcpClient); |
||||
|
if (client != null) |
||||
|
{ |
||||
|
list.Remove(client); |
||||
|
if (OnTcpDeviceMessage != null) |
||||
|
{ |
||||
|
if (client.host != null) |
||||
|
{ |
||||
|
OnTcpDeviceMessage(client.host, "报警主机掉线"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
OnTcpDeviceMessage(new TcpAlarmHostTable() { id = -1, ip = clientIP, port = client.Port, name = "未知设备" }, "报警主机掉线"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void server_ClientConnected(object sender, TcpClientConnectedEventArgs e) |
||||
|
{ |
||||
|
string error = ""; |
||||
|
string clientIP = e.TcpClient.Client.RemoteEndPoint.ToString().Split(':')[0]; |
||||
|
string port = e.TcpClient.Client.RemoteEndPoint.ToString().Split(':')[1]; |
||||
|
Console.WriteLine(clientIP + "上线"); |
||||
|
ClientMessage client = GetClientMessage(e.TcpClient); |
||||
|
if (client == null) |
||||
|
{ |
||||
|
ClientMessage msg = new ClientMessage(); |
||||
|
msg.client = e.TcpClient; |
||||
|
//JArray arr = DBCenter.center.SearchByConditionJArray("table_TCPAlarmHost", "IP='" + clientIP + "'", ref error);
|
||||
|
JArray arr = new(); |
||||
|
if (arr != null && arr.Count > 0) |
||||
|
{ |
||||
|
msg.host = JsonConvert.DeserializeObject<TcpAlarmHostTable>(arr[0].ToString(), jSetting); |
||||
|
} |
||||
|
list.Add(msg); |
||||
|
if (OnTcpDeviceMessage != null) |
||||
|
{ |
||||
|
if (msg.host != null) |
||||
|
{ |
||||
|
OnTcpDeviceMessage(msg.host, "报警主机上线"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
OnTcpDeviceMessage(new TcpAlarmHostTable() { id = -1, ip = clientIP, port = client.Port, name = "未知设备" }, "报警主机上线"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public List<SectionState> getOnlineState(int deviceId) |
||||
|
{ |
||||
|
ClientMessage msg = GetClientMessageDeviceID(deviceId); |
||||
|
if (msg != null) |
||||
|
{ |
||||
|
return msg.sectioTable.Values as List<SectionState>; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return new List<SectionState>(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
<UserControl x:Class="JiLinApp.Pages.ShakeServerManage.Main" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" |
||||
|
xmlns:prism="http://prismlibrary.com/" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
prism:ViewModelLocator.AutoWireViewModel="True" |
||||
|
mc:Ignorable="d" |
||||
|
d:DesignHeight="450" d:DesignWidth="800"> |
||||
|
<materialDesign:Card> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="250" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<GroupBox Header="震动报警服务器设置(TCP)" Grid.Row="0"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
<RowDefinition Height="1*" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
<ColumnDefinition Width="1*" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0" Margin="5"> |
||||
|
<TextBox Name="ServerIp" materialDesign:HintAssist.Hint="服务地址" Text="127.0.0.1" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1" Margin="5"> |
||||
|
<TextBox Name="ServerPort" materialDesign:HintAssist.Hint="服务端口" Text="5080" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="0" Margin="5"> |
||||
|
<TextBox Name="DeviceHeartKeep" materialDesign:HintAssist.Hint="设备心跳间隔" Text="10" Width="200" Style="{StaticResource MaterialDesignOutlinedTextBox}" /> |
||||
|
</StackPanel> |
||||
|
<WrapPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<Button Name="OpenBtn" Content="开启服务" Width="100" Margin="5" Click="OpenBtn_Click" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
<Button Name="StopBtn" Content="关闭服务" Width="100" Margin="5" Click="StopBtn_Click" IsEnabled="False" Style="{StaticResource MaterialDesignRaisedLightButton}" /> |
||||
|
</WrapPanel> |
||||
|
</Grid> |
||||
|
</GroupBox> |
||||
|
<!--<GroupBox Name="MsgBox" Header="消息窗口" Grid.Row="1" Margin="0 6 0 0"> |
||||
|
<TextBox MinHeight="200" VerticalContentAlignment="Top" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True" IsReadOnly="True" |
||||
|
Style="{StaticResource MaterialDesignOutlinedTextBox}"> |
||||
|
</TextBox> |
||||
|
</GroupBox>--> |
||||
|
</Grid> |
||||
|
</materialDesign:Card> |
||||
|
</UserControl> |
@ -0,0 +1,90 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Main.xaml 的交互逻辑
|
||||
|
/// </summary>
|
||||
|
public partial class Main : UserControl |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private TcpManager Manager { get; } = new(); |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
public Main() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Init(); |
||||
|
} |
||||
|
|
||||
|
#region Init
|
||||
|
|
||||
|
private void Init() |
||||
|
{ |
||||
|
if (DataContext != null) |
||||
|
{ |
||||
|
MainViewModel vm = DataContext as MainViewModel; |
||||
|
vm.SetView(this); |
||||
|
|
||||
|
Manager.OnTcpDeviceMessage += vm.OnTcpDeviceMessage; |
||||
|
Manager.OnTcpSectionMessage += vm.OnTcpSectionMessage; |
||||
|
Manager.OnTcpSectionAlarmOn += vm.OnTcpSectionAlarmOn; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ChangeState(bool openState) |
||||
|
{ |
||||
|
if (openState) |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = false; |
||||
|
StopBtn.IsEnabled = true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = true; |
||||
|
StopBtn.IsEnabled = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Init
|
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void OpenBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!Manager.IsRunning()) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
TcpManagerConfig config = new() |
||||
|
{ |
||||
|
ServerIp = ServerIp.Text, |
||||
|
ServerPort = int.Parse(ServerPort.Text), |
||||
|
DeviceHeartKeep = int.Parse(DeviceHeartKeep.Text) |
||||
|
}; |
||||
|
Manager.StartServer(config); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
MessageBox.Show(ex.ToString()); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
ChangeState(true); |
||||
|
} |
||||
|
|
||||
|
private void StopBtn_Click(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (Manager.IsRunning()) |
||||
|
{ |
||||
|
Manager.StopServer(); |
||||
|
} |
||||
|
ChangeState(false); |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
using JiLinApp.Mvvm; |
||||
|
using JiLinApp.Pages.Main; |
||||
|
using Prism.Events; |
||||
|
using Prism.Regions; |
||||
|
|
||||
|
namespace JiLinApp.Pages.ShakeServerManage; |
||||
|
|
||||
|
public class MainViewModel : ViewModelBase |
||||
|
{ |
||||
|
#region fields
|
||||
|
|
||||
|
private Main View { get; set; } |
||||
|
|
||||
|
#endregion fields
|
||||
|
|
||||
|
public MainViewModel(IRegionManager region, IEventAggregator ea) : base(region, ea) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override void SetView(object view) |
||||
|
{ |
||||
|
View = (Main)view; |
||||
|
} |
||||
|
|
||||
|
#region ConnEvent
|
||||
|
|
||||
|
internal void OnTcpDeviceMessage(TcpAlarmHostTable host, string msg) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
internal void OnTcpSectionMessage(TcpAlarmHostTable host, TcpSectionTable section, string msg) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
internal void OnTcpSectionAlarmOn(TcpAlarmHostMessage msg) |
||||
|
{ |
||||
|
_ea.GetEvent<ShakeTcpAlarmSendEvent>().Publish(msg); |
||||
|
} |
||||
|
|
||||
|
#endregion ConnEvent
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
{ |
||||
|
"zmq": { |
||||
|
"alarmPubAddr": "tcp://127.0.0.1:5000", |
||||
|
"alarmPubTopic": "alarmRecv" |
||||
|
}, |
||||
|
"CameraList": [ |
||||
|
{ |
||||
|
"Ip": "192.168.1.65", |
||||
|
"Port": "8000", |
||||
|
"UserName": "admin", |
||||
|
"Password": "hk123456" |
||||
|
}, |
||||
|
{ |
||||
|
"Ip": "192.168.1.65", |
||||
|
"Port": "8000", |
||||
|
"UserName": "admin", |
||||
|
"Password": "hk123456" |
||||
|
}, |
||||
|
{ |
||||
|
"Ip": "192.168.1.65", |
||||
|
"Port": "8000", |
||||
|
"UserName": "admin", |
||||
|
"Password": "hk123456" |
||||
|
} |
||||
|
] |
||||
|
} |
Loading…
Reference in new issue