using JiLinApp.Docking.VibrateAlarm; using System.Collections.Concurrent; using System.Net; using System.Timers; using Timer = System.Timers.Timer; namespace JiLinApp.Docking.FenceAlarm; public class UdpManager { #region Fields private UdpServer Server { get; set; } private UdpManagerConfig Config { get; set; } private Timer PtzCheckTimer { get; } = new(); private ConcurrentDictionary DeviceDict { get; } = new(); #region Event public delegate void FenceUdpDeviceStateEvent(UdpAlarmHost device); public delegate void FenceUdpSectorStateEvent(SectorState sector); public delegate void FenceUdpAlarmEvent(UdpAlarmHostMessage msg); public event FenceUdpDeviceStateEvent? OnFenceUdpDeviceState; public event FenceUdpSectorStateEvent? OnFenceUdpSectorState; public event FenceUdpAlarmEvent? OnFenceUdpAlarm; #endregion Event #endregion Fields public UdpManager() { } #region Server public void Start(UdpManagerConfig config) { if (IsRunning()) return; Server = new(config.ServerPort); Server.DatagramReceived += Server_DatagramReceived; Server.Start(); PtzCheckTimer.Interval = 1000;//1s PtzCheckTimer.Elapsed += PTZCheckTimer_Elapsed; PtzCheckTimer.Enabled = true; Config = config; } public void Stop() { if (!IsRunning()) return; try { Server.Stop(); } finally { Server.DatagramReceived -= Server_DatagramReceived; Server = null; DeviceDict.Clear(); PtzCheckTimer.Stop(); PtzCheckTimer.Elapsed -= PTZCheckTimer_Elapsed; } } public bool IsRunning() { return Server != null && Server.IsRunning(); } #endregion Server #region Events /// /// 计时判断设备是否在线,若超过规定时间没有新消息发来,则设备离线 /// /// /// private void PTZCheckTimer_Elapsed(object? sender, ElapsedEventArgs e) { foreach (var key in DeviceDict.Keys) { UdpAlarmHost device = DeviceDict[key]; if (device.KeepLive >= 0) device.KeepLive--; else ProcessDeviceStateEvent(ref device, 0, device.DefenceState); } } private void Server_DatagramReceived(object? sender, UdpDatagramReceivedEventArgs e) { IPEndPoint ipep = e.Ipep; //解码 byte[] msg = AlarmEncode.DecodeMessage(e.Datagram); bool vaild = msg.Length >= 8 && msg[2] == AlarmEncode.Head[0] && msg[3] == AlarmEncode.Head[1]; if (!vaild) return; Console.WriteLine("Receive from {0}:{1} => {2}", ipep.Address.ToString(), ipep.Port, DataMessage.ToHexString(msg)); //解析 DeviceCmd deviceCmd = (DeviceCmd)msg[4]; switch (deviceCmd) { case DeviceCmd.HeartBeatCmd://心跳信息 AnalysisHeartMessage(ipep, msg); break; case DeviceCmd.AlarmCmd://报警信息 AnalysisAlarmMessage(ipep, msg); break; case DeviceCmd.AllSectorStateCmd://防区信息 AnalysisAllSectorMessage(ipep, msg); break; case DeviceCmd.RtSectorStateCmd://张力防区信息 AnalysisSectorMessage(ipep, msg); break; case DeviceCmd.MaxSectorTotalCmd://最大防区信息 AnalysisMaxSectorMessage(ipep, msg); break; case DeviceCmd.BackSettingsCmd://返回报警主机设置参数回服务器,无需解析 break; default: break; } SendOk(ipep); } #endregion Events #region Analysis private void AnalysisHeartMessage(IPEndPoint ipep, byte[] msg) { string ip = ipep.Address.ToString(); int deviceId = ByteToInt(msg, 5); if (!TryGetDevice(deviceId, out UdpAlarmHost device)) { device = new() { DeviceId = deviceId, Ip = ip, Port = ipep.Port, GroupId = ByteToInt(msg, 9), UserId = ByteToInt(msg, 13), OnlineState = 1, KeepLive = Config.DeviceHeartKeep }; AddDevice(deviceId, device); } byte defenceState = msg[17]; ProcessDeviceStateEvent(ref device, 1, defenceState); device.WorkState = 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.SectorTotal = msg[25]; //在线状态 device.KeepLive = Config.DeviceHeartKeep; } private void AnalysisAlarmMessage(IPEndPoint ipep, byte[] msg) { string ip = ipep.Address.ToString(); int deviceId = ByteToInt(msg, 5); if (!TryGetDevice(deviceId, out _)) { UdpAlarmHost device = new() { DeviceId = deviceId, Ip = ip, Port = ipep.Port, GroupId = ByteToInt(msg, 9), UserId = ByteToInt(msg, 13), OnlineState = 1, KeepLive = Config.DeviceHeartKeep }; AddDevice(deviceId, device); } string alarmTime = $"20{GetBCD(msg[17])}-{GetBCD(msg[18])}-{GetBCD(msg[19])} " + $"{GetBCD(msg[20])}:{GetBCD(msg[21])}:{GetBCD(msg[22])}"; string CID = GetCID(msg[23]) + GetCID(msg[24]) + GetCID(msg[25]) + GetCID(msg[26]); int sectorId = msg[29] + msg[30] * 256; 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, SectorId = sectorId, SubSectorId = msg[31] + msg[32] * 256, ExtendArgs = msg[33].ToString("X2") + " " + msg[34].ToString("X2") + " " + msg[35].ToString("X2"), }; ReportAlarm(alarm); } private void AnalysisAllSectorMessage(IPEndPoint ipep, byte[] msg) { string ip = ipep.Address.ToString(); int deviceId = ByteToInt(msg, 5); if (!TryGetDevice(deviceId, out UdpAlarmHost device)) { device = new() { DeviceId = deviceId, Ip = ip, Port = ipep.Port, GroupId = ByteToInt(msg, 9), UserId = ByteToInt(msg, 13), OnlineState = 1, KeepLive = Config.DeviceHeartKeep }; AddDevice(deviceId, device); } device.SectorTotal = msg[17] * 256 + msg[18]; int sectorNum = msg[19], startIndex = msg[20]; for (int i = 0; i < sectorNum; i++) { int sectorId = i + startIndex;//防区序号 int pos = 21 + i;//防区信息所在byte数组未知 SectorState curSector = new(device.DeviceId, sectorId, msg[pos]); if (device.SectorDict.TryGetValue(sectorId, out SectorState? sector)) { ProcessSectorStateEvent(ref sector, curSector.State); } else { sector = curSector; device.SectorDict[sector.Id] = sector; //ProcessSectorStateEvent(ref sector); } } } private void AnalysisSectorMessage(IPEndPoint ipep, byte[] msg) { //东北没有张力防区,暂不解析 string ip = ipep.Address.ToString(); int deviceId = ByteToInt(msg, 5); if (!TryGetDevice(deviceId, out UdpAlarmHost device)) { device = new() { DeviceId = deviceId, Ip = ip, Port = ipep.Port, GroupId = ByteToInt(msg, 9), UserId = ByteToInt(msg, 13), OnlineState = 1, KeepLive = Config.DeviceHeartKeep }; AddDevice(deviceId, device); } } private void AnalysisMaxSectorMessage(IPEndPoint ipep, byte[] msg) { string ip = ipep.Address.ToString(); int deviceId = ByteToInt(msg, 5); if (!TryGetDevice(deviceId, out UdpAlarmHost device)) { device = new() { DeviceId = deviceId, Ip = ip, Port = ipep.Port, GroupId = ByteToInt(msg, 9), UserId = ByteToInt(msg, 13), OnlineState = 1, KeepLive = Config.DeviceHeartKeep }; AddDevice(deviceId, device); } device.SectorTotal = msg[17] * 256 + msg[18]; } private void ProcessDeviceStateEvent(ref UdpAlarmHost device, int onlineState, int defenceState) { bool reportFlag = false; if (device.OnlineState != onlineState) { reportFlag = true; device.OnlineState = onlineState; } if (device.DefenceState != defenceState) { reportFlag = true; device.DefenceState = defenceState; } if (reportFlag) ReportDeviceState(device); } private void ProcessSectorStateEvent(ref SectorState sector, int state) { if (sector.State != state) { sector.State = state; ReportSectorState(sector); } } private void ReportDeviceState(UdpAlarmHost device) { OnFenceUdpDeviceState?.Invoke(device); } private void ReportSectorState(SectorState sector) { OnFenceUdpSectorState?.Invoke(sector); } private void ReportAlarm(UdpAlarmHostMessage msg) { OnFenceUdpAlarm?.Invoke(msg); } #endregion Analysis #region Send /// /// 应答 /// /// /// private bool SendOk(IPEndPoint ipep) { if (!IsRunning()) return false; byte[] bytes = new byte[] { 0x08, 0x12, 0xF0, 0xFA, 0x8F, 0x06, 0x6B, 0x0D }; //byte[] bytes = AlarmEncode.GetSendMessage(0x8F, Array.Empty()); return Server.SendMessage(ipep.Address.ToString(), ipep.Port, AlarmEncode.EncodeMessage(bytes)); } /// /// 外出布防或者布防 /// /// /// public bool SetDeviceDefence(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x80, new byte[] { 0x60 }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 撤防 /// /// /// public bool WithdrawDeviceDefence(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x80, new byte[] { 0x61 }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 立即布防 /// /// /// public bool SetDeviceDefenceImmediately(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x80, new byte[] { 0x62 }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 在家布防留守布防 /// /// /// public bool SetDeviceDefenceHome(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x80, new byte[] { 0x63 }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 即时留守布防 /// /// /// public bool SetDeviceDefenceHomeImmediately(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x80, new byte[] { 0x64 }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 清除报警记忆(复位) /// /// /// public bool ClearDeviceDefence(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x80, new byte[] { 0x65 }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 校对系统时间 /// /// /// /// public bool SetDeviceTime(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] content = GetBCDTime(DateTime.Now); byte[] bytes = AlarmEncode.GetSendMessage(0x8D, content); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 设备重启 /// /// /// public bool RebootDevice(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0xA0, Array.Empty()); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 单防区布防 /// /// /// /// public bool SetSectorefence(int deviceId, int sectorId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0xC0, new byte[] { (byte)(sectorId / 256), (byte)(sectorId % 256) }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 单防区撤防 /// /// /// /// public bool WithdrawSectorDefence(int deviceId, int sectorId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0xC1, new byte[] { (byte)(sectorId / 256), (byte)(sectorId % 256) }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 单防区旁路 /// /// /// /// public bool SetSectorByway(int deviceId, int sectorId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0xC2, new byte[] { (byte)(sectorId / 256), (byte)(sectorId % 256) }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 单防区旁路恢复 /// /// /// /// public bool WithdrawSectorByway(int deviceId, int sectorId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0xC3, new byte[] { (byte)(sectorId / 256), (byte)(sectorId % 256) }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 查询防区状态 /// /// /// /// public bool SearchSectorState(int deviceId, int sectorId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { byte[] bytes = AlarmEncode.GetSendMessage(0x85, new byte[] { (byte)(sectorId / 256), (byte)(sectorId % 256) }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } /// /// 查询所有防区状态 /// /// /// public bool SearchAllSectorState(int deviceId) { UdpAlarmHost device = GetDevice(deviceId); if (CheckDevice(device)) { int sectorId = 0x00; byte[] bytes = AlarmEncode.GetSendMessage(0x85, new byte[] { (byte)(sectorId / 256), (byte)(sectorId % 256) }); return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes)); } return false; } #endregion Send #region DeviceDict public bool ContainsDevice(int deviceId) { return DeviceDict.ContainsKey(deviceId); } public UdpAlarmHost GetDevice(int deviceId) { return DeviceDict[deviceId]; } public bool TryGetDevice(int deviceId, out UdpAlarmHost device) { return DeviceDict.TryGetValue(deviceId, out device); } private bool AddDevice(int deviceId, UdpAlarmHost device) { if (ContainsDevice(deviceId)) return false; DeviceDict[deviceId] = device; return true; } private void SetDevice(int deviceId, UdpAlarmHost device) { DeviceDict[deviceId] = device; } private bool RemoveDevice(int deviceId) { return DeviceDict.Remove(deviceId, out _); } public List GetDeviceList() { return DeviceDict.Values.ToList(); } private bool CheckDevice(UdpAlarmHost device) { if (!IsRunning()) return false; if (device == null) return false; if (device.OnlineState == 0) return false; return true; } #endregion DeviceDict #region Util private int GetBit(byte bytes, int index) { return index switch { 0 => bytes & 0x01, 1 => (bytes & 0x02) >> 1, 2 => (bytes & 0x04) >> 2, 3 => (bytes & 0x08) >> 3, 4 => (bytes & 0x10) >> 4, 5 => (bytes & 0x20) >> 5, 6 => (bytes & 0x40) >> 6, 7 => (bytes & 0x80) >> 7, _ => 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] }; } private string GetCID(byte bytes) { return bytes switch { 0x00 => "0", 0x01 => "1", 0x02 => "2", 0x03 => "3", 0x04 => "4", 0x05 => "5", 0x06 => "6", 0x07 => "7", 0x08 => "8", 0x09 => "9", 0x0A => "A", 0x0B => "B", 0x0C => "C", 0x0D => "D", 0x0E => "E", 0x0F => "F", _ => "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 %= 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) }; } #endregion Util }