fajiao
2 years ago
24 changed files with 3829 additions and 6 deletions
@ -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()); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -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
|
|||
} |
File diff suppressed because it is too large
@ -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
|
|||
} |
@ -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; /*能力,位与结果为0表示不支持,非0表示支持 |
|||
|
|||
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: 1表示失败,其他值作为NET_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
|
|||
} |
@ -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
|
|||
} |
@ -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
|
|||
} |
@ -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
|
|||
} |
@ -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
|
|||
} |
@ -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(" ", "")) : JObject.Parse("{}"); |
|||
} |
|||
} |
@ -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); |
|||
} |
@ -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]; |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -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位身份证标准
|
|||
} |
|||
} |
@ -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> |
@ -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); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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;//累加发送字节数
|
|||
} |
|||
} |
@ -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> |
Loading…
Reference in new issue