Browse Source

[feat] 添加 EC.Util 库

master
fajiao 1 year ago
parent
commit
6642c17ab4
  1. 59
      EC.Util/CameraSDK/Common/CameraException.cs
  2. 16
      EC.Util/CameraSDK/Common/CameraFactory.cs
  3. 142
      EC.Util/CameraSDK/Common/CameraStruct.cs
  4. 72
      EC.Util/CameraSDK/Common/ICameraSdk.cs
  5. 1527
      EC.Util/CameraSDK/DaHua/DaHuaOriSdk.cs
  6. 180
      EC.Util/CameraSDK/DaHua/DaHuaSdk.cs
  7. 402
      EC.Util/CameraSDK/HiK/HiKOriSdk.cs
  8. 275
      EC.Util/CameraSDK/HiK/HiKSdk.cs
  9. 77
      EC.Util/CameraSDK/HiK/PlayCtrlSdk.cs
  10. 244
      EC.Util/CameraSDK/YuShi/YuShiOriSdk.cs
  11. 136
      EC.Util/CameraSDK/YuShi/YuShiSdk.cs
  12. 43
      EC.Util/Common/JsonUtil.cs
  13. 40
      EC.Util/Common/LogUnit.cs
  14. 36
      EC.Util/Common/NetworkUtil.cs
  15. 40
      EC.Util/Common/TaskUtil.cs
  16. 176
      EC.Util/Common/VerifyUtil.cs
  17. 25
      EC.Util/EC.Util.csproj
  18. 60
      EC.Util/Port/SerialPortBuilder.cs
  19. 56
      EC.Util/Port/SerialPortParam.cs
  20. 166
      EC.Util/Port/YcSerialPort.cs
  21. 29
      EC.Util/config/log4net.config
  22. 5
      JiLinApp/JiLinApp.csproj
  23. 23
      JiLinApp/Program.cs
  24. 6
      JiLinCpApp.sln

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

@ -0,0 +1,59 @@
using System.Text;
namespace EC.Util.CameraSDK;
/// <summary>
/// 相机异常
/// </summary>
public class CameraException : Exception
{
public CameraException() : base()
{
}
public CameraException(string? message) : base(message)
{
}
public CameraException(string? message, Exception? innerException) : base(message, innerException)
{
}
protected class CameraExceptionObj
{
public CameraInfo? CameraInfo { get; set; }
public int Code { get; set; }
public string? Msg { get; set; }
public override string? ToString()
{
StringBuilder builder = new();
builder.Append($"Ip:{CameraInfo?.Ip}, Manufactor:{CameraInfo?.Manufactor}, Code:{Code}");
if (!string.IsNullOrEmpty(Msg)) builder.Append($", Msg:{Msg}");
return builder.ToString();
}
}
public static CameraException New(CameraInfo cameraInfo, int code)
{
CameraExceptionObj obj = new()
{
CameraInfo = cameraInfo,
Code = code
};
return new CameraException(obj.ToString());
}
public static CameraException New(CameraInfo cameraInfo, int code, string msg)
{
CameraExceptionObj obj = new()
{
CameraInfo = cameraInfo,
Code = code,
Msg = msg
};
return new CameraException(obj.ToString());
}
}

16
EC.Util/CameraSDK/Common/CameraFactory.cs

@ -0,0 +1,16 @@
namespace EC.Util.CameraSDK;
public class CameraFactory
{
public static ICameraSdk BuildCameraSdk(CameraInfo info)
{
ICameraSdk sdk = (info.Manufactor) switch
{
CameraManufactor.HiK => new HiKSdk(info),
CameraManufactor.DaHua => new DaHuaSdk(info),
CameraManufactor.YuShi => new YuShiSdk(info),
_ => throw new NotSupportedException(),
};
return sdk;
}
}

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

@ -0,0 +1,142 @@
namespace EC.Util.CameraSDK;
/// <summary>
/// 相机信息
/// </summary>
public class CameraInfo
{
#region Fields
/// <summary>
/// id
/// </summary>
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
/// <summary>
/// 相机厂商
/// </summary>
public CameraManufactor Manufactor { get; set; }
/// <summary>
/// ip 地址
/// </summary>
public string Ip { get; set; } = string.Empty;
/// <summary>
/// 端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// 账号
/// </summary>
public string UserName { get; set; } = string.Empty;
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; } = string.Empty;
#endregion Fields
public static CameraInfo New(CameraManufactor manufactor, string ip, int port, string username, string password)
{
CameraInfo info = new() { Manufactor = manufactor, Ip = ip, Port = port, UserName = username, Password = password };
if (port <= 0) throw new Exception("Camera manufactor not support.");
return info;
}
public static CameraInfo New(CameraManufactor manufactor, string ip, string username, string password)
{
CameraInfo info = new() { Manufactor = manufactor, Ip = ip, UserName = username, Password = password };
int port = manufactor switch
{
CameraManufactor.HiK => (int)CameraPort.HiK,
CameraManufactor.DaHua => (int)CameraPort.DaHua,
CameraManufactor.YuShi => (int)CameraPort.YuShi,
_ => -1,
};
if (port <= 0) throw new Exception("Camera manufactor not support.");
info.Port = port;
return info;
}
public static CameraInfo New(int manufactor, string ip, int port, string username, string password)
{
CameraManufactor cm = (CameraManufactor)manufactor;
CameraInfo info = new() { Manufactor = cm, Ip = ip, Port = port, UserName = username, Password = password };
if (port <= 0) throw new Exception("Camera manufactor not support.");
return info;
}
public static CameraInfo New(int manufactor, string ip, string username, string password)
{
CameraManufactor cm = (CameraManufactor)manufactor;
CameraInfo info = new() { Manufactor = cm, Ip = ip, UserName = username, Password = password };
int port = cm switch
{
CameraManufactor.HiK => (int)CameraPort.HiK,
CameraManufactor.DaHua => (int)CameraPort.DaHua,
CameraManufactor.YuShi => (int)CameraPort.YuShi,
_ => -1,
};
if (port <= 0) throw new Exception("Camera manufactor not support.");
info.Port = port;
return info;
}
}
/// <summary>
/// 相机厂商
/// </summary>
public enum CameraManufactor : int
{
HiK = 1,
DaHua = 2,
YuShi = 3,
}
/// <summary>
/// 相机默认连接端口
/// </summary>
public enum CameraPort : int
{
HiK = 8000,
DaHua = 37777,
YuShi = 80,
}
/// <summary>
/// Ptz 信息
/// </summary>
public class PtzInfo
{
#region Fields
public double Pan { get; set; }
public double Tilt { get; set; }
public double Zoom { get; set; }
#endregion Fields
public PtzInfo(double pan, double tilt, double zoom)
{
Pan = pan;
Tilt = tilt;
Zoom = zoom;
}
public static PtzInfo Default
{
get { return new(0, 0, 0); }
}
public static PtzInfo New(double pan, double tilt, double zoom)
{
return new PtzInfo(pan, tilt, zoom);
}
}

72
EC.Util/CameraSDK/Common/ICameraSdk.cs

@ -0,0 +1,72 @@
namespace EC.Util.CameraSDK;
public abstract class ICameraSdk
{
#region Fields
public CameraInfo CameraInfo { get; }
#endregion Fields
public ICameraSdk(CameraInfo cameraInfo)
{
CameraInfo = cameraInfo;
}
#region Base Method
/// <summary>
/// 初始化资源
/// </summary>
/// <returns></returns>
public abstract bool Init();
/// <summary>
/// 释放资源
/// </summary>
/// <returns></returns>
public abstract bool Destory();
/// <summary>
/// 连接是否成功
/// </summary>
/// <returns></returns>
public abstract bool ConnectSuccess();
/// <summary>
/// 构建异常
/// </summary>
internal abstract void BuildException();
#endregion Base Method
#region Ptz Method
/// <summary>
/// 获取 ptz
/// </summary>
/// <returns></returns>
public abstract PtzInfo GetPtzInfo();
/// <summary>
/// 获取 ptz
/// </summary>
/// <returns></returns>
public abstract bool TryGetPtzInfo(out PtzInfo ptzInfo);
public abstract bool PtzMove(int cmd, int stop, int speed);
public abstract bool PtzPreset(int cmd, int presetId);
#endregion Ptz Method
#region Video Method
public abstract void StartPlay(IntPtr hwnd);
public abstract void StopPlay();
public abstract bool IsPlaying();
#endregion Video Method
}

1527
EC.Util/CameraSDK/DaHua/DaHuaOriSdk.cs

File diff suppressed because it is too large

180
EC.Util/CameraSDK/DaHua/DaHuaSdk.cs

@ -0,0 +1,180 @@
using System.Runtime.InteropServices;
namespace EC.Util.CameraSDK;
public class DaHuaSdk : ICameraSdk
{
#region Fields
private IntPtr LoginId { get; set; } = IntPtr.Zero;
private int Channel { get; } = 1;
#endregion Fields
public DaHuaSdk(CameraInfo cameraInfo) : base(cameraInfo)
{
}
#region Base Method
public override bool Init()
{
bool ret = ConnectSuccess();
if (ret) return true;
DaHuaOriSdk.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stuInParam = new();
stuInParam.dwSize = (uint)Marshal.SizeOf(stuInParam);
stuInParam.szIP = CameraInfo.Ip;
stuInParam.nPort = CameraInfo.Port;
stuInParam.szUserName = CameraInfo.UserName;
stuInParam.szPassword = CameraInfo.Password;
stuInParam.emSpecCap = DaHuaOriSdk.EM_LOGIN_SPAC_CAP_TYPE.TCP;
stuInParam.pCapParam = IntPtr.Zero;
DaHuaOriSdk.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stuOutParam = new();
stuOutParam.dwSize = (uint)Marshal.SizeOf(stuOutParam);
LoginId = DaHuaOriSdk.CLIENT_LoginWithHighLevelSecurity(ref stuInParam, ref stuOutParam);
ret = ConnectSuccess();
if (ret) DaHuaOriSdk.CLIENT_SetAutoReconnect(delegate (IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser)
{
LoginId = lLoginID;
}, IntPtr.Zero);
else BuildException();
return ret;
}
public override bool Destory()
{
bool ret = ConnectSuccess();
if (!ret) return true;
ret = DaHuaOriSdk.CLIENT_Logout(LoginId);
if (ret) LoginId = IntPtr.Zero;
else BuildException();
return ret;
}
public override bool ConnectSuccess()
{
return LoginId != IntPtr.Zero;
}
internal override void BuildException()
{
uint errCode = (uint)DaHuaOriSdk.CLIENT_GetLastError();
if (errCode == 0) return;
errCode -= 0x80000000;
throw CameraException.New(CameraInfo, (int)errCode);
}
#endregion Base Method
#region Ptz Method
private static class GPIParams
{
public static int Size { get; private set; }
public static Type Type { get; private set; }
static GPIParams()
{
DaHuaOriSdk.DH_PTZ_LOCATION_INFO info = new();
Size = Marshal.SizeOf(info);
Type = info.GetType();
}
}
public override PtzInfo GetPtzInfo()
{
bool ret = ConnectSuccess();
if (!ret) return PtzInfo.Default;
DaHuaOriSdk.DH_PTZ_LOCATION_INFO entity = new();
int nBufLen = GPIParams.Size;
int pRetLen = 0;
IntPtr ptrBuf = Marshal.AllocHGlobal(GPIParams.Size);
Marshal.StructureToPtr(entity, ptrBuf, true);
try
{
ret = DaHuaOriSdk.CLIENT_QueryDevState(LoginId, (int)DaHuaOriSdk.EM_DEVICE_STATE.PTZ_LOCATION, ptrBuf, nBufLen, ref pRetLen, 3000);
if (!ret) { BuildException(); return PtzInfo.Default; }
object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type);
if (objBuf == null) return PtzInfo.Default;
entity = (DaHuaOriSdk.DH_PTZ_LOCATION_INFO)objBuf;
return PtzInfo.New(entity.nPTZPan, entity.nPTZTilt, entity.nPTZZoom);
}
finally
{
Marshal.FreeHGlobal(ptrBuf);
}
}
public override bool TryGetPtzInfo(out PtzInfo ptzInfo)
{
bool ret = ConnectSuccess();
if (!ret) { ptzInfo = PtzInfo.Default; return false; }
DaHuaOriSdk.DH_PTZ_LOCATION_INFO entity = new();
int nBufLen = GPIParams.Size;
int pRetLen = 0;
IntPtr ptrBuf = Marshal.AllocHGlobal(GPIParams.Size);
Marshal.StructureToPtr(entity, ptrBuf, true);
try
{
ret = DaHuaOriSdk.CLIENT_QueryDevState(LoginId, (int)DaHuaOriSdk.EM_DEVICE_STATE.PTZ_LOCATION, ptrBuf, nBufLen, ref pRetLen, 3000);
if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; }
object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type);
if (objBuf == null) { ptzInfo = PtzInfo.Default; return false; }
entity = (DaHuaOriSdk.DH_PTZ_LOCATION_INFO)objBuf;
ptzInfo = PtzInfo.New(entity.nPTZPan, entity.nPTZTilt, entity.nPTZZoom);
return true;
}
finally
{
Marshal.FreeHGlobal(ptrBuf);
}
}
public override bool PtzMove(int cmd, int stop, int speed)
{
if (!ConnectSuccess()) return false;
bool stopret = stop == 1;
bool ret = DaHuaOriSdk.CLIENT_DHPTZControlEx2(LoginId, Channel, (uint)cmd, speed, speed, 0, stopret, IntPtr.Zero);
if (!ret) BuildException();
return ret;
}
public override bool PtzPreset(int cmd, int presetId)
{
if (!ConnectSuccess()) return false;
bool ret = DaHuaOriSdk.CLIENT_DHPTZControlEx2(LoginId, Channel, (uint)DaHuaOriSdk.EM_EXTPTZ_ControlType.POINT_MOVE, 0, presetId, 0, false, IntPtr.Zero);
if (!ret) BuildException();
return ret;
}
#endregion Ptz Method
#region Video Method
private IntPtr RealplayHandle { get; set; } = IntPtr.Zero;
public override void StartPlay(IntPtr hwnd)
{
if (!ConnectSuccess() || IsPlaying()) return;
RealplayHandle = DaHuaOriSdk.CLIENT_RealPlayEx(LoginId, Channel, hwnd, DaHuaOriSdk.EM_RealPlayType.Realplay);
if (RealplayHandle == IntPtr.Zero) BuildException();
}
public override void StopPlay()
{
if (!IsPlaying()) return;
bool ret = DaHuaOriSdk.CLIENT_StopRealPlayEx(RealplayHandle);
RealplayHandle = IntPtr.Zero;
if (!ret) BuildException();
}
public override bool IsPlaying()
{
return RealplayHandle != IntPtr.Zero;
}
#endregion Video Method
}

402
EC.Util/CameraSDK/HiK/HiKOriSdk.cs

@ -0,0 +1,402 @@
//#define Win32
#define Win64
//#define Linux32
//#define Linux64
using System.Runtime.InteropServices;
namespace EC.Util.CameraSDK;
public class HiKOriSdk
{
#region Fields
#if Win32
public const string LibSdkPath = @"./libs/hik/win32/HCNetSDK.dll";
#elif Win64
public const string LibSdkPath = @"./libs/hik/win64/HCNetSDK.dll";
#elif Linux32
public const string LibSdkPath = @"./libs/hik/linux32/libhcnetsdk.so";
#elif Linux64
public const string LibSdkPath = @"./libs/hik/linux64/libhcnetsdk.so";
#endif
private const bool Debug = true;
#endregion Fields
static HiKOriSdk()
{
GlobalInit();
}
#region Global
public static bool InitSuccess { get; private set; }
public static bool GlobalInit()
{
if (InitSuccess) return true;
bool ret = NET_DVR_Init();
InitSuccess = ret;
if (!ret) throw new Exception("HiKOriSdk global init failure.");
if (Debug) NET_DVR_SetLogToFile(3, Path.Combine("./log", "hikSdkLog"), true);
return ret;
}
public static bool GlobalDestory()
{
if (!InitSuccess) return true;
bool ret = NET_DVR_Cleanup();
if (ret) InitSuccess = false;
return ret;
}
#endregion Global
#region Sdk Const
public const int SERIALNO_LEN = 48; //序列号长度
public const int PtzSpeedMin = 1;
public const int PtzSpeedMax = 7;
public const int NET_DVR_DEV_ADDRESS_MAX_LEN = 129;
public const int NET_DVR_LOGIN_USERNAME_MAX_LEN = 64;
public const int NET_DVR_LOGIN_PASSWD_MAX_LEN = 64;
#region 用于 NET_DVR_SetDVRConfig 和 NET_DVR_GetDVRConfig
public const int NET_DVR_SET_PTZPOS = 292; //云台设置PTZ位置
public const int NET_DVR_GET_PTZPOS = 293; //云台获取PTZ位置
public const int NET_DVR_GET_PTZSCOPE = 294; //云台获取PTZ范围
#endregion 用于 NET_DVR_SetDVRConfig 和 NET_DVR_GetDVRConfig
/********************预览回调函数*********************/
public const int NET_DVR_SYSHEAD = 1;//系统头数据
public const int NET_DVR_STREAMDATA = 2;//视频流数据(包括复合流和音视频分开的视频流数据)
public const int NET_DVR_AUDIOSTREAMDATA = 3;//音频流数据
public const int NET_DVR_STD_VIDEODATA = 4;//标准视频流数据
public const int NET_DVR_STD_AUDIODATA = 5;//标准音频流数据
#region PtzMove
public const int ZOOM_IN = 11;// 焦距以速度SS变大(倍率变大)
public const int ZOOM_OUT = 12;// 焦距以速度SS变小(倍率变小)
public const int FOCUS_NEAR = 13;// 焦点以速度SS前调
public const int FOCUS_FAR = 14;// 焦点以速度SS后调
public const int IRIS_OPEN = 15;// 光圈以速度SS扩大
public const int IRIS_CLOSE = 16;// 光圈以速度SS缩小
public const int TILT_UP = 21; /* 云台以SS的速度上仰 */
public const int TILT_DOWN = 22; /* 云台以SS的速度下俯 */
public const int PAN_LEFT = 23; /* 云台以SS的速度左转 */
public const int PAN_RIGHT = 24; /* 云台以SS的速度右转 */
public const int UP_LEFT = 25; /* 云台以SS的速度上仰和左转 */
public const int UP_RIGHT = 26; /* 云台以SS的速度上仰和右转 */
public const int DOWN_LEFT = 27; /* 云台以SS的速度下俯和左转 */
public const int DOWN_RIGHT = 28; /* 云台以SS的速度下俯和右转 */
public const int PAN_AUTO = 29; /* 云台以SS的速度左右自动扫描 */
public const int GOTO_PRESET = 39; /* 快球转到预置点 */
#endregion PtzMove
#endregion Sdk Const
#region Sdk Struct
//NET_DVR_Login()参数结构
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_DEVICEINFO
{
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = SERIALNO_LEN,
ArraySubType = UnmanagedType.I1
)]
public byte[] sSerialNumber; //序列号
public byte byAlarmInPortNum; //DVR报警输入个数
public byte byAlarmOutPortNum; //DVR报警输出个数
public byte byDiskNum; //DVR硬盘个数
public byte byDVRType; //DVR类型, 1:DVR 2:ATM DVR 3:DVS ......
public byte byChanNum; //DVR 通道个数
public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1
}
//NET_DVR_Login_V30()参数结构
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_DEVICEINFO_V30
{
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = SERIALNO_LEN,
ArraySubType = UnmanagedType.I1
)]
public byte[] sSerialNumber; //序列号
public byte byAlarmInPortNum; //报警输入个数
public byte byAlarmOutPortNum; //报警输出个数
public byte byDiskNum; //硬盘个数
public byte byDVRType; //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
public byte byChanNum; //模拟通道个数
public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1
public byte byAudioChanNum; //语音通道数
public byte byIPChanNum; //最大数字通道个数,低位
public byte byZeroChanNum; //零通道编码个数 //2010-01-16
public byte byMainProto; //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp
public byte bySubProto; //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp
public byte bySupport; //能力,位与结果为0表示不支持,1表示支持,
//bySupport & 0x1, 表示是否支持智能搜索
//bySupport & 0x2, 表示是否支持备份
//bySupport & 0x4, 表示是否支持压缩参数能力获取
//bySupport & 0x8, 表示是否支持多网卡
//bySupport & 0x10, 表示支持远程SADP
//bySupport & 0x20, 表示支持Raid卡功能
//bySupport & 0x40, 表示支持IPSAN 目录查找
//bySupport & 0x80, 表示支持rtp over rtsp
public byte bySupport1; // 能力集扩充,位与结果为0表示不支持,1表示支持
//bySupport1 & 0x1, 表示是否支持snmp v30
//bySupport1 & 0x2, 支持区分回放和下载
//bySupport1 & 0x4, 是否支持布防优先级
//bySupport1 & 0x8, 智能设备是否支持布防时间段扩展
//bySupport1 & 0x10, 表示是否支持多磁盘数(超过33个)
//bySupport1 & 0x20, 表示是否支持rtsp over http
//bySupport1 & 0x80, 表示是否支持车牌新报警信息2012-9-28, 且还表示是否支持NET_DVR_IPPARACFG_V40结构体
public byte bySupport2; /*00
bySupport2 & 0x1, URL取流解码
bySupport2 & 0x2, FTPV40
bySupport2 & 0x4, ANR
bySupport2 & 0x8, CCD的通道参数配置
bySupport2 & 0x10,
bySupport2 & 0x20,
bySupport2 & 0x40, */
public ushort wDevType; //设备型号
public byte bySupport3; //能力集扩展,位与结果为0表示不支持,1表示支持
//bySupport3 & 0x1, 表示是否多码流
// bySupport3 & 0x4 表示支持按组配置, 具体包含 通道图像参数、报警输入参数、IP报警输入、输出接入参数、
// 用户参数、设备工作状态、JPEG抓图、定时和时间抓图、硬盘盘组管理
//bySupport3 & 0x8为1 表示支持使用TCP预览、UDP预览、多播预览中的"延时预览"字段来请求延时预览(后续都将使用这种方式请求延时预览)。而当bySupport3 & 0x8为0时,将使用 "私有延时预览"协议。
//bySupport3 & 0x10 表示支持"获取报警主机主要状态(V40)"。
//bySupport3 & 0x20 表示是否支持通过DDNS域名解析取流
public byte byMultiStreamProto; //是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流
public byte byStartDChan; //起始数字通道号,0表示无效
public byte byStartDTalkChan; //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效
public byte byHighDChanNum; //数字通道个数,高位
public byte bySupport4;
public byte byLanguageType; // 支持语种能力,按位表示,每一位0-不支持,1-支持
// byLanguageType 等于0 表示 老设备
// byLanguageType & 0x1表示支持中文
// byLanguageType & 0x2表示支持英文
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = 9,
ArraySubType = UnmanagedType.I1
)]
public byte[] byRes2; //保留
}
public delegate void LOGINRESULTCALLBACK(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser);
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_USER_LOGIN_INFO
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_DEV_ADDRESS_MAX_LEN, ArraySubType = UnmanagedType.I1)]
public byte[] sDeviceAddress;
public byte byUseTransport;
public ushort wPort;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_LOGIN_USERNAME_MAX_LEN, ArraySubType = UnmanagedType.I1)]
public byte[] sUserName;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_LOGIN_PASSWD_MAX_LEN, ArraySubType = UnmanagedType.I1)]
public byte[] sPassword;
public LOGINRESULTCALLBACK cbLoginResult;
public IntPtr pUser;
public bool bUseAsynLogin;
public byte byProxyType; //0:不使用代理,1:使用标准代理,2:使用EHome代理
public byte byUseUTCTime; //0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换
public byte byLoginMode; //0-Private, 1-ISAPI, 2-自适应
public byte byHttps; //0-不适用tls,1-使用tls 2-自适应
public int iProxyID; //代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值
public byte byVerifyMode; //认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 119, ArraySubType = UnmanagedType.I1)]
public byte[] byRes3;
}
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_DEVICEINFO_V40
{
public NET_DVR_DEVICEINFO_V30 struDeviceV30;
public byte bySupportLock; //设备支持锁定功能,该字段由SDK根据设备返回值来赋值的。bySupportLock为1时,dwSurplusLockTime和byRetryLoginTime有效
public byte byRetryLoginTime; //剩余可尝试登陆的次数,用户名,密码错误时,此参数有效
public byte byPasswordLevel; //admin密码安全等级0-无效,1-默认密码,2-有效密码,3-风险较高的密码。当用户的密码为出厂默认密码(12345)或者风险较高的密码时,上层客户端需要提示用户更改密码。
public byte byProxyType;//代理类型,0-不使用代理, 1-使用socks5代理, 2-使用EHome代理
public uint dwSurplusLockTime; //剩余时间,单位秒,用户锁定时,此参数有效
public byte byCharEncodeType; //字符编码类型(SDK所有接口返回的字符串编码类型,透传接口除外):0- 无字符编码信息(老设备),1- GB2312(简体中文),2- GBK,3- BIG5(繁体中文),4- Shift_JIS(日文),5- EUC-KR(韩文),6- UTF-8,7- ISO8859-1,8- ISO8859-2,9- ISO8859-3,…,依次类推,21- ISO8859-15(西欧)
public byte bySupportDev5;//支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节
public byte bySupport; //能力集扩展,位与结果:0- 不支持,1- 支持
// bySupport & 0x1: 保留
// bySupport & 0x2: 0-不支持变化上报 1-支持变化上报
public byte byLoginMode; //登录模式 0-Private登录 1-ISAPI登录
public int dwOEMCode;
public int iResidualValidity; //该用户密码剩余有效天数,单位:天,返回负值,表示密码已经超期使用,例如“-3表示密码已经超期使用3天”
public byte byResidualValidity; // iResidualValidity字段是否有效,0-无效,1-有效
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 243, ArraySubType = UnmanagedType.I1)]
public byte[] byRes2;
}
//球机位置信息
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_PTZPOS
{
public ushort wAction; //获取时该字段无效
public ushort wPanPos; //水平参数
public ushort wTiltPos; //垂直参数
public ushort wZoomPos; //变倍参数
}
//球机范围信息
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_PTZSCOPE
{
public ushort wPanPosMin; //水平参数min
public ushort wPanPosMax; //水平参数max
public ushort wTiltPosMin; //垂直参数min
public ushort wTiltPosMax; //垂直参数max
public ushort wZoomPosMin; //变倍参数min
public ushort wZoomPosMax; //变倍参数max
}
//邦诺CVR
public const int MAX_ID_COUNT = 256;
public const int MAX_STREAM_ID_COUNT = 1024;
public const int STREAM_ID_LEN = 32;
public const int PLAN_ID_LEN = 32;
//预览V40接口
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_PREVIEWINFO
{
public int lChannel; //通道号
public uint dwStreamType; // 码流类型,0-主码流,1-子码流,2-码流3,3-码流4 等以此类推
public uint dwLinkMode; // 0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-RTP/RTSP,5-RSTP/HTTP
public IntPtr hPlayWnd; //播放窗口的句柄,为NULL表示不播放图象
public bool bBlocked; //0-非阻塞取流, 1-阻塞取流, 如果阻塞SDK内部connect失败将会有5s的超时才能够返回,不适合于轮询取流操作.
public bool bPassbackRecord; //0-不启用录像回传,1启用录像回传
public byte byPreviewMode; //预览模式,0-正常预览,1-延迟预览
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = STREAM_ID_LEN,
ArraySubType = UnmanagedType.I1
)]
public byte[] byStreamID; //流ID,lChannel为0xffffffff时启用此参数
public byte byProtoType; //应用层取流协议,0-私有协议,1-RTSP协议
public byte byRes1;
public byte byVideoCodingType; //码流数据编解码类型 0-通用编码数据 1-热成像探测器产生的原始数据(温度数据的加密信息,通过去加密运算,将原始数据算出真实的温度值)
public uint dwDisplayBufNum; //播放库播放缓冲区最大缓冲帧数,范围1-50,置0时默认为1
public byte byNPQMode; //NPQ是直连模式,还是过流媒体 0-直连 1-过流媒体
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = 215,
ArraySubType = UnmanagedType.I1
)]
public byte[] byRes;
}
#endregion Sdk Struct
#region Common Method
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_Init();
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_Cleanup();
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_SetLogToFile(int bLogEnable, string strLogDir, bool bAutoDel);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern uint NET_DVR_GetLastError();
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern int NET_DVR_Login_V30(string sDVRIP, int wDVRPort, string sUserName, string sPassword, ref NET_DVR_DEVICEINFO_V30 lpDeviceInfo);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern int NET_DVR_Login_V40(ref NET_DVR_USER_LOGIN_INFO pLoginInfo, ref NET_DVR_DEVICEINFO_V40 lpDeviceInfo);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_Logout(int iUserID);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_SetReconnect(uint dwInterval, int bEnableRecon);
//参数配置 begin
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_GetDVRConfig(int lUserID, uint dwCommand, int lChannel, IntPtr lpOutBuffer, uint dwOutBufferSize, ref uint lpBytesReturned);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_PTZControlWithSpeed_Other(int lUserID, int lChannel, uint dwPTZCommand, uint dwStop, uint dwSpeed);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_PTZPreset_Other(int lUserID, int lChannel, uint dwPTZPresetCmd, uint dwPresetIndex);
/*********************************************************
Function: REALDATACALLBACK
Desc:
Input: lRealHandle
dwDataType
pBuffer
dwBufSize
pUser
Output:
Return: void
**********************************************************/
public delegate void RealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser);
/*********************************************************
Function: NET_DVR_RealPlay_V40
Desc:
Input: lUserID [in] NET_DVR_Login()NET_DVR_Login_V30()
lpPreviewInfo [in]
fRealDataCallBack_V30 [in]
pUser [in]
Output:
Return: 1NET_DVR_StopRealPlay等函数的句柄参数
**********************************************************/
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern int NET_DVR_RealPlay_V40(int iUserID, ref NET_DVR_PREVIEWINFO lpPreviewInfo, RealDataCallBack fRealDataCallBack_V30, IntPtr pUser);
/*********************************************************
Function: NET_DVR_StopRealPlay
Desc:
Input: lRealHandle [in] NET_DVR_RealPlay或者NET_DVR_RealPlay_V30的返回值
Output:
Return:
**********************************************************/
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool NET_DVR_StopRealPlay(int iRealHandle);
#endregion Common Method
}

275
EC.Util/CameraSDK/HiK/HiKSdk.cs

@ -0,0 +1,275 @@
using System.Runtime.InteropServices;
using System.Text;
namespace EC.Util.CameraSDK;
public class HiKSdk : ICameraSdk
{
#region Fields
private int LoginId { get; set; } = -1;
private int Channel { get; } = 1;
#endregion Fields
public HiKSdk(CameraInfo cameraInfo) : base(cameraInfo)
{
}
#region Base Method
public override bool Init()
{
bool ret = ConnectSuccess();
if (ret) return true;
HiKOriSdk.NET_DVR_USER_LOGIN_INFO loginInfo = new()
{
bUseAsynLogin = false,
sDeviceAddress = new byte[129],
wPort = (ushort)CameraInfo.Port,
sUserName = new byte[64],
sPassword = new byte[64]
};
Encoding.Default.GetBytes(CameraInfo.Ip).CopyTo(loginInfo.sDeviceAddress, 0);
Encoding.Default.GetBytes(CameraInfo.UserName).CopyTo(loginInfo.sUserName, 0);
Encoding.Default.GetBytes(CameraInfo.Password).CopyTo(loginInfo.sPassword, 0);
HiKOriSdk.NET_DVR_DEVICEINFO_V40 deviceInfo = new();
LoginId = HiKOriSdk.NET_DVR_Login_V40(ref loginInfo, ref deviceInfo);
ret = ConnectSuccess();
if (ret) HiKOriSdk.NET_DVR_SetReconnect(10000, 1);
else BuildException();
//HiKOriSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new();
//LoginId = HiKOriSDK.NET_DVR_Login_V30(CameraInfo.Ip, CameraInfo.Port, CameraInfo.UserName, CameraInfo.Password, ref deviceInfo);
return ret;
}
public override bool Destory()
{
bool ret = ConnectSuccess();
if (!ret) return true;
ret = HiKOriSdk.NET_DVR_Logout(LoginId);
if (ret) LoginId = -1;
else BuildException();
return ret;
}
public override bool ConnectSuccess()
{
return LoginId >= 0;
}
internal override void BuildException()
{
uint errCode = HiKOriSdk.NET_DVR_GetLastError();
if (errCode == 0) return;
throw CameraException.New(CameraInfo, (int)errCode);
}
private void BuildPlayCtrlException(int nPort)
{
string err = $"PlayCtrlSdk failed, error code={PlayCtrlSdk.PlayM4_GetLastError(nPort)}";
throw CameraException.New(CameraInfo, -1, err);
}
#endregion Base Method
#region Ptz Method
private static class GPIParams
{
public static int Size { get; private set; }
public static Type Type { get; private set; }
static GPIParams()
{
HiKOriSdk.NET_DVR_PTZPOS ptzPos = new();
Size = Marshal.SizeOf(ptzPos);
Type = ptzPos.GetType();
}
}
public override PtzInfo GetPtzInfo()
{
bool ret = ConnectSuccess();
if (!ret) return PtzInfo.Default;
HiKOriSdk.NET_DVR_PTZPOS entity = new();
int dwSize = GPIParams.Size;
uint dwReturned = 0;
IntPtr ptrBuf = Marshal.AllocHGlobal(dwSize);
Marshal.StructureToPtr(entity, ptrBuf, true);
try
{
ret = HiKOriSdk.NET_DVR_GetDVRConfig(LoginId, HiKOriSdk.NET_DVR_GET_PTZPOS, 0, ptrBuf, (uint)dwSize, ref dwReturned);
if (!ret) { BuildException(); return PtzInfo.Default; }
object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type);
if (objBuf == null) return PtzInfo.Default;
entity = (HiKOriSdk.NET_DVR_PTZPOS)objBuf;
return PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos);
}
finally
{
Marshal.FreeHGlobal(ptrBuf);
}
}
public override bool TryGetPtzInfo(out PtzInfo ptzInfo)
{
bool ret = ConnectSuccess();
if (!ret) { ptzInfo = PtzInfo.Default; return false; }
HiKOriSdk.NET_DVR_PTZPOS entity = new();
int dwSize = GPIParams.Size;
uint dwReturned = 0;
IntPtr ptrBuf = Marshal.AllocHGlobal(dwSize);
Marshal.StructureToPtr(entity, ptrBuf, true);
try
{
ret = HiKOriSdk.NET_DVR_GetDVRConfig(LoginId, HiKOriSdk.NET_DVR_GET_PTZPOS, 0, ptrBuf, (uint)dwSize, ref dwReturned);
if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; }
object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type);
if (objBuf == null) { ptzInfo = PtzInfo.Default; return false; }
entity = (HiKOriSdk.NET_DVR_PTZPOS)objBuf;
ptzInfo = PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos);
return true;
}
finally
{
Marshal.FreeHGlobal(ptrBuf);
}
}
public override bool PtzMove(int cmd, int stop, int speed)
{
if (!ConnectSuccess()) return false;
bool ret = HiKOriSdk.NET_DVR_PTZControlWithSpeed_Other(LoginId, Channel, (uint)cmd, (uint)stop, (uint)speed);
if (!ret) BuildException();
return ret;
}
public override bool PtzPreset(int cmd, int presetId)
{
if (!ConnectSuccess()) return false;
bool ret = HiKOriSdk.NET_DVR_PTZPreset_Other(LoginId, Channel, (uint)cmd, (uint)presetId);
if (!ret) BuildException();
return ret;
}
#endregion Ptz Method
#region Video Method
private int RealplayHandle { get; set; } = -1;
private int RealpalyPort { get; set; } = -1;
private IntPtr Hwnd { get; set; }
public override void StartPlay(IntPtr hwnd)
{
if (!ConnectSuccess() || IsPlaying()) return;
Hwnd = hwnd;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) StartPlayWindows();
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) StartPlayLinux();
else Hwnd = IntPtr.Zero;
}
private void StartPlayWindows()
{
HiKOriSdk.NET_DVR_PREVIEWINFO previewInfo = new()
{
hPlayWnd = Hwnd, //预览窗口
lChannel = 1, //预览的设备通道
dwStreamType = 0, //码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
dwLinkMode = 0, //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
bBlocked = true, //0- 非阻塞取流,1- 阻塞取流
};
IntPtr pUser = new(); //用户数据
RealplayHandle = HiKOriSdk.NET_DVR_RealPlay_V40(LoginId, ref previewInfo, null, pUser);
if (RealplayHandle < 0) BuildException();
}
private void StartPlayLinux()
{
if (RealpalyPort < 0)
{
int nPort = -1;
bool ret = PlayCtrlSdk.PlayM4_GetPort(ref nPort);
if (!ret) BuildPlayCtrlException(nPort);
RealpalyPort = nPort;
}
HiKOriSdk.NET_DVR_PREVIEWINFO previewInfo = new()
{
hPlayWnd = IntPtr.Zero, //预览窗口
lChannel = 1, //预览的设备通道
dwStreamType = 0, //码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
dwLinkMode = 0, //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
bBlocked = true, //0- 非阻塞取流,1- 阻塞取流
};
RealplayHandle = HiKOriSdk.NET_DVR_RealPlay_V40(LoginId, ref previewInfo, RealDataCallBack, IntPtr.Zero);
if (RealplayHandle < 0) BuildException();
}
private void RealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser)
{
if (dwBufSize <= 0) return;
switch (dwDataType)
{
case HiKOriSdk.NET_DVR_SYSHEAD:
try
{
PlayCtrlSdk.PlayM4_SetStreamOpenMode(RealpalyPort, 0);
PlayCtrlSdk.PlayM4_OpenStream(RealpalyPort, pBuffer, dwBufSize, 2 * 1024 * 1024);
if (!PlayCtrlSdk.PlayM4_Play(RealpalyPort, Hwnd)) BuildPlayCtrlException(RealpalyPort);
}
catch (Exception)
{
StopPlay();
throw;
}
break;
case HiKOriSdk.NET_DVR_STREAMDATA:
PlayCtrlSdk.PlayM4_InputData(RealpalyPort, pBuffer, dwBufSize);
break;
}
}
public override void StopPlay()
{
if (!IsPlaying()) return;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) StopPlayWindows();
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) StopPlayLinux();
Hwnd = IntPtr.Zero;
}
public void StopPlayWindows()
{
bool ret = HiKOriSdk.NET_DVR_StopRealPlay(RealplayHandle);
RealplayHandle = -1;
if (!ret) BuildException();
}
public void StopPlayLinux()
{
bool ret = HiKOriSdk.NET_DVR_StopRealPlay(RealplayHandle);
RealplayHandle = -1;
if (RealpalyPort >= 0)
{
//if(!PlayCtrlSdk.PlayM4_Stop(RealpalyPort)) BuildPlayCtrlException(RealpalyPort);
PlayCtrlSdk.PlayM4_Stop(RealpalyPort);
PlayCtrlSdk.PlayM4_CloseStream(RealpalyPort);
PlayCtrlSdk.PlayM4_FreePort(RealpalyPort);
RealpalyPort = -1;
}
if (!ret) BuildException();
}
public override bool IsPlaying()
{
return RealplayHandle >= 0;
}
#endregion Video Method
}

77
EC.Util/CameraSDK/HiK/PlayCtrlSdk.cs

@ -0,0 +1,77 @@
//#define Win32
#define Win64
//#define Linux32
//#define Linux64
using System.Runtime.InteropServices;
namespace EC.Util.CameraSDK;
public class PlayCtrlSdk
{
#region Fields
#if Win32
public const string LibSdkPath = @"./libs/hik/win32/PlayCtrl.dll";
#elif Win64
public const string LibSdkPath = @"./libs/hik/win64/PlayCtrl.dll";
#elif Linux32
public const string LibSdkPath = @"./libs/hik/linux32/libPlayCtrl.so";
#elif Linux64
public const string LibSdkPath = @"./libs/hik/linux64/libPlayCtrl.so";
#endif
#endregion Fields
static PlayCtrlSdk()
{
}
#region Sdk Struct
public struct FRAME_INFO
{
public int nWidth;
public int nHeight;
public int nStamp;
public int nType;
public int nFrameRate;
public uint dwFrameNum;
}
#endregion Sdk Struct
#region Sdk Method
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_GetPort(ref int nPort);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_FreePort(int nPort);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern uint PlayM4_GetLastError(int nPort);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_SetStreamOpenMode(int nPort, uint nMode);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_OpenStream(int nPort, IntPtr pFileHeadBuf, uint nSize, uint nBufPoolSize);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_CloseStream(int nPort);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_SetDisplayBuf(int nPort, uint nNum);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_InputData(int nPort, IntPtr pBuf, uint nSize);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_Play(int nPort, IntPtr hWnd);
[DllImport(LibSdkPath, CallingConvention = CallingConvention.StdCall)]
public static extern bool PlayM4_Stop(int nPort);
#endregion Sdk Method
}

244
EC.Util/CameraSDK/YuShi/YuShiOriSdk.cs

@ -0,0 +1,244 @@
//#define Win32
#define Win64
//#define Linux32
//#define Linux64
using System.Runtime.InteropServices;
namespace EC.Util.CameraSDK;
public class YuShiOriSdk
{
#region Fields
#if Win32
public const string LibSdkPath = @"./libs/yushi/win32/NetDEVSDK.dll";
#elif Win64
public const string LibSdkPath = @"./libs/yushi/win64/NetDEVSDK.dll";
#elif Linux32
public const string LibSdkPath = @"./libs/yushi/linux64/libNetDEVSDK.so";
#elif Linux64
public const string LibSdkPath = @"./libs/yushi/linux64/libNetDEVSDK.so";
#endif
private const bool Debug = true;
#endregion Fields
static YuShiOriSdk()
{
GlobalInit();
}
#region Global
public static bool InitSuccess { get; private set; }
public static bool GlobalInit()
{
if (InitSuccess) return true;
bool ret = NETDEV_Init();
InitSuccess = ret;
if (!ret) throw new Exception("YuShiOriSDK global init failure.");
return ret;
}
public static bool GlobalDestory()
{
if (!InitSuccess) return true;
bool ret = NETDEV_Cleanup();
if (ret) InitSuccess = false;
return ret;
}
#endregion Global
#region Sdk Const
public const int TRUE = 1;
public const int FALSE = 0;
public const int PtzSpeedMin = 1;
public const int PtzSpeedMax = 9;
/* Common length */
public const int NETDEV_LEN_64 = 64;
public const int NETDEV_LEN_128 = 128;
public const int NETDEV_LEN_132 = 132;
public const int NETDEV_LEN_260 = 260;
/* NETDEV_PTZ_E */
public const int IRISCLOSE_STOP = 0x0101; /* Iris close stop */
public const int IRISCLOSE = 0x0102; /* Iris close */
public const int IRISOPEN_STOP = 0x0103; /* Iris open stop */
public const int IRISOPEN = 0x0104; /* Iris open */
public const int FOCUSNEAR_STOP = 0x0201; /* Focus near stop */
public const int FOCUSNEAR = 0x0202; /* Focus near */
public const int FOCUSFAR_STOP = 0x0203; /* Focus far stop */
public const int FOCUSFAR = 0x0204; /* Focus far */
public const int ZOOMTELE_STOP = 0x0301; /* Zoom in stop */
public const int ZOOMTELE = 0x0302; /* Zoom in */
public const int ZOOMWIDE_STOP = 0x0303; /* Zoom out stop */
public const int ZOOMWIDE = 0x0304; /* Zoom out */
public const int TILTUP = 0x0402; /* Tilt up */
public const int TILTDOWN = 0x0404; /* Tilt down */
public const int PANRIGHT = 0x0502; /* Pan right */
public const int PANLEFT = 0x0504; /* Pan left */
public const int LEFTUP = 0x0702; /* Move up left */
public const int LEFTDOWN = 0x0704; /* Move down left */
public const int RIGHTUP = 0x0802; /* Move up right */
public const int RIGHTDOWN = 0x0804; /* Move down right */
public const int ALLSTOP = 0x0901; /* All-stop command word */
public const int FOCUS_AND_IRIS_STOP = 0x0907; /* Focus & Iris-stop command word */
public const int MOVE_STOP = 0x0908; /* move stop command word */
public const int ZOOM_STOP = 0x0909; /* zoom stop command word */
/* NETDEV_PTZ_PRESETCMD_E */
public const int PRESET_SET = 0; /* Set preset */
public const int PRESET_CLE = 1; /* Clear preset */
public const int PRESET_GOTO = 2; /* Go to preset */
public enum NETDEV_LIVE_STREAM_INDEX_E : int
{
NETDEV_LIVE_STREAM_INDEX_MAIN = 0, /* Main stream */
NETDEV_LIVE_STREAM_INDEX_SUB = 1, /* Sub stream */
NETDEV_LIVE_STREAM_INDEX_THIRD = 2, /* Third stream */
NETDEV_LIVE_STREAM_INDEX_INVALID
}
public enum NETDEV_PROTOCAL_E : int
{
NETDEV_TRANSPROTOCAL_RTPUDP = 0, /* UDP */
NETDEV_TRANSPROTOCAL_RTPTCP = 1 /* TCP */
}
public enum NETDEV_PICTURE_FLUENCY_E
{
NETDEV_PICTURE_REAL = 0, /* Real-time first */
NETDEV_PICTURE_FLUENCY = 1, /* Fluency first */
NETDEV_PICTURE_BALANCE_NEW = 3, /* Balance */
NETDEV_PICTURE_RTMP_FLUENCY = 4, /* RTMP fluency first */
NETDEV_PICTURE_FLUENCY_INVALID = 0xff /* Invalid value */
}
#endregion Sdk Const
#region Sdk Struct
[StructLayout(LayoutKind.Sequential)]
public struct NETDEV_DEVICE_LOGIN_INFO_S
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_260)]
public string szIPAddr; /* IP地址/域名 */
public int dwPort; /* 端口号 */
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_132)]
public string szUserName; /* 用户名 */
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_128)]
public string szPassword; /* 密码 */
public int dwLoginProto; /* 登录协议, 参见NETDEV_LOGIN_PROTO_E */
public int dwDeviceType; /* 设备类型, 参见NETDEV_DEVICE_TYPE_E */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] byRes; /* Reserved */
};
[StructLayout(LayoutKind.Sequential)]
public struct NETDEV_SELOG_INFO_S
{
public int dwSELogCount;
public int dwSELogTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] byRes;
};
[StructLayout(LayoutKind.Sequential)]
public struct NETDEV_VIDEO_CHL_DETAIL_INFO_S
{
public int dwChannelID;
public int bPtzSupported; /* Whether ptz is supported */
public int enStatus; /* Channel status */
public int dwStreamNum; /* Number of streams */
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_64)]
public string szChnName; /* Device serial number */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] szReserve;
}
[StructLayout(LayoutKind.Sequential)]
public struct NETDEV_PTZ_STATUS_S
{
public float fPanTiltX; /* 绝对水平坐标 Absolute horizontal coordinates*/
public float fPanTiltY; /* 绝对竖直坐标 Absolute vertical coordinates*/
public float fZoomX; /* 绝对聚焦倍数 Absolute multiples*/
public int enPanTiltStatus;/* 云台状态 PTZ Status*/
public int enZoomStatus; /* 聚焦状态 Focus Status*/
};
[StructLayout(LayoutKind.Sequential)]
public struct NETDEV_PREVIEWINFO_S
{
public int dwChannelID; /* ID Channel ID */
public int dwStreamType; /* #NETDEV_LIVE_STREAM_INDEX_E Stream type, see enumeration #NETDEV_LIVE_STREAM_INDEX_E */
public int dwLinkMode; /* #NETDEV_PROTOCAL_E Transport protocol, see enumeration #NETDEV_PROTOCAL_E */
public IntPtr hPlayWnd; /* Play window handle */
public int dwFluency; /* #NETDEV_PICTURE_FLUENCY_E image play fluency*/
public int dwStreamMode; /* #NETDEV_STREAM_MODE_E start stream mode see #NETDEV_STREAM_MODE_E*/
public int dwLiveMode; /* #NETDEV_PULL_STREAM_MODE_E Rev. Flow pattern */
public int dwDisTributeCloud; /* #NETDEV_DISTRIBUTE_CLOUD_SRV_E distribution */
public int dwallowDistribution; /* allow or no distribution*/
public int dwTransType; /* 传输类型,参见枚举# NETDEV_TRANS_TYPE_E */
public int dwStreamProtocol; /* 起流协议,参见枚举# NETDEV_START_STREAM_PROT_E */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 236)]
public byte[] szReserve; /* Reserved */
}
#endregion Sdk Struct
#region Common Method
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool NETDEV_Init();
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool NETDEV_Cleanup();
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int NETDEV_GetLastError();
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr NETDEV_Login_V30(ref NETDEV_DEVICE_LOGIN_INFO_S pstDevLoginInfo, ref NETDEV_SELOG_INFO_S pstSELogInfo);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool NETDEV_Logout(IntPtr lpUserID);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int NETDEV_QueryVideoChlDetailList(IntPtr lpUserID, ref int pdwChlCount, IntPtr pstVideoChlList);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool NETDEV_PTZGetStatus(IntPtr lpUserID, int dwChannelID, ref NETDEV_PTZ_STATUS_S pstPTZStaus);
//public boolean NETDEV_GetDevConfig(Pointer lpUserID, int dwChannelID, int dwCommand, Pointer lpOutBuffer, int dwOutBufferSize, IntByReference pdwBytesReturned);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int NETDEV_PTZControl_Other(IntPtr lpUserID, int dwChannelID, int dwPTZCommand, int dwSpeed);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int NETDEV_PTZPreset_Other(IntPtr lpUserID, int dwChannelID, int dwPTZPresetCmd, byte[] szPresetName, int dwPresetID);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr NETDEV_RealPlay(IntPtr lpUserID, ref NETDEV_PREVIEWINFO_S pstPreviewInfo, IntPtr cbPlayDataCallBack, IntPtr lpUserData);
[DllImport(LibSdkPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int NETDEV_StopRealPlay(IntPtr lpRealHandle);
#endregion Common Method
}

136
EC.Util/CameraSDK/YuShi/YuShiSdk.cs

@ -0,0 +1,136 @@
namespace EC.Util.CameraSDK;
public class YuShiSdk : ICameraSdk
{
#region Fields
private IntPtr LoginId { get; set; } = IntPtr.Zero;
private int Channel { get; } = 1;
#endregion Fields
public YuShiSdk(CameraInfo cameraInfo) : base(cameraInfo)
{
}
#region Base Method
public override bool Init()
{
bool ret = ConnectSuccess();
if (ret) return true;
YuShiOriSdk.NETDEV_DEVICE_LOGIN_INFO_S loginInfo = new();
loginInfo.szIPAddr = CameraInfo.Ip;
loginInfo.dwPort = CameraInfo.Port;
loginInfo.szUserName = CameraInfo.UserName;
loginInfo.szPassword = CameraInfo.Password;
YuShiOriSdk.NETDEV_SELOG_INFO_S logInfo = new();
LoginId = YuShiOriSdk.NETDEV_Login_V30(ref loginInfo, ref logInfo);
ret = ConnectSuccess();
if(!ret) BuildException();
return ret;
}
public override bool Destory()
{
bool ret = ConnectSuccess();
if (!ret) return true;
ret = YuShiOriSdk.NETDEV_Logout(LoginId);
if (ret) LoginId = IntPtr.Zero;
else BuildException();
return ret;
}
public override bool ConnectSuccess()
{
return LoginId != IntPtr.Zero;
}
internal override void BuildException()
{
int errCode = YuShiOriSdk.NETDEV_GetLastError();
if (errCode == 0) return;
throw CameraException.New(CameraInfo, errCode);
}
#endregion Base Method
#region Ptz Method
public override PtzInfo GetPtzInfo()
{
bool ret = ConnectSuccess();
if (!ret) return PtzInfo.Default;
YuShiOriSdk.NETDEV_PTZ_STATUS_S entity = new();
ret = YuShiOriSdk.NETDEV_PTZGetStatus(LoginId, Channel, ref entity);
if (!ret) { BuildException(); return PtzInfo.Default; }
return PtzInfo.New(entity.fPanTiltX, entity.fPanTiltY, entity.fZoomX);
}
public override bool TryGetPtzInfo(out PtzInfo ptzInfo)
{
bool ret = ConnectSuccess();
if (!ret) { ptzInfo = PtzInfo.Default; return false; }
YuShiOriSdk.NETDEV_PTZ_STATUS_S entity = new();
ret = YuShiOriSdk.NETDEV_PTZGetStatus(LoginId, Channel, ref entity);
if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; }
ptzInfo = PtzInfo.New(entity.fPanTiltX, entity.fPanTiltY, entity.fZoomX);
return true;
}
public override bool PtzMove(int cmd, int stop, int speed)
{
if (!ConnectSuccess()) return false;
if (stop == 1) cmd = YuShiOriSdk.ALLSTOP;
int retNum = YuShiOriSdk.NETDEV_PTZControl_Other(LoginId, Channel, cmd, speed);
bool ret = retNum == YuShiOriSdk.TRUE;
if (!ret) BuildException();
return ret;
}
public override bool PtzPreset(int cmd, int presetId)
{
if (!ConnectSuccess()) return false;
int retNum = YuShiOriSdk.NETDEV_PTZPreset_Other(LoginId, Channel, cmd, Array.Empty<byte>(), presetId);
bool ret = retNum == YuShiOriSdk.TRUE;
if (!ret) BuildException();
return ret;
}
#endregion Ptz Method
#region Video Method
private IntPtr RealplayHandle { get; set; } = IntPtr.Zero;
public override void StartPlay(IntPtr hwnd)
{
if (!ConnectSuccess() || IsPlaying()) return;
YuShiOriSdk.NETDEV_PREVIEWINFO_S stPreviewInfo = new()
{
hPlayWnd = hwnd,
dwChannelID = Channel,
dwStreamType = 0, // YuShiOriSDK.NETDEV_LIVE_STREAM_INDEX_E
dwLinkMode = 1, // YuShiOriSDK.NETDEV_PROTOCAL_E
dwFluency = 0, // YuShiOriSDK.NETDEV_PICTURE_FLUENCY_E
};
RealplayHandle = YuShiOriSdk.NETDEV_RealPlay(LoginId, ref stPreviewInfo, IntPtr.Zero, IntPtr.Zero);
if (RealplayHandle == IntPtr.Zero) BuildException();
}
public override void StopPlay()
{
if (!IsPlaying()) return;
int ret = YuShiOriSdk.NETDEV_StopRealPlay(RealplayHandle);
RealplayHandle = IntPtr.Zero;
if (ret == YuShiOriSdk.FALSE) BuildException();
}
public override bool IsPlaying()
{
return RealplayHandle != IntPtr.Zero;
}
#endregion Video Method
}

43
EC.Util/Common/JsonUtil.cs

@ -0,0 +1,43 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
namespace EC.Util.Common;
public static class JsonUtil
{
public static object ToJson(string Json)
{
object? obj = JsonConvert.DeserializeObject(Json);
return obj ?? new();
}
public static string ToJson(object obj)
{
IsoDateTimeConverter timeConverter = new() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
return JsonConvert.SerializeObject(obj, timeConverter);
}
public static string ToJson(object obj, string datetimeformats)
{
IsoDateTimeConverter timeConverter = new() { DateTimeFormat = datetimeformats };
return JsonConvert.SerializeObject(obj, timeConverter);
}
public static T ToObject<T>(string Json)
{
T? obj = JsonConvert.DeserializeObject<T>(Json);
return obj ?? Activator.CreateInstance<T>();
}
public static List<T> ToList<T>(string Json)
{
List<T>? list = JsonConvert.DeserializeObject<List<T>>(Json);
return list ?? new List<T>();
}
public static JObject ToJObject(string Json)
{
return Json != null ? JObject.Parse(Json.Replace("&nbsp;", "")) : JObject.Parse("{}");
}
}

40
EC.Util/Common/LogUnit.cs

@ -0,0 +1,40 @@
using log4net;
using log4net.Config;
namespace EC.Util.Common;
public class LogUnit
{
private static readonly ILog logger;
static LogUnit()
{
string fileName = Path.Combine("config", "log4net.config");
if (!File.Exists(fileName)) throw new FileNotFoundException(fileName);
XmlConfigurator.Configure(new FileInfo(fileName));
logger = LogManager.GetLogger(typeof(LogUnit));
}
public static void Init()
{ }
public static void Debug(string msg) => logger.Debug(msg);
public static void Info(string msg) => logger.Info(msg);
public static void Warn(string msg) => logger.Warn(msg);
public static void Fatal(string msg) => logger.Fatal(msg);
public static void Error(string msg) => logger.Error(msg);
public static void Error(Exception e) => logger.Error(e);
public static void Error(object obj, string msg) => logger.Error(obj.GetType(), new Exception(msg));
public static void Error(object obj, Exception e) => logger.Error(obj.GetType(), e);
public static void Error(Type type, string msg) => logger.Error(type, new Exception(msg));
public static void Error(Type type, Exception e) => logger.Error(type, e);
}

36
EC.Util/Common/NetworkUtil.cs

@ -0,0 +1,36 @@
using System.Net.Sockets;
namespace EC.Util.Common;
public static class NetworkUtil
{
public static string LocalAddr(this TcpClient client)
{
return client.Client.LocalEndPoint?.ToString() ?? ":";
}
public static string LocalIp(this TcpClient client)
{
return LocalAddr(client).Split(':')[0];
}
public static string LocalPort(this TcpClient client)
{
return LocalAddr(client).Split(':')[1];
}
public static string ClientAddr(this TcpClient client)
{
return client.Client.RemoteEndPoint?.ToString() ?? ":";
}
public static string ClientIp(this TcpClient client)
{
return ClientAddr(client).Split(':')[0];
}
public static string ClientPort(this TcpClient client)
{
return ClientAddr(client).Split(':')[1];
}
}

40
EC.Util/Common/TaskUtil.cs

@ -0,0 +1,40 @@
namespace EC.Util.Common;
public class TaskUtil
{
public static Task Run(Action action)
{
Task.Run(action);
return Task.Run(action);
}
/// <summary>
/// 相比于 Run,直接捕获并记录异常
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public static Task RunCatch(Action action)
{
return Task.Run(() =>
{
try
{
action();
}
catch (Exception e)
{
LogUnit.Error(typeof(TaskUtil), e);
}
});
}
/// <summary>
/// 相比于 Run,能及时抛出并全局捕获异常
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public static Task LongRun(Action action)
{
return Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);
}
}

176
EC.Util/Common/VerifyUtil.cs

@ -0,0 +1,176 @@
using System.Text.RegularExpressions;
namespace EC.Util.Common;
/// <summary>
/// 验证工具类
/// </summary>
public class VerifyUtil
{
/// <summary>
/// 验证是否为空
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static bool IsEmpty(string str)
{
return string.IsNullOrEmpty(str);
}
/// <summary>
/// 验证是否为邮件
/// </summary>
/// <param name="emailStr"></param>
/// <returns></returns>
public static bool IsEmail(string emailStr)
{
if (string.IsNullOrEmpty(emailStr)) return false;
string match = @"^([a-zA-Z0-9]+[_|\-|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\-|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$";
Regex r = new(match, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return r.IsMatch(emailStr.Trim());
}
/// <summary>
/// 验证是否为数字
/// </summary>
/// <param name="numberStr"></param>
/// <returns></returns>
public static bool IsNumber(string numberStr)
{
if (string.IsNullOrEmpty(numberStr)) return false;
string match = @"^(0|[1-9][0-9]*)$";
Regex r = new(match, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return r.IsMatch(numberStr.Trim());
}
/// <summary>
/// 验证是否为浮点数
/// </summary>
/// <param name="decimalStr"></param>
/// <returns></returns>
public static bool IsDecimal(string decimalStr)
{
if (string.IsNullOrEmpty(decimalStr)) return false;
string match = @"^(-?\d+)(\.\d+)?$";
Regex r = new(match, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return r.IsMatch(decimalStr.Trim());
}
/// <summary>
/// 验证是否为手机号码
/// </summary>
/// <param name="mobileStr"></param>
/// <returns></returns>
public static bool IsMobile(string mobileStr)
{
if (string.IsNullOrEmpty(mobileStr)) return false;
string match = @"^[1]+[3,5,7,8]+\d{9}";
Regex r = new(match, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return r.IsMatch(mobileStr.Trim());
}
/// <summary>
/// 验证是否为电话号码
/// </summary>
/// <param name="telStr"></param>
/// <returns></returns>
public static bool IsTel(string telStr)
{
if (string.IsNullOrEmpty(telStr)) return false;
string match = @"^(\+86\s{1,1})?((\d{3,4}\-)\d{7,8})$";
Regex r = new(match, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return r.IsMatch(telStr.Trim());
}
/// <summary>
/// 验证是否为Ip地址
/// </summary>
/// <param name="ipStr"></param>
/// <returns></returns>
public static bool IsIp(string ipStr)
{
if (string.IsNullOrEmpty(ipStr)) return false;
string match = @"^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$";
Regex r = new(match);
return r.IsMatch(ipStr.Trim());
}
/// <summary>
/// 验证是否为身份证
/// </summary>
/// <param name="idcardStr">身份证号</param>
/// <returns></returns>
public static bool CheckIDCard(string idcardStr)
{
if (string.IsNullOrEmpty(idcardStr)) return false;
if (idcardStr.Length == 18) return CheckIDCard18(idcardStr);
else if (idcardStr.Length == 15) return CheckIDCard15(idcardStr);
return false;
}
/// <summary>
/// 18位身份证验证
/// </summary>
/// <param name="Id">身份证号</param>
/// <returns></returns>
private static bool CheckIDCard18(string Id)
{
long n = 0;
if (long.TryParse(Id.Remove(17), out n) == false || n < Math.Pow(10, 16) || long.TryParse(Id.Replace('x', '0').Replace('X', '0'), out n) == false)
{
return false;//数字验证
}
string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
if (address.IndexOf(Id.Remove(2)) == -1)
{
return false;//省份验证
}
string birth = Id.Substring(6, 8).Insert(6, "-").Insert(4, "-");
DateTime time = new DateTime();
if (DateTime.TryParse(birth, out time) == false)
{
return false;//生日验证
}
string[] arrVarifyCode = ("1,0,x,9,8,7,6,5,4,3,2").Split(',');
string[] Wi = ("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2").Split(',');
char[] Ai = Id.Remove(17).ToCharArray();
int sum = 0;
for (int i = 0; i < 17; i++)
{
sum += int.Parse(Wi[i]) * int.Parse(Ai[i].ToString());
}
int y = -1;
Math.DivRem(sum, 11, out y);
if (arrVarifyCode[y] != Id.Substring(17, 1).ToLower())
{
return false;//校验码验证
}
return true;//符合GB11643-1999标准
}
/// <summary>
/// 15位身份证验证
/// </summary>
/// <param name="Id">身份证号</param>
/// <returns></returns>
private static bool CheckIDCard15(string Id)
{
long n = 0;
if (long.TryParse(Id, out n) == false || n < Math.Pow(10, 14))
{
return false;//数字验证
}
string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
if (address.IndexOf(Id.Remove(2)) == -1)
{
return false;//省份验证
}
string birth = Id.Substring(6, 6).Insert(4, "-").Insert(2, "-");
DateTime time = new DateTime();
if (DateTime.TryParse(birth, out time) == false)
{
return false;//生日验证
}
return true;//符合15位身份证标准
}
}

25
EC.Util/EC.Util.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="config\log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="libs\" />
</ItemGroup>
</Project>

60
EC.Util/Port/SerialPortBuilder.cs

@ -0,0 +1,60 @@
namespace EC.Util.Port;
/// <summary>
/// 串口构建类
/// </summary>
public class SerialPortBuilder
{
/// <summary>
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public static YcSerialPort CreateSerialPort(SerialPortParam param)
{
return new YcSerialPort(param);
}
/// <summary>
/// </summary>
/// <param name="comName"></param>
public static YcSerialPort CreateSerialPort(string comName)
{
var param = new SerialPortParam
{
ComName = comName
};
return new YcSerialPort(param);
}
/// <summary>
/// </summary>
/// <param name="comName"></param>
/// <param name="baudRate"></param>
/// <returns></returns>
public static YcSerialPort CreateSerialPort(string comName, int baudRate)
{
var param = new SerialPortParam
{
ComName = comName,
BaudRate = baudRate
};
return new YcSerialPort(param);
}
/// <summary>
/// </summary>
/// <param name="comName"></param>
/// <param name="baudRate"></param>
/// <param name="receivedBytesThreshold"></param>
/// <returns></returns>
public static YcSerialPort CreateSerialPort(string comName, int baudRate, int receivedBytesThreshold)
{
var param = new SerialPortParam
{
ComName = comName,
BaudRate = baudRate,
ReceivedBytesThreshold = receivedBytesThreshold
};
return new YcSerialPort(param);
}
}

56
EC.Util/Port/SerialPortParam.cs

@ -0,0 +1,56 @@
namespace EC.Util.Port;
/// <summary>
/// 串口参数类
/// </summary>
public class SerialPortParam
{
#region Fields
/// <summary>
/// 串口名称
/// </summary>
public string ComName { get; set; }
/// <summary>
///波特率
/// </summary>
public int BaudRate { get; set; }
/// <summary>
/// 奇偶校验0-4=no,odd,even,mark,space
/// </summary>
public int Parity { get; set; }
/// <summary>
/// 校验位对应值
/// </summary>
public int ParityValue { get; set; }
/// <summary>
///数据位 默认
/// </summary>
public int DataBits { get; set; }
/// <summary>
/// 停止位
/// </summary>
public int StopBits { get; set; }
/// <summary>
/// ?Byte时,触发一次事件。设置为1时,易造成线程死锁
/// </summary>
public int ReceivedBytesThreshold { get; set; }
#endregion Fields
public SerialPortParam()
{
ComName = string.Empty;
BaudRate = 9600;
Parity = 0;
DataBits = 8;
StopBits = 1;
ReceivedBytesThreshold = 128;
}
}

166
EC.Util/Port/YcSerialPort.cs

@ -0,0 +1,166 @@
using System.IO.Ports;
using System.Text.RegularExpressions;
namespace EC.Util.Port;
/// <summary>
/// 串口类
/// </summary>
public class YcSerialPort
{
private SerialPort _port;//声明一个串口
private readonly SerialPortParam _param;
public long RecCount { get; set; }//接收计数
public long SendCount { get; set; }//发送计数
public YcSerialPort()
{
}
public YcSerialPort(SerialPortParam param)
{
_param = param;
}
/// <summary>
/// 打开串口
/// </summary>
/// <returns></returns>
public bool OpenCom()
{
if (IsOpen())
CloseCom();
if (string.IsNullOrEmpty(_param.ComName))
throw new Exception("请插入串口设备!");
_port = new SerialPort
{
PortName = _param.ComName,//串口名
BaudRate = _param.BaudRate,//波特率
DataBits = _param.DataBits,//数据位
Parity = (Parity)_param.Parity,//奇偶校验0-4=no,odd,even,mark,space
StopBits = (StopBits)Convert.ToInt32(_param.StopBits),//停止位
ReadTimeout = 500,//读超时
WriteTimeout = 2000,//写超时
//ReadBufferSize = 1024,
//WriteBufferSize = 1024,
ReceivedBytesThreshold = _param.ReceivedBytesThreshold,//128Byte时触发一次事件,设置为1时易造成线程死锁。
RtsEnable = true,
DtrEnable = true,
};
_port.DataReceived += RecData;
//port.DataReceived += new SerialDataReceivedEventHandler(Comm_DataReceived);
_port.Open();
return IsOpen();
}
/// <summary>
/// 关闭串口
/// </summary>
public bool CloseCom()
{
if (IsOpen())
{
_port.Close();
_port = null;
}
return !IsOpen();
}
public bool IsOpen()
{
if (_port == null)
return false;
if (!_port.IsOpen)
return false;
return true;
}
public event EventHandler<byte[]> OnRecData; //定义一个委托类型的事件
private void RecData(object sender, EventArgs e)
{
var count = _port.BytesToRead;//获取缓存区字节数
var buf = new byte[count];//存储串口数据用
_port.Read(buf, 0, count);//读取缓冲数据
RecCount += count;//接收计数
OnRecData?.Invoke(this, buf);
}
/// <summary>
/// 发送 Ascii
/// </summary>
/// <param name="text"></param>
/// <param name="newLine"></param>
public void SendAscii(string text, bool newLine = false)
{
//定义一个变量,记录发送了几个字节
int count;
if (newLine)
{
_port.Write(text + "\r\n");
count = text.Length + 2;
}
else//不包含换行符
{
_port.Write(text);
count = text.Length;
}
SendCount += count;//累加发送字节数
}
/// <summary>
/// 发送 Hex
/// </summary>
/// <param name="text"></param>
/// <param name="newLine"></param>
public void SendHex(string text, bool newLine = false)
{
int count;//定义一个变量,记录发送了几个字节
var mc = Regex.Matches(text, @"(?i)[\da-f]{2}");//正则得到有效的十六进制数(?i)对大小写不敏感,[/da-f],{2}连续出现2次
var buf = new List<byte>();//填充到这个临时列表中
foreach (Match m in mc)
{
buf.Add(byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber));//依次添加到列表中
}
_port.Write(buf.ToArray(), 0, buf.Count);//转换列表为数组后发送
if (newLine)
{
_port.Write("\r\n");
count = buf.Count + 2;
}
else//不包含换行符
{
count = buf.Count;
}
SendCount += count;//累加发送字节数
}
/// <summary>
/// 发送 Hex
/// </summary>
/// <param name="buf"></param>
/// <param name="newline"></param>
public void SendHex(byte[] buf, bool newline = false)
{
int count;//定义一个变量,记录发送了几个字节
var bufLen = buf.Count();
_port.Write(buf, 0, bufLen);
if (newline)
{ //记录发送的字节数
_port.WriteLine("\n");
count = bufLen + 2;
}
else
{
count = bufLen;
}
SendCount += count;//累加发送字节数
}
}

29
EC.Util/config/log4net.config

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<log4net>
<root>
<level value="Info" />
<!--文件形式记录日志-->
<appender-ref ref="RollingLogFileAppender" />
</root>
<!--定义输出到文件中-->
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="logs/" />
<param name="Encoding" value="UTF-8" />
<param name="RollingStyle" value="Date" />
<param name="DatePattern" value="yyyy-MM-dd'.txt'" />
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="AppendToFile" value="true" />
<param name="StaticLogFileName" value="false" />
<param name="MaxSizeRollBackups" value="30" />
<param name="maximumFileSize" value="5MB" />
<layout type="log4net.Layout.PatternLayout">
<!--输出格式-->
<conversionPattern value="【日志级别】%-5level 【记录时间】%date 【线程编号】[%thread]【执行时间】[%r]毫秒 【当前的类】%logger 属性[%property{NDC}]%n【日志描述】%message%n%n" />
</layout>
</appender>
</log4net>
</configuration>

5
JiLinApp/JiLinApp.csproj

@ -23,4 +23,9 @@
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EC.Util\EC.Util.csproj" />
</ItemGroup>
</Project>

23
JiLinApp/Program.cs

@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Media;
using Avalonia.ReactiveUI;
using EC.Util.Common;
using JiLinApp.Core.Avalonia;
using ReactiveUI;
using System;
@ -22,10 +23,9 @@ internal class Program
AppBuilder appBuilder = BuildAvaloniaApp();
appBuilder.StartWithClassicDesktopLifetime(args);
}
catch (Exception)
catch (Exception e)
{
//The global try-catch
throw;
LogUnit.Error(e);
}
}
@ -54,18 +54,29 @@ internal class Program
private static void GlobalInit()
{
// Active to initialize
LogUnit.Init();
// HandleExceptions
// Exceptions from another thread
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
if (e.ExceptionObject is Exception ex) LogUnit.Error(ex);
};
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
e.SetObserved();
LogUnit.Error(e.Exception);
};
// Exceptions from Reactive UI
RxAppExceptionHandler.Instance.OnExceptionHandler += e =>
{
};
RxAppExceptionHandler.Instance.OnExceptionHandler += LogUnit.Error;
RxApp.DefaultExceptionHandler = RxAppExceptionHandler.Instance;
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
throw new NotImplementedException();
}
#endregion extend
}

6
JiLinCpApp.sln

@ -5,6 +5,8 @@ VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiLinApp", "JiLinApp\JiLinApp.csproj", "{9D1063BD-2C84-4FF3-90CF-B16159B3E803}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EC.Util", "EC.Util\EC.Util.csproj", "{B5D7ED30-805C-4A5D-BD41-D2F910806340}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{9D1063BD-2C84-4FF3-90CF-B16159B3E803}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D1063BD-2C84-4FF3-90CF-B16159B3E803}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D1063BD-2C84-4FF3-90CF-B16159B3E803}.Release|Any CPU.Build.0 = Release|Any CPU
{B5D7ED30-805C-4A5D-BD41-D2F910806340}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5D7ED30-805C-4A5D-BD41-D2F910806340}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5D7ED30-805C-4A5D-BD41-D2F910806340}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5D7ED30-805C-4A5D-BD41-D2F910806340}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Loading…
Cancel
Save