BallCamera.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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._type == BuKongQiu {
  180. var data PTZ
  181. ch := make(chan bool)
  182. SerialStartHandle, err := Core.SerialStart(this.userId, func(lSerialHandle Core.LONG, lChannel Core.LONG, pRecvDataBuffer []byte, dwBufSize Core.DWORD, pUser unsafe.Pointer) {
  183. if dwBufSize != 7 {
  184. ch <- false
  185. return
  186. }
  187. Type := pRecvDataBuffer[3]
  188. this.mu.Lock()
  189. expected := this.expectedType
  190. this.mu.Unlock()
  191. if Type != expected {
  192. ch <- false
  193. return
  194. }
  195. switch Type {
  196. case 0x59:
  197. data.P = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100.
  198. case 0x5B:
  199. data.T = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100.
  200. case 0x5D:
  201. data.Z = float32(binary.BigEndian.Uint16(pRecvDataBuffer[4:6])) / 100.
  202. default:
  203. ch <- false
  204. }
  205. ch <- true
  206. })
  207. if err != nil {
  208. return data, err
  209. }
  210. defer func() {
  211. err = Core.SerialStop(SerialStartHandle)
  212. if err != nil {
  213. println(err.Error())
  214. }
  215. time.Sleep(1 * time.Second)
  216. }()
  217. // 获取P值
  218. this.mu.Lock()
  219. this.expectedType = 0x59
  220. this.mu.Unlock()
  221. if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x51, 0x00, 0x00, 0x52}, 5, ch); err != nil {
  222. return data, fmt.Errorf("获取P值失败: %w", err)
  223. }
  224. this.mu.Lock()
  225. this.expectedType = 0x5B
  226. this.mu.Unlock()
  227. if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x53, 0x00, 0x00, 0x54}, 5, ch); err != nil {
  228. return data, fmt.Errorf("获取T值失败: %w", err)
  229. }
  230. this.mu.Lock()
  231. this.expectedType = 0x5D
  232. this.mu.Unlock()
  233. if err := this.retrySend(SerialStartHandle, []byte{0xff, 0x01, 0x00, 0x55, 0x00, 0x00, 0x56}, 5, ch); err != nil {
  234. return data, fmt.Errorf("获取Z值失败: %w", err)
  235. }
  236. return data, nil
  237. }
  238. var data Core.CDVR_PTZPOS
  239. var dataPtr = unsafe.Pointer(&data)
  240. err := Core.GetDVRConfig(this.userId, 293, 1, dataPtr, Core.DWORD(unsafe.Sizeof(data)))
  241. if err != nil {
  242. return PTZ{}, err
  243. }
  244. res := data.Go()
  245. return PTZ{
  246. P: float32(res.WPanPos),
  247. T: float32(res.WTiltPos),
  248. Z: float32(res.WZoomPos),
  249. }, nil
  250. }
  251. func padding(n int) ([]byte, error) {
  252. if n < 0 || n > 65535 {
  253. return []byte{0x00, 0x00}, errors.New("n must be in the range 0-65535")
  254. }
  255. return []byte{byte(n >> 8), byte(n & 0xFF)}, nil
  256. }
  257. func (this *BallCamera) PtzGotoPut(Action int, P, T, Z float64) error {
  258. if this._type == BuKongQiu {
  259. SerialStartHandle, err := Core.SerialStart(this.userId, func(lSerialHandle Core.LONG, lChannel Core.LONG, pRecvDataBuffer []byte, dwBufSize Core.DWORD, pUser unsafe.Pointer) {
  260. })
  261. if err != nil {
  262. return err
  263. }
  264. defer func() {
  265. err = Core.SerialStop(SerialStartHandle)
  266. if err != nil {
  267. println(err.Error())
  268. }
  269. time.Sleep(1 * time.Second)
  270. }()
  271. PByte, err := padding(int(P * 100))
  272. if err != nil {
  273. return err
  274. }
  275. TByte, err := padding(int(T * 100))
  276. if err != nil {
  277. return err
  278. }
  279. ZByte, err := padding(int(Z * 100))
  280. if err != nil {
  281. return err
  282. }
  283. pBuf := append([]byte{0xff, 0x01, 0x00, 0x4b}, PByte...)
  284. tBuf := append([]byte{0xff, 0x01, 0x00, 0x4d}, TByte...)
  285. zBuf := append([]byte{0xff, 0x01, 0x00, 0x4f}, ZByte...)
  286. pBufv, err := verify(pBuf)
  287. if err != nil {
  288. return err
  289. }
  290. tBufv, err := verify(tBuf)
  291. if err != nil {
  292. return err
  293. }
  294. zBufv, err := verify(zBuf)
  295. if err != nil {
  296. return err
  297. }
  298. pBuf = append(pBuf, pBufv)
  299. tBuf = append(tBuf, tBufv)
  300. zBuf = append(zBuf, zBufv)
  301. switch Action {
  302. case 1:
  303. err = Core.SerialSend(SerialStartHandle, pBuf)
  304. if err != nil {
  305. return err
  306. }
  307. err = Core.SerialSend(SerialStartHandle, tBuf)
  308. if err != nil {
  309. return err
  310. }
  311. err = Core.SerialSend(SerialStartHandle, zBuf)
  312. if err != nil {
  313. return err
  314. }
  315. break
  316. case 2:
  317. err = Core.SerialSend(SerialStartHandle, pBuf)
  318. if err != nil {
  319. return err
  320. }
  321. break
  322. case 3:
  323. err = Core.SerialSend(SerialStartHandle, tBuf)
  324. if err != nil {
  325. return err
  326. }
  327. break
  328. case 4:
  329. err = Core.SerialSend(SerialStartHandle, zBuf)
  330. if err != nil {
  331. return err
  332. }
  333. break
  334. case 5:
  335. err = Core.SerialSend(SerialStartHandle, pBuf)
  336. if err != nil {
  337. return err
  338. }
  339. err = Core.SerialSend(SerialStartHandle, tBuf)
  340. if err != nil {
  341. return err
  342. }
  343. break
  344. default:
  345. return errors.New("action error")
  346. }
  347. return nil
  348. }
  349. var data Core.CDVR_PTZPOS
  350. data.Set(float64(Action), P, T, Z)
  351. var dataPtr = unsafe.Pointer(&data)
  352. err := Core.SetDVRConfig(this.userId, 292, 1, dataPtr, Core.DWORD(unsafe.Sizeof(data)))
  353. if err != nil {
  354. return err
  355. }
  356. return nil
  357. }
  358. func (this *BallCamera) retrySend(handle Core.LONG, cmd []byte, maxRetries int, ch <-chan bool) error {
  359. for retry := 0; retry < maxRetries; retry++ {
  360. if err := Core.SerialSend(handle, cmd); err != nil {
  361. return err
  362. }
  363. select {
  364. case success := <-ch:
  365. if success {
  366. return nil
  367. }
  368. if retry == maxRetries-1 {
  369. return fmt.Errorf("达到最大重试次数 %d", maxRetries)
  370. }
  371. case <-time.After(2 * time.Second): // 添加超时机制
  372. if retry == maxRetries-1 {
  373. return fmt.Errorf("响应超时,重试 %d 次后失败", maxRetries)
  374. }
  375. }
  376. }
  377. return nil
  378. }
  379. func (receiver *BallCamera) StartBus(direction int, speed int) error {
  380. err := Core.PTZControlWithSpeed_Other(receiver.userId, Core.LONG(receiver.deviceInfo.ByStartChan), Core.DWORD(PTZEnum.toHikPTZEnum(direction)), Core.DWORD(0), Core.DWORD(speed))
  381. if err != nil {
  382. return err
  383. }
  384. return nil
  385. }
  386. func (receiver *BallCamera) StopBus(direction int, speed int) error {
  387. err := Core.PTZControlWithSpeed_Other(receiver.userId, Core.LONG(receiver.deviceInfo.ByStartChan), Core.DWORD(PTZEnum.toHikPTZEnum(direction)), Core.DWORD(1), Core.DWORD(speed))
  388. if err != nil {
  389. return err
  390. }
  391. return nil
  392. }
  393. func verify(data []byte) (byte, error) {
  394. if len(data) < 6 {
  395. return 0, fmt.Errorf("data too short")
  396. }
  397. sum := 0
  398. for i := 1; i < 6; i++ {
  399. sum += int(data[i])
  400. }
  401. // 取模并转换为16进制
  402. checksum := sum % 0x100
  403. return byte(checksum), nil
  404. }
  405. func (this *BallCamera) Logout() error {
  406. return Core.Logout(this.userId)
  407. }