package HikSDK /* #cgo windows,amd64 LDFLAGS: -L${SRCDIR}/library/amd64_windows/lib -lHCCore -lhcnetsdk #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/library/amd64_linux/lib -lHCCore -lhcnetsdk #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/library/arm64_linux/lib -lHCCore -lhcnetsdk #cgo windows,amd64 CFLAGS: -I${SRCDIR}/library/amd64_windows/include #cgo linux,amd64 CFLAGS: -I${SRCDIR}/library/amd64_linux/include #cgo linux,arm64 CFLAGS: -I${SRCDIR}/library/arm64_linux/include #include #include #include #include #include #include #include "HCNetSDK.h" typedef struct DEVICEINFO { BYTE byChanNum; BYTE byStartChan; } DEVICEINFO; typedef struct PTZ{ WORD P; WORD T; WORD Z; } PTZ; typedef struct TimeRange { DWORD StartYear; DWORD StartMonth; DWORD StartDay; DWORD StartHour; DWORD StartMinute; DWORD StartSecond; DWORD EndYear; DWORD EndMonth; DWORD EndDay; DWORD EndHour; DWORD EndMinute; DWORD EndSecond; } TimeRange; LONG Login(char *sDVRIP,WORD wDVRPort,char *sUserName,char *sPassword,struct DEVICEINFO *info){ NET_DVR_DEVICEINFO hikInfo; LONG lUserID = NET_DVR_Login(sDVRIP, wDVRPort, sUserName, sPassword,&hikInfo); info->byChanNum = hikInfo.byChanNum; info->byStartChan = hikInfo.byStartChan; return lUserID; } int GetTimeZone(LONG lUserID){ NET_DVR_NETAPPCFG NTPData; DWORD RESLEN; NET_DVR_GetDVRConfig(lUserID,222,0,&NTPData,sizeof(NTPData),&RESLEN); return NTPData.struNtpClientParam.cTimeDifferenceH*60 + NTPData.struNtpClientParam.cTimeDifferenceM*((NTPData.struNtpClientParam.cTimeDifferenceH>>7)?-1:1); } void GetPTZ(LONG lUserID,PTZ *info){ NET_DVR_PTZPOS PTZPOS; DWORD RESLEN; NET_DVR_GetDVRConfig(lUserID,293,1,&PTZPOS,sizeof(PTZPOS),&RESLEN); info->P = PTZPOS.wPanPos; info->T = PTZPOS.wTiltPos; info->Z = PTZPOS.wZoomPos; return; } void SetPTZ(LONG lUserID,WORD action,WORD p,WORD t,WORD z){ NET_DVR_PTZPOS PTZPOS; PTZPOS.wAction = action; PTZPOS.wPanPos = p; PTZPOS.wTiltPos = t; PTZPOS.wZoomPos = z; NET_DVR_SetDVRConfig(lUserID,292,1,&PTZPOS,sizeof(PTZPOS)); } void QueryMonth(LONG lUserID,WORD Year,BYTE Month,DWORD Channel,BYTE *byRecordDistribution){ NET_DVR_MRD_SEARCH_PARAM SEARCH_PARAM; SEARCH_PARAM.dwSize = sizeof(SEARCH_PARAM); SEARCH_PARAM.wYear = Year; SEARCH_PARAM.byMonth = Month; SEARCH_PARAM.struStreamInfo.dwChannel = 32 + Channel; SEARCH_PARAM.byLocalOrUTC = 1; SEARCH_PARAM.byDrawFrame = 0; SEARCH_PARAM.byStreamType = 0; LPVOID lpStatusList = malloc(sizeof(SEARCH_PARAM)); NET_DVR_MRD_SEARCH_RESULT SEARCH_RESULT; NET_DVR_GetDeviceConfig(lUserID,6164,0,&SEARCH_PARAM,sizeof(SEARCH_PARAM),lpStatusList,&SEARCH_RESULT,sizeof(SEARCH_RESULT)); free(lpStatusList); memcpy(byRecordDistribution,SEARCH_RESULT.byRecordDistribution,32); } LONG QueryDayHandle(LONG lUserID,DWORD Year,DWORD Month,DWORD Day,LONG Channel){ NET_DVR_FILECOND FindFile; FindFile.dwFileType = 0xff; FindFile.dwIsLocked = 0xff; FindFile.dwUseCardNo = 0; FindFile.lChannel = 32 + Channel; FindFile.struStartTime.dwYear = Year; FindFile.struStartTime.dwMonth = Month; FindFile.struStartTime.dwDay = Day; FindFile.struStartTime.dwHour = 0; FindFile.struStartTime.dwMinute = 0; FindFile.struStartTime.dwSecond = 0; FindFile.struStopTime.dwYear = Year; FindFile.struStopTime.dwMonth = Month; FindFile.struStopTime.dwDay = Day; FindFile.struStopTime.dwHour = 23; FindFile.struStopTime.dwMinute = 59; FindFile.struStopTime.dwSecond = 59; return NET_DVR_FindFile_V30(lUserID, &FindFile); } LONG QueryDayNextFile(LONG QueryHandle,struct TimeRange *TimeRange){ NET_DVR_FINDDATA_V30 Data; LONG STATE = NET_DVR_FindNextFile_V30(QueryHandle,&Data); TimeRange->StartYear = Data.struStartTime.dwYear; TimeRange->StartMonth = Data.struStartTime.dwMonth; TimeRange->StartDay = Data.struStartTime.dwDay; TimeRange->StartHour = Data.struStartTime.dwHour; TimeRange->StartMinute = Data.struStartTime.dwMinute; TimeRange->StartSecond = Data.struStartTime.dwSecond; TimeRange->EndYear = Data.struStopTime.dwYear; TimeRange->EndMonth = Data.struStopTime.dwMonth; TimeRange->EndDay = Data.struStopTime.dwDay; TimeRange->EndHour = Data.struStopTime.dwHour; TimeRange->EndMinute = Data.struStopTime.dwMinute; TimeRange->EndSecond = Data.struStopTime.dwSecond; return STATE; } struct SerialData { float p; float t; float z; }; struct SerialData serialData; void CALLBACK g_fSerialDataCallBack(LONG lSerialHandle, char *pRecvDataBuffer, DWORD dwBufSize, DWORD dwUser) { char type = pRecvDataBuffer[3]; printf("type: %x\n", type); if (type == 0x59){ serialData.p = (float)ntohs(*(uint16_t*)(pRecvDataBuffer + 4))/100.0f; }else if (type == 0x5b){ serialData.t = (float)ntohs(*(uint16_t*)(pRecvDataBuffer + 4))/100.0f; }else if (type == 0x5d){ serialData.z = (float)ntohs(*(uint16_t*)(pRecvDataBuffer + 4))/100.0f; } } void GetPTZPOS(LONG lUserID) { char p[7] = {0xff, 0x01, 0x00, 0x51, 0x00, 0x00, 0x52}; char t[7] = {0xff, 0x01, 0x00, 0x53, 0x00, 0x00, 0x54}; char z[7] = {0xff, 0x01, 0x00, 0x55, 0x00, 0x00, 0x56}; LONG lTranHandle = NET_DVR_SerialStart(lUserID, 2,g_fSerialDataCallBack,6); LONG lSerialChan = 0; sleep(1); NET_DVR_SerialSend(lTranHandle, lSerialChan, p, 7); sleep(1); NET_DVR_SerialSend(lTranHandle, lSerialChan, t, 7); sleep(1); NET_DVR_SerialSend(lTranHandle, lSerialChan, z, 7); sleep(1); NET_DVR_SerialStop(lTranHandle); } void SetPTZPOS(LONG lUserID,char* P,char* T,char *Z) { LONG lTranHandle = NET_DVR_SerialStart(lUserID, 2,g_fSerialDataCallBack,6); LONG lSerialChan = 0; sleep(1); NET_DVR_SerialSend(lTranHandle, lSerialChan, P, 7); sleep(1); NET_DVR_SerialSend(lTranHandle, lSerialChan, T, 7); sleep(1); NET_DVR_SerialSend(lTranHandle, lSerialChan, Z, 7); sleep(1); NET_DVR_SerialStop(lTranHandle); sleep(1); } */ import "C" import ( "math" "sync" "unsafe" ) type LONG int32 type BYTE uint8 type DWORD uint32 type WORD uint16 type NET_DVR_DEVICEINFO struct { ByChanNum BYTE ByStartChan BYTE // 起始数字通道号,0表示无数字通道,比如DVR或IPC } // Init 初始化SDK,调用其他SDK函数的前提。 func Init() error { if C.NET_DVR_Init() != 1 { return lastError("NET_DVR_Init") } return nil } // Cleanup 释放SDK资源,在程序结束之前调用。在调用时不能同时调用其他任何SDK接口。 Init 和 Cleanup 需要配对使用,即程序里面调用多少次 Init ,退出时就需要调用多少次 Cleanup。 func Cleanup() error { if C.NET_DVR_Cleanup() != 1 { return lastError("NET_DVR_Cleanup") } return nil } func login(Ip string, Port int, Username string, Password string) (LONG, NET_DVR_DEVICEINFO, error) { cIp := C.CString(Ip) cUser := C.CString(Username) cPass := C.CString(Password) defer C.free(unsafe.Pointer(cIp)) defer C.free(unsafe.Pointer(cUser)) defer C.free(unsafe.Pointer(cPass)) var info C.DEVICEINFO userId := LONG(C.Login(cIp, C.WORD(Port), cUser, cPass, &info)) err := lastError("login") if err != nil { return 0, NET_DVR_DEVICEINFO{}, err } return userId, NET_DVR_DEVICEINFO{ ByChanNum: BYTE(info.byChanNum), ByStartChan: BYTE(info.byStartChan)}, nil } func lastError(funcName string) error { ErrorCode := uint(C.NET_DVR_GetLastError()) if ErrorCode == 0 { return nil } var text string if ErrorCode == 3 { text = "sdk not init." return NewHcnetError(int(ErrorCode), text, funcName) } cErrorCode := C.LONG(ErrorCode) cText := C.NET_DVR_GetErrorMsg(&cErrorCode) text = C.GoString(cText) return NewHcnetError(int(ErrorCode), text, funcName) } func getTimeZone(lUserId LONG) int { return int(C.GetTimeZone(C.LONG(lUserId))) } func deviceOnline(lUserId LONG) bool { return C.NET_DVR_RemoteControl(C.LONG(lUserId), C.DWORD(20005), nil, C.DWORD(0)) == C.TRUE } func logout(lUserId LONG) error { if lUserId > -1 { cResult := C.NET_DVR_Logout(C.LONG(lUserId)) if cResult != 1 { return lastError("NET_DVR_Logout") } } return nil } func pTZControlWithSpeed_Other(lUserID LONG, dwPTZCommand DWORD, dwStop DWORD, dwSpeed DWORD) error { state := C.NET_DVR_PTZControlWithSpeed_Other(C.LONG(lUserID), 1, C.DWORD(dwPTZCommand), C.DWORD(dwStop), C.DWORD(dwSpeed)) if state == C.FALSE { return lastError("NET_DVR_PTZControlWithSpeed_Other") } return nil } func getPTZBase(lUserID LONG) (PTZ, error) { var info C.PTZ C.GetPTZ(C.LONG(lUserID), &info) err := lastError("GetPTZ") if err != nil { return PTZ{}, err } return PTZ{ P: HEX2DEC(WORD(info.P)), T: HEX2DEC(WORD(info.T)), Z: HEX2DEC(WORD(info.Z))}, nil } func setPTZBase(lUserID LONG, ptz PTZ) error { C.SetPTZ(C.LONG(lUserID), C.WORD(ptz.Action), C.WORD(DEC2HEX(float64(ptz.P))), C.WORD(DEC2HEX(float64(ptz.T))), C.WORD(DEC2HEX(float64(ptz.Z)))) return lastError("SetPTZ") } // HEX2DEC 将十六进制整数转换为十进制浮点数 func HEX2DEC(hex WORD) float64 { // 提取十六进制数的千位(对应十进制的百位) bai := byte(hex >> 12) hex = hex - WORD(bai)*WORD(math.Pow(16, 3)) // 提取十六进制数的百位(对应十进制的十位) shi := byte(hex >> 8) hex = hex - WORD(shi)*WORD(math.Pow(16, 2)) // 提取十六进制数的十位(对应十进制的个位) ge := byte(hex >> 4) hex = hex - WORD(ge)*WORD(math.Pow(16, 1)) // 提取十六进制数的个位(对应十进制的十分位) xiao := byte(hex) // 计算对应的十进制浮点数 return float64(bai)*math.Pow(10, 2) + float64(shi)*math.Pow(10, 1) + float64(ge)*math.Pow(10, 0) + float64(xiao)*math.Pow(10, -1) } // DEC2HEX 将十进制浮点数转换为十六进制整数 func DEC2HEX(dec float64) WORD { // 提取千位(对应十进制的百位) bai := uint16(dec / math.Pow(10, 2)) dec -= float64(bai) * math.Pow(10, 2) // 提取百位(对应十进制的十位) shi := uint16(dec / math.Pow(10, 1)) dec -= float64(shi) * math.Pow(10, 1) // 提取十位(对应十进制的个位) ge := uint16(dec / math.Pow(10, 0)) dec -= float64(ge) * math.Pow(10, 0) // 提取个位(对应十进制的十分位) xiao := uint16(dec * 10) // 合成十六进制数 hex := WORD(bai)<<12 | WORD(shi)<<8 | WORD(ge)<<4 | WORD(xiao) return hex } func QueryMonth(lUserID LONG, Year WORD, Month BYTE, Channel DWORD) (res []uint8, err error) { buf := (*C.BYTE)(C.malloc(32)) defer C.free(unsafe.Pointer(buf)) C.QueryMonth(C.LONG(lUserID), C.WORD(Year), C.BYTE(Month), C.DWORD(Channel), buf) goBuf := C.GoBytes(unsafe.Pointer(buf), 32) for i := 0; i < 32; i++ { if goBuf[i] != 0 { res = append(res, uint8(i+1)) } } err = lastError("QueryMonth") return } func QueryDayHandle(lUserID LONG, Year, Month, Day DWORD, Channel LONG) LONG { return LONG(C.QueryDayHandle(C.LONG(lUserID), C.DWORD(Year), C.DWORD(Month), C.DWORD(Day), C.LONG(Channel))) } func QueryDayNextFile(Handle LONG) (TimeRange, LONG, error) { var FindData C.TimeRange state := LONG(C.QueryDayNextFile(C.LONG(Handle), &FindData)) if state < 0 { return TimeRange{}, state, lastError("QueryDayNextFile") } return TimeRange{ StartYear: DWORD(FindData.StartYear), StartMonth: DWORD(FindData.StartMonth), StartDay: DWORD(FindData.StartDay), StartHour: DWORD(FindData.StartHour), StartMinute: DWORD(FindData.StartMinute), StartSecond: DWORD(FindData.StartSecond), EndYear: DWORD(FindData.EndYear), EndMonth: DWORD(FindData.EndMonth), EndDay: DWORD(FindData.EndDay), EndHour: DWORD(FindData.EndHour), EndMinute: DWORD(FindData.EndMinute), EndSecond: DWORD(FindData.EndSecond), }, state, nil } func FindClose(Handle LONG) error { C.NET_DVR_FindClose_V30(C.LONG(Handle)) return lastError("NET_DVR_FindClose_V30") } var SerialMux sync.Mutex func SetPTZPos(lUserID LONG, P []byte, T []byte, Z []byte) error { cP := C.CBytes(P) cT := C.CBytes(T) cZ := C.CBytes(Z) defer C.free(cP) defer C.free(cT) defer C.free(cZ) SerialMux.Lock() C.SetPTZPOS(C.LONG(lUserID), (*C.char)(cP), (*C.char)(cT), (*C.char)(cZ)) SerialMux.Unlock() return lastError("SetPTZPOS") } func GetPTZPOS(lUserID LONG) (PTZ, error) { SerialMux.Lock() C.GetPTZPOS(C.LONG(lUserID)) p := float32(C.serialData.p) t := float32(C.serialData.t) z := float32(C.serialData.z) SerialMux.Unlock() return PTZ{ P: float64(p), T: float64(t), Z: float64(z), }, lastError("GetPTZPOS") }