From f7714971dd6e03720d05a256c5498969ce7abe96 Mon Sep 17 00:00:00 2001 From: fajiao <1519100073@qq.com> Date: Fri, 7 Apr 2023 14:07:28 +0800 Subject: [PATCH] update frame --- EC.Util/EC.Util.csproj | 1 - EC.Util/Port/SerialPortParam.cs | 2 +- EC.Util/Zmq/ZmqUtil.cs | 2 +- JiLinApp.Biz/JiLinApp.Biz.csproj | 13 + JiLinApp.Biz/Transmit/Entity/AlarmMessage.cs | 33 + .../Transmit/Entity/AlarmMessageHelper.cs | 40 + .../Transmit/Service/AlarmMqttService.cs | 5 + .../Transmit/Service/AlarmZmqService.cs | 5 + .../Service/Interfaces/IAlarmService.cs | 5 + JiLinApp.Docking/Alarm/AlarmCode.cs | 9 + JiLinApp.Docking/Alarm/AlarmCodeHelper.cs | 41 + .../FenceAlarm/Entity/DeviceStateMessage.cs | 25 + .../FenceAlarm/Entity/SectorState.cs | 67 + .../FenceAlarm/Entity/UdpAlarmHostDevice.cs | 170 ++ .../FenceAlarm/Entity/UdpAlarmHostMessage.cs | 30 + .../FenceAlarm/Entity/UdpManagerConfig.cs | 12 + .../FenceAlarm/Service/AlarmEncode.cs | 141 ++ JiLinApp.Docking/FenceAlarm/Service/Udp.cs | 85 + .../FenceAlarm/Service/UdpManager.cs | 838 +++++++ JiLinApp.Docking/JiLinApp.Docking.csproj | 19 + JiLinApp.Docking/Ptz/DCamera.cs | 130 + JiLinApp.Docking/Ptz/PelcoD.cs | 242 ++ JiLinApp.Docking/Ptz/PelcoP.cs | 339 +++ JiLinApp.Docking/Ptz/PtzCmd.cs | 219 ++ .../VibrateAlarm/Entity/ClientMessage.cs | 73 + .../VibrateAlarm/Entity/DataMessage.cs | 89 + .../VibrateAlarm/Entity/DataRequest.cs | 14 + .../VibrateAlarm/Entity/SectionState.cs | 57 + .../Entity/TcpAlarmHostMessage.cs | 20 + .../VibrateAlarm/Entity/TcpAlarmHostTable.cs | 16 + .../VibrateAlarm/Entity/TcpManagerConfig.cs | 10 + .../VibrateAlarm/Entity/TcpSectionTable.cs | 17 + .../VibrateAlarm/Service/AsyncTcpServer.cs | 522 ++++ JiLinApp.Docking/VibrateAlarm/Service/CRC8.cs | 49 + .../Service/TcpClientConnectedEventArgs.cs | 26 + .../Service/TcpClientDisconnectedEventArgs.cs | 26 + .../VibrateAlarm/Service/TcpClientState.cs | 47 + .../Service/TcpDatagramReceivedEventArgs.cs | 29 + .../VibrateAlarm/Service/TcpManager.cs | 685 +++++ JiLinApp.Docking/config/alarmcode.json | 2198 +++++++++++++++++ JiLinApp.sln | 14 +- 41 files changed, 6361 insertions(+), 4 deletions(-) create mode 100644 JiLinApp.Biz/JiLinApp.Biz.csproj create mode 100644 JiLinApp.Biz/Transmit/Entity/AlarmMessage.cs create mode 100644 JiLinApp.Biz/Transmit/Entity/AlarmMessageHelper.cs create mode 100644 JiLinApp.Biz/Transmit/Service/AlarmMqttService.cs create mode 100644 JiLinApp.Biz/Transmit/Service/AlarmZmqService.cs create mode 100644 JiLinApp.Biz/Transmit/Service/Interfaces/IAlarmService.cs create mode 100644 JiLinApp.Docking/Alarm/AlarmCode.cs create mode 100644 JiLinApp.Docking/Alarm/AlarmCodeHelper.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Entity/DeviceStateMessage.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Entity/SectorState.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostDevice.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostMessage.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Entity/UdpManagerConfig.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Service/AlarmEncode.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Service/Udp.cs create mode 100644 JiLinApp.Docking/FenceAlarm/Service/UdpManager.cs create mode 100644 JiLinApp.Docking/JiLinApp.Docking.csproj create mode 100644 JiLinApp.Docking/Ptz/DCamera.cs create mode 100644 JiLinApp.Docking/Ptz/PelcoD.cs create mode 100644 JiLinApp.Docking/Ptz/PelcoP.cs create mode 100644 JiLinApp.Docking/Ptz/PtzCmd.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/ClientMessage.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/DataMessage.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/DataRequest.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/SectionState.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostMessage.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostTable.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/TcpManagerConfig.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Entity/TcpSectionTable.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/AsyncTcpServer.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/CRC8.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/TcpClientConnectedEventArgs.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/TcpClientDisconnectedEventArgs.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/TcpClientState.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/TcpDatagramReceivedEventArgs.cs create mode 100644 JiLinApp.Docking/VibrateAlarm/Service/TcpManager.cs create mode 100644 JiLinApp.Docking/config/alarmcode.json diff --git a/EC.Util/EC.Util.csproj b/EC.Util/EC.Util.csproj index 50886e3..3ab8825 100644 --- a/EC.Util/EC.Util.csproj +++ b/EC.Util/EC.Util.csproj @@ -37,7 +37,6 @@ - diff --git a/EC.Util/Port/SerialPortParam.cs b/EC.Util/Port/SerialPortParam.cs index 8f129f9..0dd221b 100644 --- a/EC.Util/Port/SerialPortParam.cs +++ b/EC.Util/Port/SerialPortParam.cs @@ -5,7 +5,7 @@ /// public class SerialPortParam { - #region fields + #region Fields /// /// 串口名称 diff --git a/EC.Util/Zmq/ZmqUtil.cs b/EC.Util/Zmq/ZmqUtil.cs index 2335201..cbdc72a 100644 --- a/EC.Util/Zmq/ZmqUtil.cs +++ b/EC.Util/Zmq/ZmqUtil.cs @@ -2,7 +2,7 @@ internal class ZmqUtil { - //#region fields + //#region Fields //private SubscriberSocket SubSocket { get; set; } //private PublisherSocket PubSocket { get; set; } diff --git a/JiLinApp.Biz/JiLinApp.Biz.csproj b/JiLinApp.Biz/JiLinApp.Biz.csproj new file mode 100644 index 0000000..982d279 --- /dev/null +++ b/JiLinApp.Biz/JiLinApp.Biz.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/JiLinApp.Biz/Transmit/Entity/AlarmMessage.cs b/JiLinApp.Biz/Transmit/Entity/AlarmMessage.cs new file mode 100644 index 0000000..86802f6 --- /dev/null +++ b/JiLinApp.Biz/Transmit/Entity/AlarmMessage.cs @@ -0,0 +1,33 @@ +namespace JiLinApp.Biz.Transmit; + +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-报警,3-故障,)*/ + public int kind; + /** 现场照片*/ + public string imgUrl; + + public override string ToString() + { + return string.Format("{{ labelCode:{0}, warnType:{1}, warnLevel:{2}, warnContent:{3}, createTime:{4} }}", + labelCode, warnType, warnLevel, warnContent, createTime); + } +} \ No newline at end of file diff --git a/JiLinApp.Biz/Transmit/Entity/AlarmMessageHelper.cs b/JiLinApp.Biz/Transmit/Entity/AlarmMessageHelper.cs new file mode 100644 index 0000000..c05b7b2 --- /dev/null +++ b/JiLinApp.Biz/Transmit/Entity/AlarmMessageHelper.cs @@ -0,0 +1,40 @@ +using JiLinApp.Docking.Alarm; +using JiLinApp.Docking.FenceAlarm; +using JiLinApp.Docking.VibrateAlarm; + +namespace JiLinApp.Biz.Transmit; + +public static class AlarmMessageHelper +{ + public static AlarmMessage ToAlarmMessage(this TcpAlarmHostMessage msg) + { + AlarmCode code = AlarmCodeHelper.Get(msg.AlarmId); + AlarmMessage obj = new() + { + labelCode = Convert.ToString(msg.DeviceID), + warnType = 3, + warnLevel = code.Level, + warnContent = code.Content, + dealStatus = 1, + createTime = Convert.ToDateTime(msg.AlarmTime), + kind = 2, + }; + return obj; + } + + public static AlarmMessage ToAlarmMessage(this UdpAlarmHostMessage msg) + { + AlarmCode code = AlarmCodeHelper.Get(msg.CID); + AlarmMessage obj = new() + { + labelCode = Convert.ToString(msg.DeviceID), + warnType = 4, + warnLevel = code.Level, + warnContent = code.Content, + dealStatus = 1, + createTime = Convert.ToDateTime(msg.AlarmTime), + kind = 2, + }; + return obj; + } +} \ No newline at end of file diff --git a/JiLinApp.Biz/Transmit/Service/AlarmMqttService.cs b/JiLinApp.Biz/Transmit/Service/AlarmMqttService.cs new file mode 100644 index 0000000..4be7bc0 --- /dev/null +++ b/JiLinApp.Biz/Transmit/Service/AlarmMqttService.cs @@ -0,0 +1,5 @@ +using JiLinApp.Biz.Transmit; + +public class AlarmMqttService : IAlarmService +{ +} \ No newline at end of file diff --git a/JiLinApp.Biz/Transmit/Service/AlarmZmqService.cs b/JiLinApp.Biz/Transmit/Service/AlarmZmqService.cs new file mode 100644 index 0000000..cc04baa --- /dev/null +++ b/JiLinApp.Biz/Transmit/Service/AlarmZmqService.cs @@ -0,0 +1,5 @@ +using JiLinApp.Biz.Transmit; + +public class AlarmZmqService : IAlarmService +{ +} \ No newline at end of file diff --git a/JiLinApp.Biz/Transmit/Service/Interfaces/IAlarmService.cs b/JiLinApp.Biz/Transmit/Service/Interfaces/IAlarmService.cs new file mode 100644 index 0000000..582e7d8 --- /dev/null +++ b/JiLinApp.Biz/Transmit/Service/Interfaces/IAlarmService.cs @@ -0,0 +1,5 @@ +namespace JiLinApp.Biz.Transmit; + +public interface IAlarmService +{ +} \ No newline at end of file diff --git a/JiLinApp.Docking/Alarm/AlarmCode.cs b/JiLinApp.Docking/Alarm/AlarmCode.cs new file mode 100644 index 0000000..5f2c4b0 --- /dev/null +++ b/JiLinApp.Docking/Alarm/AlarmCode.cs @@ -0,0 +1,9 @@ +namespace JiLinApp.Docking.Alarm; + +public class AlarmCode +{ + public string Id { get; set; } + public int Level { get; set; } + public string Type { get; set; } + public string Content { get; set; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/Alarm/AlarmCodeHelper.cs b/JiLinApp.Docking/Alarm/AlarmCodeHelper.cs new file mode 100644 index 0000000..37086db --- /dev/null +++ b/JiLinApp.Docking/Alarm/AlarmCodeHelper.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; + +namespace JiLinApp.Docking.Alarm; + +public class AlarmCodeHelper +{ + #region Fields + + private static readonly Dictionary AlarmCodeDict; + private static readonly List LevelList; + private static readonly List TypeList; + + #endregion fields + + static AlarmCodeHelper() + { + using StreamReader r = new(Path.Combine("config", "alarmcode.json")); + string jsonStr = r.ReadToEnd(); + List list = JsonConvert.DeserializeObject>(jsonStr) ?? new(); + AlarmCodeDict = list.ToDictionary(item => item.Id, item => item); + LevelList = list.GroupBy(item => item.Level) + .Select(it => it.First().Level).ToList(); + TypeList = list.GroupBy(item => item.Type) + .Select(it => it.First().Type).ToList(); + } + + public static void Init() + { } + + public static AlarmCode Get(string id) + { + return AlarmCodeDict[id]; + } + + public static bool TryGet(string id, out AlarmCode alarmCode) + { + bool flag = AlarmCodeDict.TryGetValue(id, out AlarmCode? temp); + alarmCode = temp ?? new(); + return flag; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Entity/DeviceStateMessage.cs b/JiLinApp.Docking/FenceAlarm/Entity/DeviceStateMessage.cs new file mode 100644 index 0000000..e522438 --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Entity/DeviceStateMessage.cs @@ -0,0 +1,25 @@ +namespace JiLinApp.Docking.FenceAlarm; + +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) + { + deviceID = id; + StatusTime = time.ToString("yyyy-MM-dd HH:mm:ss"); + channel = Channel; + StatusType = statusType; + } + + public DeviceStateMessage() + { + deviceID = -1; + StatusTime = ""; + channel = -1; + StatusType = -1; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Entity/SectorState.cs b/JiLinApp.Docking/FenceAlarm/Entity/SectorState.cs new file mode 100644 index 0000000..de7d8e5 --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Entity/SectorState.cs @@ -0,0 +1,67 @@ +namespace JiLinApp.Docking.FenceAlarm; + +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; + state = data & 0x0F; + type = data >> 4; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostDevice.cs b/JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostDevice.cs new file mode 100644 index 0000000..fc2ec7f --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostDevice.cs @@ -0,0 +1,170 @@ +namespace JiLinApp.Docking.FenceAlarm; + +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 channelState { get; set; }//分区布防撤防状态,0为撤防,1为布防 + public List channelAlarmState { get; set; }//分区报警状态,0为报警中,1为未报警 + + //-------------------------------防区信息-----------------------------// + public int maxSectorNum { get; set; }//最大防区号 + + public List 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; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostMessage.cs b/JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostMessage.cs new file mode 100644 index 0000000..a987c96 --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Entity/UdpAlarmHostMessage.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json.Linq; + +namespace JiLinApp.Docking.FenceAlarm; + +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; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Entity/UdpManagerConfig.cs b/JiLinApp.Docking/FenceAlarm/Entity/UdpManagerConfig.cs new file mode 100644 index 0000000..0ab414c --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Entity/UdpManagerConfig.cs @@ -0,0 +1,12 @@ +namespace JiLinApp.Docking.FenceAlarm; + +public class UdpManagerConfig +{ + public string ServerIp { get; set; } + + public int ServerPort { get; set; } + + public int DevicePort { get; set; } + + public int DeviceHeartKeep { get; set; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Service/AlarmEncode.cs b/JiLinApp.Docking/FenceAlarm/Service/AlarmEncode.cs new file mode 100644 index 0000000..59e9e49 --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Service/AlarmEncode.cs @@ -0,0 +1,141 @@ +namespace JiLinApp.Docking.FenceAlarm; + +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; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Service/Udp.cs b/JiLinApp.Docking/FenceAlarm/Service/Udp.cs new file mode 100644 index 0000000..d7a5f23 --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Service/Udp.cs @@ -0,0 +1,85 @@ +using System.ComponentModel; +using System.Net; +using System.Net.Sockets; + +namespace JiLinApp.Docking.FenceAlarm; + +public class Udp +{ + private BackgroundWorker back = null; + + /// + /// 用于UDP发送的网络服务类 + /// + private UdpClient udpcSend = null; + + /// + /// 用于UDP接收的网络服务类 + /// + 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() + { + Stop(); + } + + public void Stop() + { + if (back != null) + { + back.CancelAsync(); + back = null; + } + if (udpcRecv != null) + { + udpcRecv.Close(); + udpcRecv = null; + } + if (udpcSend != null) + { + udpcSend.Close(); + udpcSend = null; + } + } + + 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 + { + } + } + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/FenceAlarm/Service/UdpManager.cs b/JiLinApp.Docking/FenceAlarm/Service/UdpManager.cs new file mode 100644 index 0000000..fdc1cde --- /dev/null +++ b/JiLinApp.Docking/FenceAlarm/Service/UdpManager.cs @@ -0,0 +1,838 @@ +using System.Data; +using System.Timers; +using Timer = System.Timers.Timer; + +namespace JiLinApp.Docking.FenceAlarm; + +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 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 getDeviceAll() + { + return deviceList; + } + + public UdpAlarmHostDevice getDevice(int deviceID) + { + foreach (UdpAlarmHostDevice p1 in deviceList) + { + if (p1.deviceID == deviceID) return p1; + } + return null; + } + + public List 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_ReceivePort = Port; + this.udp_sendPort = device_port; + this.keep_alive = keep_alive; + try + { + //启动UDP协议 + myUdp = new Udp(IP, udp_ReceivePort); + myUdp.myUDPReceive += myUDPReceive; + } + catch (Exception ex) + { + myUdp = null; + return false; + } + if (keep_alive > 0) + { + PtzCheckTimer.Enabled = true; + } + return true; + } + + private bool AlarmHostLoginOut() + { + PtzCheckTimer.Enabled = false; + if (myUdp != null) + { + myUdp.myUDPReceive -= myUDPReceive; + myUdp.Stop(); + 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(); + device.channelAlarmState = new List(); + 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]); + + 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"), + }; + + 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(); + } + 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 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; + } + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/JiLinApp.Docking.csproj b/JiLinApp.Docking/JiLinApp.Docking.csproj new file mode 100644 index 0000000..2b31c0d --- /dev/null +++ b/JiLinApp.Docking/JiLinApp.Docking.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + PreserveNewest + + + + diff --git a/JiLinApp.Docking/Ptz/DCamera.cs b/JiLinApp.Docking/Ptz/DCamera.cs new file mode 100644 index 0000000..5a2f8e7 --- /dev/null +++ b/JiLinApp.Docking/Ptz/DCamera.cs @@ -0,0 +1,130 @@ +using System; + +namespace JiLinApp.Docking.Ptz; + +public class DCamera +{ + #region Fields + + #region Data3 + + public static double SpeedMin = 1; + public static double SpeedMax = 60; + + #endregion Data3 + + #endregion fields + + #region BaseMethod + + private static byte[] CommandPara(byte com1, byte com2, int data1, int data2) + { + byte[] b = new byte[11]; + b[0] = 0xA1; + int temp1 = data1; + int temp2 = data2; + b[1] = 0x00; + b[2] = 0x0B; + b[3] = com1; + b[4] = com2; + b[5] = (byte)(data1 >> 8 & 0xFF); + b[6] = (byte)(temp1 & 0xFF); + b[7] = (byte)(data2 >> 8 & 0xFF); + b[8] = (byte)(temp2 & 0xFF); + b[9] = (byte)(b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ^ b[5] ^ b[6] ^ b[7] ^ b[8]); + b[10] = 0xAF; + return b; + } + + private static byte[] SendJoystick(double headSpeed, double pitchSpeed) + { + return CommandPara(0x4D, 0x58, (int)(headSpeed * 100), (int)(pitchSpeed * 100)); + } + + #endregion BaseMethod + + #region PtzMethod + + public static byte[] Left(double headSpeed) + { + double absHs = Math.Abs(headSpeed); + if (absHs < SpeedMin) headSpeed = -SpeedMin; + if (absHs > SpeedMax) headSpeed = -SpeedMax; + return SendJoystick(headSpeed, 0); + } + + public static byte[] Right(double headSpeed) + { + double absHs = Math.Abs(headSpeed); + if (absHs < SpeedMin) headSpeed = SpeedMin; + if (absHs > SpeedMax) headSpeed = SpeedMax; + return SendJoystick(headSpeed, 0); + } + + public static byte[] Up(double pitchSpeed) + { + double absPs = Math.Abs(pitchSpeed); + if (absPs < SpeedMin) pitchSpeed = SpeedMin; + if (absPs > SpeedMax) pitchSpeed = SpeedMax; + return SendJoystick(0, pitchSpeed); + } + + public static byte[] Down(double pitchSpeed) + { + double absPs = Math.Abs(pitchSpeed); + if (absPs < SpeedMin) pitchSpeed = -SpeedMin; + if (absPs > SpeedMax) pitchSpeed = -SpeedMax; + return SendJoystick(0, pitchSpeed); + } + + public static byte[] LeftUp(double headSpeed, double pitchSpeed) + { + double absHs = Math.Abs(headSpeed); + if (absHs < SpeedMin) headSpeed = -SpeedMin; + if (absHs > SpeedMax) headSpeed = -SpeedMax; + double absPs = Math.Abs(pitchSpeed); + if (absPs < SpeedMin) pitchSpeed = SpeedMin; + if (absPs > SpeedMax) pitchSpeed = SpeedMax; + return SendJoystick(headSpeed, pitchSpeed); + } + + public static byte[] LeftDown(double headSpeed, double pitchSpeed) + { + double absHs = Math.Abs(headSpeed); + if (absHs < SpeedMin) headSpeed = -SpeedMin; + if (absHs > SpeedMax) headSpeed = -SpeedMax; + double absPs = Math.Abs(pitchSpeed); + if (absPs < SpeedMin) pitchSpeed = -SpeedMin; + if (absPs > SpeedMax) pitchSpeed = -SpeedMax; + return SendJoystick(headSpeed, pitchSpeed); + } + + public static byte[] RightUp(double headSpeed, double pitchSpeed) + { + double absHs = Math.Abs(headSpeed); + if (absHs < SpeedMin) headSpeed = SpeedMin; + if (absHs > SpeedMax) headSpeed = SpeedMax; + double absPs = Math.Abs(pitchSpeed); + if (absPs < SpeedMin) pitchSpeed = SpeedMin; + if (absPs > SpeedMax) pitchSpeed = SpeedMax; + return SendJoystick(headSpeed, pitchSpeed); + } + + public static byte[] RightDown(double headSpeed, double pitchSpeed) + { + double absHs = Math.Abs(headSpeed); + if (absHs < SpeedMin) headSpeed = SpeedMin; + if (absHs > SpeedMax) headSpeed = SpeedMax; + double absPs = Math.Abs(pitchSpeed); + if (absPs < SpeedMin) pitchSpeed = -SpeedMin; + if (absPs > SpeedMax) pitchSpeed = -SpeedMax; + return SendJoystick(headSpeed, pitchSpeed); + } + + public static byte[] Stop() + { + return SendJoystick(0, 0); + } + + #endregion PtzMethod +} \ No newline at end of file diff --git a/JiLinApp.Docking/Ptz/PelcoD.cs b/JiLinApp.Docking/Ptz/PelcoD.cs new file mode 100644 index 0000000..549358b --- /dev/null +++ b/JiLinApp.Docking/Ptz/PelcoD.cs @@ -0,0 +1,242 @@ +using System; + +namespace JiLinApp.Docking.Ptz; + +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); + } + + /// + /// 上下控制 + /// + /// + /// + /// + /// + + 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[] 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 }; + } + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/Ptz/PelcoP.cs b/JiLinApp.Docking/Ptz/PelcoP.cs new file mode 100644 index 0000000..df7e521 --- /dev/null +++ b/JiLinApp.Docking/Ptz/PelcoP.cs @@ -0,0 +1,339 @@ +using System; + +namespace JiLinApp.Docking.Ptz; + +/// +/// dot.NET Implementation of Pelco P Protocol +/// +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 += 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 = action switch + { + PatternAction.Start => 0x1F, + PatternAction.Stop => 0x21, + PatternAction.Run => 0x23, + _ => 0x23, + }; + 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_tiltMessage = CameraTilt(deviceAddress, tiltAction, tiltSpeed); + byte[] m_panMessage = CameraPan(deviceAddress, panAction, panSpeed); + byte[] 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 }; + } + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/Ptz/PtzCmd.cs b/JiLinApp.Docking/Ptz/PtzCmd.cs new file mode 100644 index 0000000..5962239 --- /dev/null +++ b/JiLinApp.Docking/Ptz/PtzCmd.cs @@ -0,0 +1,219 @@ +using EC.Util.CameraSDK; +using System; + +namespace JiLinApp.Docking.Ptz; + +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.LeftTop, + "TopRight" => PtzCmdType.RightTop, + "DownLeft" => PtzCmdType.LeftDown, + "DownRight" => PtzCmdType.RightDown, + "Stop" => PtzCmdType.Stop, + "AutoStart" => PtzCmdType.AutoStart, + "AutoStop" => PtzCmdType.AutoStop, + "PresetSet" => PtzCmdType.PresetSet, + "PresetClear" => PtzCmdType.PresetClear, + "PresetGoto" => PtzCmdType.PresetGoto, + _ => PtzCmdType.None + }; + } + + /// + /// GetPelcoDCmd + /// GetPelcoPCmd + /// DCamearCmd + /// + /// + /// + /// + /// + public static byte[] GetCmd(PtzControlType ctrlType, PtzCmdType cmdType, object[] args = null) + { + byte[] cmd = ctrlType switch + { + PtzControlType.PelcoD => GetPelcoDCmd(cmdType, args), + PtzControlType.PelcoP => GetPelcoPCmd(cmdType, args), + PtzControlType.DCamera => GetDCameraCmd(cmdType, args), + _ => Array.Empty(), + }; + return cmd; + } + + public static byte[] GetPelcoDCmd(PtzCmdType cmdType, object[] args) + { + uint addr = (byte)args[0]; + uint panSpeed = 0x2f; + uint tiltSpeed = (uint)(PelcoD.TiltSpeedMax + PelcoD.TiltSpeedMin) / 2; + byte[] cmd = cmdType switch + { + PtzCmdType.Left => PelcoD.CameraPan(addr, PelcoD.Pan.Left, panSpeed), + PtzCmdType.Right => PelcoD.CameraPan(addr, PelcoD.Pan.Right, panSpeed), + PtzCmdType.Top => PelcoD.CameraTilt(addr, PelcoD.Tilt.Up, tiltSpeed), + PtzCmdType.Down => PelcoD.CameraTilt(addr, PelcoD.Tilt.Down, tiltSpeed), + PtzCmdType.LeftTop => PelcoD.CameraPan(addr, PelcoD.Pan.LeftUp, panSpeed), + PtzCmdType.LeftDown => PelcoD.CameraPan(addr, PelcoD.Pan.LeftDown, panSpeed), + PtzCmdType.RightTop => PelcoD.CameraPan(addr, PelcoD.Pan.RightUp, panSpeed), + PtzCmdType.RightDown => 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, (byte)args[1]), + _ => Array.Empty(), + }; + return cmd; + } + + public static byte[] GetPelcoPCmd(PtzCmdType cmdType, object[] args) + { + uint addr = (byte)args[0]; + uint panSpeed = (uint)(PelcoP.PanSpeedMax + PelcoP.PanSpeedMin) / 2; + uint tiltSpeed = (uint)(PelcoP.TiltSpeedMax + PelcoP.TiltSpeedMin) / 2; + byte[] cmd = cmdType switch + { + PtzCmdType.Left => PelcoP.CameraPan(addr, PelcoP.Pan.Left, panSpeed), + PtzCmdType.Right => PelcoP.CameraPan(addr, PelcoP.Pan.Right, panSpeed), + PtzCmdType.Top => PelcoP.CameraTilt(addr, PelcoP.Tilt.Up, tiltSpeed), + PtzCmdType.Down => PelcoP.CameraTilt(addr, PelcoP.Tilt.Down, tiltSpeed), + PtzCmdType.LeftTop => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Left, panSpeed, PelcoP.Tilt.Up, tiltSpeed), + PtzCmdType.LeftDown => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Left, panSpeed, PelcoP.Tilt.Down, tiltSpeed), + PtzCmdType.RightTop => PelcoP.CameraPanTilt(addr, PelcoP.Pan.Right, panSpeed, PelcoP.Tilt.Up, tiltSpeed), + PtzCmdType.RightDown => 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, (byte)args[1]), + _ => Array.Empty(), + }; + return cmd; + } + + public static byte[] GetDCameraCmd(PtzCmdType cmdType, object[] args) + { + double speed = (DCamera.SpeedMax + DCamera.SpeedMin) / 2; + byte[] cmd = cmdType switch + { + PtzCmdType.Left => DCamera.Left(speed), + PtzCmdType.Right => DCamera.Right(speed), + PtzCmdType.Top => DCamera.Up(speed), + PtzCmdType.Down => DCamera.Down(speed), + PtzCmdType.LeftTop => DCamera.LeftUp(speed, speed), + PtzCmdType.LeftDown => DCamera.LeftDown(speed, speed), + PtzCmdType.RightTop => DCamera.RightUp(speed, speed), + PtzCmdType.RightDown => DCamera.RightDown(speed, speed), + PtzCmdType.Stop => DCamera.Stop(), + //PtzCmdType.PresetGoto => DCamera.Up(speed), + _ => Array.Empty(), + }; + 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.Left: + arr[0] = HiKOriSDK.PAN_LEFT; + sdk.PtzMove(arr); + break; + + case PtzCmdType.Right: + arr[0] = HiKOriSDK.PAN_RIGHT; + sdk.PtzMove(arr); + break; + + 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.LeftTop: + arr[0] = HiKOriSDK.UP_LEFT; + sdk.PtzMove(arr); + break; + + case PtzCmdType.LeftDown: + arr[0] = HiKOriSDK.DOWN_LEFT; + sdk.PtzMove(arr); + break; + + case PtzCmdType.RightTop: + arr[0] = HiKOriSDK.UP_RIGHT; + sdk.PtzMove(arr); + break; + + case PtzCmdType.RightDown: + 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, + DCamera, + HikSdk, + None, +} + +public enum PtzCmdType +{ + Top, + Down, + Left, + Right, + LeftTop, + LeftDown, + RightTop, + RightDown, + Stop, + AutoStart, + AutoStop, + PresetSet, + PresetClear, + PresetGoto, + None +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/ClientMessage.cs b/JiLinApp.Docking/VibrateAlarm/Entity/ClientMessage.cs new file mode 100644 index 0000000..5b2ecec --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/ClientMessage.cs @@ -0,0 +1,73 @@ +using System.Collections; +using System.Net.Sockets; + +namespace JiLinApp.Docking.VibrateAlarm; + +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 list { get; set; } + + public Hashtable sectioTable { get; set; } + + public ClientMessage() + { + list = new List(); + host = null; + sectioTable = new Hashtable(); + } + + public List getMessageList() + { + List msglist = new List(); + 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; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/DataMessage.cs b/JiLinApp.Docking/VibrateAlarm/Entity/DataMessage.cs new file mode 100644 index 0000000..7b6aa84 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/DataMessage.cs @@ -0,0 +1,89 @@ +using System.Text; + +namespace JiLinApp.Docking.VibrateAlarm; + +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; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/DataRequest.cs b/JiLinApp.Docking/VibrateAlarm/Entity/DataRequest.cs new file mode 100644 index 0000000..d3e39e3 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/DataRequest.cs @@ -0,0 +1,14 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +public class DataRequest +{ + public DataMessage request { get; set; } + + public DataMessage responce { get; set; } + + public DataRequest() + { + responce = null; + request = null; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/SectionState.cs b/JiLinApp.Docking/VibrateAlarm/Entity/SectionState.cs new file mode 100644 index 0000000..0b6339e --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/SectionState.cs @@ -0,0 +1,57 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +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; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostMessage.cs b/JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostMessage.cs new file mode 100644 index 0000000..4a92739 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostMessage.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json.Linq; + +namespace JiLinApp.Docking.VibrateAlarm; + +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; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostTable.cs b/JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostTable.cs new file mode 100644 index 0000000..2a40f91 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/TcpAlarmHostTable.cs @@ -0,0 +1,16 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +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; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/TcpManagerConfig.cs b/JiLinApp.Docking/VibrateAlarm/Entity/TcpManagerConfig.cs new file mode 100644 index 0000000..6d3ce78 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/TcpManagerConfig.cs @@ -0,0 +1,10 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +public class TcpManagerConfig +{ + public string ServerIp { get; set; } + + public int ServerPort { get; set; } + + public int DeviceHeartKeep { get; set; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Entity/TcpSectionTable.cs b/JiLinApp.Docking/VibrateAlarm/Entity/TcpSectionTable.cs new file mode 100644 index 0000000..42b4ff2 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Entity/TcpSectionTable.cs @@ -0,0 +1,17 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +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; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/AsyncTcpServer.cs b/JiLinApp.Docking/VibrateAlarm/Service/AsyncTcpServer.cs new file mode 100644 index 0000000..7eb9fba --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/AsyncTcpServer.cs @@ -0,0 +1,522 @@ +using System.Collections.Concurrent; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Text; + +namespace JiLinApp.Docking.VibrateAlarm; + +public class AsyncTcpServer : IDisposable +{ + #region Fields + + private TcpListener _listener; + private ConcurrentDictionary _clients; + private bool _disposed = false; + + #endregion Fields + + #region Ctors + + private byte[] inOptionValues; + + /// + /// 异步TCP服务器 + /// + /// 监听的端口 + 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); + } + + /// + /// 异步TCP服务器 + /// + /// 监听的终结点 + 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); + } + + /// + /// 异步TCP服务器 + /// + /// 监听的IP地址 + /// 监听的端口 + 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(); + + _listener = new TcpListener(Address, Port); + _listener.AllowNatTraversal(true); + } + + #endregion Ctors + + #region Properties + + /// + /// 服务器是否正在运行 + /// + public bool IsRunning { get; private set; } + + /// + /// 监听的IP地址 + /// + public IPAddress Address { get; private set; } + + /// + /// 监听的端口 + /// + public int Port { get; private set; } + + /// + /// 通信使用的编码 + /// + public Encoding Encoding { get; set; } + + #endregion Properties + + #region Server + + /// + /// 启动服务器 + /// + /// 异步TCP服务器 + public AsyncTcpServer Start() + { + return Start(30); + } + + /// + /// 启动服务器 + /// + /// 服务器所允许的挂起连接序列的最大长度 + /// 异步TCP服务器 + public AsyncTcpServer Start(int backlog) + { + if (IsRunning) return this; + + IsRunning = true; + _listener.Start(backlog); + ContinueAcceptTcpClient(_listener); + + return this; + } + + /// + /// 停止服务器 + /// + /// 异步TCP服务器 + 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 + + /// + /// 接收到数据报文事件 + /// + public event EventHandler> DatagramReceived; + + private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) + { + if (DatagramReceived != null) + { + DatagramReceived(this, new TcpDatagramReceivedEventArgs(sender, datagram)); + } + } + + /// + /// 与客户端的连接已建立事件 + /// + public event EventHandler ClientConnected; + + /// + /// 与客户端的连接已断开事件 + /// + public event EventHandler 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."); + } + + /// + /// 发送报文至指定的客户端 + /// + /// 客户端 + /// 报文 + 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); + } + } + + /// + /// 发送报文至指定的客户端 + /// + /// 客户端 + /// 报文 + public void Send(TcpClient tcpClient, string datagram) + { + Send(tcpClient, Encoding.GetBytes(datagram)); + } + + /// + /// 发送报文至所有客户端 + /// + /// 报文 + public void SendToAll(byte[] datagram) + { + GuardRunning(); + + foreach (var client in _clients.Values) + { + Send(client.TcpClient, datagram); + } + } + + public ICollection GetAllClient() + { + return _clients.Values; + } + + /// + /// 发送报文至所有客户端 + /// + /// 报文 + 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); + } + } + + /// + /// 发送报文至指定的客户端 + /// + /// 客户端 + /// 报文 + 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); + } + } + + /// + /// 发送报文至指定的客户端 + /// + /// 客户端 + /// 报文 + public void SyncSend(TcpClient tcpClient, string datagram) + { + SyncSend(tcpClient, Encoding.GetBytes(datagram)); + } + + /// + /// 发送报文至所有客户端 + /// + /// 报文 + public void SyncSendToAll(byte[] datagram) + { + GuardRunning(); + + foreach (var client in _clients.Values) + { + SyncSend(client.TcpClient, datagram); + } + } + + /// + /// 发送报文至所有客户端 + /// + /// 报文 + public void SyncSendToAll(string datagram) + { + GuardRunning(); + + SyncSendToAll(Encoding.GetBytes(datagram)); + } + + #endregion Send + + #region IDisposable Members + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; + /// false to release only unmanaged resources. + 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 +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/CRC8.cs b/JiLinApp.Docking/VibrateAlarm/Service/CRC8.cs new file mode 100644 index 0000000..55fb289 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/CRC8.cs @@ -0,0 +1,49 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +public class CRC8 +{ + /// + /// CRC8位校验表 + /// + 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; + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/TcpClientConnectedEventArgs.cs b/JiLinApp.Docking/VibrateAlarm/Service/TcpClientConnectedEventArgs.cs new file mode 100644 index 0000000..5445a6e --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/TcpClientConnectedEventArgs.cs @@ -0,0 +1,26 @@ +using System.Net.Sockets; + +namespace JiLinApp.Docking.VibrateAlarm; + +/// +/// 与客户端的连接已建立事件参数 +/// +public class TcpClientConnectedEventArgs : EventArgs +{ + /// + /// 与客户端的连接已建立事件参数 + /// + /// 客户端 + public TcpClientConnectedEventArgs(TcpClient tcpClient) + { + if (tcpClient == null) + throw new ArgumentNullException("tcpClient"); + + TcpClient = tcpClient; + } + + /// + /// 客户端 + /// + public TcpClient TcpClient { get; private set; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/TcpClientDisconnectedEventArgs.cs b/JiLinApp.Docking/VibrateAlarm/Service/TcpClientDisconnectedEventArgs.cs new file mode 100644 index 0000000..25f96e4 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/TcpClientDisconnectedEventArgs.cs @@ -0,0 +1,26 @@ +using System.Net.Sockets; + +namespace JiLinApp.Docking.VibrateAlarm; + +/// +/// 与客户端的连接已断开事件参数 +/// +public class TcpClientDisconnectedEventArgs : EventArgs +{ + /// + /// 与客户端的连接已断开事件参数 + /// + /// 客户端 + public TcpClientDisconnectedEventArgs(TcpClient tcpClient) + { + if (tcpClient == null) + throw new ArgumentNullException("tcpClient"); + + TcpClient = tcpClient; + } + + /// + /// 客户端 + /// + public TcpClient TcpClient { get; private set; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/TcpClientState.cs b/JiLinApp.Docking/VibrateAlarm/Service/TcpClientState.cs new file mode 100644 index 0000000..b9b5fe7 --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/TcpClientState.cs @@ -0,0 +1,47 @@ +using System.Net.Sockets; + +namespace JiLinApp.Docking.VibrateAlarm; + +public class TcpClientState +{ + /// + /// Constructor for a new Client + /// + /// The TCP client + /// The byte array buffer + 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; + } + + /// + /// Gets the TCP Client + /// + public TcpClient TcpClient { get; private set; } + + /// + /// Gets the Buffer. + /// + public byte[] Buffer { get; private set; } + + /// + /// TCP接收到但未处理的数据 + /// + public string temp { get; set; } + + /// + /// Gets the network stream + /// + public NetworkStream NetworkStream + { + get + { + return TcpClient.GetStream(); + } + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/TcpDatagramReceivedEventArgs.cs b/JiLinApp.Docking/VibrateAlarm/Service/TcpDatagramReceivedEventArgs.cs new file mode 100644 index 0000000..c2ef7bd --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/TcpDatagramReceivedEventArgs.cs @@ -0,0 +1,29 @@ +namespace JiLinApp.Docking.VibrateAlarm; + +/// +/// 接收到数据报文事件参数 +/// +/// 报文类型 +public class TcpDatagramReceivedEventArgs : EventArgs +{ + /// + /// 接收到数据报文事件参数 + /// + /// 客户端 + /// 报文 + public TcpDatagramReceivedEventArgs(TcpClientState tcpClient, T datagram) + { + TcpClient = tcpClient; + Datagram = datagram; + } + + /// + /// 客户端 + /// + public TcpClientState TcpClient { get; private set; } + + /// + /// 报文 + /// + public T Datagram { get; private set; } +} \ No newline at end of file diff --git a/JiLinApp.Docking/VibrateAlarm/Service/TcpManager.cs b/JiLinApp.Docking/VibrateAlarm/Service/TcpManager.cs new file mode 100644 index 0000000..3a82d9e --- /dev/null +++ b/JiLinApp.Docking/VibrateAlarm/Service/TcpManager.cs @@ -0,0 +1,685 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using Timer = System.Timers.Timer; + +namespace JiLinApp.Docking.VibrateAlarm; + +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 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 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", 5080); + + 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 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(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(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; + 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() + }; + ProcessAlarmDB(alarm); + } + + //处理报警事件 + private void ProcessAlarmDB(TcpAlarmHostMessage msg) + { + if (OnTcpSectionAlarmOn != null) OnTcpSectionAlarmOn(msg); + } + + 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 reqlist = new List(); + 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 SetDeviceCheck(int deviceId, ref string error) + { + List list = new List(); + //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 SetAllCheck(ref string error) + { + List list = new List(); + //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(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 getOnlineState(int deviceId) + { + ClientMessage msg = GetClientMessageDeviceID(deviceId); + if (msg != null) + { + return msg.sectioTable.Values as List; + } + else + { + return new List(); + } + } +} \ No newline at end of file diff --git a/JiLinApp.Docking/config/alarmcode.json b/JiLinApp.Docking/config/alarmcode.json new file mode 100644 index 0000000..9e6b6a2 --- /dev/null +++ b/JiLinApp.Docking/config/alarmcode.json @@ -0,0 +1,2198 @@ +[ + { + "Id": "1000", + "Level": "0", + "Type": "错误", + "Content": "接收到未定义的代码" + }, + { + "Id": "1100", + "Level": "1", + "Type": "紧急", + "Content": "个人救护报警" + }, + { + "Id": "1101", + "Level": "1", + "Type": "紧急", + "Content": "个人救护报警,紧急按钮" + }, + { + "Id": "1102", + "Level": "1", + "Type": "紧急", + "Content": "报到失败" + }, + { + "Id": "1103", + "Level": "1", + "Type": "紧急", + "Content": "紧急报警" + }, + { + "Id": "1104", + "Level": "1", + "Type": "紧急", + "Content": "紧急报警" + }, + { + "Id": "1110", + "Level": "1", + "Type": "火警", + "Content": "火警报警" + }, + { + "Id": "1111", + "Level": "1", + "Type": "火警", + "Content": "烟感探头" + }, + { + "Id": "1112", + "Level": "1", + "Type": "火警", + "Content": "燃烧" + }, + { + "Id": "1113", + "Level": "1", + "Type": "火警", + "Content": "消防水流" + }, + { + "Id": "1114", + "Level": "1", + "Type": "火警", + "Content": "热感探头" + }, + { + "Id": "1115", + "Level": "1", + "Type": "火警", + "Content": "火警手动报警" + }, + { + "Id": "1117", + "Level": "1", + "Type": "火警", + "Content": "火焰探头" + }, + { + "Id": "1118", + "Level": "1", + "Type": "火警", + "Content": "接近警报" + }, + { + "Id": "1119", + "Level": "1", + "Type": "火警", + "Content": "煤气泄漏" + }, + { + "Id": "1120", + "Level": "1", + "Type": "劫盗", + "Content": "劫盗" + }, + { + "Id": "1121", + "Level": "1", + "Type": "劫盗", + "Content": "挟持" + }, + { + "Id": "1122", + "Level": "1", + "Type": "劫盗", + "Content": "无声劫盗" + }, + { + "Id": "1123", + "Level": "1", + "Type": "劫盗", + "Content": "有声劫盗" + }, + { + "Id": "1124", + "Level": "1", + "Type": "窃盗", + "Content": "异地劫持" + }, + { + "Id": "1130", + "Level": "1", + "Type": "窃盗", + "Content": "窃盗" + }, + { + "Id": "1131", + "Level": "1", + "Type": "窃盗", + "Content": "周界窃盗" + }, + { + "Id": "1132", + "Level": "1", + "Type": "窃盗", + "Content": "内部窃盗" + }, + { + "Id": "1133", + "Level": "1", + "Type": "窃盗", + "Content": "24小时窃盗" + }, + { + "Id": "1134", + "Level": "1", + "Type": "窃盗", + "Content": "出/入窃盗" + }, + { + "Id": "1135", + "Level": "1", + "Type": "窃盗", + "Content": "日/夜防区" + }, + { + "Id": "1136", + "Level": "1", + "Type": "窃盗", + "Content": "室外窃盗" + }, + { + "Id": "1137", + "Level": "1", + "Type": "窃盗", + "Content": "拆动报警" + }, + { + "Id": "1138", + "Level": "1", + "Type": "窃盗", + "Content": "接近报警" + }, + { + "Id": "1140", + "Level": "1", + "Type": "警报", + "Content": "一般报警" + }, + { + "Id": "1141", + "Level": "1", + "Type": "警报", + "Content": "总线开路" + }, + { + "Id": "1142", + "Level": "1", + "Type": "警报", + "Content": "总线短路" + }, + { + "Id": "1143", + "Level": "1", + "Type": "警报", + "Content": "扩充器故障" + }, + { + "Id": "1144", + "Level": "1", + "Type": "警报", + "Content": "探头被拆动" + }, + { + "Id": "1145", + "Level": "1", + "Type": "警报", + "Content": "扩充器被拆" + }, + { + "Id": "1150", + "Level": "1", + "Type": "警报", + "Content": "24小时非盗窃报警" + }, + { + "Id": "1156", + "Level": "1", + "Type": "警报", + "Content": "日间防区" + }, + { + "Id": "1158", + "Level": "1", + "Type": "警报", + "Content": "温度过高" + }, + { + "Id": "1159", + "Level": "1", + "Type": "警报", + "Content": "温度过低" + }, + { + "Id": "1161", + "Level": "1", + "Type": "周界窃盗", + "Content": "攀爬报警" + }, + { + "Id": "1170", + "Level": "1", + "Type": "故障", + "Content": "用户离线" + }, + { + "Id": "1180", + "Level": "1", + "Type": "故障", + "Content": "GPRS设备断线" + }, + { + "Id": "1181", + "Level": "1", + "Type": "周界窃盗", + "Content": "张力围栏报警" + }, + { + "Id": "1190", + "Level": "1", + "Type": "周界窃盗", + "Content": "脉冲围栏断路报警" + }, + { + "Id": "1191", + "Level": "1", + "Type": "周界窃盗", + "Content": "脉冲围栏短路报警" + }, + { + "Id": "1192", + "Level": "1", + "Type": "周界窃盗", + "Content": "振动光纤断光" + }, + { + "Id": "1193", + "Level": "1", + "Type": "周界窃盗", + "Content": "振动光纤触网" + }, + { + "Id": "1200", + "Level": "2", + "Type": "监控", + "Content": "火警监视" + }, + { + "Id": "1201", + "Level": "2", + "Type": "监控", + "Content": "水压过低" + }, + { + "Id": "1202", + "Level": "2", + "Type": "监控", + "Content": "二氧化碳过低" + }, + { + "Id": "1203", + "Level": "2", + "Type": "监控", + "Content": "阀门感应" + }, + { + "Id": "1300", + "Level": "3", + "Type": "故障", + "Content": "系统故障" + }, + { + "Id": "1301", + "Level": "3", + "Type": "故障", + "Content": "无交流" + }, + { + "Id": "1302", + "Level": "3", + "Type": "故障", + "Content": "电池低压" + }, + { + "Id": "1303", + "Level": "3", + "Type": "故障", + "Content": "RAM校验和故障" + }, + { + "Id": "1304", + "Level": "3", + "Type": "故障", + "Content": "ROM校验和故障" + }, + { + "Id": "1305", + "Level": "3", + "Type": "故障", + "Content": "系统重新设定" + }, + { + "Id": "1306", + "Level": "3", + "Type": "故障", + "Content": "编程改动" + }, + { + "Id": "1307", + "Level": "3", + "Type": "故障", + "Content": "自检故障" + }, + { + "Id": "1308", + "Level": "3", + "Type": "故障", + "Content": "主机停机使用" + }, + { + "Id": "1309", + "Level": "3", + "Type": "故障", + "Content": "电池测试故障" + }, + { + "Id": "130A", + "Level": "3", + "Type": "故障", + "Content": "系统复位" + }, + { + "Id": "1310", + "Level": "3", + "Type": "故障", + "Content": "接地故障" + }, + { + "Id": "1320", + "Level": "3", + "Type": "故障", + "Content": "警号/继电器" + }, + { + "Id": "1321", + "Level": "3", + "Type": "故障", + "Content": "警铃#1" + }, + { + "Id": "1322", + "Level": "3", + "Type": "故障", + "Content": "警铃#2" + }, + { + "Id": "1323", + "Level": "3", + "Type": "故障", + "Content": "警报继电器" + }, + { + "Id": "1324", + "Level": "3", + "Type": "故障", + "Content": "故障继电器" + }, + { + "Id": "1325", + "Level": "3", + "Type": "故障", + "Content": "逆转继电器" + }, + { + "Id": "132A", + "Level": "3", + "Type": "故障", + "Content": "警铃保险管烧坏" + }, + { + "Id": "1330", + "Level": "3", + "Type": "故障", + "Content": "系统周边" + }, + { + "Id": "1331", + "Level": "3", + "Type": "故障", + "Content": "总线开路" + }, + { + "Id": "1332", + "Level": "3", + "Type": "故障", + "Content": "总线短路" + }, + { + "Id": "1333", + "Level": "3", + "Type": "故障", + "Content": "防区掉线" + }, + { + "Id": "1334", + "Level": "3", + "Type": "故障", + "Content": "单元控制器掉线楼道机" + }, + { + "Id": "1335", + "Level": "3", + "Type": "故障", + "Content": "打印机无纸" + }, + { + "Id": "1339", + "Level": "3", + "Type": "故障", + "Content": "振动光纤断光" + }, + { + "Id": "1340", + "Level": "3", + "Type": "故障", + "Content": "网络设备离线" + }, + { + "Id": "1336", + "Level": "3", + "Type": "故障", + "Content": "打印机故障" + }, + { + "Id": "1350", + "Level": "3", + "Type": "故障", + "Content": "通讯故障" + }, + { + "Id": "1351", + "Level": "3", + "Type": "故障", + "Content": "电话线1故障" + }, + { + "Id": "1352", + "Level": "3", + "Type": "故障", + "Content": "电话线2故障" + }, + { + "Id": "1353", + "Level": "3", + "Type": "故障", + "Content": "长距离无线发射器故障" + }, + { + "Id": "1354", + "Level": "3", + "Type": "故障", + "Content": "通讯失败" + }, + { + "Id": "1355", + "Level": "3", + "Type": "故障", + "Content": "失去长距无线监控" + }, + { + "Id": "1356", + "Level": "3", + "Type": "故障", + "Content": "失去长距无线中央监控" + }, + { + "Id": "1357", + "Level": "3", + "Type": "故障", + "Content": "无线干扰" + }, + { + "Id": "1360", + "Level": "3", + "Type": "故障", + "Content": "防区故障" + }, + { + "Id": "1361", + "Level": "3", + "Type": "故障", + "Content": "防拆故障" + }, + { + "Id": "1362", + "Level": "3", + "Type": "故障", + "Content": "充电故障" + }, + { + "Id": "1363", + "Level": "3", + "Type": "故障", + "Content": "模块未准备就绪" + }, + { + "Id": "1370", + "Level": "3", + "Type": "故障", + "Content": "保护回路" + }, + { + "Id": "1371", + "Level": "3", + "Type": "故障", + "Content": "保护回路开路" + }, + { + "Id": "1372", + "Level": "3", + "Type": "故障", + "Content": "保护回路短路" + }, + { + "Id": "1373", + "Level": "3", + "Type": "故障", + "Content": "火警回路故障" + }, + { + "Id": "137A", + "Level": "3", + "Type": "故障", + "Content": "回路故障" + }, + { + "Id": "1380", + "Level": "3", + "Type": "故障", + "Content": "感应器故障" + }, + { + "Id": "1381", + "Level": "3", + "Type": "故障", + "Content": "无线监控故障" + }, + { + "Id": "1382", + "Level": "3", + "Type": "故障", + "Content": "总线监控故障" + }, + { + "Id": "1383", + "Level": "3", + "Type": "故障", + "Content": "感应器被拆" + }, + { + "Id": "1384", + "Level": "3", + "Type": "故障", + "Content": "无线感应器电池过低" + }, + { + "Id": "1393", + "Level": "3", + "Type": "故障", + "Content": "电话故障" + }, + { + "Id": "1394", + "Level": "3", + "Type": "故障", + "Content": "卡故障" + }, + { + "Id": "13A0", + "Level": "3", + "Type": "故障", + "Content": "请求服务" + }, + { + "Id": "13A1", + "Level": "3", + "Type": "故障", + "Content": "时间重设" + }, + { + "Id": "13A2", + "Level": "3", + "Type": "故障", + "Content": "5(12)伏电源故障" + }, + { + "Id": "13A3", + "Level": "3", + "Type": "故障", + "Content": "电话线故障" + }, + { + "Id": "13A4", + "Level": "3", + "Type": "故障", + "Content": "卡故障" + }, + { + "Id": "13A5", + "Level": "3", + "Type": "故障", + "Content": "失去电池" + }, + { + "Id": "13A6", + "Level": "3", + "Type": "故障", + "Content": "进入编程模式" + }, + { + "Id": "13A7", + "Level": "3", + "Type": "故障", + "Content": "未知故障" + }, + { + "Id": "13A8", + "Level": "3", + "Type": "故障", + "Content": "无效报告" + }, + { + "Id": "13B0", + "Level": "3", + "Type": "故障", + "Content": "用户密码更改" + }, + { + "Id": "13B1", + "Level": "3", + "Type": "故障", + "Content": "错误信息" + }, + { + "Id": "1400", + "Level": "4", + "Type": "撤防", + "Content": "撤防" + }, + { + "Id": "1401", + "Level": "4", + "Type": "撤防", + "Content": "用户撤防" + }, + { + "Id": "1402", + "Level": "4", + "Type": "撤防", + "Content": "集体撤防" + }, + { + "Id": "1403", + "Level": "4", + "Type": "撤防", + "Content": "自动撤防" + }, + { + "Id": "1404", + "Level": "4", + "Type": "撤防", + "Content": "过迟撤防" + }, + { + "Id": "1405", + "Level": "4", + "Type": "撤防", + "Content": "不适用" + }, + { + "Id": "1406", + "Level": "4", + "Type": "撤防", + "Content": "取消" + }, + { + "Id": "1407", + "Level": "4", + "Type": "撤防", + "Content": "遥控撤防" + }, + { + "Id": "1408", + "Level": "4", + "Type": "撤防", + "Content": "快速撤防" + }, + { + "Id": "1409", + "Level": "4", + "Type": "撤防", + "Content": "开关撤防" + }, + { + "Id": "140A", + "Level": "4", + "Type": "撤防", + "Content": "部分撤防" + }, + { + "Id": "140B", + "Level": "4", + "Type": "撤防", + "Content": "周边撤防" + }, + { + "Id": "1411", + "Level": "4", + "Type": "遥控", + "Content": "要求回电" + }, + { + "Id": "1412", + "Level": "4", + "Type": "遥控", + "Content": "遥控编程成功" + }, + { + "Id": "1413", + "Level": "4", + "Type": "遥控", + "Content": "遥控不成功" + }, + { + "Id": "1414", + "Level": "4", + "Type": "遥控", + "Content": "关闭系统" + }, + { + "Id": "1415", + "Level": "4", + "Type": "遥控", + "Content": "关闭通讯" + }, + { + "Id": "1416", + "Level": "4", + "Type": "撤防", + "Content": "撤防操作" + }, + { + "Id": "1417", + "Level": "4", + "Type": "撤防", + "Content": "防区撤防" + }, + { + "Id": "1421", + "Level": "4", + "Type": "出入", + "Content": "拒绝出入-用户" + }, + { + "Id": "1422", + "Level": "4", + "Type": "出入", + "Content": "成功出入-用户" + }, + { + "Id": "1441", + "Level": "4", + "Type": "出入", + "Content": "在家布防" + }, + { + "Id": "1450", + "Level": "4", + "Type": "出入", + "Content": "非正常时段撤防" + }, + { + "Id": "1451", + "Level": "4", + "Type": "出入", + "Content": "过早撤防" + }, + { + "Id": "1452", + "Level": "4", + "Type": "出入", + "Content": "过迟撤防" + }, + { + "Id": "1453", + "Level": "4", + "Type": "出入", + "Content": "撤防失败" + }, + { + "Id": "1454", + "Level": "4", + "Type": "出入", + "Content": "布防失败" + }, + { + "Id": "1455", + "Level": "4", + "Type": "出入", + "Content": "自动布防失败" + }, + { + "Id": "1456", + "Level": "4", + "Type": "出入", + "Content": "部分布防" + }, + { + "Id": "1457", + "Level": "4", + "Type": "出入", + "Content": "外出错误" + }, + { + "Id": "1458", + "Level": "4", + "Type": "出入", + "Content": "操作员在现场" + }, + { + "Id": "1459", + "Level": "4", + "Type": "出入", + "Content": "最近布防" + }, + { + "Id": "1480", + "Level": "4", + "Type": "出入", + "Content": "关警号" + }, + { + "Id": "1520", + "Level": "5", + "Type": "停用", + "Content": "停用警号/继电器" + }, + { + "Id": "1521", + "Level": "5", + "Type": "停用", + "Content": "警铃1停用" + }, + { + "Id": "1522", + "Level": "5", + "Type": "停用", + "Content": "警铃2停用" + }, + { + "Id": "1523", + "Level": "5", + "Type": "停用", + "Content": "停用警报继电器" + }, + { + "Id": "1524", + "Level": "5", + "Type": "停用", + "Content": "停用故障继电器" + }, + { + "Id": "1525", + "Level": "5", + "Type": "停用", + "Content": "逆反继电器" + }, + { + "Id": "1530", + "Level": "5", + "Type": "停用", + "Content": "停用系统周边" + }, + { + "Id": "1540", + "Level": "5", + "Type": "停用", + "Content": "停用系统周边" + }, + { + "Id": "1551", + "Level": "5", + "Type": "停用", + "Content": "通讯器停用" + }, + { + "Id": "1552", + "Level": "5", + "Type": "停用", + "Content": "无线发射器停用" + }, + { + "Id": "1570", + "Level": "5", + "Type": "旁路", + "Content": "防区旁路" + }, + { + "Id": "1571", + "Level": "5", + "Type": "旁路", + "Content": "火警旁路" + }, + { + "Id": "1572", + "Level": "5", + "Type": "旁路", + "Content": "24小时防区旁路" + }, + { + "Id": "1573", + "Level": "5", + "Type": "旁路", + "Content": "窃盗旁路" + }, + { + "Id": "1574", + "Level": "5", + "Type": "旁路", + "Content": "集体旁路" + }, + { + "Id": "1580", + "Level": "5", + "Type": "旁路", + "Content": "旁路操作" + }, + { + "Id": "1601", + "Level": "6", + "Type": "测试", + "Content": "手动测试" + }, + { + "Id": "1602", + "Level": "6", + "Type": "测试", + "Content": "定期测试" + }, + { + "Id": "1603", + "Level": "6", + "Type": "测试", + "Content": "定期无线发射器测试" + }, + { + "Id": "1604", + "Level": "6", + "Type": "测试", + "Content": "火警测试" + }, + { + "Id": "1605", + "Level": "6", + "Type": "测试", + "Content": "状态报告" + }, + { + "Id": "1606", + "Level": "6", + "Type": "测试", + "Content": "监听" + }, + { + "Id": "1607", + "Level": "6", + "Type": "测试", + "Content": "不行测试模式" + }, + { + "Id": "1609", + "Level": "6", + "Type": "测试", + "Content": "图像传输" + }, + { + "Id": "1630", + "Level": "6", + "Type": "测试", + "Content": "改动时间表" + }, + { + "Id": "1631", + "Level": "6", + "Type": "测试", + "Content": "改动例外时间表" + }, + { + "Id": "1632", + "Level": "6", + "Type": "测试", + "Content": "改动出入时间表" + }, + { + "Id": "1695", + "Level": "6", + "Type": "用户", + "Content": "提早布防" + }, + { + "Id": "1696", + "Level": "6", + "Type": "用户", + "Content": "未及时布防" + }, + { + "Id": "1697", + "Level": "6", + "Type": "用户", + "Content": "提早撤防" + }, + { + "Id": "1698", + "Level": "6", + "Type": "用户", + "Content": "未及时撤防" + }, + { + "Id": "1699", + "Level": "6", + "Type": "用户", + "Content": "超时测试间隔信号" + }, + { + "Id": "16A0", + "Level": "6", + "Type": "用户", + "Content": "用户缴费时间到" + }, + { + "Id": "16B0", + "Level": "6", + "Type": "测试", + "Content": "手动测试操作" + }, + { + "Id": "16CC", + "Level": "6", + "Type": "错误", + "Content": "测试" + }, + { + "Id": "3100", + "Level": "1", + "Type": "紧急恢复", + "Content": "个人救护报警恢复" + }, + { + "Id": "3101", + "Level": "1", + "Type": "紧急恢复", + "Content": "个人救护报警,紧急按钮恢复" + }, + { + "Id": "3102", + "Level": "1", + "Type": "紧急恢复", + "Content": "报到失败恢复" + }, + { + "Id": "3103", + "Level": "1", + "Type": "紧急恢复", + "Content": "紧急报警恢复" + }, + { + "Id": "3104", + "Level": "1", + "Type": "紧急恢复", + "Content": "紧急报警恢复" + }, + { + "Id": "3110", + "Level": "1", + "Type": "火警恢复", + "Content": "火警报警恢复" + }, + { + "Id": "3111", + "Level": "1", + "Type": "火警恢复", + "Content": "烟感探头恢复" + }, + { + "Id": "3112", + "Level": "1", + "Type": "火警恢复", + "Content": "燃烧熄灭" + }, + { + "Id": "3113", + "Level": "1", + "Type": "火警恢复", + "Content": "消防水流恢复" + }, + { + "Id": "3114", + "Level": "1", + "Type": "火警恢复", + "Content": "热感探头恢复" + }, + { + "Id": "3115", + "Level": "1", + "Type": "火警恢复", + "Content": "火警手动报警恢复" + }, + { + "Id": "3116", + "Level": "1", + "Type": "火警恢复", + "Content": "空调槽烟感恢复" + }, + { + "Id": "3117", + "Level": "1", + "Type": "火警恢复", + "Content": "火焰探头恢复" + }, + { + "Id": "3118", + "Level": "1", + "Type": "火警恢复", + "Content": "接近警报恢复" + }, + { + "Id": "3119", + "Level": "1", + "Type": "火警恢复", + "Content": "煤气泄漏恢复" + }, + { + "Id": "3120", + "Level": "1", + "Type": "劫盗恢复", + "Content": "劫盗恢复" + }, + { + "Id": "3121", + "Level": "1", + "Type": "劫盗恢复", + "Content": "挟持恢复" + }, + { + "Id": "3122", + "Level": "1", + "Type": "劫盗恢复", + "Content": "无声劫盗恢复" + }, + { + "Id": "3123", + "Level": "1", + "Type": "劫盗恢复", + "Content": "有声劫盗恢复" + }, + { + "Id": "3124", + "Level": "1", + "Type": "劫盗恢复", + "Content": "异地劫持恢复" + }, + { + "Id": "3130", + "Level": "1", + "Type": "窃盗恢复", + "Content": "窃盗恢复" + }, + { + "Id": "3131", + "Level": "1", + "Type": "窃盗恢复", + "Content": "周界窃盗恢复" + }, + { + "Id": "3132", + "Level": "1", + "Type": "窃盗恢复", + "Content": "内部窃盗恢复" + }, + { + "Id": "3133", + "Level": "1", + "Type": "窃盗恢复", + "Content": "24小时窃盗恢复" + }, + { + "Id": "3134", + "Level": "1", + "Type": "窃盗恢复", + "Content": "出/入窃盗恢复" + }, + { + "Id": "3135", + "Level": "1", + "Type": "窃盗恢复", + "Content": "日/夜防区恢复" + }, + { + "Id": "3136", + "Level": "1", + "Type": "窃盗恢复", + "Content": "室外窃盗恢复" + }, + { + "Id": "3137", + "Level": "1", + "Type": "窃盗恢复", + "Content": "拆动报警恢复" + }, + { + "Id": "3138", + "Level": "1", + "Type": "窃盗恢复", + "Content": "接近报警恢复" + }, + { + "Id": "3140", + "Level": "1", + "Type": "警报恢复", + "Content": "一般报警恢复" + }, + { + "Id": "3141", + "Level": "1", + "Type": "警报恢复", + "Content": "总线开路恢复" + }, + { + "Id": "3142", + "Level": "1", + "Type": "警报恢复", + "Content": "总线短路恢复" + }, + { + "Id": "3143", + "Level": "1", + "Type": "警报恢复", + "Content": "扩充器恢复" + }, + { + "Id": "3144", + "Level": "1", + "Type": "警报恢复", + "Content": "探头被拆动恢复" + }, + { + "Id": "3145", + "Level": "1", + "Type": "警报恢复", + "Content": "扩充器被拆恢复" + }, + { + "Id": "3150", + "Level": "1", + "Type": "警报恢复", + "Content": "24小时非窃盗报警恢复" + }, + { + "Id": "3151", + "Level": "1", + "Type": "警报恢复", + "Content": "气体恢复" + }, + { + "Id": "3152", + "Level": "1", + "Type": "警报恢复", + "Content": "冷藏器恢复" + }, + { + "Id": "3153", + "Level": "1", + "Type": "警报恢复", + "Content": "加热系统恢复" + }, + { + "Id": "3154", + "Level": "1", + "Type": "警报恢复", + "Content": "漏水恢复" + }, + { + "Id": "3155", + "Level": "1", + "Type": "警报恢复", + "Content": "箔片破损恢复" + }, + { + "Id": "3156", + "Level": "1", + "Type": "警报恢复", + "Content": "日间防区恢复" + }, + { + "Id": "3157", + "Level": "1", + "Type": "警报恢复", + "Content": "气体水平过低恢复" + }, + { + "Id": "3158", + "Level": "1", + "Type": "警报恢复", + "Content": "温度过高恢复" + }, + { + "Id": "3159", + "Level": "1", + "Type": "警报恢复", + "Content": "温度过低恢复" + }, + { + "Id": "3161", + "Level": "1", + "Type": "警报恢复", + "Content": "空气流动恢复" + }, + { + "Id": "3170", + "Level": "1", + "Type": "故障恢复", + "Content": "用户离线恢复" + }, + { + "Id": "3180", + "Level": "1", + "Type": "故障", + "Content": "GPRS设备恢复连接" + }, + { + "Id": "3200", + "Level": "2", + "Type": "监控恢复", + "Content": "火警监控恢复" + }, + { + "Id": "3201", + "Level": "2", + "Type": "监控恢复", + "Content": "水压过低恢复" + }, + { + "Id": "3202", + "Level": "2", + "Type": "监控恢复", + "Content": "二氧化碳过低恢复" + }, + { + "Id": "3203", + "Level": "2", + "Type": "监控恢复", + "Content": "阀门感应恢复" + }, + { + "Id": "3204", + "Level": "2", + "Type": "监控恢复", + "Content": "水压过低恢复" + }, + { + "Id": "3205", + "Level": "2", + "Type": "监控恢复", + "Content": "水泵关闭" + }, + { + "Id": "3206", + "Level": "2", + "Type": "监控恢复", + "Content": "水泵故障恢复" + }, + { + "Id": "3300", + "Level": "3", + "Type": "故障恢复", + "Content": "系统故障恢复" + }, + { + "Id": "3301", + "Level": "3", + "Type": "故障恢复", + "Content": "交流恢复" + }, + { + "Id": "3302", + "Level": "3", + "Type": "故障恢复", + "Content": "电池低压恢复" + }, + { + "Id": "3303", + "Level": "3", + "Type": "故障恢复", + "Content": "RAM校验和故障恢复" + }, + { + "Id": "3304", + "Level": "3", + "Type": "故障恢复", + "Content": "ROM检验和故障恢复" + }, + { + "Id": "3305", + "Level": "3", + "Type": "故障恢复", + "Content": "系统重新设定恢复" + }, + { + "Id": "3306", + "Level": "3", + "Type": "故障恢复", + "Content": "编程改动恢复" + }, + { + "Id": "3307", + "Level": "3", + "Type": "故障恢复", + "Content": "自检故障恢复" + }, + { + "Id": "3308", + "Level": "3", + "Type": "故障恢复", + "Content": "主机停机使用恢复" + }, + { + "Id": "3309", + "Level": "3", + "Type": "故障恢复", + "Content": "电池测试故障恢复" + }, + { + "Id": "330A", + "Level": "3", + "Type": "故障恢复", + "Content": "系统复位恢复" + }, + { + "Id": "3310", + "Level": "3", + "Type": "故障恢复", + "Content": "接地故障恢复" + }, + { + "Id": "3320", + "Level": "3", + "Type": "故障恢复", + "Content": "警号/继电器恢复" + }, + { + "Id": "3321", + "Level": "3", + "Type": "故障恢复", + "Content": "警铃#1恢复" + }, + { + "Id": "3322", + "Level": "3", + "Type": "故障恢复", + "Content": "警铃#2恢复" + }, + { + "Id": "3323", + "Level": "3", + "Type": "故障恢复", + "Content": "警报继电器恢复" + }, + { + "Id": "3324", + "Level": "3", + "Type": "故障恢复", + "Content": "故障继电器恢复" + }, + { + "Id": "3325", + "Level": "3", + "Type": "故障恢复", + "Content": "逆转继电器恢复" + }, + { + "Id": "332A", + "Level": "3", + "Type": "故障恢复", + "Content": "警铃保险管烧坏恢复" + }, + { + "Id": "3330", + "Level": "3", + "Type": "故障恢复", + "Content": "系统周边恢复" + }, + { + "Id": "3331", + "Level": "3", + "Type": "故障恢复", + "Content": "总线开路恢复" + }, + { + "Id": "3332", + "Level": "3", + "Type": "故障恢复", + "Content": "总线短路恢复" + }, + { + "Id": "3333", + "Level": "3", + "Type": "故障恢复", + "Content": "扩充器故障" + }, + { + "Id": "3334", + "Level": "3", + "Type": "故障恢复", + "Content": "重复器故障恢复" + }, + { + "Id": "3335", + "Level": "3", + "Type": "故障恢复", + "Content": "打印机无纸恢复" + }, + { + "Id": "3336", + "Level": "3", + "Type": "故障恢复", + "Content": "打印机故障恢复" + }, + { + "Id": "3339", + "Level": "3", + "Type": "故障恢复", + "Content": "振动光纤断光恢复" + }, + { + "Id": "3340", + "Level": "3", + "Type": "故障恢复", + "Content": "网络设备在线" + }, + { + "Id": "3350", + "Level": "3", + "Type": "故障恢复", + "Content": "通讯故障恢复" + }, + { + "Id": "3351", + "Level": "3", + "Type": "故障恢复", + "Content": "电话线1故障恢复" + }, + { + "Id": "3352", + "Level": "3", + "Type": "故障恢复", + "Content": "电话线2故障恢复" + }, + { + "Id": "3353", + "Level": "3", + "Type": "故障恢复", + "Content": "长距离无线发射器故障恢复" + }, + { + "Id": "3354", + "Level": "3", + "Type": "故障恢复", + "Content": "通讯失败恢复" + }, + { + "Id": "3355", + "Level": "3", + "Type": "故障恢复", + "Content": "失去长距无线监控恢复" + }, + { + "Id": "3356", + "Level": "3", + "Type": "故障恢复", + "Content": "失去长距无线中央监控恢复" + }, + { + "Id": "3357", + "Level": "3", + "Type": "故障恢复", + "Content": "无线感干扰恢复" + }, + { + "Id": "3360", + "Level": "3", + "Type": "故障恢复", + "Content": "防区故障恢复" + }, + { + "Id": "3361", + "Level": "3", + "Type": "故障恢复", + "Content": "防拆故障恢复" + }, + { + "Id": "3362", + "Level": "3", + "Type": "故障恢复", + "Content": "充电故障恢复" + }, + { + "Id": "3363", + "Level": "3", + "Type": "故障恢复", + "Content": "模块已准备就绪" + }, + { + "Id": "3370", + "Level": "3", + "Type": "故障恢复", + "Content": "保护回路恢复" + }, + { + "Id": "3371", + "Level": "3", + "Type": "故障恢复", + "Content": "保护回路开路恢复" + }, + { + "Id": "3372", + "Level": "3", + "Type": "故障恢复", + "Content": "保护回路短路恢复" + }, + { + "Id": "3373", + "Level": "3", + "Type": "故障恢复", + "Content": "火警回路故障恢复" + }, + { + "Id": "337A", + "Level": "3", + "Type": "故障恢复", + "Content": "回路故障恢复" + }, + { + "Id": "3380", + "Level": "3", + "Type": "故障恢复", + "Content": "感应器故障恢复" + }, + { + "Id": "3381", + "Level": "3", + "Type": "故障恢复", + "Content": "无线监控故障恢复" + }, + { + "Id": "3382", + "Level": "3", + "Type": "故障恢复", + "Content": "总线监控故障恢复" + }, + { + "Id": "3383", + "Level": "3", + "Type": "故障恢复", + "Content": "感应器被拆恢复" + }, + { + "Id": "3384", + "Level": "3", + "Type": "故障恢复", + "Content": "无线感应器电池过低恢复" + }, + { + "Id": "3393", + "Level": "3", + "Type": "故障恢复", + "Content": "电话故障恢复" + }, + { + "Id": "3394", + "Level": "3", + "Type": "故障恢复", + "Content": "卡故障恢复" + }, + { + "Id": "33A0", + "Level": "3", + "Type": "故障恢复", + "Content": "请求服务恢复" + }, + { + "Id": "33A1", + "Level": "3", + "Type": "故障恢复", + "Content": "设置时间恢复" + }, + { + "Id": "33A2", + "Level": "3", + "Type": "故障恢复", + "Content": "5(12)伏电源故障恢复" + }, + { + "Id": "33A3", + "Level": "3", + "Type": "故障恢复", + "Content": "电话线故障恢复" + }, + { + "Id": "33A4", + "Level": "3", + "Type": "故障恢复", + "Content": "卡故障恢复" + }, + { + "Id": "33A5", + "Level": "3", + "Type": "故障恢复", + "Content": "失去电池恢复" + }, + { + "Id": "33A6", + "Level": "3", + "Type": "故障恢复", + "Content": "进入编程模式恢复" + }, + { + "Id": "33A7", + "Level": "3", + "Type": "故障恢复", + "Content": "未知故障恢复" + }, + { + "Id": "33A8", + "Level": "3", + "Type": "故障恢复", + "Content": "无效报告恢复" + }, + { + "Id": "33B0", + "Level": "3", + "Type": "密码恢复", + "Content": "用户密码更改恢复" + }, + { + "Id": "33B1", + "Level": "3", + "Type": "故障恢复", + "Content": "错误恢复" + }, + { + "Id": "3400", + "Level": "4", + "Type": "布防", + "Content": "布防" + }, + { + "Id": "3401", + "Level": "4", + "Type": "布防", + "Content": "用户布防" + }, + { + "Id": "3402", + "Level": "4", + "Type": "布防", + "Content": "集体布防" + }, + { + "Id": "3403", + "Level": "4", + "Type": "布防", + "Content": "自动布防" + }, + { + "Id": "3404", + "Level": "4", + "Type": "布防", + "Content": "过迟布防" + }, + { + "Id": "3405", + "Level": "4", + "Type": "布防", + "Content": "不适用恢复" + }, + { + "Id": "3406", + "Level": "4", + "Type": "布防", + "Content": "取消恢复" + }, + { + "Id": "3407", + "Level": "4", + "Type": "布防", + "Content": "遥控布防" + }, + { + "Id": "3408", + "Level": "4", + "Type": "布防", + "Content": "快速布防" + }, + { + "Id": "3409", + "Level": "4", + "Type": "布防", + "Content": "开关布防" + }, + { + "Id": "340A", + "Level": "4", + "Type": "布防", + "Content": "部分布防" + }, + { + "Id": "340B", + "Level": "4", + "Type": "布防", + "Content": "周边布防" + }, + { + "Id": "3411", + "Level": "4", + "Type": "遥控恢复", + "Content": "要求回电恢复" + }, + { + "Id": "3412", + "Level": "4", + "Type": "遥控恢复", + "Content": "遥控编程成功恢复" + }, + { + "Id": "3413", + "Level": "4", + "Type": "遥控恢复", + "Content": "遥控不成功恢复" + }, + { + "Id": "3414", + "Level": "4", + "Type": "遥控恢复", + "Content": "关闭系统恢复" + }, + { + "Id": "3415", + "Level": "4", + "Type": "遥控恢复", + "Content": "关闭通讯恢复" + }, + { + "Id": "3416", + "Level": "4", + "Type": "布防", + "Content": "布防操作" + }, + { + "Id": "3417", + "Level": "4", + "Type": "布防", + "Content": "防区布防" + }, + { + "Id": "3421", + "Level": "4", + "Type": "出入恢复", + "Content": "拒绝出入-用户恢复" + }, + { + "Id": "3422", + "Level": "4", + "Type": "出入恢复", + "Content": "成功出入-用户恢复" + }, + { + "Id": "3441", + "Level": "4", + "Type": "布防", + "Content": "留守布防" + }, + { + "Id": "3450", + "Level": "4", + "Type": "出入恢复", + "Content": "非正常时段布防" + }, + { + "Id": "3451", + "Level": "4", + "Type": "出入恢复", + "Content": "过早布防" + }, + { + "Id": "3452", + "Level": "4", + "Type": "出入恢复", + "Content": "过迟布防" + }, + { + "Id": "3453", + "Level": "4", + "Type": "出入恢复", + "Content": "撤防失败恢复" + }, + { + "Id": "3454", + "Level": "4", + "Type": "出入恢复", + "Content": "布防失败恢复" + }, + { + "Id": "3455", + "Level": "4", + "Type": "出入恢复", + "Content": "自动布防失败恢复" + }, + { + "Id": "3456", + "Level": "4", + "Type": "出入恢复", + "Content": "部分布防恢复" + }, + { + "Id": "3457", + "Level": "4", + "Type": "出入恢复", + "Content": "外出错误恢复" + }, + { + "Id": "3458", + "Level": "4", + "Type": "出入恢复", + "Content": "操作员在现场恢复" + }, + { + "Id": "3459", + "Level": "4", + "Type": "出入恢复", + "Content": "最近布防恢复" + }, + { + "Id": "3480", + "Level": "4", + "Type": "用户恢复", + "Content": "开警号" + }, + { + "Id": "3520", + "Level": "5", + "Type": "停用恢复", + "Content": "停用警号/继电器恢复" + }, + { + "Id": "3521", + "Level": "5", + "Type": "停用恢复", + "Content": "警铃1停用恢复" + }, + { + "Id": "3522", + "Level": "5", + "Type": "停用恢复", + "Content": "警铃2停用恢复" + }, + { + "Id": "3523", + "Level": "5", + "Type": "停用恢复", + "Content": "停用警报继电器恢复" + }, + { + "Id": "3524", + "Level": "5", + "Type": "停用恢复", + "Content": "停用故障继电器恢复" + }, + { + "Id": "3525", + "Level": "5", + "Type": "停用恢复", + "Content": "逆反继电器恢复" + }, + { + "Id": "3530", + "Level": "5", + "Type": "停用恢复", + "Content": "停用系统周边恢复" + }, + { + "Id": "3540", + "Level": "5", + "Type": "停用恢复", + "Content": "停用系统周边恢复" + }, + { + "Id": "3551", + "Level": "5", + "Type": "停用恢复", + "Content": "通讯器停用恢复" + }, + { + "Id": "3552", + "Level": "5", + "Type": "停用恢复", + "Content": "无线发射器停用恢复" + }, + { + "Id": "3570", + "Level": "5", + "Type": "旁路恢复", + "Content": "防区旁路恢复" + }, + { + "Id": "3571", + "Level": "5", + "Type": "旁路恢复", + "Content": "火警旁路恢复" + }, + { + "Id": "3572", + "Level": "5", + "Type": "旁路恢复", + "Content": "24小时防区旁路恢复" + }, + { + "Id": "3573", + "Level": "5", + "Type": "旁路恢复", + "Content": "窃盗旁路恢复" + }, + { + "Id": "3574", + "Level": "5", + "Type": "旁路恢复", + "Content": "集体旁路恢复" + }, + { + "Id": "3580", + "Level": "5", + "Type": "旁路恢复", + "Content": "旁路操作恢复" + }, + { + "Id": "3601", + "Level": "6", + "Type": "测试恢复", + "Content": "手动测试恢复" + }, + { + "Id": "3602", + "Level": "6", + "Type": "测试恢复", + "Content": "定期测试恢复" + }, + { + "Id": "3603", + "Level": "6", + "Type": "测试恢复", + "Content": "定期无线发射器测试恢复" + }, + { + "Id": "3604", + "Level": "6", + "Type": "测试恢复", + "Content": "火警测试恢复" + }, + { + "Id": "3605", + "Level": "6", + "Type": "测试恢复", + "Content": "状态报告恢复" + }, + { + "Id": "3606", + "Level": "6", + "Type": "测试恢复", + "Content": "监听恢复" + }, + { + "Id": "3607", + "Level": "6", + "Type": "测试恢复", + "Content": "步行测试模式恢复" + }, + { + "Id": "3609", + "Level": "6", + "Type": "测试恢复", + "Content": "图像传输恢复" + }, + { + "Id": "3630", + "Level": "6", + "Type": "测试恢复", + "Content": "改动时间表恢复" + }, + { + "Id": "3631", + "Level": "6", + "Type": "测试恢复", + "Content": "改动例外时间表恢复" + }, + { + "Id": "3632", + "Level": "6", + "Type": "测试恢复", + "Content": "改动出入时间表恢复" + }, + { + "Id": "3695", + "Level": "6", + "Type": "用户恢复", + "Content": "提早布防恢复" + }, + { + "Id": "3696", + "Level": "6", + "Type": "用户恢复", + "Content": "未及时布防恢复" + }, + { + "Id": "3697", + "Level": "6", + "Type": "用户恢复", + "Content": "提早撤防恢复" + }, + { + "Id": "3698", + "Level": "6", + "Type": "用户恢复", + "Content": "未及时撤防恢复" + }, + { + "Id": "3699", + "Level": "6", + "Type": "用户恢复", + "Content": "超过测试间隔信号恢复" + }, + { + "Id": "36B0", + "Level": "6", + "Type": "测试恢复", + "Content": "手动测试操作恢复" + } +] \ No newline at end of file diff --git a/JiLinApp.sln b/JiLinApp.sln index 82cd743..3105430 100644 --- a/JiLinApp.sln +++ b/JiLinApp.sln @@ -5,7 +5,11 @@ 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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EC.Util", "EC.Util\EC.Util.csproj", "{A41E47C9-1930-4FF0-955E-B91EC859D262}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiLinApp.Docking", "JiLinApp.Docking\JiLinApp.Docking.csproj", "{B664DFEE-E137-44AC-A766-95D384E3F70B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiLinApp.Biz", "JiLinApp.Biz\JiLinApp.Biz.csproj", "{7CE63A50-C92C-4554-8E0C-F7BED355C1FD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +25,14 @@ Global {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 + {B664DFEE-E137-44AC-A766-95D384E3F70B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B664DFEE-E137-44AC-A766-95D384E3F70B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B664DFEE-E137-44AC-A766-95D384E3F70B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B664DFEE-E137-44AC-A766-95D384E3F70B}.Release|Any CPU.Build.0 = Release|Any CPU + {7CE63A50-C92C-4554-8E0C-F7BED355C1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CE63A50-C92C-4554-8E0C-F7BED355C1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CE63A50-C92C-4554-8E0C-F7BED355C1FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CE63A50-C92C-4554-8E0C-F7BED355C1FD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE