Browse Source

first commit

master
fajiao 2 years ago
parent
commit
54bbd24814
  1. 59
      EC.Util/CameraSDK/Common/CameraException.cs
  2. 111
      EC.Util/CameraSDK/Common/CameraStruct.cs
  3. 58
      EC.Util/CameraSDK/Common/ICameraSDK.cs
  4. 245
      EC.Util/CameraSDK/HiK/HiKOriSDK.cs
  5. 143
      EC.Util/CameraSDK/HiK/HiKSDK.cs
  6. 43
      EC.Util/Common/JsonUtil.cs
  7. 12
      EC.Util/Common/SystemUtil.cs
  8. 45
      EC.Util/EC.Util.csproj
  9. 60
      EC.Util/Port/SerialPortBuilder.cs
  10. 56
      EC.Util/Port/SerialPortParam.cs
  11. 166
      EC.Util/Port/YcSerialPort.cs
  12. 11
      EC.Util/Zmq/ZmqUtil.cs
  13. BIN
      EC.Util/libs/hik-win64/HCCore.dll
  14. BIN
      EC.Util/libs/hik-win64/HCNetSDK.dll
  15. BIN
      EC.Util/libs/hik-win64/HCNetSDKCom/HCCoreDevCfg.dll
  16. BIN
      EC.Util/libs/hik-win64/HCNetSDKCom/HCPreview.dll
  17. BIN
      EC.Util/libs/hik-win64/libcrypto-1_1-x64.dll
  18. BIN
      EC.Util/libs/hik-win64/libssl-1_1-x64.dll
  19. 31
      JiLinApp.sln
  20. 20
      JiLinApp/App.xaml
  21. 79
      JiLinApp/App.xaml.cs
  22. 17
      JiLinApp/Core/Config.cs
  23. 42
      JiLinApp/Core/Global.cs
  24. 23
      JiLinApp/Core/TaskUtil.cs
  25. 64
      JiLinApp/Docking/AlarmMessage.cs
  26. 24
      JiLinApp/JiLinApp.csproj
  27. 30
      JiLinApp/Mvvm/RegionViewModelBase.cs
  28. 34
      JiLinApp/Mvvm/ViewModelBase.cs
  29. 141
      JiLinApp/Pages/FenceServerManage/Core/AlarmEncode.cs
  30. 31
      JiLinApp/Pages/FenceServerManage/Core/Entity/DeviceStateMessage.cs
  31. 67
      JiLinApp/Pages/FenceServerManage/Core/Entity/SectorState.cs
  32. 172
      JiLinApp/Pages/FenceServerManage/Core/Entity/UdpAlarmHostDevice.cs
  33. 30
      JiLinApp/Pages/FenceServerManage/Core/Entity/UdpAlarmHostMessage.cs
  34. 12
      JiLinApp/Pages/FenceServerManage/Core/Entity/UdpManagerConfig.cs
  35. 71
      JiLinApp/Pages/FenceServerManage/Core/Udp.cs
  36. 885
      JiLinApp/Pages/FenceServerManage/Core/UdpManager.cs
  37. 54
      JiLinApp/Pages/FenceServerManage/Main.xaml
  38. 93
      JiLinApp/Pages/FenceServerManage/Main.xaml.cs
  39. 42
      JiLinApp/Pages/FenceServerManage/MainViewModel.cs
  40. 17
      JiLinApp/Pages/Main/Core/MessageEvent.cs
  41. 5
      JiLinApp/Pages/Main/Core/PageNames.cs
  42. 6
      JiLinApp/Pages/Main/Core/RegionNames.cs
  43. 55
      JiLinApp/Pages/Main/MainWindow.xaml
  44. 47
      JiLinApp/Pages/Main/MainWindow.xaml.cs
  45. 242
      JiLinApp/Pages/PtzManage/Core/PelcoD.cs
  46. 364
      JiLinApp/Pages/PtzManage/Core/PelcoP.cs
  47. 191
      JiLinApp/Pages/PtzManage/Core/PtzCmd.cs
  48. 176
      JiLinApp/Pages/PtzManage/Main.xaml
  49. 315
      JiLinApp/Pages/PtzManage/Main.xaml.cs
  50. 78
      JiLinApp/Pages/PtzManage/MainViewModel.cs
  51. 525
      JiLinApp/Pages/ShakeServerManage/Core/AsyncTcpServer.cs
  52. 51
      JiLinApp/Pages/ShakeServerManage/Core/CRC8.cs
  53. 74
      JiLinApp/Pages/ShakeServerManage/Core/Entity/ClientMessage.cs
  54. 90
      JiLinApp/Pages/ShakeServerManage/Core/Entity/DataMessage.cs
  55. 14
      JiLinApp/Pages/ShakeServerManage/Core/Entity/DataRequest.cs
  56. 57
      JiLinApp/Pages/ShakeServerManage/Core/Entity/SectionState.cs
  57. 20
      JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpAlarmHostMessage.cs
  58. 22
      JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpAlarmHostTable.cs
  59. 10
      JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpManagerConfig.cs
  60. 23
      JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpSectionTable.cs
  61. 31
      JiLinApp/Pages/ShakeServerManage/Core/TcpClientConnectedEventArgs.cs
  62. 31
      JiLinApp/Pages/ShakeServerManage/Core/TcpClientDisconnectedEventArgs.cs
  63. 48
      JiLinApp/Pages/ShakeServerManage/Core/TcpClientState.cs
  64. 34
      JiLinApp/Pages/ShakeServerManage/Core/TcpDatagramReceivedEventArgs.cs
  65. 753
      JiLinApp/Pages/ShakeServerManage/Core/TcpManager.cs
  66. 51
      JiLinApp/Pages/ShakeServerManage/Main.xaml
  67. 90
      JiLinApp/Pages/ShakeServerManage/Main.xaml.cs
  68. 41
      JiLinApp/Pages/ShakeServerManage/MainViewModel.cs
  69. 26
      JiLinApp/config.json

59
EC.Util/CameraSDK/Common/CameraException.cs

@ -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());
}
}

111
EC.Util/CameraSDK/Common/CameraStruct.cs

@ -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);
}
}

58
EC.Util/CameraSDK/Common/ICameraSDK.cs

@ -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
}

245
EC.Util/CameraSDK/HiK/HiKOriSDK.cs

@ -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; /*00
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
}

143
EC.Util/CameraSDK/HiK/HiKSDK.cs

@ -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
}

43
EC.Util/Common/JsonUtil.cs

@ -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("&nbsp;", "")) : JObject.Parse("{}");
}
}

12
EC.Util/Common/SystemUtil.cs

@ -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();
}

45
EC.Util/EC.Util.csproj

@ -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>

60
EC.Util/Port/SerialPortBuilder.cs

@ -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);
}
}

56
EC.Util/Port/SerialPortParam.cs

@ -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;
}
}

166
EC.Util/Port/YcSerialPort.cs

@ -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;//累加发送字节数
}
}

11
EC.Util/Zmq/ZmqUtil.cs

@ -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
}

BIN
EC.Util/libs/hik-win64/HCCore.dll

Binary file not shown.

BIN
EC.Util/libs/hik-win64/HCNetSDK.dll

Binary file not shown.

BIN
EC.Util/libs/hik-win64/HCNetSDKCom/HCCoreDevCfg.dll

Binary file not shown.

BIN
EC.Util/libs/hik-win64/HCNetSDKCom/HCPreview.dll

Binary file not shown.

BIN
EC.Util/libs/hik-win64/libcrypto-1_1-x64.dll

Binary file not shown.

BIN
EC.Util/libs/hik-win64/libssl-1_1-x64.dll

Binary file not shown.

31
JiLinApp.sln

@ -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

20
JiLinApp/App.xaml

@ -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>

79
JiLinApp/App.xaml.cs

@ -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
}

17
JiLinApp/Core/Config.cs

@ -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; }
}

42
JiLinApp/Core/Global.cs

@ -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()
{
}
}

23
JiLinApp/Core/TaskUtil.cs

@ -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);
}
});
}
}

64
JiLinApp/Docking/AlarmMessage.cs

@ -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;
}
}

24
JiLinApp/JiLinApp.csproj

@ -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>

30
JiLinApp/Mvvm/RegionViewModelBase.cs

@ -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)
{
}
}

34
JiLinApp/Mvvm/ViewModelBase.cs

@ -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)
{
}
}

141
JiLinApp/Pages/FenceServerManage/Core/AlarmEncode.cs

@ -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;
}
}

31
JiLinApp/Pages/FenceServerManage/Core/Entity/DeviceStateMessage.cs

@ -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;
}
}

67
JiLinApp/Pages/FenceServerManage/Core/Entity/SectorState.cs

@ -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;
}
}

172
JiLinApp/Pages/FenceServerManage/Core/Entity/UdpAlarmHostDevice.cs

@ -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;
}
}

30
JiLinApp/Pages/FenceServerManage/Core/Entity/UdpAlarmHostMessage.cs

@ -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; }
}

12
JiLinApp/Pages/FenceServerManage/Core/Entity/UdpManagerConfig.cs

@ -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; }
}

71
JiLinApp/Pages/FenceServerManage/Core/Udp.cs

@ -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
{
}
}
}
}

885
JiLinApp/Pages/FenceServerManage/Core/UdpManager.cs

@ -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;
}
}
}

54
JiLinApp/Pages/FenceServerManage/Main.xaml

@ -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>

93
JiLinApp/Pages/FenceServerManage/Main.xaml.cs

@ -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
}

42
JiLinApp/Pages/FenceServerManage/MainViewModel.cs

@ -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
}

17
JiLinApp/Pages/Main/Core/MessageEvent.cs

@ -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>
{
}

5
JiLinApp/Pages/Main/Core/PageNames.cs

@ -0,0 +1,5 @@
namespace JiLinApp.Pages.Main;
public static class PageNames
{
}

6
JiLinApp/Pages/Main/Core/RegionNames.cs

@ -0,0 +1,6 @@
namespace JiLinApp.Pages.Main;
public static class RegionNames
{
public static string ContentRegion { get; } = "ContentRegion";
}

55
JiLinApp/Pages/Main/MainWindow.xaml

@ -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>

47
JiLinApp/Pages/Main/MainWindow.xaml.cs

@ -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");
}
}

242
JiLinApp/Pages/PtzManage/Core/PelcoD.cs

@ -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 };
}
}
}

364
JiLinApp/Pages/PtzManage/Core/PelcoP.cs

@ -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 };
}
}
}

191
JiLinApp/Pages/PtzManage/Core/PtzCmd.cs

@ -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
}

176
JiLinApp/Pages/PtzManage/Main.xaml

@ -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>

315
JiLinApp/Pages/PtzManage/Main.xaml.cs

@ -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
}

78
JiLinApp/Pages/PtzManage/MainViewModel.cs

@ -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
}

525
JiLinApp/Pages/ShakeServerManage/Core/AsyncTcpServer.cs

@ -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
}

51
JiLinApp/Pages/ShakeServerManage/Core/CRC8.cs

@ -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;
}
}

74
JiLinApp/Pages/ShakeServerManage/Core/Entity/ClientMessage.cs

@ -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;
}
}

90
JiLinApp/Pages/ShakeServerManage/Core/Entity/DataMessage.cs

@ -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;
}
}

14
JiLinApp/Pages/ShakeServerManage/Core/Entity/DataRequest.cs

@ -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;
}
}

57
JiLinApp/Pages/ShakeServerManage/Core/Entity/SectionState.cs

@ -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;
}
}

20
JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpAlarmHostMessage.cs

@ -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; }
}

22
JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpAlarmHostTable.cs

@ -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; }
}

10
JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpManagerConfig.cs

@ -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; }
}

23
JiLinApp/Pages/ShakeServerManage/Core/Entity/TcpSectionTable.cs

@ -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; }
}

31
JiLinApp/Pages/ShakeServerManage/Core/TcpClientConnectedEventArgs.cs

@ -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; }
}

31
JiLinApp/Pages/ShakeServerManage/Core/TcpClientDisconnectedEventArgs.cs

@ -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; }
}

48
JiLinApp/Pages/ShakeServerManage/Core/TcpClientState.cs

@ -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();
}
}
}

34
JiLinApp/Pages/ShakeServerManage/Core/TcpDatagramReceivedEventArgs.cs

@ -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; }
}

753
JiLinApp/Pages/ShakeServerManage/Core/TcpManager.cs

@ -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>();
}
}
}

51
JiLinApp/Pages/ShakeServerManage/Main.xaml

@ -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>

90
JiLinApp/Pages/ShakeServerManage/Main.xaml.cs

@ -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
}

41
JiLinApp/Pages/ShakeServerManage/MainViewModel.cs

@ -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
}

26
JiLinApp/config.json

@ -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…
Cancel
Save