You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

726 lines
22 KiB

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<int, UdpAlarmHost> 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
/// <summary>
/// 计时判断设备是否在线,若超过规定时间没有新消息发来,则设备离线
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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<byte[]> 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
/// <summary>
/// 应答
/// </summary>
/// <param name="ipep"></param>
/// <returns></returns>
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<byte>());
return Server.SendMessage(ipep.Address.ToString(), ipep.Port, AlarmEncode.EncodeMessage(bytes));
}
/// <summary>
/// 外出布防或者布防
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 撤防
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 立即布防
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 在家布防留守布防
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 即时留守布防
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 清除报警记忆(复位)
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 校对系统时间
/// </summary>
/// <param name="deviceId"></param>
/// <param name="time"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 设备重启
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
public bool RebootDevice(int deviceId)
{
UdpAlarmHost device = GetDevice(deviceId);
if (CheckDevice(device))
{
byte[] bytes = AlarmEncode.GetSendMessage(0xA0, Array.Empty<byte>());
return Server.SendMessage(device.Ip, device.Port, AlarmEncode.EncodeMessage(bytes));
}
return false;
}
/// <summary>
/// 单防区布防
/// </summary>
/// <param name="deviceId"></param>
/// <param name="sectorId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 单防区撤防
/// </summary>
/// <param name="deviceId"></param>
/// <param name="sectorId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 单防区旁路
/// </summary>
/// <param name="deviceId"></param>
/// <param name="sectorId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 单防区旁路恢复
/// </summary>
/// <param name="deviceId"></param>
/// <param name="sectorId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 查询防区状态
/// </summary>
/// <param name="deviceId"></param>
/// <param name="sectorId"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 查询所有防区状态
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
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<UdpAlarmHost> 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
}