BallCamera.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. package HikSDK
  2. /*
  3. #cgo LDFLAGS: -Wl,--allow-multiple-definition
  4. #include <stdio.h>
  5. #include <string.h>
  6. */
  7. import "C"
  8. import (
  9. "encoding/binary"
  10. "errors"
  11. "fmt"
  12. "gitea.com/kunmeng/HikNetSDKPkg/Core"
  13. "sync"
  14. "time"
  15. "unsafe"
  16. )
  17. const (
  18. Base = 0
  19. BuKongQiu = 1
  20. )
  21. type PTZEnumObj struct {
  22. PTZ_LEFT int
  23. PTZ_RIGHT int
  24. PTZ_UP int
  25. PTZ_DOWN int
  26. PTZ_UP_LEFT int
  27. PTZ_UP_RIGHT int
  28. PTZ_DOWN_LEFT int
  29. PTZ_DOWN_RIGHT int
  30. PTZ_ZOOM_IN int
  31. PTZ_ZOOM_OUT int
  32. PTZ_Focus_Far int
  33. PTZ_Focus_Near int
  34. }
  35. func (receiver *PTZEnumObj) toHikPTZEnum(v int) int {
  36. switch v {
  37. case PTZEnum.PTZ_LEFT:
  38. return HikPTZEnum.PAN_LEFT
  39. case PTZEnum.PTZ_RIGHT:
  40. return HikPTZEnum.PAN_RIGHT
  41. case PTZEnum.PTZ_UP:
  42. return HikPTZEnum.TILT_UP
  43. case PTZEnum.PTZ_DOWN:
  44. return HikPTZEnum.TILT_DOWN
  45. case PTZEnum.PTZ_ZOOM_IN:
  46. return HikPTZEnum.ZOOM_IN
  47. case PTZEnum.PTZ_ZOOM_OUT:
  48. return HikPTZEnum.ZOOM_OUT
  49. case PTZEnum.PTZ_Focus_Far:
  50. return HikPTZEnum.FOCUS_FAR
  51. case PTZEnum.PTZ_Focus_Near:
  52. return HikPTZEnum.FOCUS_NEAR
  53. case PTZEnum.PTZ_UP_LEFT:
  54. return HikPTZEnum.UP_LEFT
  55. case PTZEnum.PTZ_UP_RIGHT:
  56. return HikPTZEnum.UP_RIGHT
  57. case PTZEnum.PTZ_DOWN_LEFT:
  58. return HikPTZEnum.DOWN_LEFT
  59. case PTZEnum.PTZ_DOWN_RIGHT:
  60. return HikPTZEnum.DOWN_RIGHT
  61. default:
  62. return -1
  63. }
  64. }
  65. var PTZEnum = PTZEnumObj{
  66. PTZ_LEFT: 1,
  67. PTZ_RIGHT: 2,
  68. PTZ_UP: 3,
  69. PTZ_DOWN: 4,
  70. PTZ_UP_LEFT: 5,
  71. PTZ_UP_RIGHT: 6,
  72. PTZ_DOWN_LEFT: 7,
  73. PTZ_DOWN_RIGHT: 8,
  74. PTZ_ZOOM_IN: 9,
  75. PTZ_ZOOM_OUT: 10,
  76. PTZ_Focus_Far: 11,
  77. PTZ_Focus_Near: 12,
  78. }
  79. var HikPTZEnum = struct {
  80. LIGHT_PWRON int //接通灯光电源
  81. WIPER_PWRON int //接通雨刷开关
  82. FAN_PWRON int //接通风扇开关
  83. HEATER_PWRON int //接通加热器开关
  84. AUX_PWRON1 int //接通辅助设备开关
  85. AUX_PWRON2 int //接通辅助设备开关
  86. ZOOM_IN int //焦距变大(倍率变大)
  87. ZOOM_OUT int //焦距变小(倍率变小)
  88. FOCUS_NEAR int //焦点前调
  89. FOCUS_FAR int //焦点后调
  90. IRIS_OPEN int //光圈扩大
  91. IRIS_CLOSE int //光圈缩小
  92. TILT_UP int //云台上仰
  93. TILT_DOWN int //云台下俯
  94. PAN_LEFT int //云台左转
  95. PAN_RIGHT int //云台右转
  96. UP_LEFT int //云台上仰和左转
  97. UP_RIGHT int //云台上仰和右转
  98. DOWN_LEFT int //云台下俯和左转
  99. DOWN_RIGHT int //云台下俯和右转
  100. PAN_AUTO int //云台左右自动扫描
  101. TILT_DOWN_ZOOM_IN int //云台下俯和焦距变大(倍率变大)
  102. TILT_DOWN_ZOOM_OUT int //云台下俯和焦距变小(倍率变小)
  103. PAN_LEFT_ZOOM_IN int //云台左转和焦距变大(倍率变大)
  104. PAN_LEFT_ZOOM_OUT int //云台左转和焦距变小(倍率变小)
  105. PAN_RIGHT_ZOOM_IN int //云台右转和焦距变大(倍率变大)
  106. PAN_RIGHT_ZOOM_OUT int //云台右转和焦距变小(倍率变小)
  107. UP_LEFT_ZOOM_IN int //云台上仰和左转和焦距变大(倍率变大)
  108. UP_LEFT_ZOOM_OUT int //云台上仰和左转和焦距变小(倍率变小)
  109. UP_RIGHT_ZOOM_IN int //云台上仰和右转和焦距变大(倍率变大)
  110. UP_RIGHT_ZOOM_OUT int //云台上仰和右转和焦距变小(倍率变小)
  111. DOWN_LEFT_ZOOM_IN int //云台下俯和左转和焦距变大(倍率变大)
  112. DOWN_LEFT_ZOOM_OUT int //云台下俯和左转和焦距变小(倍率变小)
  113. DOWN_RIGHT_ZOOM_IN int //云台下俯和右转和焦距变大(倍率变大)
  114. DOWN_RIGHT_ZOOM_OUT int //云台下俯和右转和焦距变小(倍率变小)
  115. TILT_UP_ZOOM_IN int //云台上仰和焦距变大(倍率变大)
  116. TILT_UP_ZOOM_OUT int //云台上仰和焦距变小(倍率变小)
  117. }{LIGHT_PWRON: 2,
  118. WIPER_PWRON: 3,
  119. FAN_PWRON: 4,
  120. HEATER_PWRON: 5,
  121. AUX_PWRON1: 6,
  122. AUX_PWRON2: 7,
  123. ZOOM_IN: 11,
  124. ZOOM_OUT: 12,
  125. FOCUS_NEAR: 13,
  126. FOCUS_FAR: 14,
  127. IRIS_OPEN: 15,
  128. IRIS_CLOSE: 16,
  129. TILT_UP: 21,
  130. TILT_DOWN: 22,
  131. PAN_LEFT: 23,
  132. PAN_RIGHT: 24,
  133. UP_LEFT: 25,
  134. UP_RIGHT: 26,
  135. DOWN_LEFT: 27,
  136. DOWN_RIGHT: 28,
  137. PAN_AUTO: 29,
  138. TILT_DOWN_ZOOM_IN: 58,
  139. TILT_DOWN_ZOOM_OUT: 59,
  140. PAN_LEFT_ZOOM_IN: 60,
  141. PAN_LEFT_ZOOM_OUT: 61,
  142. PAN_RIGHT_ZOOM_IN: 62,
  143. PAN_RIGHT_ZOOM_OUT: 63,
  144. UP_LEFT_ZOOM_IN: 64,
  145. UP_LEFT_ZOOM_OUT: 65,
  146. UP_RIGHT_ZOOM_IN: 66,
  147. UP_RIGHT_ZOOM_OUT: 67,
  148. DOWN_LEFT_ZOOM_IN: 68,
  149. DOWN_LEFT_ZOOM_OUT: 69,
  150. DOWN_RIGHT_ZOOM_IN: 70,
  151. DOWN_RIGHT_ZOOM_OUT: 71,
  152. TILT_UP_ZOOM_IN: 72,
  153. TILT_UP_ZOOM_OUT: 73,
  154. }
  155. type BallCamera struct {
  156. userId Core.LONG
  157. _type uint8
  158. deviceInfo Core.NET_DVR_DEVICEINFO_V30
  159. mu sync.Mutex
  160. expectedType byte
  161. }
  162. func NewBallCamera(Ip string, Port int, Username, Password string, Type uint8) (*BallCamera, error) {
  163. UserId, DeviceInfo, err := Core.Login(Ip, Port, Username, Password)
  164. if err != nil {
  165. return nil, err
  166. }
  167. return &BallCamera{
  168. userId: UserId,
  169. _type: Type,
  170. deviceInfo: DeviceInfo,
  171. }, nil
  172. }
  173. type PTZ struct {
  174. P float32
  175. T float32
  176. Z float32
  177. }
  178. func (this *BallCamera) GetPTZ() (PTZ, error) {
  179. if this == nil {
  180. return PTZ{}, errors.New("BallCamera is nil")
  181. }
  182. if this._type == BuKongQiu {
  183. var data PTZ
  184. ch := make(chan bool)
  185. SerialStartHandle, err := Core.SerialStart(this.userId, func(lSerialHandle Core.LONG, lChannel Core.LONG, pRecvDataBuffer []byte, dwBufSize Core.DWORD, pUser unsafe.Pointer) {
  186. if dwBufSize != 7 {
  187. ch <- false
  188. return
  189. }
  190. Type := pRecvDataBuffer[3]
  191. this.mu.Lock()
  192. expected := this.expectedType
  193. this.mu.Unlock()
  194. if Type != expected {
  195. ch <- false
  196. return
  197. }
  198. switch Type {
  199. case 0x59:
  200. data.P = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100.
  201. case 0x5B:
  202. data.T = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100.
  203. case 0x5D:
  204. data.Z = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100.
  205. default:
  206. ch <- false
  207. }
  208. ch <- true
  209. })
  210. if err != nil {
  211. return data, err
  212. }
  213. defer func() {
  214. err = Core.SerialStop(SerialStartHandle)
  215. if err != nil {
  216. println(err.Error())
  217. }
  218. time.Sleep(1 * time.Second)
  219. }()
  220. // 获取P值
  221. this.mu.Lock()
  222. this.expectedType = 0x59
  223. this.mu.Unlock()
  224. if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x51, 0x00, 0x00, 0x52}, 5, ch); err != nil {
  225. return data, fmt.Errorf("获取P值失败: %w", err)
  226. }
  227. this.mu.Lock()
  228. this.expectedType = 0x5B
  229. this.mu.Unlock()
  230. if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x53, 0x00, 0x00, 0x54}, 5, ch); err != nil {
  231. return data, fmt.Errorf("获取T值失败: %w", err)
  232. }
  233. this.mu.Lock()
  234. this.expectedType = 0x5D
  235. this.mu.Unlock()
  236. if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x55, 0x00, 0x00, 0x56}, 5, ch); err != nil {
  237. return data, fmt.Errorf("获取Z值失败: %w", err)
  238. }
  239. return data, nil
  240. }
  241. var data Core.CDVR_PTZPOS
  242. var dataPtr = unsafe.Pointer(&data)
  243. err := Core.GetDVRConfig(this.userId, 293, 1, dataPtr, Core.DWORD(unsafe.Sizeof(data)))
  244. if err != nil {
  245. return PTZ{}, err
  246. }
  247. res := data.Go()
  248. return PTZ{
  249. P: float32(res.WPanPos),
  250. T: float32(res.WTiltPos),
  251. Z: float32(res.WZoomPos),
  252. }, nil
  253. }
  254. func padding(n int) ([]byte, error) {
  255. if n < 0 || n > 65535 {
  256. return []byte{0x00, 0x00}, errors.New("n must be in the range 0-65535")
  257. }
  258. return []byte{byte(n >> 8), byte(n & 0xFF)}, nil
  259. }
  260. func (this *BallCamera) PtzGotoPut(Action int, P, T, Z float64) error {
  261. if this == nil {
  262. return errors.New("BallCamera is nil")
  263. }
  264. if this._type == BuKongQiu {
  265. SerialStartHandle, err := Core.SerialStart(this.userId, func(lSerialHandle Core.LONG, lChannel Core.LONG, pRecvDataBuffer []byte, dwBufSize Core.DWORD, pUser unsafe.Pointer) {
  266. })
  267. if err != nil {
  268. return err
  269. }
  270. defer func() {
  271. err = Core.SerialStop(SerialStartHandle)
  272. if err != nil {
  273. println(err.Error())
  274. }
  275. time.Sleep(1 * time.Second)
  276. }()
  277. PByte, err := padding(int(P * 100))
  278. if err != nil {
  279. return err
  280. }
  281. TByte, err := padding(int(T * 100))
  282. if err != nil {
  283. return err
  284. }
  285. ZByte, err := padding(int(Z * 100))
  286. if err != nil {
  287. return err
  288. }
  289. pBuf := append([]byte{0xff, 0x01, 0x00, 0x4b}, PByte...)
  290. tBuf := append([]byte{0xff, 0x01, 0x00, 0x4d}, TByte...)
  291. zBuf := append([]byte{0xff, 0x01, 0x00, 0x4f}, ZByte...)
  292. pBufv, err := verify(pBuf)
  293. if err != nil {
  294. return err
  295. }
  296. tBufv, err := verify(tBuf)
  297. if err != nil {
  298. return err
  299. }
  300. zBufv, err := verify(zBuf)
  301. if err != nil {
  302. return err
  303. }
  304. pBuf = append(pBuf, pBufv)
  305. tBuf = append(tBuf, tBufv)
  306. zBuf = append(zBuf, zBufv)
  307. switch Action {
  308. case 1:
  309. err = Core.SerialSend(SerialStartHandle, pBuf)
  310. if err != nil {
  311. return err
  312. }
  313. err = Core.SerialSend(SerialStartHandle, tBuf)
  314. if err != nil {
  315. return err
  316. }
  317. err = Core.SerialSend(SerialStartHandle, zBuf)
  318. if err != nil {
  319. return err
  320. }
  321. break
  322. case 2:
  323. err = Core.SerialSend(SerialStartHandle, pBuf)
  324. if err != nil {
  325. return err
  326. }
  327. break
  328. case 3:
  329. err = Core.SerialSend(SerialStartHandle, tBuf)
  330. if err != nil {
  331. return err
  332. }
  333. break
  334. case 4:
  335. err = Core.SerialSend(SerialStartHandle, zBuf)
  336. if err != nil {
  337. return err
  338. }
  339. break
  340. case 5:
  341. err = Core.SerialSend(SerialStartHandle, pBuf)
  342. if err != nil {
  343. return err
  344. }
  345. err = Core.SerialSend(SerialStartHandle, tBuf)
  346. if err != nil {
  347. return err
  348. }
  349. break
  350. default:
  351. return errors.New("action error")
  352. }
  353. return nil
  354. }
  355. var data Core.CDVR_PTZPOS
  356. data.Set(float64(Action), P, T, Z)
  357. var dataPtr = unsafe.Pointer(&data)
  358. err := Core.SetDVRConfig(this.userId, 292, 1, dataPtr, Core.DWORD(unsafe.Sizeof(data)))
  359. if err != nil {
  360. return err
  361. }
  362. return nil
  363. }
  364. func (this *BallCamera) retrySend(handle Core.LONG, cmd []byte, maxRetries int, ch <-chan bool) error {
  365. for retry := 0; retry < maxRetries; retry++ {
  366. if err := Core.SerialSend(handle, cmd); err != nil {
  367. return err
  368. }
  369. select {
  370. case success := <-ch:
  371. if success {
  372. return nil
  373. }
  374. if retry == maxRetries-1 {
  375. return fmt.Errorf("达到最大重试次数 %d", maxRetries)
  376. }
  377. case <-time.After(2 * time.Second): // 添加超时机制
  378. if retry == maxRetries-1 {
  379. return fmt.Errorf("响应超时,重试 %d 次后失败", maxRetries)
  380. }
  381. }
  382. }
  383. return nil
  384. }
  385. func (receiver *BallCamera) StartBus(direction int, speed int) error {
  386. if receiver == nil {
  387. return errors.New("BallCamera is nil")
  388. }
  389. err := Core.PTZControlWithSpeed_Other(receiver.userId, Core.LONG(receiver.deviceInfo.ByStartChan), Core.DWORD(PTZEnum.toHikPTZEnum(direction)), Core.DWORD(0), Core.DWORD(speed))
  390. if err != nil {
  391. return err
  392. }
  393. return nil
  394. }
  395. func (receiver *BallCamera) StopBus(direction int, speed int) error {
  396. if receiver == nil {
  397. return errors.New("BallCamera is nil")
  398. }
  399. err := Core.PTZControlWithSpeed_Other(receiver.userId, Core.LONG(receiver.deviceInfo.ByStartChan), Core.DWORD(PTZEnum.toHikPTZEnum(direction)), Core.DWORD(1), Core.DWORD(speed))
  400. if err != nil {
  401. return err
  402. }
  403. return nil
  404. }
  405. func verify(data []byte) (byte, error) {
  406. if len(data) < 6 {
  407. return 0, fmt.Errorf("data too short")
  408. }
  409. sum := 0
  410. for i := 1; i < 6; i++ {
  411. sum += int(data[i])
  412. }
  413. // 取模并转换为16进制
  414. checksum := sum % 0x100
  415. return byte(checksum), nil
  416. }
  417. func (this *BallCamera) Logout() error {
  418. if this == nil {
  419. return errors.New("BallCamera is nil")
  420. }
  421. return Core.Logout(this.userId)
  422. }
  423. func (this *BallCamera) Status() bool {
  424. if this == nil {
  425. return false
  426. }
  427. return Core.NET_DVR_RemoteControl(this.userId)
  428. }