單位的項目需要測溫,同事買了個海康威視的人體測溫機芯,型號位:TB 4117 3/S,給了一份pdf的說明書。 按說明書把設備連接設置好,從官網下載了sdk,我的個乖乖,壓縮包就有70多M,把他家的所有東西都給了我,有各種Demo,就是沒有測溫的,暈死,差點想打退堂鼓不玩了。 最後,最後得到如下成果 ...
單位的項目需要測溫,同事買了個海康威視的人體測溫機芯,型號位:TB-4117-3/S,給了一份pdf的說明書。
按說明書把設備連接設置好,從官網下載了sdk,我的個乖乖,壓縮包就有70多M,把他家的所有東西都給了我,有各種Demo,就是沒有測溫的,暈死,差點想打退堂鼓不玩了。
最後,最後得到如下成果:
一、所需的DLL
- HCCore.dll
- HCCoreDevCfg.dll 這玩意必須在運行目錄
- HCGeneralCfgMgr.dll 這鬼也必須在運行目錄
- HCNetSDK.dll
- libeay32.dll
- ssleay32.dll
以上6個文件必須的,幹啥用俺也不知道,反正缺一不可。
二、委托、dll封裝、數據結果
public delegate void LOGINRESULTCALLBACK(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser);
public delegate void UpdateTextStatusCallback(string strLogStatus, IntPtr lpDeviceInfo);
public delegate void RemoteConfigCallback(uint dwType, IntPtr lpBuffer, uint dwBufLen, IntPtr pUserData);
#region DllWrapper
const string DllFileName = "HCNetSDK.dll";
[DllImport(DllFileName)]
public static extern bool NET_DVR_Init();
[DllImport(DllFileName)]
public static extern int NET_DVR_Login_V40(ref NET_DVR_USER_LOGIN_INFO pLoginInfo, ref NET_DVR_DEVICEINFO_V40 lpDeviceInfo);
[DllImportAttribute(DllFileName)]
public static extern int NET_DVR_StartRemoteConfig(int lUserID, int dwCommand, IntPtr lpInBuffer, Int32 dwInBufferLen, RemoteConfigCallback cbStateCallback, IntPtr pUserData);
[DllImport(DllFileName)]
public static extern bool NET_DVR_Logout(int iUserID);
[DllImport(DllFileName)]
public static extern bool NET_DVR_Cleanup();
[DllImport(DllFileName)]
public static extern uint NET_DVR_GetLastError();
#endregion
#region Data
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_THERMOMETRY_UPLOAD
{
public uint dwSize;
public uint dwRelativeTime; // 相對時標
public uint dwAbsTime; // 絕對時標
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
public byte[] szRuleName;//規則名稱
public byte byRuleID;//規則ID號
public byte byRuleCalibType;//規則標定類型 0-點,1-框,2-線
public ushort wPresetNo; //預置點號
[MarshalAs(UnmanagedType.Struct)]
public NET_DVR_POINT_THERM_CFG struPointThermCfg;
[MarshalAs(UnmanagedType.Struct)]
public NET_DVR_LINEPOLYGON_THERM_CFG struLinePolygonThermCfg;
public byte byThermometryUnit;//測溫單位: 0-攝氏度(℃),1-華氏度(℉),2-開爾文(K)
public byte byDataType;//數據狀態類型:0-檢測中,1-開始,2-結束
public byte byRes1;
/*
bit0-中心點測溫:0-不支持,1-支持;
bit1-最高點測溫:0-不支持,1-支持;
bit2-最低點測溫:0-不支持,1-支持;
*/
public byte bySpecialPointThermType;// 是否支持特殊點測溫
public float fCenterPointTemperature;//中心點溫度,精確到小數點後一位(-40-1500),(浮點數+100)*10 (由bySpecialPointThermType判斷是否支持中心點)
public float fHighestPointTemperature;//最高點溫度,精確到小數點後一位(-40-1500),(浮點數+100)*10(由bySpecialPointThermType判斷是否支持最高點)
public float fLowestPointTemperature;//最低點溫度,精確到小數點後一位(-40-1500),(浮點數+100)*10(由bySpecialPointThermType判斷是否支持最低點)
[MarshalAs(UnmanagedType.Struct)]
public NET_VCA_POINT struHighestPoint;//線、框測溫最高溫度位置坐標(當規則標定類型為線、框的時候生效)
[MarshalAs(UnmanagedType.Struct)]
public NET_VCA_POINT struLowestPoint;//線、框測溫最低溫度位置坐標(當規則標定類型為線、框的時候生效)
public byte byIsFreezedata;//是否數據凍結 0-否 1-是
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I1)]
public byte[] byRes2;
public uint dwChan; //通道號,查詢條件中通道號為0xffffffff時該欄位生效
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 88, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_POINT_THERM_CFG
{
public float fTemperature;
public NET_VCA_POINT struPoint;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 120, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_LINEPOLYGON_THERM_CFG
{
public float fMaxTemperature;
public float fMinTemperature;
public float fAverageTemperature;
public float fTemperatureDiff;
public NET_VCA_POLYGON struRegion;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}
public const int VCA_MAX_POLYGON_POINT_NUM = 10;//檢測區域最多支持10個點的多邊形
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_VCA_POLYGON
{
/// DWORD->unsigned int
public uint dwPointNum;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = VCA_MAX_POLYGON_POINT_NUM, ArraySubType = UnmanagedType.Struct)]
public NET_VCA_POINT[] struPos;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_VCA_POINT
{
public float fX;// X軸坐標, 0.001~1
public float fY;//Y軸坐標, 0.001~1
}
[StructLayout(LayoutKind.Sequential)]
public struct NET_DVR_REALTIME_THERMOMETRY_COND
{
public uint dwSize;
public uint dwChan;//通道號,從1開始,0xffffffff代表獲取全部通道
public byte byRuleID; //規則ID 0-代表獲取全部規則,具體規則ID從1開始
/*
1-定時模式:設備每隔一秒上傳各個規則測溫數據的最高溫、最低溫和平均溫度值、溫差
2-溫差模式:若上一秒與下一秒的最高溫或者最低溫或者平均溫或者溫差值的溫差大於等於2攝氏度,則上傳最高溫、最低溫和平均溫度值。若大於等於一個小時溫差值均小於2攝氏度,則上傳最高溫、最低溫、平均溫和溫差值
*/
public byte byMode; //長連接模式, 0-保留(為相容老設備),1-定時模式,2-溫差模式
public ushort wInterval; //上傳間隔,僅溫差模式支持,1~3600S,填0則預設3600S上傳一次
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = UnmanagedType.I1)]
public byte[] byRes; //保留
}
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;
[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; //字元編碼類型
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;
}
public const int SERIALNO_LEN = 48;//序列號長度
//NET_DVR_Login_V30()參數結構
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_DEVICEINFO_V30
{
[MarshalAsAttribute(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表示支持英文
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 9, ArraySubType = UnmanagedType.I1)]
public byte[] byRes2; //保留
}
#endregion
三、測溫
const string IPAddress = "192.168.1.64";
const string UserName = "admin";
const string Password = "13245678";
const ushort PortNo = 8000;
static void Main(string[] args)
{
//初始化
if (!NET_DVR_Init())
{
Console.WriteLine("NET_DVR_Init error!");
return;
}
//登陸
var struLogInfo = new NET_DVR_USER_LOGIN_INFO();
//設備IP地址或者功能變數名稱
byte[] byIP = System.Text.Encoding.Default.GetBytes(IPAddress);
struLogInfo.sDeviceAddress = new byte[129];
byIP.CopyTo(struLogInfo.sDeviceAddress, 0);
//設備用戶名
byte[] byUserName = System.Text.Encoding.Default.GetBytes(UserName);
struLogInfo.sUserName = new byte[64];
byUserName.CopyTo(struLogInfo.sUserName, 0);
//設備密碼
byte[] byPassword = System.Text.Encoding.Default.GetBytes(Password);
struLogInfo.sPassword = new byte[64];
byPassword.CopyTo(struLogInfo.sPassword, 0);
struLogInfo.wPort = PortNo;//設備服務埠號
struLogInfo.bUseAsynLogin = false; //是否非同步登錄:0- 否,1- 是
var DeviceInfo = new NET_DVR_DEVICEINFO_V40();
//登錄設備 Login the device
var m_lUserID = NET_DVR_Login_V40(ref struLogInfo, ref DeviceInfo);
if (m_lUserID < 0)
{
Console.WriteLine("登陸失敗,錯誤代碼:" + NET_DVR_GetLastError()); //登錄失敗,輸出錯誤號
return;
}
//配置測溫
var size = Marshal.SizeOf(typeof(NET_DVR_REALTIME_THERMOMETRY_COND));
NET_DVR_REALTIME_THERMOMETRY_COND struThermCond = new NET_DVR_REALTIME_THERMOMETRY_COND();
struThermCond.dwSize = (uint)size;
struThermCond.byRuleID = 0; //規則ID,0代表獲取全部規則,具體規則ID從1開始
struThermCond.dwChan = 1;// dwChannel; //從1開始,0xffffffff代表獲取全部通道
IntPtr pCond = Marshal.AllocCoTaskMem(size);
Marshal.StructureToPtr(struThermCond, pCond, false);
var ret = NET_DVR_StartRemoteConfig(m_lUserID, 3629, pCond, size, Callback, IntPtr.Zero);
if (ret < 0)
{
Console.WriteLine("配置測溫失敗, 錯誤代碼:" + NET_DVR_GetLastError()); //登錄失敗,輸出錯誤號
return;
}
Console.WriteLine("開始測溫...");
Console.ReadKey();
//退出登錄
NET_DVR_Logout(m_lUserID);
NET_DVR_Cleanup();
}
/// <summary>
/// 只顯示最高溫度
/// </summary>
/// <param name="dwType"></param>
/// <param name="lpBuffer"></param>
/// <param name="dwBufLen"></param>
/// <param name="pUserData"></param>
static void Callback(uint dwType, IntPtr lpBuffer, uint dwBufLen, IntPtr pUserData)
{
var ret = Marshal.PtrToStructure<NET_DVR_THERMOMETRY_UPLOAD>(lpBuffer);
Console.WriteLine(ret.struLinePolygonThermCfg.fMaxTemperature);
}
哎,就這麼點事,弄得很複雜。