1. 使用CGO对代码进行重构
This commit is contained in:
		
							
								
								
									
										444
									
								
								BallCamera.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								BallCamera.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,444 @@ | ||||
| package HikSDK | ||||
|  | ||||
| /* | ||||
| #cgo LDFLAGS: -Wl,--allow-multiple-definition | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"gitea.com/kunmeng/HikNetSDKPkg/core" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	Base      = 0 | ||||
| 	BuKongQiu = 1 | ||||
| ) | ||||
|  | ||||
| type PTZEnumObj struct { | ||||
| 	PTZ_LEFT       int | ||||
| 	PTZ_RIGHT      int | ||||
| 	PTZ_UP         int | ||||
| 	PTZ_DOWN       int | ||||
| 	PTZ_UP_LEFT    int | ||||
| 	PTZ_UP_RIGHT   int | ||||
| 	PTZ_DOWN_LEFT  int | ||||
| 	PTZ_DOWN_RIGHT int | ||||
| 	PTZ_ZOOM_IN    int | ||||
| 	PTZ_ZOOM_OUT   int | ||||
| 	PTZ_Focus_Far  int | ||||
| 	PTZ_Focus_Near int | ||||
| } | ||||
|  | ||||
| func (receiver *PTZEnumObj) toHikPTZEnum(v int) int { | ||||
| 	switch v { | ||||
| 	case PTZEnum.PTZ_LEFT: | ||||
| 		return HikPTZEnum.PAN_LEFT | ||||
| 	case PTZEnum.PTZ_RIGHT: | ||||
| 		return HikPTZEnum.PAN_RIGHT | ||||
| 	case PTZEnum.PTZ_UP: | ||||
| 		return HikPTZEnum.TILT_UP | ||||
| 	case PTZEnum.PTZ_DOWN: | ||||
| 		return HikPTZEnum.TILT_DOWN | ||||
| 	case PTZEnum.PTZ_ZOOM_IN: | ||||
| 		return HikPTZEnum.ZOOM_IN | ||||
| 	case PTZEnum.PTZ_ZOOM_OUT: | ||||
| 		return HikPTZEnum.ZOOM_OUT | ||||
| 	case PTZEnum.PTZ_Focus_Far: | ||||
| 		return HikPTZEnum.FOCUS_FAR | ||||
| 	case PTZEnum.PTZ_Focus_Near: | ||||
| 		return HikPTZEnum.FOCUS_NEAR | ||||
| 	case PTZEnum.PTZ_UP_LEFT: | ||||
| 		return HikPTZEnum.UP_LEFT | ||||
| 	case PTZEnum.PTZ_UP_RIGHT: | ||||
| 		return HikPTZEnum.UP_RIGHT | ||||
| 	case PTZEnum.PTZ_DOWN_LEFT: | ||||
| 		return HikPTZEnum.DOWN_LEFT | ||||
| 	case PTZEnum.PTZ_DOWN_RIGHT: | ||||
| 		return HikPTZEnum.DOWN_RIGHT | ||||
|  | ||||
| 	default: | ||||
| 		return -1 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var PTZEnum = PTZEnumObj{ | ||||
| 	PTZ_LEFT:       1, | ||||
| 	PTZ_RIGHT:      2, | ||||
| 	PTZ_UP:         3, | ||||
| 	PTZ_DOWN:       4, | ||||
| 	PTZ_UP_LEFT:    5, | ||||
| 	PTZ_UP_RIGHT:   6, | ||||
| 	PTZ_DOWN_LEFT:  7, | ||||
| 	PTZ_DOWN_RIGHT: 8, | ||||
| 	PTZ_ZOOM_IN:    9, | ||||
| 	PTZ_ZOOM_OUT:   10, | ||||
| 	PTZ_Focus_Far:  11, | ||||
| 	PTZ_Focus_Near: 12, | ||||
| } | ||||
|  | ||||
| var HikPTZEnum = struct { | ||||
| 	LIGHT_PWRON         int //接通灯光电源 | ||||
| 	WIPER_PWRON         int //接通雨刷开关 | ||||
| 	FAN_PWRON           int //接通风扇开关 | ||||
| 	HEATER_PWRON        int //接通加热器开关 | ||||
| 	AUX_PWRON1          int //接通辅助设备开关 | ||||
| 	AUX_PWRON2          int //接通辅助设备开关 | ||||
| 	ZOOM_IN             int //焦距变大(倍率变大) | ||||
| 	ZOOM_OUT            int //焦距变小(倍率变小) | ||||
| 	FOCUS_NEAR          int //焦点前调 | ||||
| 	FOCUS_FAR           int //焦点后调 | ||||
| 	IRIS_OPEN           int //光圈扩大 | ||||
| 	IRIS_CLOSE          int //光圈缩小 | ||||
| 	TILT_UP             int //云台上仰 | ||||
| 	TILT_DOWN           int //云台下俯 | ||||
| 	PAN_LEFT            int //云台左转 | ||||
| 	PAN_RIGHT           int //云台右转 | ||||
| 	UP_LEFT             int //云台上仰和左转 | ||||
| 	UP_RIGHT            int //云台上仰和右转 | ||||
| 	DOWN_LEFT           int //云台下俯和左转 | ||||
| 	DOWN_RIGHT          int //云台下俯和右转 | ||||
| 	PAN_AUTO            int //云台左右自动扫描 | ||||
| 	TILT_DOWN_ZOOM_IN   int //云台下俯和焦距变大(倍率变大) | ||||
| 	TILT_DOWN_ZOOM_OUT  int //云台下俯和焦距变小(倍率变小) | ||||
| 	PAN_LEFT_ZOOM_IN    int //云台左转和焦距变大(倍率变大) | ||||
| 	PAN_LEFT_ZOOM_OUT   int //云台左转和焦距变小(倍率变小) | ||||
| 	PAN_RIGHT_ZOOM_IN   int //云台右转和焦距变大(倍率变大) | ||||
| 	PAN_RIGHT_ZOOM_OUT  int //云台右转和焦距变小(倍率变小) | ||||
| 	UP_LEFT_ZOOM_IN     int //云台上仰和左转和焦距变大(倍率变大) | ||||
| 	UP_LEFT_ZOOM_OUT    int //云台上仰和左转和焦距变小(倍率变小) | ||||
| 	UP_RIGHT_ZOOM_IN    int //云台上仰和右转和焦距变大(倍率变大) | ||||
| 	UP_RIGHT_ZOOM_OUT   int //云台上仰和右转和焦距变小(倍率变小) | ||||
| 	DOWN_LEFT_ZOOM_IN   int //云台下俯和左转和焦距变大(倍率变大) | ||||
| 	DOWN_LEFT_ZOOM_OUT  int //云台下俯和左转和焦距变小(倍率变小) | ||||
| 	DOWN_RIGHT_ZOOM_IN  int //云台下俯和右转和焦距变大(倍率变大) | ||||
| 	DOWN_RIGHT_ZOOM_OUT int //云台下俯和右转和焦距变小(倍率变小) | ||||
| 	TILT_UP_ZOOM_IN     int //云台上仰和焦距变大(倍率变大) | ||||
| 	TILT_UP_ZOOM_OUT    int //云台上仰和焦距变小(倍率变小) | ||||
| }{LIGHT_PWRON: 2, | ||||
| 	WIPER_PWRON:         3, | ||||
| 	FAN_PWRON:           4, | ||||
| 	HEATER_PWRON:        5, | ||||
| 	AUX_PWRON1:          6, | ||||
| 	AUX_PWRON2:          7, | ||||
| 	ZOOM_IN:             11, | ||||
| 	ZOOM_OUT:            12, | ||||
| 	FOCUS_NEAR:          13, | ||||
| 	FOCUS_FAR:           14, | ||||
| 	IRIS_OPEN:           15, | ||||
| 	IRIS_CLOSE:          16, | ||||
| 	TILT_UP:             21, | ||||
| 	TILT_DOWN:           22, | ||||
| 	PAN_LEFT:            23, | ||||
| 	PAN_RIGHT:           24, | ||||
| 	UP_LEFT:             25, | ||||
| 	UP_RIGHT:            26, | ||||
| 	DOWN_LEFT:           27, | ||||
| 	DOWN_RIGHT:          28, | ||||
| 	PAN_AUTO:            29, | ||||
| 	TILT_DOWN_ZOOM_IN:   58, | ||||
| 	TILT_DOWN_ZOOM_OUT:  59, | ||||
| 	PAN_LEFT_ZOOM_IN:    60, | ||||
| 	PAN_LEFT_ZOOM_OUT:   61, | ||||
| 	PAN_RIGHT_ZOOM_IN:   62, | ||||
| 	PAN_RIGHT_ZOOM_OUT:  63, | ||||
| 	UP_LEFT_ZOOM_IN:     64, | ||||
| 	UP_LEFT_ZOOM_OUT:    65, | ||||
| 	UP_RIGHT_ZOOM_IN:    66, | ||||
| 	UP_RIGHT_ZOOM_OUT:   67, | ||||
| 	DOWN_LEFT_ZOOM_IN:   68, | ||||
| 	DOWN_LEFT_ZOOM_OUT:  69, | ||||
| 	DOWN_RIGHT_ZOOM_IN:  70, | ||||
| 	DOWN_RIGHT_ZOOM_OUT: 71, | ||||
| 	TILT_UP_ZOOM_IN:     72, | ||||
| 	TILT_UP_ZOOM_OUT:    73, | ||||
| } | ||||
|  | ||||
| type BallCamera struct { | ||||
| 	userId       core.LONG | ||||
| 	_type        uint8 | ||||
| 	deviceInfo   core.NET_DVR_DEVICEINFO_V30 | ||||
| 	mu           sync.Mutex | ||||
| 	expectedType byte | ||||
| } | ||||
|  | ||||
| func NewBallCamera(Ip string, Port int, Username, Password string, Type uint8) (*BallCamera, error) { | ||||
| 	UserId, DeviceInfo, err := core.Login(Ip, Port, Username, Password) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &BallCamera{ | ||||
| 		userId:     UserId, | ||||
| 		_type:      Type, | ||||
| 		deviceInfo: DeviceInfo, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type PTZ struct { | ||||
| 	P float32 | ||||
| 	T float32 | ||||
| 	Z float32 | ||||
| } | ||||
|  | ||||
| func (this *BallCamera) GetPTZ() (PTZ, error) { | ||||
| 	if this._type == BuKongQiu { | ||||
| 		var data PTZ | ||||
|  | ||||
| 		ch := make(chan bool) | ||||
| 		SerialStartHandle, err := core.SerialStart(this.userId, func(lSerialHandle core.LONG, lChannel core.LONG, pRecvDataBuffer []byte, dwBufSize core.DWORD, pUser unsafe.Pointer) { | ||||
| 			if dwBufSize != 7 { | ||||
| 				ch <- false | ||||
| 				return | ||||
| 			} | ||||
| 			Type := pRecvDataBuffer[3] | ||||
| 			this.mu.Lock() | ||||
| 			expected := this.expectedType | ||||
| 			this.mu.Unlock() | ||||
| 			if Type != expected { | ||||
| 				ch <- false | ||||
| 				return | ||||
| 			} | ||||
| 			switch Type { | ||||
| 			case 0x59: | ||||
| 				data.P = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100. | ||||
| 			case 0x5B: | ||||
| 				data.T = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100. | ||||
| 			case 0x5D: | ||||
| 				data.Z = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100. | ||||
| 			default: | ||||
| 				ch <- false | ||||
| 			} | ||||
| 			ch <- true | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return data, err | ||||
| 		} | ||||
| 		defer func() { | ||||
| 			err = core.SerialStop(SerialStartHandle) | ||||
| 			if err != nil { | ||||
| 				println(err.Error()) | ||||
| 			} | ||||
| 			time.Sleep(1 * time.Second) | ||||
| 		}() | ||||
|  | ||||
| 		// 获取P值 | ||||
| 		this.mu.Lock() | ||||
| 		this.expectedType = 0x59 | ||||
| 		this.mu.Unlock() | ||||
| 		if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x51, 0x00, 0x00, 0x52}, 5, ch); err != nil { | ||||
| 			return data, fmt.Errorf("获取P值失败: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		this.mu.Lock() | ||||
| 		this.expectedType = 0x5B | ||||
| 		this.mu.Unlock() | ||||
| 		if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x53, 0x00, 0x00, 0x54}, 5, ch); err != nil { | ||||
| 			return data, fmt.Errorf("获取T值失败: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		this.mu.Lock() | ||||
| 		this.expectedType = 0x5D | ||||
| 		this.mu.Unlock() | ||||
| 		if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x55, 0x00, 0x00, 0x56}, 5, ch); err != nil { | ||||
| 			return data, fmt.Errorf("获取Z值失败: %w", err) | ||||
| 		} | ||||
| 		return data, nil | ||||
| 	} | ||||
| 	var data core.CDVR_PTZPOS | ||||
| 	var dataPtr = unsafe.Pointer(&data) | ||||
| 	err := core.GetDVRConfig(this.userId, 293, 1, dataPtr, core.DWORD(unsafe.Sizeof(data))) | ||||
| 	if err != nil { | ||||
| 		return PTZ{}, err | ||||
| 	} | ||||
| 	res := data.Go() | ||||
| 	return PTZ{ | ||||
| 		P: float32(res.WPanPos), | ||||
| 		T: float32(res.WTiltPos), | ||||
| 		Z: float32(res.WZoomPos), | ||||
| 	}, nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func padding(n int) ([]byte, error) { | ||||
| 	if n < 0 || n > 65535 { | ||||
| 		return []byte{0x00, 0x00}, errors.New("n must be in the range 0-65535") | ||||
| 	} | ||||
| 	return []byte{byte(n >> 8), byte(n & 0xFF)}, nil | ||||
| } | ||||
|  | ||||
| func (this *BallCamera) PtzGotoPut(Action int, P, T, Z float64) error { | ||||
| 	if this._type == BuKongQiu { | ||||
| 		SerialStartHandle, err := core.SerialStart(this.userId, func(lSerialHandle core.LONG, lChannel core.LONG, pRecvDataBuffer []byte, dwBufSize core.DWORD, pUser unsafe.Pointer) { | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		defer func() { | ||||
| 			err = core.SerialStop(SerialStartHandle) | ||||
| 			if err != nil { | ||||
| 				println(err.Error()) | ||||
| 			} | ||||
| 			time.Sleep(1 * time.Second) | ||||
| 		}() | ||||
|  | ||||
| 		PByte, err := padding(int(P * 100)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		TByte, err := padding(int(T * 100)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ZByte, err := padding(int(Z * 100)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		//println(PByte, TByte, ZByte) | ||||
| 		pBuf := append([]byte{0xff, 0x01, 0x00, 0x4b}, PByte...) | ||||
| 		tBuf := append([]byte{0xff, 0x01, 0x00, 0x4d}, TByte...) | ||||
| 		zBuf := append([]byte{0xff, 0x01, 0x00, 0x4f}, ZByte...) | ||||
|  | ||||
| 		pBufv, err := verify(pBuf) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		tBufv, err := verify(tBuf) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		zBufv, err := verify(zBuf) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		pBuf = append(pBuf, pBufv) | ||||
| 		tBuf = append(tBuf, tBufv) | ||||
| 		zBuf = append(zBuf, zBufv) | ||||
| 		switch Action { | ||||
| 		case 1: | ||||
| 			err = core.SerialSend(SerialStartHandle, pBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			err = core.SerialSend(SerialStartHandle, tBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			err = core.SerialSend(SerialStartHandle, zBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			break | ||||
| 		case 2: | ||||
| 			err = core.SerialSend(SerialStartHandle, pBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			break | ||||
| 		case 3: | ||||
| 			err = core.SerialSend(SerialStartHandle, tBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			break | ||||
| 		case 4: | ||||
| 			err = core.SerialSend(SerialStartHandle, zBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			break | ||||
| 		case 5: | ||||
| 			err = core.SerialSend(SerialStartHandle, pBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			err = core.SerialSend(SerialStartHandle, tBuf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			break | ||||
| 		default: | ||||
| 			return errors.New("action error") | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	var data core.CDVR_PTZPOS | ||||
| 	data.Set(float64(Action), P, T, Z) | ||||
| 	var dataPtr = unsafe.Pointer(&data) | ||||
| 	err := core.SetDVRConfig(this.userId, 292, 1, dataPtr, core.DWORD(unsafe.Sizeof(data))) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (this *BallCamera) retrySend(handle core.LONG, cmd []byte, maxRetries int, ch <-chan bool) error { | ||||
| 	for retry := 0; retry < maxRetries; retry++ { | ||||
| 		if err := core.SerialSend(handle, cmd); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		select { | ||||
| 		case success := <-ch: | ||||
| 			if success { | ||||
| 				return nil | ||||
| 			} | ||||
| 			if retry == maxRetries-1 { | ||||
| 				return fmt.Errorf("达到最大重试次数 %d", maxRetries) | ||||
| 			} | ||||
| 		case <-time.After(2 * time.Second): // 添加超时机制 | ||||
| 			if retry == maxRetries-1 { | ||||
| 				return fmt.Errorf("响应超时,重试 %d 次后失败", maxRetries) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (receiver *BallCamera) StartBus(direction int, speed int) error { | ||||
| 	err := core.PTZControlWithSpeed_Other(receiver.userId, core.LONG(receiver.deviceInfo.ByStartChan), core.DWORD(direction), core.DWORD(0), core.DWORD(speed)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| func (receiver *BallCamera) StopBus(direction int, speed int) error { | ||||
| 	err := core.PTZControlWithSpeed_Other(receiver.userId, core.LONG(receiver.deviceInfo.ByStartChan), core.DWORD(direction), core.DWORD(1), core.DWORD(speed)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func verify(data []byte) (byte, error) { | ||||
| 	if len(data) < 6 { | ||||
| 		return 0, fmt.Errorf("data too short") | ||||
| 	} | ||||
| 	sum := 0 | ||||
| 	for i := 1; i < 6; i++ { | ||||
| 		sum += int(data[i]) | ||||
| 	} | ||||
|  | ||||
| 	// 取模并转换为16进制 | ||||
| 	checksum := sum % 0x100 | ||||
| 	return byte(checksum), nil | ||||
| } | ||||
|  | ||||
| func (receiver *BallCamera) Logout() error { | ||||
| 	//if receiver._type == BuKongQiu { | ||||
| 	//	err := core.SerialStop(receiver.serialStartHandle) | ||||
| 	//	if err != nil { | ||||
| 	//		return err | ||||
| 	//	} | ||||
| 	//} | ||||
| 	err := core.Logout(receiver.userId) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 kunmeng
					kunmeng