本文通过一个常用的登录设备的例子,演示学习go1.17 unsafe.Slice方法的使用。具体例子如下:
package main
/*
#cgo CFLAGS: -I./libs/hiksdk-6.1.4.51/include/
#cgo LDFLAGS: -L./libs/hiksdk-6.1.4.51/lib/ -lHCCore -lhcnetsdk
#include "HCNetSDK.h"
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"reflect"
"unsafe"
)
type NET_DVR_LOCAL_SDK_PATH struct {
Path [256]byte
Res [128]byte
}
func main() {
ret := C.NET_DVR_Init()
if int(ret) != 1 {
fmt.Printf("NET_DVR_Init failed,error code = %v\n", C.NET_DVR_GetLastError())
return
}
defer C.NET_DVR_Cleanup()
// 开启调试日志,不开启可以注掉,sdk的日志能看到详细的错误信息
logPath := "/tmp"
C.NET_DVR_SetLogToFile(3, C.CString(logPath), 1)
// 如果动态库加载失败,可调用SDK手动设置海康动态库的路径,不设置可以注掉,如果加载不成功,尝试显示设置下
var comPath = NET_DVR_LOCAL_SDK_PATH{}
copy(comPath.Path[:], "/root/script/src/nvr/libs/hiksdk-6.1.4.51/lib/")
C.NET_DVR_SetSDKInitCfg(C.NET_SDK_INIT_CFG_SDK_PATH, unsafe.Pointer(&comPath))
var userLoginInfo C.NET_DVR_USER_LOGIN_INFO
var deviceInfo C.NET_DVR_DEVICEINFO_V40
userLoginInfo.wPort = 8000 // your device port,default 8000
username := "your device username"
// 转换成C字节数组
pUsername := C.CBytes([]byte(username))
defer C.free(pUsername)
// 使用memcpy函数进行拷贝
C.memcpy(unsafe.Pointer(&userLoginInfo.sUserName), pUsername, C.ulong(len(username)))
password := "you device password"
pPassword := C.CBytes([]byte(password))
defer C.free(pPassword)
C.memcpy(unsafe.Pointer(&userLoginInfo.sPassword), pPassword, C.ulong(len(password)))
deviceIp := "your device ip"
pDeviceIp := C.CBytes([]byte(deviceIp))
defer C.free(pDeviceIp)
C.memcpy(unsafe.Pointer(&userLoginInfo.sDeviceAddress), pDeviceIp, C.ulong(len(deviceIp)))
// 调用登录接口
loginId := C.NET_DVR_Login_V40((C.LPNET_DVR_USER_LOGIN_INFO)(&userLoginInfo), (C.LPNET_DVR_DEVICEINFO_V40)(&deviceInfo))
if int32(loginId) < 0 {
fmt.Printf("NET_DVR_Login_V40 failed,error code = %v", C.NET_DVR_GetLastError())
return
}
byIPChanNum := uint8(deviceInfo.struDeviceV30.byIPChanNum)
byHighDChanNum := uint8(deviceInfo.struDeviceV30.byHighDChanNum)
// go1.17 unsafe.Slice 从给定的地址和长度产生一个任意类型的切片,须保证在使用中地址不能被释放
// 下面参数中的地址未C内存结构的数字第一个元素的地址
serialNo := unsafe.Slice((*byte)(unsafe.Pointer(&deviceInfo.struDeviceV30.sSerialNumber[0])), int(C.SERIALNO_LEN))
fmt.Printf("用户ID:%d\n", int32(loginId))
fmt.Printf("序列号:%s\n", string(serialNo))
fmt.Printf("硬盘个数:%d\n", uint8(deviceInfo.struDeviceV30.byDiskNum))
fmt.Printf("设备类型:%d\n", uint8(deviceInfo.struDeviceV30.byDVRType))
fmt.Printf("设备模拟通道个数:%d\n", uint8(deviceInfo.struDeviceV30.byChanNum))
fmt.Printf("设备模拟通道起始通道号:%d\n", uint8(deviceInfo.struDeviceV30.byStartChan))
fmt.Printf("设备数字通道起始通道号:%d\n", uint8(deviceInfo.struDeviceV30.byStartDChan))
fmt.Printf("设备IP通道个数:%d\n", uint16(byIPChanNum)+uint16(byHighDChanNum)*256)
}
运行结果如下:
用户ID:0
序列号:DS-删掉后面若干
硬盘个数:2
设备类型:90
设备模拟通道个数:0
设备模拟通道起始通道号:1
设备数字通道起始通道号:33
设备IP通道个数:16