stouchinglhh Claude Code commited on
Commit
383d0b9
·
1 Parent(s): 849e0ae

collector: 更新采集工程至 v1.3.5(RGB 断联根因=DECXIN 停在等时档 alt7 每 68~116 秒静默停摆,改自适应档位:libuvc 新增 uvc_set_altsetting_override() 运行时接口、起始取最保守档、连停 2 次或连开不起来 3 次自动降档并落盘;camera-service 加静默卡死自愈与 SIGTERM 有界收尾;夹爪扫描配对从 USB 根端口改走 ESP32 NVS 序列号;s80c 上色工具修隔帧重复。另:不含误提交的 rec003.zip)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. collector/.gitignore +2 -0
  2. collector/README.md +164 -1
  3. collector/config/__init__.py +1 -1
  4. collector/core/gripper/camera_service_src/CMakeLists.txt +100 -0
  5. collector/core/gripper/camera_service_src/README.md +181 -0
  6. collector/core/gripper/camera_service_src/build.sh +244 -0
  7. collector/core/gripper/camera_service_src/src/camera_service.c +1514 -0
  8. collector/core/gripper/camera_service_src/tests/test_altsetting_ladder.c +202 -0
  9. collector/core/gripper/camera_service_src/tests/test_frame_integrity.c +45 -0
  10. collector/core/gripper/camera_service_src/third_party/libuvc/CMakeLists.txt +230 -0
  11. collector/core/gripper/camera_service_src/third_party/libuvc/LICENSE.txt +31 -0
  12. collector/core/gripper/camera_service_src/third_party/libuvc/README.md +29 -0
  13. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_imac.txt +228 -0
  14. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_macbook.txt +228 -0
  15. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/logitech_hd_pro_920.txt +1817 -0
  16. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/ms_lifecam_show.txt +767 -0
  17. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000.txt +1543 -0
  18. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_builtin_ctrls.txt +13 -0
  19. collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_extra_ctrls.txt +18 -0
  20. collector/core/gripper/camera_service_src/third_party/libuvc/changelog.txt +140 -0
  21. collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindJpegPkg.cmake +82 -0
  22. collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindLibUSB.cmake +51 -0
  23. collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindOpenCVPkg.cmake +86 -0
  24. collector/core/gripper/camera_service_src/third_party/libuvc/doxygen.conf +0 -0
  25. collector/core/gripper/camera_service_src/third_party/libuvc/include/libuvc/libuvc.h +833 -0
  26. collector/core/gripper/camera_service_src/third_party/libuvc/include/libuvc/libuvc_config.h.in +22 -0
  27. collector/core/gripper/camera_service_src/third_party/libuvc/include/libuvc/libuvc_internal.h +326 -0
  28. collector/core/gripper/camera_service_src/third_party/libuvc/include/utlist.h +490 -0
  29. collector/core/gripper/camera_service_src/third_party/libuvc/libuvc.pc.in +11 -0
  30. collector/core/gripper/camera_service_src/third_party/libuvc/libuvcConfig.cmake +17 -0
  31. collector/core/gripper/camera_service_src/third_party/libuvc/src/ctrl-gen.c +2259 -0
  32. collector/core/gripper/camera_service_src/third_party/libuvc/src/ctrl-gen.py +302 -0
  33. collector/core/gripper/camera_service_src/third_party/libuvc/src/ctrl.c +165 -0
  34. collector/core/gripper/camera_service_src/third_party/libuvc/src/device.c +2005 -0
  35. collector/core/gripper/camera_service_src/third_party/libuvc/src/diag.c +376 -0
  36. collector/core/gripper/camera_service_src/third_party/libuvc/src/example.c +226 -0
  37. collector/core/gripper/camera_service_src/third_party/libuvc/src/frame-mjpeg.c +222 -0
  38. collector/core/gripper/camera_service_src/third_party/libuvc/src/frame.c +475 -0
  39. collector/core/gripper/camera_service_src/third_party/libuvc/src/init.c +163 -0
  40. collector/core/gripper/camera_service_src/third_party/libuvc/src/misc.c +58 -0
  41. collector/core/gripper/camera_service_src/third_party/libuvc/src/stream.c +1752 -0
  42. collector/core/gripper/camera_service_src/third_party/libuvc/src/test.c +153 -0
  43. collector/core/gripper/camera_service_src/third_party/libuvc/standard-units.yaml +518 -0
  44. collector/core/gripper/camera_service_src/tools/discover_uvc_config.c +1463 -0
  45. collector/core/gripper/camera_service_src/tools/sonix_flash_probe.c +618 -0
  46. collector/core/gripper/devices/gripper_serial.py +67 -15
  47. collector/core/gripper/devices/uvc_camera_service.py +195 -36
  48. collector/core/gripper/fays_serial_probe.py +23 -2
  49. collector/core/gripper/fays_single.py +170 -81
  50. collector/core/gripper/paths.py +6 -0
collector/.gitignore CHANGED
@@ -28,6 +28,8 @@ venv_lite/
28
  .claude/
29
  keypoints_output/
30
  exports/
 
 
31
  tools/weights/
32
  wheels/ # scripts/pack_wheels.py 生成的离线部署包(不入库,拷给客户用)
33
  imgui.ini
 
28
  .claude/
29
  keypoints_output/
30
  exports/
31
+ # 本地取回的录制素材与上色产物(双目原视频等,体积大且属外部数据)
32
+ rec001(1)/
33
  tools/weights/
34
  wheels/ # scripts/pack_wheels.py 生成的离线部署包(不入库,拷给客户用)
35
  imgui.ini
collector/README.md CHANGED
@@ -1,6 +1,6 @@
1
  # collector — Multimodal Data Acquisition SDK · 多模态数据采集 SDK
2
 
3
- ![Version](https://img.shields.io/badge/version-1.3.4-blue)
4
  ![Python](https://img.shields.io/badge/python-3.12-blue)
5
  ![License](https://img.shields.io/badge/license-TBD-lightgrey)
6
 
@@ -361,6 +361,128 @@ are documented in [docs/index.md](docs/index.md#开发约定).
361
 
362
  ### Changelog
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  - **v1.3.4** — a newly plugged-in gripper now generates its own runtime
365
  calibration and connects, with no manual step. Previously onboarding a new
366
  Fays S80M took two manual steps — click `device_setup` on the gripper's host
@@ -833,6 +955,47 @@ i18n 文案经 `tr()` 翻译、PyQt5 信号参数用 `object` 封送大整数、
833
 
834
  ### 更新记录
835
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
836
  - **v1.3.4** — 新夹爪接入即自动生成运行标定并连接,不再需要任何人工步骤。
837
  此前接入一只新 Fays S80M 要人工两步——先在夹爪上位机点 `device_setup`、
838
  再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序
 
1
  # collector — Multimodal Data Acquisition SDK · 多模态数据采集 SDK
2
 
3
+ ![Version](https://img.shields.io/badge/version-1.3.5-blue)
4
  ![Python](https://img.shields.io/badge/python-3.12-blue)
5
  ![License](https://img.shields.io/badge/license-TBD-lightgrey)
6
 
 
361
 
362
  ### Changelog
363
 
364
+ - **v1.3.5** — the camera service heals itself, and gripper scan pairing moved
365
+ from USB root ports to NVS serials.
366
+ **Cameras:** the UVC cameras (DECXIN `1bcf:2d4f` plus two Sightac `0c45:636f`)
367
+ can wedge silently with no process touching them — on 2026-09-15 the right
368
+ Sightac was streaming normally at 21:53 and simply refused to start at 09:24,
369
+ with no usbfs or uvcvideo message in between and the machine awake all night.
370
+ What the user sees ("RGB shows only the first frame", "camera-service did not
371
+ obtain valid MJPG frames from all cameras within the time limit") is really a
372
+ failure to recover, not a failure to stay up. Two different wedges need two
373
+ different cures: a **stall** (stream running, `received` freezes, not a single
374
+ kernel message, 6–82 s at random, load-correlated) recovers from rebuilding
375
+ the libusb context alone (6/6 and 5/5 measured — a USB reset is a wasted
376
+ cost), while a **hard failure** (`uvc_start_streaming failed: I/O error`,
377
+ `UVC format/interface negotiation failed: Invalid mode`, or
378
+ `negotiated_payload` alternating 3072/0) does not (9 consecutive attempts
379
+ failed; the device firmware is wedged) and only a USB reset / re-enumeration
380
+ clears it. Added a 3-second stall watchdog (`STREAM_STALL_TIMEOUT_SECONDS`,
381
+ 4 s for the first frame); stalls rebuild the libusb context, hard failures
382
+ escalate to a USB reset after **2 consecutive** attempts (capped at
383
+ `USB_RESET_LIMIT` 3, since without a cap a genuinely dead device would reset
384
+ every 2 seconds and pin the two neighbours on the same hub), and a stall
385
+ clears that counter so stalls can never add up into a spurious reset. The
386
+ reset now happens **before** `uvc_stop_streaming` (`teardown_failed_open`):
387
+ on a wedged device `uvc_stop_streaming` waits for isochronous transfers that
388
+ never return, which measurably burns the client's 2-second grace period and
389
+ gets the process SIGKILLed mid-teardown, leaving the device on an active alt
390
+ setting so the next start fails the same way. Every threshold is derived
391
+ backwards from the client's `SERVICE_START_TIMEOUT_S = 10.0` (second failure
392
+ at t≈2 s → reset → frames by t≈3 s); the old "reset after 20 s of zero
393
+ frames" gate could never fire in a real start, and was attached to the
394
+ zero-frame branch the observed `I/O error` never reaches. Measured reset
395
+ semantics: on a healthy device it is an in-place port reset (kernel logs
396
+ `reset high-speed USB device number N`, devnum unchanged); on a wedged device
397
+ the device drops and re-enumerates (devnum changes) — that is what heals it,
398
+ and libusb reports `rc=-4 (No such device)` during that window, which is
399
+ misleading but harmless. Also fixed the per-second fps reporting baseline
400
+ (it counted from zero, so a restart reported the whole process lifetime as
401
+ one window: 164/207/251 fake fps).
402
+ **RGB disconnects, root cause:** self-healing was only half the story — the
403
+ camera still dropped out afterwards. DECXIN stalls silently every 68–116 s
404
+ while running the high-bandwidth isochronous setting alt7, on **both**
405
+ controllers tested (AMD `1022:43fc`/PCI `0000:0a:00.0` and
406
+ `1022:15b7`/`0000:74:00.4`). The mechanism is **not determined**: measured
407
+ throughput at the moment of the stalls was only 1.66 MB/s mean / 2.63 peak,
408
+ far under the 10.24 MB/s alt7 reserves, so "not enough bandwidth" does not
409
+ explain it. alt6 holds, and both rungs deliver **identical 30.00 fps**, so
410
+ alt7's extra per-frame headroom (327680 vs 241664 B) buys nothing observable.
411
+ Two earlier conclusions are retracted: *"alt7 is fine on bus 1"* — that
412
+ supposedly clean leg never ran at alt7 at all, because the old binary's ini
413
+ fields were inert and the service merely echoed them, so the only trustworthy
414
+ indicator of a leg's real setting is the `[LIBUVC-QUIRK] ... alt=N payload=M
415
+ ... xfers=` line; and the controller-specific claim that followed from it.
416
+ `forced_altsetting`/`forced_payload` are now **authoritative** through a new
417
+ libuvc runtime API `uvc_set_altsetting_override()` (declared in `libuvc.h`,
418
+ implemented in `device.c`) — before this they were only validated and
419
+ printed, so editing the ini changed nothing, which is very easy to misread.
420
+ The starting rung is chosen in Python, not hardcoded per machine: learned >
421
+ the table's most conservative rung > the scanner's preferred one, because the
422
+ rack's bus is not permanent. A ladder then steps down one rung and persists
423
+ the conclusion under `vid:pid × controller PCI path × camera serial` after 2
424
+ consecutive stalls or 3 consecutive failed opens (the latter covers a
425
+ setting that will not fit at STREAMON, where the stream never starts and the
426
+ stall path can never fire); `CLEAN_RUN_SECONDS = 300` clears the stall
427
+ counter. A downgrade must clear **both** counters — the thresholds are
428
+ equality tests, so a counter left standing on its threshold never fires
429
+ again and the failed-open path would jam after a single step. Both log lines
430
+ capture the count *before* the downgrade clears it. The scanner truthfully
431
+ reports the descriptor's preferred rung (alt7); the app checks it is *any*
432
+ rung of the ladder and refuses only on a genuine desync. The C source and its
433
+ build recipe moved into `core/gripper/camera_service_src/` (`./build.sh` is
434
+ the single entry point), and `--test` now runs `ctest` — the ladder test was
435
+ registered with `add_test` but had never actually been executed, and the
436
+ jam-bug above fell exactly inside what it should have covered. Verified on
437
+ hardware: forced alt7 stalled at 78 s and 116 s, the service logged the
438
+ downgrade and recovered to alt6 for 169 s at 30 fps with zero stalls; the
439
+ app-generated ini (alt6 default) then ran **600 s across three legs with 0
440
+ stalls / 0 rebuilds / 0 failed opens / 0 resets** (17513/17496/17487 frames),
441
+ and a post-install 300 s regression on the deployed binary was clean too. The
442
+ ladder test was reverse-verified as non-vacuous: removing the counter reset
443
+ makes it abort.
444
+ **Grippers:** ported the scan chain from the delivery package
445
+ `设备扫描逻辑与程序_20260914`. Pairing used to go through USB root
446
+ ports/controllers — a premise that was simply wrong, since the Fays is a
447
+ USB3/FT602 device on its own 5000M bus and never shared a root with the
448
+ UVC/ESP32 devices. The chain is now: UVC group → the unique ESP32 (path
449
+ starting `bus-outer.`) → send `QF` over serial to read the Fays serial bound
450
+ in its NVS → match against the official SDK's enumerated `device.serial`,
451
+ with a clear refusal when any step is not unique and no fallback to guessing
452
+ by port or enumeration order. The SDK probe is preceded by a
453
+ `validate_fays_superspeed` pre-check and then enumerates serials fast
454
+ (`--serial-only-fast`; a timeout now decodes stdout/stderr and appends the
455
+ last 20 lines instead of reporting a bare timeout). Dual-rig runs skip a
456
+ device another rig holds instead of claiming it. On the serial side the fixed
457
+ boot delay became a 2-second polling `?` handshake, the port is opened
458
+ `exclusive=True`, and `QF` (query) / `WF:<serial>` (write) commands were
459
+ added; `GripperSerial.send()` looked commands up by their first character
460
+ only (`[:1]`), so `"QF"` could never match its own expected list. Prerequisite:
461
+ the ESP32 firmware must understand `QF`/`WF:` — the current `online/esp32_proc`
462
+ firmware does not, and will fail closed with "查询 Fays 序列号失败: ERR".
463
+ Added the offline self-check `tools/tests/test_gripper_fays_pairing.py`.
464
+ **s80c colorize tool:** fixed a duplicated-every-other-frame bug in
465
+ `tools/s80c_arm_convert/convert_arm_dataset.py` (an independent fix committed
466
+ after v1.3.4). `pooled_episodes_v1` recordings write **two rows per frame**
467
+ (`frame_index` = 0,0,1,1,…, with identical `timestamp`/`hardware_ns` in both
468
+ rows) while the video has one frame; the tool used the row count as the frame
469
+ count and then indexed `hw_ns[i]` by video frame number, so every timestamp
470
+ was sent twice — and the offline ISP reuses the previous output for a
471
+ duplicate timestamp, which is what duplicated every other frame. Measured on
472
+ rec001's lossless output: 394 of 833 frames byte-identical to their
473
+ predecessor, all 394 at odd positions (the second of each timestamp pair),
474
+ versus 0 in the source video. The same root cause also **halved the IMU
475
+ sidecar** — `hw_ns[:n_frames]` only reached the 417th timestamp and every
476
+ later IMU sample was dropped by the "later than the last frame" rule, leaving
477
+ 416 rows / 13.8 s; after the fix, 832 rows / 27.7 s against a 27.8 s video.
478
+ Redundant rows are now folded by `frame_index`, but **only when every row
479
+ under that index has identical `timestamp` and `hardware_ns`**; otherwise it
480
+ warns and leaves the data untouched. Of the 142 parquets carrying
481
+ `frame_index`, 129 already had one row per frame (no-op), 1 was genuinely
482
+ redundant (rec001, 1666 rows → 833 frames), and 12 had differing timestamps
483
+ between rows (folding would lose them, so they are warn-only). The colorize
484
+ chain itself is untouched: same config, same offline ISP, `--sdk-wb-auto` as
485
+ before, with grey-world gains bit-identical to the pre-fix run.
486
  - **v1.3.4** — a newly plugged-in gripper now generates its own runtime
487
  calibration and connects, with no manual step. Previously onboarding a new
488
  Fays S80M took two manual steps — click `device_setup` on the gripper's host
 
955
 
956
  ### 更新记录
957
 
958
+ - **v1.3.5** — 相机服务能自愈了;夹爪扫描配对从 USB ��端口改走 NVS 序列号。
959
+ **相机侧**:UVC 相机(DECXIN `1bcf:2d4f` 与两个 Sightac `0c45:636f`)会**静默
960
+ 卡死、且不需要任何进程碰它**——2026-09-15 实证右目 Sightac 是自己夜里坏的
961
+ (21:53 还在正常推流,09:24 启动就坏,中间没有任何进程打开过它、内核无
962
+ usbfs/uvcvideo 消息,机器整夜没睡)。用户看到的「RGB 只剩第一帧」「未在限定
963
+ 时间取得全部相机的有效 MJPG 帧」,根子是**服务不会自愈**,不是**服务会倒**。
964
+ 两种卡死要分开治:**停摆**(开着流突然不出帧、`received` 冻住、内核一条消息
965
+ 都没有,6~82 秒随机、与负载正相关)**重建 libusb 上下文就够**(实测 6/6、5/5
966
+ 全恢复,USB 复位是白付的代价);**开不起来**(`uvc_start_streaming failed:
967
+ I/O error`、`UVC format/interface negotiation failed: Invalid mode`、
968
+ `negotiated_payload` 在 3072↔0 之间跳)**重建上下文救不回来**(实测连试 9 次
969
+ 全败,设备固件侧卡死了),只有 USB 复位/重枚举能洗。新增 3 秒停滞看门狗
970
+ (`STREAM_STALL_TIMEOUT_SECONDS`,首帧 4 秒);停摆(`rc>0`)重建 libusb
971
+ 上下文;开不起来(`rc<0`)**连续 2 次**升级成 USB 复位,`USB_RESET_LIMIT` 3 次
972
+ 封顶(设备真坏了时不设上限会变成每 2 秒复位一次、把同 Hub 的另外两路一直按在
973
+ 地上),而停摆会清零该计数,免得几次停摆凑数误触发复位去打扰邻居。**复位要抢在
974
+ `uvc_stop_streaming` 之前**(`teardown_failed_open`)——卡死设备上
975
+ `uvc_stop_streaming` 会一直等它那批永远回不来的等时传输,实测能把客户端那 2 秒
976
+ 宽限耗光而被 SIGKILL,进程死在这中间、设备就停在激活的 alt setting 上,下一轮
977
+ 照样起不来(09:24 的日志正是断在 startup failed 与 usb reset 之间)。所有阈值由
978
+ 客户端窗口 `SERVICE_START_TIMEOUT_S = 10.0` 倒推:第 2 次失败在 t≈2 秒触发复位、
979
+ t≈3 秒就能出帧;旧的「重开 20 秒零帧才复位」在真实启动场景**永远够不到**,且只
980
+ 挂在零帧分支上。复位语义实测:打在**健康**设备上是原地端口复位(devnum 不变),
981
+ 打在**卡死**设备上是掉线重枚举(devnum 变了)**这才会好**,libusb 在那窗口里返回
982
+ `rc=-4 (No such device)` 是报错但事办了。真机验证:第 1 次失败不复位、第 2 次
983
+ `usb reset: rc=0 (Success)`、打满 3 次后停手;三路 90 秒回归 0 停摆 0 误复位
984
+ (2694/2683/2684 帧 ≈29.9fps);SIGTERM 退出 1.16 秒,不超客户端 2 秒宽限。
985
+ **夹爪侧**:移植交付包「设备扫描逻辑与程序_20260914」。配对从 **USB 根端口/
986
+ 控制器**改走 **NVS 序列号**——旧规则(外加「同一 USB2 总线出现双 rig 就拒扫」)
987
+ 的前提就是错的:Fays 是 USB3/FT602 挂在配套的 5000M 总线上,跟 UVC/ESP32 本来
988
+ 就不共根,只能靠猜。新链路:UVC 组 → 唯一 ESP32(`bus-outer.` 开头)→ 串口发
989
+ `QF` 读它 NVS 里绑定的 Fays 序列号 → 与官方 SDK 枚举出的 `device.serial` 比对,
990
+ 任一步不唯一就明确拒绝,不再按端口或枚举顺序猜。SDK 探测前先做超速预检,再以
991
+ `--serial-only-fast` 快速枚举序列号(超时不再只报一句 timeout,解码
992
+ stdout/stderr 并附最后 20 行);双 rig 会「在用时跳过」另一 rig 正持有的设备
993
+ 而不是占用。串口侧:固定 2 秒死等改成轮询 `?` 握手,端口加 `exclusive=True`,
994
+ 新增 `QF` 查询 / `WF:<serial>` 写入;顺带修 `send()` 只拿首字符查命令表
995
+ (`[:1]`)导致 `"QF"` 永远匹配不上自己期望表的 bug。**前置条件:ESP32 固件必须
996
+ 认识 `QF`/`WF:`,当前 `online/esp32_proc` 的固件还不认识,会失败关闭并报
997
+ 「查询 Fays 序列号失败: ERR」,需先烧固件。** 新增离线自检
998
+ `tools/tests/test_gripper_fays_pairing.py`。
999
  - **v1.3.4** — 新夹爪接入即自动生成运行标定并连接,不再需要任何人工步骤。
1000
  此前接入一只新 Fays S80M 要人工两步——先在夹爪上位机点 `device_setup`、
1001
  再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序
collector/config/__init__.py CHANGED
@@ -3,4 +3,4 @@
3
  版本号集中定义于此:settings.APP_VERSION 及其他模块均从这里取值。
4
  """
5
 
6
- __version__ = "1.3.4" # 新夹爪接入即自动生成运行标定并连接(Fays S80M):此前接入一只新夹爪要人工两步——先在夹爪上位机点 `device_setup`、再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序直接拒绝启动(「当前 Fays 缺少运行标定文件…请先在夹爪上位机中运行 device_setup」);现在 `SingleFaysLease.acquire()` 发现 per-serial YAML 缺失时,就在设备锁内调厂商导出程序从**这只夹爪自身**读出厂标定、生成 SDK YAML 与 ORB YAML(鱼眼 `stereoRectify` 求 P1/R1 + IMU 外参 `T_b_c1` + 探针读五项噪声/频率),复核落盘路径后直接连上,已有标定走 `isfile` 快路径(启动零额外开销、不碰设备)——这两个文件是**逐设备**出厂标定不可跨设备复用(实测 098/099 三组全不同),只能现场读;设备面板夹爪条目右键加「重新读取出厂标定」(录制中禁用,标定前自动关该夹爪、完成后开回),`tools/import_gripper_calibration.py` 加 `--generate`(旧文件先备份 `.bak_<时间戳>`)供命令行强制重生成;顺带修掉生成产物第 3 行的出处注释——厂商模板写死指向 `3500000261870088`,照抄会让每只新夹爪的 IMU 外参都被记成「取自另一台设备」,现改写成本机序列号(历史产物不动)。承接 v1.3.3 的力矩阵/触觉力与 RGB 视频的时间戳对齐:**力侧此前完全没有时间戳**——同一行里的 RGB 帧和力样本不是同时刻采集的,RGB 走外部帧源队列取队头最旧帧、力/矩阵走 latest-wins 单槽取当下最新,于是「行号相同」≠「时刻相同」,力恒领先 RGB 且领先量随录制时长增长(RGB 源 30.84fps vs 写线程 30fps,实测约 1 帧/秒,下游观测到的滞后 3 帧就是这么来的),力矩阵走独立泵线程还与 3 向量力各记各的时刻。修法是让每行自描述:`tactile_ready` 加第 5 个载荷 `capture_ns`(在 SDK 回调入口取),`pipeline.write_tactile_force/_force_matrix` 落成独立的 `observation.gripper_{side}_force_ns` / `_force_matrix_ns` 稀疏 int64 列(与 `hardware_ns` 同宿主单调钟时基,features 里声明 `encoding: host_monotonic_ns`),下游按时间取最近邻即可还原真实配对,精度上界=半个力样本间隔;顺带修 `rgb_frame_ready`/`stereo_frame_ready` 的 `pyqtSignal(int)` 把 `time.monotonic_ns()` 按 C++ qint32 静默截断成负数(每 2.147s 翻符号),改 `object` 封送——这也解释了此前用 `hardware_ns` 解回卷时凭空造出上百帧假漂移、把"中位 5.8 帧 / 最大 ±80 帧"报成对齐误差(真值是 ~3 帧,正确规则是**无符号**:单调钟 + FIFO 消费 ⇒ 真步长恒非负);新增 `scripts/align_modalities.py` 处理端最近邻对齐工具,对 v1.3.3 之前录的 episode 明确报「无法对齐(只能重录)」而不用增长率去猜。承接 v1.3.2 的 SLAM 陈旧帧入库前拦截与轨迹显示深拷贝修复。:桥接按「连续回退次数」判定——单帧脏读丢弃、连丢 30 帧才判定时钟真跳变并换基准放行(此前每一帧回退都会让核心库清空 IMU 队并重建地图、位姿停发 0.2–1.34 s,静止时更久),新增 `[TIME_DROP]`/`[TIME_REBASE]` 现场行并**无条件**打进 GUI 日志(此前落进未匹配行被 50 条上限吃掉——实测原生日志 4 次回退、GUI 日志 0 条,真出事时反而看不见),且带 `seq`/`prev_seq` 对比结论以区分「SDK 乱序投递 / 重复投递同一帧 / 帧配了旧时间戳」三种成因(时间戳上三者长得一模一样,对策完全不同);逐秒遥测 `[FPS_DATA]` 改「只在异常时出声」(健康静默、进入异常与恢复各一行、持续异常每 30 s 重复,全量逐秒流仍在原生日志里),并修 `wait_sdk_ready` 就绪门被**粘滞** `state.error` 锁死——任何信息性输出(如 ld.so 的 `cannot be preloaded ... ignored.`)都会让标定明明已完成的这一次返回 False、报出误导的「未等到 [FAYS-CALIB] 标记」(2026-09-10 18:32 假超时事故,文案白名单 + 去掉粘滞判断双管修);原生日志在 runtime 目录 `rmtree` 之前留档到 `logs/slam_native/`(保留最近 20 份),修「一次干净退出的会话其原生日志不可恢复」——排查 SLAM 崩溃时唯一的证据曾随目录一起被删;轨迹显示去掉 Qt 主线程上的整条深拷贝(正是这次拷贝让 `_rendered_trajectory is traj` 判等恒为假、每个位姿都在主线程复制随会话线性增长的点列,即「画一段时间后帧率变低」的直接原因),显示上限 400→6000,并以向量化投影 + 一次 `drawPolyline` 绘制,修「十几秒后轨迹显出折角」(降采样按 stride 翻倍使顶点数恒落 [上限/2, 上限],上限 400 时每段跨 67 ms 且随 stride 每翻一倍继续变粗��观感像 SLAM 出点变慢而数据一直满 30 Hz,是绘制侧丢的);RGB 外部队列在录制开始/结束/中止三个边界排空,修「上一段残留 + 本段启动窗口累积被写成新视频开头」(实测每段开头约 28 帧与上一段 episode 末帧逐帧匹配,队列满时还占 ~110 MB/槽);任务进度只上报后端当前任务列表里存在的任务(本地自建任务平台没这个项目,上报必被拒 400),且后端该项目口径为 `"sessions"`(从没收到过任何上报)时首次送本机**全量**当基线——只送增量会把后端计数从 session 数砸成增量本身(现场:3/3/3 的项目再录一条变 1)。承接 v1.3.1 的力矩阵 5 档落盘与 SLAM 停落 slam_pose 列。
 
3
  版本号集中定义于此:settings.APP_VERSION 及其他模块均从这里取值。
4
  """
5
 
6
+ __version__ = "1.3.5" # 夹爪扫描配对改走 ESP32 NVS 序列号 + camera-service 自愈(两个都是「不恢复」的毛病,不是「会坏」的毛病)。相机侧:UVC 相机(DECXIN 1bcf:2d4f + 两个 Sightac 0c45:636f)会**静默卡死且不需要任何进程碰它**,用户看到的「RGB 只剩第一帧」「camera-service 未在限定时间取得全部相机的有效 MJPG 帧」根子是**服务不会自愈**——实证 2026-09-15 右目 Sightac 是自己夜里坏的(21:53 还在正常推流,09:24 启动就坏,中间没有任何进程打开过它、内核无 usbfs/uvcvideo 消息,机器整夜没睡、14.9 万条内核日志里查不到肇事者)→ 别再去查「谁把它弄脏的」,服务必须能自愈。两种卡死要分开治:**停摆**(开着流突然不出帧、`received` 冻住、内核一条消息都没有,6~82 秒随机、与负载正相关)**重建 libusb 上下文就够**(实测 6/6、5/5 全恢复,USB 复位是白付的代价);**开不起来**(`uvc_start_streaming failed: I/O error` / `UVC format/interface negotiation failed: Invalid mode` / `negotiated_payload` 在 3072↔0 之间跳)**重建上下文救不回来**(实测连试 9 次全败,设备固件侧卡死了),只有 USB 复位/重枚举能洗。改动:新增 3 秒停滞看门狗(`STREAM_STALL_TIMEOUT_SECONDS`,首帧 4 秒)——此前整路静默报废没有任何人管;停摆(`rc>0`)走 `uvc_exit`+`uvc_init` 重建上下文;开不起来(`rc<0`)计入 `hard_failures`,**连续 2 次**升级成 USB 复位(`USB_RESET_LIMIT` 3 次封顶——设备真坏了时不设上限会变成每 2 秒复位一次、把同 Hub 的另外两路一直按在地上),而停摆会**清零**该计数,免得几次停摆凑数误触发复位去打扰邻居;**复位要抢在 `uvc_stop_streaming` 之前**(`teardown_failed_open`)——卡死设备上 `uvc_stop_streaming` 会一直等它那批永远回不来的等时传输,实测能把客户端那 2 秒宽限耗光而被 SIGKILL,进程死在这中间、设备就停在激活的 alt setting 上,下一轮启动照样起不来(用户 09:24 的日志正是断在 startup failed 与 usb reset 之间);所有阈值由客户端窗口倒推(`SERVICE_START_TIMEOUT_S = 10.0`:每次失败约 0.3 秒 + 1 秒间隔,第 2 次失败在 t≈2 秒触发复位、重枚举加重开约 1 秒、t≈3 秒就能出帧,10 秒够用;旧的「重开 20 秒零帧才复位」在真实启动场景**永远够不到**——20 > 10,且只挂在零帧分支上,实测到的 `I/O error` 根本不走那条);复位语义实测——打在**健康**设备上是原地端口复位(内核 `reset high-speed USB device number N`,**devnum 不变**),打在**卡死**设备上是掉线再重枚举(`USB disconnect` + `new high-speed USB device`,**devnum 变了**)**这才会好**,而 libusb 在掉线重枚举的窗口里返回 `rc=-4 (No such device)` 是**报错但事办了**、别被它误导;`libusb_reset_device` 用 `dlsym(RTLD_DEFAULT, …)` 取,不新增 NEEDED、不需要 root(设备节点 udev MODE=0666);顺带修每秒 fps 上报基线(`previous_received` 从 0 起算,重开后把进程启动至今的全部帧数当成本窗口增量,算出 164/207/251 的假速率——纯日志问题,但会把人带偏)。真机验证:确定性升级测试(第 1 次失败不复位、第 2 次 `usb reset: rc=0 (Success)`、打满 3 次后停手)、三路 90 秒回归 0 停摆 0 误复位(2694/2683/2684 帧 ≈29.9fps)、SIGTERM 退出 1.16 秒(旧 1.13 秒)不超客户端 2 秒宽限。**源码位置**:`online/` 在 .gitignore:56 里、不入库;本次把这两个程序的源码连同构建配方搬进了 `core/gripper/camera_service_src/`(`./build.sh` 是唯一构建入口——它替我们处理 libusb 的 pkg-config shim、`-DCMAKE_POLICY_VERSION_MINIMUM=3.5`、以及链接后去掉 RUNPATH 里那个空条目,手工 cmake 会在这些地方卡住;产物装到 `core/gripper/native/camera_service/build/`,旧件按 `.pre_rebuild_<时间戳>` 备份),以后不必再从 libusb 头文件、pkg-config、RUNPATH 那一整串摸起。交付副本 `programs/camera_service/src/camera_service.c` 未动、与 `程序清单.txt` 第 18 行一致。**RGB 断联���根因(2026-09-15 查明,本条是用户「还是会断联」的正面回答):服务自愈之后相机仍会断,断的原因是 DECXIN 跑在高带宽等时档 alt7 上时每 68~116 秒静默停摆一次,两块控制器(AMD `1022:43fc`/PCI `0000:0a:00.0` 与 `1022:15b7`/`0000:74:00.4`)上都一样。机制**未查明**:停摆当时实际吞吐只有 1.66 MB/s(峰值 2.63),离 alt7 预留的 10.24 MB/s 差得远,「带宽不够」解释不通——**别把机制写死**。alt6 同样三路下长跑不停,而两档出帧率一模一样(都 30.00 fps),alt7 多出来的每帧余量(327680 对 241664 字节)换不到任何看得见的好处。此前两个结论已推翻、别再引用:「bus 1 上 alt7 是好的」——那条所谓干净腿根本没跑在 alt7 上,旧二进制里 ini 的 `forced_*` 是死的、服务只把 ini 的值原样打进日志,读到的 `alt=7 payload=1280` 是它在**复读**,**判断一条腿真实档位只认 `[LIBUVC-QUIRK] ... alt=N payload=M ... xfers=` 那一行**;以及同源的「停摆是控制器特异的」。改动:libuvc 新增运行时接口 `uvc_set_altsetting_override()`(声明在 `include/libuvc/libuvc.h`、实现在 `src/device.c`,`uvc_device_handle_t` 是 calloc 出来的、新字段自动零初始化),`forced_altsetting`/`forced_payload` 从此**真正生效**——此前这两个 ini 字段只用于校验和打印,改 ini 完全不改变行为,极容易误判;起始档位由 app 决定、取**档位表里最保守的一档**(`uvc_camera_service.py` 的 `_starting_mode` 优先级:上一轮学到的 > 最后一档 > 扫描程序报的首选档),**不按机器/控制器写死**(机架插在哪条总线不固定,用户明说不是永久的),曾经那张「敌意控制器」表已删;降档梯子 `maybe_downgrade_altsetting`:当前档位连着停摆 2 次、或连着开不起来 3 次(后者覆盖 STREAMON 阶段就排不下带宽、流根本起不来的情形,停摆那条路永远等不到)就退一档并把结论**落盘**(键 = `vid:pid × 控制器 PCI 路径 × 相机序列号`,一个键一个文件,放 `native/gripper_version1/camera_modes/`——**不能放服务的 runtime 目录,那里每次租约释放整个删掉**),稳定跑满 `CLEAN_RUN_SECONDS=300` 清零停摆计数;**降档必须同时清掉两个计数**——门槛是拿 `==` 比的,只清一个的话另一条路降完一档就永远不再命中,表里剩下的档位形同不存在(DECXIN 只有两档,正好把这个缺陷盖住了);两条路的日志都在调用**之前**抓计数,否则清零后只能打出「0 停摆」,正好把最该看的那次降档说成没有依据;`tools/discover_uvc_config.c` 如实报**相机描述符里的首选档**(alt7),app 拿它跟服务端档位表对一遍、确认这一对是梯子上的任意一档,对不上就报「扫描程序与服务端档位表已经脱节」(那说明两个程序分开编了,必须一起重编);`./build.sh --test` 从点名跑 `test-frame-integrity` 改成走 `ctest`——`tests/test_altsetting_ladder.c` 虽然在 `CMakeLists.txt` 里注册了 `add_test`,此前却一次也没被执行过,上面那个「降一档就卡死」正好落在它本该覆盖的范围内。真机验证:ini 强制 alt7 → 78 秒停摆 → 116 秒再停 → 服务打出 `2 stalls at alt=7; dropping to alt=6 payload=944` → 重开在 alt6 → 169 秒 30fps 零停摆,整条降档+恢复路径走通;装 app 自己生成的 ini(alt6 默认)跑 **600 秒三路:0 停摆 / 0 重建 / 0 启动失败 / 0 复位**,17513/17496/17487 帧(30.00/30.00/29.80 fps),日志里 `[LIBUVC-QUIRK] … alt=6 payload=944 endpoint=944 xfers=32 (altsetting override)` 证明确实跑在 alt6 上、ini 真的生效了;装机后再做一次 300 秒回归同样全零停摆;装机产物与源码构建逐个 md5 相同、RUNPATH 仍只有 `$ORIGIN/third_party/libuvc`。离线侧新增 `tools/tests/test_camera_altsetting_mode.py`(19 条,覆盖最保守档/学到值优先/表外值忽略/扫描程序与服务端脱节必须先报错,并钉死与 C 测试共用的落盘键串),`test_altsetting_ladder.c` 补上「两个计数都要清零」的断言并**反向验证过不是空跑的**(把清零那行注释掉,该测试当场断言中止)。装机后需重启主程序才能同时拿到新的 `uvc_camera_service.py` 与新服务,否则两边档位要求对不上会像 2026-09-15 09:24 那样整个起不来。扫描侧:移植交付包「设备扫描逻辑与程序_20260914」,夹爪与 UVC/ESP32 的配对从 **USB 根端口/控制器**改走 **NVS 序列号**——旧规则(`_bus_root`/`_root_port`,外加「同一 USB2 总线出现双 rig 就拒扫」)的前提就是错的:Fays 是 USB3/FT602 挂在配套的 5000M 总线上,跟 UVC/ESP32 本来就不共根,只能靠猜。新链路:UVC 组 → 唯一 ESP32(`bus-outer.` 开头)→ 串口发 `QF` 读它 NVS 里绑定的 Fays 序列号 → 与官方 SDK 枚举出的 `device.serial` 比对(`_resolve_fays_group` 三步,任一步不唯一就明确拒绝;`_match_esp` 拒收空序列号,不再按端口或枚举顺序猜)。SDK 探测前先 `validate_fays_superspeed` 预检,再以 `serial_only_fast=True` 快速枚举序列号(`fays_serial_probe.py` 加 `--serial-only-fast`;超时不再只报一句 timeout,解码 stdout/stderr 并附最后 20 行),`_probe_serial` 交叉核对 SDK serial 与 NVS 绑定;双 rig 新增「在用时跳过」——`fays_device_guard(port, timeout=0.0)` 探到另一 rig 正持有该设备就跳过而不是占用。串口侧:`CONNECT_BOOT_DELAY = 2.0` 死等改成 `CONNECT_BOOT_TIMEOUT = 2.0` 轮询 `?` 握手(实际尝试次数按真实值上报,不再报上限),打开加 `exclusive=True`,新增 `query_fays_serial()`/`set_fays_serial()`(`QF` 查询 / `WF:<serial>` 写入,值校验 `[A-Za-z0-9._-]{1,64}`);顺带修 `GripperSerial.send()` 只拿首字符去查命令表(`[:1]`)——`"QF"` 因此永远匹配不上自己的期望表,改成先查全命令再退回首字符。UVC 发现程序侧:`_native_env(binary)` 改成优先用二进制自带的 `third_party/libuvc`(不再指望环境里恰好有),`_run_discovery` 加互斥的 `--topology-only`/`--identity-only`/`--skip-flash` 三种扫描深度。**前置条件:ESP32 固件必须认识 `QF`/`WF:`,当前 `online/esp32_proc` 的固件还不认识,会失败关闭并报「查询 Fays 序列号失败: ERR」,需先烧固件。** 新增离线自检 `tools/tests/test_gripper_fays_pairing.py`(假串口 + 假桥接 + 假探针,覆盖 QF/WF 往返、ESP 匹配、按序列号解析、整套 acquire、UVC 关联,并核对部署的原生程序确实内嵌了新参数)。s80c 上色工具修隔帧重复(`tools/s80c_arm_convert/convert_arm_dataset.py`,v1.3.4 之后单独提交的补丁):`pooled_episodes_v1` 这版录制**每帧写两行**(`frame_index` = 0,0,1,1,…,同一帧两行的 `timestamp`/`hardware_ns` 逐值相同)而视频只有一帧,工具把行数当帧数(`n = tbl.num_rows`)、主流程再按视频帧号 1:1 取 `hw_ns[i]`,于是每个时间戳被连送两遍——离线 ISP 对重复时间戳复用上一帧的输出,输出视频就隔帧重复。实测 rec001 无损版 833 帧里 394 帧与前一帧逐字节相同、且 394 个全落在奇数位(每对时间戳的第二个),源视频 0 重复;同一根因还让 IMU 侧车**少一半**(修复前 `hw_ns[:n_frames]` 只够到第 417 个时间戳,其后的 IMU 样本全被「晚于末帧 hw」规则丢掉,输出只剩 416 行 / 13.8 秒,修复后 832 行 / 27.7 秒,与视频时长 27.8 秒对上)。现按 `frame_index` 折叠冗余行,但**只在同一 `frame_index` 名下所有行的 `timestamp` 与 `hardware_ns` 逐值相同时才折**,否则打告警原样不动——全库 142 个带 `frame_index` 的 parquet 里 129 个本就每帧一行(空操作)、1 个真冗余(rec001,1666 行 → 833 帧)、12 个行间时间戳互不相同(折叠会丢时间戳,一律只告警)。上色链路一行未动,同一份 config、同一个离线 ISP、`--sdk-wb-auto` 照旧,灰世界增益与修复前逐位相同。承接 v1.3.4 的新夹爪接入即自动生成运行标定并连接(Fays S80M):此前接入一只新夹爪要人工两步——先在夹爪上位机点 `device_setup`、再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序直接拒绝启动(「当前 Fays 缺少运行标定文件…请先在夹爪上位机中运行 device_setup」);现在 `SingleFaysLease.acquire()` 发现 per-serial YAML 缺失时,就在设备锁内调厂商导出程序从**这只夹爪自身**读出厂标定、生成 SDK YAML 与 ORB YAML(鱼眼 `stereoRectify` 求 P1/R1 + IMU 外参 `T_b_c1` + 探针读五项噪声/频率),复核落盘路径后直接连上,已有标定走 `isfile` 快路径(启动零额外开销、不碰设备)——这两个文件是**逐设备**出厂标定不可跨设备复用(实测 098/099 三组全不同),只能现场读;设备面板夹爪条目右键加「重新读取出厂标定」(录制中禁用,标定前自动关该夹爪、完成后开回),`tools/import_gripper_calibration.py` 加 `--generate`(旧文件先备份 `.bak_<时间戳>`)供命令行强制重生成;顺带修掉生成产物第 3 行的出处注释——厂商模板写死指向 `3500000261870088`,照抄会让每只新夹爪的 IMU 外参都被记成「取自另一台设备」,现改写成本机序列号(历史产物不动)。承接 v1.3.3 的力矩阵/触觉力与 RGB 视频的时间戳对齐:**力侧此前完全没有时间戳**——同一行里的 RGB 帧和力样本不是同时刻采集的,RGB 走外部帧源队列取队头最旧帧、力/矩阵走 latest-wins 单槽取当下最新,于是「行号相同」≠「时刻相同」,力恒领先 RGB 且领先量随录制时长增长(RGB 源 30.84fps vs 写线程 30fps,实测约 1 帧/秒,下游观测到的滞后 3 帧就是这么来的),力矩阵走独立泵线程还与 3 向量力各记各的时刻。修法是让每行自描述:`tactile_ready` 加第 5 个载荷 `capture_ns`(在 SDK 回调入口取),`pipeline.write_tactile_force/_force_matrix` 落成独立的 `observation.gripper_{side}_force_ns` / `_force_matrix_ns` 稀疏 int64 列(与 `hardware_ns` 同宿主单调钟时基,features 里声明 `encoding: host_monotonic_ns`),下游按时间取最近邻即可还原真实配对,精度上界=半个力样本间隔;顺带修 `rgb_frame_ready`/`stereo_frame_ready` 的 `pyqtSignal(int)` 把 `time.monotonic_ns()` 按 C++ qint32 静默截断成负数(每 2.147s 翻符号),改 `object` 封送——这也解释了此前用 `hardware_ns` 解回卷时凭空造出上百帧假漂移、把"中位 5.8 帧 / 最大 ±80 帧"报成对齐误差(真值是 ~3 帧,正确规则是**无符号**:单调钟 + FIFO 消费 ⇒ 真步长恒非负);新增 `scripts/align_modalities.py` 处理端最近邻对齐工具,对 v1.3.3 之前录的 episode 明确报「无法对齐(只能重录)」而不用增长率去猜。承接 v1.3.2 的 SLAM 陈旧帧入库前拦截与轨迹显示深拷贝修复。:桥接按「连续回退次数」判定——单帧脏读丢弃、连丢 30 帧才判定时钟真跳变并换基准放行(此前每一帧回退都会让核心库清空 IMU 队并重建地图、位姿停发 0.2–1.34 s,静止时更久),新增 `[TIME_DROP]`/`[TIME_REBASE]` 现场行并**无条件**打进 GUI 日志(此前落进未匹配行被 50 条上限吃掉——实测原生日志 4 次回退、GUI 日志 0 条,真出事时反而看不见),且带 `seq`/`prev_seq` 对比结论以区分「SDK 乱序投递 / 重复投递同一帧 / 帧配了旧时间戳」三种成因(时间戳上三者长得一模一样,对策完全不同);逐秒遥测 `[FPS_DATA]` 改「只在异常时出声」(健康静默、进入异常与恢复各一行、持续异常每 30 s 重复,全量逐秒流仍在原生日志里),并修 `wait_sdk_ready` 就绪门被**粘滞** `state.error` 锁死——任何信息性输出(如 ld.so 的 `cannot be preloaded ... ignored.`)都会让标定明明已完成的这一次返回 False、报出误导的「未等到 [FAYS-CALIB] 标记」(2026-09-10 18:32 假超时事故,文案白名单 + 去掉粘滞判断双管修);原生日志在 runtime 目录 `rmtree` 之前留档到 `logs/slam_native/`(保留最近 20 份),修「一次干净退出的会话其原生日志不可恢复」——排查 SLAM 崩溃时唯一的证据曾随目录一起被删;轨迹显示去掉 Qt 主线程上的整条深拷贝(正是这次拷贝让 `_rendered_trajectory is traj` 判等恒为假、每个位姿都在主线程复制随会话线性增长的点列,即「画一段时间后帧率变低」的直接原因),显示上限 400→6000,并以向量化投影 + 一次 `drawPolyline` 绘制,修「十几秒后轨迹显出折角」(降采样按 stride 翻倍使顶点数恒落 [上限/2, 上限],上限 400 时每段跨 67 ms 且随 stride 每翻一倍继续变粗,观感像 SLAM 出点变慢而数据一直满 30 Hz,是绘制侧丢的);RGB 外部队列在录制开始/结束/中止三个边界排空,修「上一段残留 + 本段启动窗口累积被写成新视频开头」(实测每段开头约 28 帧与上一段 episode 末帧逐帧匹配,队列满时还占 ~110 MB/槽);任务进度只上报后端当前任务列表里存在的任务(本地自建任务平台没这个项目,上报必被拒 400),且后端该项目口径为 `"sessions"`(从没收到过任何上报)时首次送本机**全量**当基线——只送增量会把后端计数从 session 数砸成增量本身(现场:3/3/3 的项目再录一条变 1)。承接 v1.3.1 的力矩阵 5 档落盘与 SLAM 停落 slam_pose 列。
collector/core/gripper/camera_service_src/CMakeLists.txt ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.16)
2
+ project(ksq_camera_service C)
3
+
4
+ set(CMAKE_C_STANDARD 11)
5
+ set(CMAKE_C_STANDARD_REQUIRED ON)
6
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
7
+
8
+ set(BUILD_EXAMPLE OFF CACHE BOOL "" FORCE)
9
+ set(BUILD_TEST OFF CACHE BOOL "" FORCE)
10
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
11
+
12
+ add_subdirectory(third_party/libuvc)
13
+
14
+ find_package(Threads REQUIRED)
15
+ find_package(PkgConfig REQUIRED)
16
+ pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0)
17
+
18
+ add_executable(ksq-camera-service
19
+ src/camera_service.c
20
+ )
21
+ target_include_directories(ksq-camera-service PRIVATE
22
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libuvc/include
23
+ )
24
+ target_compile_definitions(ksq-camera-service PRIVATE
25
+ _GNU_SOURCE
26
+ )
27
+ target_compile_options(ksq-camera-service PRIVATE
28
+ -Wall -Wextra -Wpedantic
29
+ )
30
+ target_link_libraries(ksq-camera-service PRIVATE
31
+ LibUVC::UVC
32
+ PkgConfig::LIBUSB
33
+ Threads::Threads
34
+ )
35
+
36
+ add_executable(sonix-flash-probe
37
+ tools/sonix_flash_probe.c
38
+ )
39
+ target_compile_options(sonix-flash-probe PRIVATE
40
+ -Wall -Wextra -Wpedantic
41
+ )
42
+ target_link_libraries(sonix-flash-probe PRIVATE
43
+ PkgConfig::LIBUSB
44
+ )
45
+
46
+ add_executable(discover-uvc-config
47
+ tools/discover_uvc_config.c
48
+ )
49
+ target_include_directories(discover-uvc-config PRIVATE
50
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libuvc/include
51
+ )
52
+ target_compile_definitions(discover-uvc-config PRIVATE
53
+ _GNU_SOURCE
54
+ )
55
+ target_compile_options(discover-uvc-config PRIVATE
56
+ -Wall -Wextra -Wpedantic
57
+ )
58
+ target_link_libraries(discover-uvc-config PRIVATE
59
+ LibUVC::UVC
60
+ PkgConfig::LIBUSB
61
+ )
62
+
63
+ install(TARGETS ksq-camera-service RUNTIME DESTINATION bin)
64
+
65
+ # Hardware-free integrity regression tests for the production callback.
66
+ enable_testing()
67
+ add_executable(test-frame-integrity tests/test_frame_integrity.c)
68
+ target_compile_definitions(test-frame-integrity PRIVATE _GNU_SOURCE)
69
+ target_compile_options(test-frame-integrity PRIVATE -Wall -Wextra -Wpedantic)
70
+ target_link_libraries(test-frame-integrity PRIVATE
71
+ LibUVC::UVC PkgConfig::LIBUSB Threads::Threads)
72
+ add_test(NAME frame-integrity COMMAND test-frame-integrity)
73
+
74
+ # The altsetting ladder decides which isochronous setting each camera is opened
75
+ # with, and its state-file key has to be derived identically in Python. Neither
76
+ # is observable without hardware, so pin both here.
77
+ add_executable(test-altsetting-ladder tests/test_altsetting_ladder.c)
78
+ target_compile_definitions(test-altsetting-ladder PRIVATE _GNU_SOURCE)
79
+ target_compile_options(test-altsetting-ladder PRIVATE -Wall -Wextra -Wpedantic)
80
+ target_link_libraries(test-altsetting-ladder PRIVATE
81
+ LibUVC::UVC PkgConfig::LIBUSB Threads::Threads)
82
+ add_test(NAME altsetting-ladder COMMAND test-altsetting-ladder)
83
+
84
+ # Checkout deployment keeps the bundled libuvc next to these executables.
85
+ # Avoid CMake embedding the build machine's absolute checkout directory.
86
+ #
87
+ # CMake appends an empty element to this list for ksq-camera-service (it counts
88
+ # Threads::Threads as an empty link directory), which would leave the RUNPATH as
89
+ # "$ORIGIN/third_party/libuvc:" -- and an empty element means "also search the
90
+ # current working directory". build.sh strips that element after the link and
91
+ # fails the build if it survives; do not "fix" it here by hand, the per-target
92
+ # SKIP_BUILD_RPATH and global CMAKE_SKIP_RPATH routes both make it worse
93
+ # (CMake then emits the entire empty list).
94
+ foreach(_target ksq-camera-service discover-uvc-config test-frame-integrity
95
+ test-altsetting-ladder)
96
+ set_target_properties(${_target} PROPERTIES
97
+ BUILD_RPATH "$ORIGIN/third_party/libuvc"
98
+ INSTALL_RPATH "$ORIGIN/../lib"
99
+ BUILD_RPATH_USE_ORIGIN TRUE)
100
+ endforeach()
collector/core/gripper/camera_service_src/README.md ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 相机服务与 UVC 扫描程序(源码入库版)
2
+
3
+ `ksq-camera-service`(libuvc 推流服务,走 IPC 给主程序供帧)与
4
+ `discover-uvc-config`(UVC 相机扫描:拓扑枚举 + Flash 身份读取 + 生成配置)的
5
+ **源码**。用 `./build.sh` 构建,产物安装到
6
+ `core/gripper/native/camera_service/build/`。
7
+
8
+ ## 为什么源码在这里
9
+
10
+ 这两个程序的源码原先**只存在于 `online/`**(`.gitignore:56` 整个目录不上传),
11
+ `core/gripper/native/` 下只有编译好的二进制,重建配方只活在当时那次排查的会话里
12
+ —— 二进制一旦丢失或要改一行,就得从头摸清 libusb 头文件、pkg-config、RUNPATH
13
+ 这一整串。2026-09-15 把源码连同构建配方搬进 core,让采集程序自己的相机逻辑随包入库。
14
+
15
+ ## 目录
16
+
17
+ ```
18
+ CMakeLists.txt 与交付包 online/camera_service/CMakeLists.txt **逐字节一致**
19
+ src/camera_service.c 推流服务
20
+ tools/discover_uvc_config.c UVC 扫描程序(三档扫描深度)
21
+ tools/sonix_flash_probe.c Sonix Flash 读写工具(CMakeLists 里的目标之一)
22
+ tests/test_frame_integrity.c 无硬件回归测试(MJPEG 回调完整性)
23
+ third_party/libuvc/ vendored libuvc 0.0.7,含本地补丁 ksq_altsetting_quirks
24
+ (src/stream.c:DECXIN 3060→1280、Sightac 3072→800)
25
+ build.sh 构建脚本(唯一入口)
26
+ ```
27
+
28
+ ## 构建
29
+
30
+ ```sh
31
+ core/gripper/camera_service_src/build.sh # 构建 + 安装(旧的先备份)
32
+ core/gripper/camera_service_src/build.sh --test # 顺带跑 test-frame-integrity
33
+ core/gripper/camera_service_src/build.sh --no-install
34
+ ```
35
+
36
+ 依赖:`gcc`、`cmake >= 3.16`、`make`、libusb-1.0 头文件(`libusb-1.0-0-dev`,或退到
37
+ conda 的 `include/libusb-1.0`)。libjpeg 头文件可选,但**缺了 libuvc 会退化成不支持
38
+ MJPEG 解码**,构建脚本会告警 —— 线上产物是带 libjpeg 的,两者不一致。
39
+
40
+ 安装会按 `.pre_rebuild_<时间戳>` 备份旧二进制,回退就是覆盖回去。
41
+
42
+ ## 三个已踩过的坑(改脚本前先看)
43
+
44
+ 1. **`*** 目标模式不含有"%"`**:真正的病因是 vendored `FindLibUSB.cmake` 走
45
+ `find_library()` 找不到库(系统只有 `libusb-1.0.so.0`,没有给链接器用的
46
+ `libusb-1.0.so`),把 `LibUSB::LibUSB-NOTFOUND` 写进了依赖表;GNU make 把那条
47
+ 依赖里的第二个冒号当成静态模式规则的分隔符,于是报出这个与病因毫不相干的错。
48
+ 解法是 `-DLibUSB_LIBRARY=...` 预置缓存,让 `find_library` 整个跳过。
49
+ 2. **pkg-config 里只能有一个 `-I`**:`FindLibUSB.cmake` 把 `${LibUSB_INCLUDE_DIRS}`
50
+ 不 quote 地交给 `set_target_properties`,两个 `-I` 就变成三个实参报错。而
51
+ libuvc 内部用 `<libusb.h>`、两个工具用 `<libusb-1.0/libusb.h>`,两种写法都要能
52
+ 解析 —— 所以 shim 目录里同时放 `libusb-1.0/` 与 `libusb.h` 两个软链,只给一个 `-I`。
53
+ 3. **`ksq-camera-service` 的 RUNPATH 会多一个空条目**(`$ORIGIN/third_party/libuvc:`):
54
+ CMake 把它链的 `Threads::Threads` 在本机算成了空目录。RUNPATH 里的空条目等于让
55
+ 加载器去**当前工作目录**找 `libuvc.so.0`,线上那份手工链的没有这个口子,所以
56
+ 构建脚本会在链接后把这个冒号就地改成字符串终止符(等价 `chrpath -d` 的收缩改写;
57
+ 本机没有 chrpath/patchelf)。校验段会断言空条目已消失。
58
+
59
+ ## 等时档位(altsetting):ini 说了算,服务会自己降档
60
+
61
+ **`forced_altsetting` / `forced_payload` 是真正生效的**,不是校验用的装饰。服务
62
+ 打开设备后立刻把这两个值交给 libuvc 的新 API `uvc_set_altsetting_override()`
63
+ (声明在 `include/libuvc/libuvc.h`,实现在 `src/device.c`,`uvc_device_handle_t`
64
+ 是 `calloc` 出来的,新字段自动零初始化,没设过就退回编译期那张
65
+ `ksq_altsetting_quirks` 表)。**改档位只需要改 ini。**
66
+
67
+ 在此之前这两个 ini 字段只用于校验和打印,真正决定档位的是编译进 libuvc 的表
68
+ ——所以「改 ini」完全不改变行为,这一点极容易误判。**判断一条腿实际跑在哪个档
69
+ 位,只认日志里的 `[LIBUVC-QUIRK] ... alt=N payload=M ... xfers=` 那一行**(带
70
+ `(altsetting override)` 后缀表示走的覆盖值);服务自己那行
71
+ `vidpid=... alt=7 payload=1280` 只是 ini 的回声,在旧二进制上与真实档位无关。
72
+
73
+ 档位表在 `src/camera_service.c`(`kDecxinModes` / `kSightacModes`),**必须按
74
+ 从好到差降序**,降档梯子按表往下走一格、走到最后一项就不再降。两个门槛分开计:
75
+ 连着停摆 `STALLS_BEFORE_ALTSETTING_DOWNGRADE`(2) 次降档;连着开不起来
76
+ `OPEN_FAILURES_BEFORE_ALTSETTING_DOWNGRADE`(3) 次也降档(覆盖「STREAMON 阶段
77
+ 就排不下带宽、流根本起不来」那种,停摆那条路永远等不到)。结论按
78
+ 「相机序列号 × 控制器 PCI 路径���落盘到 `state_dir`,下次开机直接读。
79
+
80
+ **降档必须把两个计数都清零**(2026-09-15 修)。门槛是拿 `==` 比的,计数停在
81
+ 门槛上就再也不会命中——原来 `maybe_downgrade_altsetting` 只清了 `stalls_at_mode`,
82
+ 于是「开不起来」那条路**降完一档就永久卡死**,表里剩下的档位形同不存在
83
+ (DECXIN 只有两档,正好被掩盖住;三档机型上就会露出来)。两条路的日志都在
84
+ 调用**之前**抓计数,否则清零后只能打出「0 failed opens」,把最该看的那次降档
85
+ 说成没有依据。
86
+
87
+ **这套东西能测,而且以前从来没被测过**(2026-09-15 修)。`tests/test_altsetting_ladder.c`
88
+ 一直在 `CMakeLists.txt` 里注册着 `add_test`,但 `build.sh --test` 是点名跑
89
+ `test-frame-integrity` 的,梯子那个**一次也没执行过**——上面那个「降一档就卡死」
90
+ 的 bug 正好落在它本该覆盖的范围内。现在 `--test` 走 `ctest`,新增测试只要
91
+ `add_test` 就自动纳进来。反向验证过:把清零那行注释掉,`altsetting-ladder`
92
+ 立刻断言中止,不是个空跑的测试。
93
+
94
+ **起始档位由 app 决定,不在这张表里**:`uvc_camera_service.py` 的
95
+ `_starting_mode` 取**表里最保守的一档**(=最后一项)。实测 DECXIN 的 alt7
96
+ (10.24 MB/s)在整机三路一起出流时每 45~130 秒必停摆一次,alt6(7.552 MB/s)
97
+ 同样三路下长跑不停,而**两档出帧率一模一样(都 30.00fps)**——alt7 多出来的每帧
98
+ 余量(327680 对 241664 B)换不到任何看得见的好处,所以默认不用它。想要那点余量
99
+ 就把 ini 改回 alt7,服务停两次会自己退回 alt6 并把结论落盘。
100
+
101
+ `tools/discover_uvc_config.c` 报的是**相机描述符里的首选档**(alt7),是如实汇报
102
+ 硬件,不是起始档;app 拿它跟服务端档位表对一遍,对不上就报「扫描程序与服务端
103
+ 档位表已经脱节」——那说明两个程序分开编了,必须一起重编。
104
+
105
+ ## SIGTERM 收尾:join 必须有界(2026-09-15 修)
106
+
107
+ **症状**:服务收到 SIGTERM 后退不出来。实测线上二进制卡了 3 分钟以上,只攥着
108
+ DECXIN 的 `/dev/bus/usb/007/032` 一个设备 fd(left/right 都已干净释放),日志
109
+ 停在断流那一刻——连 `[SUPERVISION] parent exited` 都没打出来。
110
+
111
+ **病根**:相机线程陷在 `uvc_open` 的同步 libusb 调用里(卡死的设备上它不返回),
112
+ 永远走不到循环头那个 `g_stop` 判断;而 `main` 堵在 `pthread_join` 上等它。
113
+ `g_stop` 置了也没用——没人去看。
114
+
115
+ **后果**:客户端只等 2 秒(`uvc_camera_service.py` 的 `terminate()` → 等 2 秒 →
116
+ `kill()`),超了就是 SIGKILL,进程死在 libusb 调用中间、设备停在激活的 alt
117
+ setting 上,下一轮照样起不来——正是 2026-09-15 09:24 那次事故的形状。
118
+ `teardown_failed_open` 里「复位抢在 `uvc_stop_streaming` 之前」只覆盖**失败路径**,
119
+ 覆盖不到「线程已经卡在 `uvc_open` 里」这一种。
120
+
121
+ **改法**:`pthread_join` → `pthread_timedjoin_np`。整体预算 1.5 秒、单路 0.8 秒,
122
+ 超时就 `pthread_detach` 掉继续走,`main` 一返回进程即结束(内核替我们释放句柄),
123
+ 并打一行 `收尾超时:线程未在预算内退出(多半卡在设备调用里),不再等它`。
124
+ 跳过超时那一路的统计与 `pthread_mutex_destroy`——线程可能还在用,销毁是 UAF。
125
+
126
+ **一个坑(第一版就踩了)**:这个 join 循环**同时就是服务的主运行循环**——它在
127
+ **启动时**进入、一直跑到 `g_stop`,不是「收尾时才走的一段」。所以截止时间不能在
128
+ 进循环前算好:第一版把 `shutdown_deadline` 放在 `for` 之前,结果服务启动 1.5 秒后
129
+ 三路一起「收尾超时」、自己退出了(现象:三路 `总帧=0`、日志里三行收尾超时、
130
+ `SIGTERM → pid` 那行根本没机会打)。现在改成**等 `g_stop` 真置位时才开始计时**,
131
+ 没置位时只用 200ms 短超时轮询(成本可忽略)。
132
+
133
+ **验证**:正常路径真机 45 秒三路 —— left/right 各 1351 帧满帧、decxin 1111 帧,
134
+ SIGTERM 退出 **0.71 秒**(改前 0.56 秒,仍在 2 秒宽限内),服务全程不自杀。
135
+ **超时那条分支本身没能在真机上触发**(没法按需把设备弄卡),只做了代码审查。
136
+
137
+ ## 与交付包的关系
138
+
139
+ `CMakeLists.txt` 与四个 C 源文件都从交付包 `online/camera_service/` 原样搬来
140
+ (逐字节一致),本仓库只新增 `build.sh` 与这份 README。**改这里的 C 源码时要同步
141
+ 回交付包**,否则两边会分叉。
142
+
143
+ 构建产物与线上二进制的实测关系(2026-09-15):
144
+
145
+ | 产物 | 与线上二进制 |
146
+ |---|---|
147
+ | `discover-uvc-config` | **逐字节一致**(sha256 `b9d8bba870f60c11…`)——配方忠实 |
148
+ | `ksq-camera-service` | **源码已领先线上**(多了下面的 SIGTERM 收尾修复),且编译选项不同:CMake Release �� `-O3 -DNDEBUG`,线上那份是手工 `-O2`(源码无 `assert()`,`NDEBUG` 无语义影响) |
149
+ | `sonix-flash-probe` | 同上,代码同源、编译选项不同 |
150
+ | `libuvc.so.0.0.7` | 代码同源、编译选项不同;`ksq_altsetting_quirks` 补丁与 `[LIBUVC-QUIRK]` 日志**都在**,NEEDED 三者一致(libusb-1.0.so.0 / libjpeg.so.8 / libc.so.6) |
151
+
152
+ 也就是说 `build.sh` 现在是**单一机制**(一套 CMake 配置编全部目标),代价是
153
+ `ksq-camera-service` 与当年手工链的那个二进制不是同一个字节。重新构建后应重新做
154
+ 一次三路相机回归,而不是假定等价。
155
+
156
+ **2026-09-15 19:29 已按此装机**(`STAMP=20260915_192940`):`ksq-camera-service`
157
+ 现在带自适应档位 + 两个计数都清零的修复。装机前三路回归已做(app 生成的 ini、
158
+ alt6 默认,**600 秒三路零停摆零重建,decxin/left 30.00fps、right 29.80fps**,
159
+ 17513/17496/17487 帧),装机后又做了一次 300 秒回归。
160
+
161
+ **2026-09-15 11:34 曾按此装机**(`STAMP=20260915_113444`):
162
+ `core/gripper/native/camera_service/build/` 里的 `ksq-camera-service` 当时是
163
+ `07f1f5a34b569b7b`(带 SIGTERM 收尾修复),旧件 `b64b74d810abe482` 备份在同目录
164
+ `.pre_rebuild_20260915_113444`;`discover-uvc-config` 装前装后同为
165
+ `b9d8bba870f60c11`,装不装等价。装机前三路回归已做(90 秒 ×2 腿 + 45 秒修复腿)。
166
+ **另注意 `build.sh` 的安装段不备份 `third_party/libuvc/`**(`rm -f` 直接覆盖、
167
+ `include/` 还是 `rm -rf`),所以这次装机前手工备份了库文件为
168
+ `libuvc.so.0.0.7.pre_rebuild_20260915_113330` + `include.pre_rebuild_20260915_113330/`。
169
+ 改脚本时补上这段备份更稳妥。
170
+
171
+ ### glibc 下限:`ksq-camera-service` 2.34 → 2.38(不是新约束)
172
+
173
+ 新编的 `ksq-camera-service` 引用 `__isoc23_strtol@GLIBC_2.38`(GCC 15 默认 C23,
174
+ `strtol` 解析成 C23 语义的符号),最低 glibc 从线上的 2.34 抬到 2.38。看着像门槛
175
+ 变高,其实**没有新增约束**:那个**逐字节一致**的 `discover-uvc-config` 本来就要求
176
+ GLIBC_2.38,而它是扫描时每次都要在采集机上跑的 —— 能跑扫描程序就一定能跑这个
177
+ 服务。其余产物(`sonix-flash-probe`、libuvc)两边都是 2.34。
178
+
179
+ 不要去给 CMake 钉 `-DCMAKE_C_STANDARD=17` 来消掉它:那会连带把
180
+ `discover-uvc-config` 的 `strtol` 换回旧符号,而它正是目前唯一能逐字节复现线上
181
+ 二进制的产物,是「配方忠实」的活证据。
collector/core/gripper/camera_service_src/build.sh ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # 构建 libuvc 相机服务(ksq-camera-service)与 UVC 扫描程序(discover-uvc-config),
3
+ # 产物安装到 core/gripper/native/camera_service/build/。
4
+ #
5
+ # 为什么有这份脚本:这两个程序的源码原先只在 online/(.gitignore 里),core/ 下
6
+ # 只有编译好的二进制,重建配方只活在当时那次会话里 —— 一旦二进制丢了或要改一行
7
+ # 就得从头摸。现在源码随包入库(core/gripper/camera_service_src/),配方固化于此。
8
+ #
9
+ # 依赖:gcc、cmake(>=3.16)、make、libusb-1.0 头文件;libjpeg 头文件可选(缺了
10
+ # libuvc 会退化:不支持 MJPEG 解码,实测产物 NEEDED 里就没有 libjpeg.so.8)。
11
+ #
12
+ # 用法:
13
+ # ./build.sh 构建 + 安装(旧的同名二进制先备份为 .pre_rebuild_<时间戳>)
14
+ # ./build.sh --no-install 只构建,不动 core/gripper/native/
15
+ # ./build.sh --test 构建后跑 ctest(全部无硬件回归测试)
16
+ # ./build.sh --jobs 4 限制并行度
17
+ set -euo pipefail
18
+
19
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ REPO="$(cd "$HERE/../../.." && pwd)"
21
+ OUT="$REPO/core/gripper/native/camera_service/build"
22
+ BUILD="$HERE/build"
23
+ SHIM="$BUILD/shim"
24
+
25
+ DO_INSTALL=1
26
+ DO_TEST=0
27
+ JOBS="$(nproc 2>/dev/null || echo 4)"
28
+
29
+ while [ $# -gt 0 ]; do
30
+ case "$1" in
31
+ --no-install) DO_INSTALL=0 ;;
32
+ --test) DO_TEST=1 ;;
33
+ --jobs) JOBS="${2:?--jobs 需要一个数字}"; shift ;;
34
+ -h|--help) sed -n '2,18p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0 ;;
35
+ *) echo "未知参数: $1(-h 看用法)" >&2; exit 2 ;;
36
+ esac
37
+ shift
38
+ done
39
+
40
+ die() { echo "错误: $*" >&2; exit 1; }
41
+
42
+ # ---------------------------------------------------------------- 依赖定位
43
+
44
+ # libusb 头文件:系统装了 libusb-1.0-0-dev 最省事;否则退到 conda 的 include。
45
+ # 注意头文件父目录要进 -I,因为源码里既有 <libusb-1.0/libusb.h>(sonix_flash_probe)
46
+ # 也有 <libusb.h>(libuvc 自己),两种写法都得能解析。
47
+ find_libusb_include() {
48
+ local candidate
49
+ for candidate in \
50
+ "${LIBUSB_INCLUDE_PARENT:-}" \
51
+ /usr/include \
52
+ /usr/local/include \
53
+ "${CONDA_PREFIX:-}/include" \
54
+ "$HOME/miniconda3/include" \
55
+ "$HOME/anaconda3/include"
56
+ do
57
+ [ -n "$candidate" ] && [ -f "$candidate/libusb-1.0/libusb.h" ] && {
58
+ echo "$candidate"; return 0; }
59
+ done
60
+ return 1
61
+ }
62
+
63
+ # libusb 运行库:优先系统 multiarch 的 .so.0(只链 soname,产物不带任何本机
64
+ # RUNPATH 依赖),再退到 conda。
65
+ find_libusb_library() {
66
+ local candidate
67
+ for candidate in \
68
+ "${LIBUSB_LIBRARY:-}" \
69
+ /usr/lib/x86_64-linux-gnu/libusb-1.0.so.0 \
70
+ /usr/lib/libusb-1.0.so.0 \
71
+ /usr/local/lib/libusb-1.0.so.0 \
72
+ "${CONDA_PREFIX:-}/lib/libusb-1.0.so" \
73
+ "$HOME/miniconda3/lib/libusb-1.0.so" \
74
+ "$HOME/anaconda3/lib/libusb-1.0.so"
75
+ do
76
+ [ -n "$candidate" ] && [ -e "$candidate" ] && { echo "$candidate"; return 0; }
77
+ done
78
+ return 1
79
+ }
80
+
81
+ LIBUSB_INC_PARENT="$(find_libusb_include)" \
82
+ || die "找不到 libusb-1.0 头文件。装 libusb-1.0-0-dev,或用 LIBUSB_INCLUDE_PARENT=<含 libusb-1.0/ 的目录> 指定。"
83
+ LIBUSB_LIB="$(find_libusb_library)" \
84
+ || die "找不到 libusb-1.0 运行库。装 libusb-1.0-0,或用 LIBUSB_LIBRARY=<路径> 指定。"
85
+
86
+ # libjpeg:FindJpegPkg 会先走 CMake 自带的 FindJPEG,这里预置缓存值把它钉死在
87
+ # 系统头/库上,免得 cmake 是 conda 装的时候误抓 conda 的 libjpeg。
88
+ JPEG_ARGS=()
89
+ if [ -f /usr/include/jpeglib.h ]; then
90
+ JPEG_ARGS+=("-DJPEG_INCLUDE_DIR=/usr/include")
91
+ for lib in /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/libjpeg.so; do
92
+ [ -e "$lib" ] && { JPEG_ARGS+=("-DJPEG_LIBRARY=$lib"); break; }
93
+ done
94
+ else
95
+ echo "警告: 没有 /usr/include/jpeglib.h,libuvc 将编译成不支持 MJPEG 解码" >&2
96
+ fi
97
+
98
+ # ---------------------------------------------------------------- 头文件 shim
99
+ #
100
+ # 顶层的 CMakeLists 用 pkg_check_modules(LIBUSB REQUIRED ... libusb-1.0),而系统
101
+ # 上根本没有 libusb-1.0.pc(那个文件由 -dev 包提供)。这里现造一个,指向真实头
102
+ # 文件和运行库的 soname(-l:libusb-1.0.so.0 不带 -L,所以不会给产物塞 RUNPATH)。
103
+ #
104
+ # 只有**一个** -I,而且是 shim 目录而不是真实头目录:vendored 的
105
+ # FindLibUSB.cmake 把 ${LibUSB_INCLUDE_DIRS} 不 quote 地交给
106
+ # set_target_properties,一旦 pkg-config 给出两个 -I,它就会变成三个实参报
107
+ # 「set_target_properties called with incorrect number of arguments」。
108
+ # 而两种 include 写法都得满足 —— libuvc 内部是 <libusb.h>,两个工具是
109
+ # <libusb-1.0/libusb.h> —— 所以 shim 目录里同时放 libusb-1.0/ 和 libusb.h 两个软链。
110
+
111
+ mkdir -p "$SHIM/include" "$SHIM/pkgconfig"
112
+ ln -sfn "$LIBUSB_INC_PARENT/libusb-1.0" "$SHIM/include/libusb-1.0"
113
+ ln -sfn "$LIBUSB_INC_PARENT/libusb-1.0/libusb.h" "$SHIM/include/libusb.h"
114
+
115
+ cat > "$SHIM/pkgconfig/libusb-1.0.pc" <<EOF
116
+ prefix=$SHIM
117
+ exec_prefix=\${prefix}
118
+ libdir=$(dirname "$LIBUSB_LIB")
119
+ includedir=$SHIM/include
120
+
121
+ Name: libusb-1.0
122
+ Description: C API for USB device access from Linux, Mac OS X, Windows, OpenBSD/NetBSD and Solaris userspace
123
+ Version: 1.0.27
124
+ Libs: -l:$(basename "$LIBUSB_LIB")
125
+ Cflags: -I\${includedir}
126
+ EOF
127
+
128
+ # ---------------------------------------------------------------- 配置 + 构建
129
+ #
130
+ # -DCMAKE_POLICY_VERSION_MINIMUM=3.5:libuvc 的 cmake_minimum_required 是 3.1,
131
+ # CMake 4.x 直接拒绝,给个下限放行。
132
+ # -DLibUSB_LIBRARY=...:vendored 的 FindLibUSB.cmake 走 find_library(NAMES
133
+ # ${LibUSB_LIBRARIES}),而系统的 libusb 只有 .so.0、没有给链接器用的 .so 软链,
134
+ # find_library 会失败并把 "LibUSB::LibUSB-NOTFOUND" 写进依赖表 —— GNU make 会
135
+ # 把那条依赖里的第二个冒号当成静态模式规则分隔符,报出与病因毫不相干的
136
+ # 「*** 目标模式不含有"%"」。预置这个缓存变量让 find_library 整个跳过。
137
+
138
+ echo "libusb 头文件 : $LIBUSB_INC_PARENT"
139
+ echo "libusb 运行库 : $LIBUSB_LIB"
140
+ echo "构建目录 : $BUILD"
141
+
142
+ PKG_CONFIG_PATH="$SHIM/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" \
143
+ cmake -S "$HERE" -B "$BUILD" \
144
+ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
145
+ -DBUILD_EXAMPLE=OFF \
146
+ -DBUILD_TEST=OFF \
147
+ -DLibUSB_LIBRARY="$LIBUSB_LIB" \
148
+ "${JPEG_ARGS[@]}"
149
+
150
+ cmake --build "$BUILD" -j"$JOBS"
151
+
152
+ # ksq-camera-service 的 RUNPATH 末尾会多出一个空条目("$ORIGIN/third_party/libuvc:")——
153
+ # CMake 把它链的 Threads::Threads 在本机算成了空目录,空条目进了 rpath 列表。RUNPATH
154
+ # 里的空条目等于让加载器去**当前工作目录**找 libuvc.so.0,线上那份是手工 gcc 链的、
155
+ # 没有这个口子。这里把那个冒号就地改成字符串终止符:长度不变、ELF 结构不动,等价于
156
+ # `chrpath -d` 的收缩改写(chrpath/patchelf 本机都没有)。只在真的出现时才改写。
157
+
158
+ strip_empty_rpath_entry() {
159
+ local binary="$1"
160
+ [ -f "$binary" ] || return 0
161
+ command -v python3 >/dev/null 2>&1 || return 0
162
+ python3 - "$binary" <<'PY'
163
+ import sys
164
+ path = sys.argv[1]
165
+ needle = b"$ORIGIN/third_party/libuvc:\x00"
166
+ fixed = b"$ORIGIN/third_party/libuvc\x00\x00"
167
+ with open(path, "rb") as handle:
168
+ data = handle.read()
169
+ if needle not in data:
170
+ sys.exit(0)
171
+ with open(path, "wb") as handle:
172
+ handle.write(data.replace(needle, fixed))
173
+ print(f" 去掉 RUNPATH 空条目: {path}")
174
+ PY
175
+ }
176
+
177
+ for binary in ksq-camera-service discover-uvc-config sonix-flash-probe; do
178
+ strip_empty_rpath_entry "$BUILD/$binary"
179
+ done
180
+
181
+ # ---------------------------------------------------------------- 校验
182
+ #
183
+ # 产物必须链上 libuvc.so.0 且 RUNPATH 为 $ORIGIN/third_party/libuvc —— 部署布局
184
+ # 靠的就是这个相对路径(ksq-camera-service 里 libusb_reset_device 是 dlsym 取的,
185
+ # 所以它自己 NEEDED 里没有 libusb,libuvc 带进来就够)。
186
+
187
+ for binary in ksq-camera-service discover-uvc-config; do
188
+ [ -x "$BUILD/$binary" ] || die "没有产出 $BUILD/$binary"
189
+ if command -v readelf >/dev/null 2>&1; then
190
+ readelf -d "$BUILD/$binary" | grep -q 'libuvc.so.0' \
191
+ || die "$binary 没有链接 libuvc.so.0"
192
+ readelf -d "$BUILD/$binary" | grep -q '\$ORIGIN/third_party/libuvc' \
193
+ || die "$binary 的 RUNPATH 不是 \$ORIGIN/third_party/libuvc"
194
+ readelf -d "$BUILD/$binary" | grep -q 'libuvc:' \
195
+ && die "$binary 的 RUNPATH 里还有空条目(strip_empty_rpath_entry 没生效)"
196
+ fi
197
+ done
198
+ readelf -d "$BUILD/third_party/libuvc/libuvc.so.0.0.7" 2>/dev/null | grep -q libjpeg \
199
+ && echo "libuvc: 带 libjpeg(支持 MJPEG 解码)" \
200
+ || echo "警告: libuvc 没链上 libjpeg —— 不带 MJPEG 解码,与线上产物不一致" >&2
201
+
202
+ if [ "$DO_TEST" = 1 ]; then
203
+ # 走 ctest 而不是点名跑某一个:以前这里写死跑 test-frame-integrity,
204
+ # 结果 test-altsetting-ladder 虽然在 CMakeLists 里注册了 add_test,却
205
+ # 从来没有被任何入口调起来 —— 降档梯子是真机上最难复现、最该靠测试
206
+ # 兜住的一块,却一直没人跑。新增测试只要 add_test 就自动纳进来。
207
+ echo "--- ctest ---"
208
+ ( cd "$BUILD" && ctest --output-on-failure )
209
+ fi
210
+
211
+ if [ "$DO_INSTALL" = 0 ]; then
212
+ echo "已完成构建(--no-install,未改动 core/gripper/native/)"
213
+ exit 0
214
+ fi
215
+
216
+ # ---------------------------------------------------------------- 安装
217
+ #
218
+ # 旧的同名二进制按 .pre_rebuild_<时间戳> 备份,保留现场可比对(历史上这里存过
219
+ # pre_stall_watchdog / pre_usb_reset_escalation 两份,都是用来回退的)。
220
+
221
+ [ -d "$OUT" ] || die "安装目标不存在: $OUT"
222
+
223
+ STAMP="$(date +%Y%m%d_%H%M%S)"
224
+ for binary in ksq-camera-service discover-uvc-config sonix-flash-probe; do
225
+ [ -f "$BUILD/$binary" ] || continue
226
+ if [ -f "$OUT/$binary" ]; then
227
+ cp -p "$OUT/$binary" "$OUT/$binary.pre_rebuild_$STAMP"
228
+ fi
229
+ cp -p "$BUILD/$binary" "$OUT/$binary"
230
+ echo "安装 $binary → $OUT/$binary"
231
+ done
232
+
233
+ mkdir -p "$OUT/third_party/libuvc"
234
+ for name in libuvc.so libuvc.so.0 libuvc.so.0.0.7; do
235
+ [ -e "$BUILD/third_party/libuvc/$name" ] || continue
236
+ rm -f "$OUT/third_party/libuvc/$name"
237
+ cp -a "$BUILD/third_party/libuvc/$name" "$OUT/third_party/libuvc/$name"
238
+ done
239
+ rm -rf "$OUT/third_party/libuvc/include"
240
+ cp -a "$BUILD/third_party/libuvc/include" "$OUT/third_party/libuvc/include"
241
+ echo "安装 libuvc → $OUT/third_party/libuvc/"
242
+
243
+ echo
244
+ echo "完成。回退:把 $OUT/<名字>.pre_rebuild_$STAMP 覆盖回去即可。"
collector/core/gripper/camera_service_src/src/camera_service.c ADDED
@@ -0,0 +1,1514 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* pthread_timedjoin_np 是 GNU 扩展,必须在任何头文件之前打开。 */
2
+ #define _GNU_SOURCE
3
+
4
+ #include <errno.h>
5
+ #include <fcntl.h>
6
+ #include <limits.h>
7
+ #include <poll.h>
8
+ #include <signal.h>
9
+ #include <stdint.h>
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+ #include <sys/socket.h>
14
+ #include <sys/stat.h>
15
+ #include <sys/time.h>
16
+ #include <sys/types.h>
17
+ #include <sys/un.h>
18
+ #include <sys/uio.h>
19
+ #include <time.h>
20
+ #include <unistd.h>
21
+
22
+ #include <libuvc/libuvc.h>
23
+
24
+ #include <dlfcn.h>
25
+ #include <pthread.h>
26
+
27
+ #define MAX_CAMERAS 8
28
+ #define FRAME_QUEUE_DEPTH 4
29
+ #define MAX_LINE 512
30
+ #define IPC_MAGIC 0x4b535146u /* "KSQF" */
31
+ #define IPC_VERSION 1u
32
+ /* 等时流静默停摆看门狗。DECXIN (1bcf:2d4f) 会在 6~82 秒之间无声停止推帧,
33
+ * 此后永不恢复,内核也不报任何错误(实测:同一总线同一 Hub 上的两路
34
+ * Sightac 全程 30fps 正常,只有 DECXIN 自己死)。停滞不是「暂时掉帧」:
35
+ * libuvc 丢完等时包后不会自愈,必须重开流。停滞超过这个秒数就中断本路,
36
+ * 交给 camera_main 的重试循环重开——否则整场会话只剩最后一帧,客户端
37
+ * 重连也只能重连进空气。 */
38
+ #define STREAM_STALL_TIMEOUT_SECONDS 3.0
39
+
40
+ /* 首次启动等首帧的时限(秒)。 */
41
+ #define FIRST_FRAME_TIMEOUT_SECONDS 4.0
42
+ /* 停摆重开时等首帧的时限(秒)。实测 DECXIN 被拆流后不会立刻回来,
43
+ * 4 秒内一帧都没有(会被误判成 startup failed 再拆一次,越拆越糟),
44
+ * 放宽到 20 秒再判死。 */
45
+ #define RESTART_FIRST_FRAME_TIMEOUT_SECONDS 20.0
46
+
47
+ /* 连着停摆几次才降档。
48
+ *
49
+ * 设成 2 而不是 1:单次停摆多半只是设备自己抽了一下——实测停摆 6 次里每次
50
+ * 单靠重建 libusb 上下文就能恢复;一停就降会把 alt7 的带宽白白让出去,而
51
+ * alt6 的单帧上限只有 241664 B(实测最大帧 234148 B,3% 余量),降下去是有
52
+ * 代价的。两次说明当前档位确实撑不住:实测 alt7 在整机三路出流时每 45~130 秒
53
+ * 必停一次(AMD 1022:15b7 / PCI 0000:74:00.4,以及 1022:43fc / PCI
54
+ * 0000:0a:00.0,两块都是),两次最多赔 260 秒,且结论会落盘,每台机器只赔这
55
+ * 一回。 */
56
+ #define STALLS_BEFORE_ALTSETTING_DOWNGRADE 2
57
+
58
+ /* 开不起来(rc<0)连着几次才降档。
59
+ *
60
+ * 与停摆分开计、门槛也更高:开不起来多半是设备侧卡死,而那有自己的一条恢复
61
+ * 路径(连续 2 次失败升级成 USB 复位,实测 t≈3 秒就能出帧),一开不起来就降
62
+ * 档会在正常恢复路径上白降。门槛 3 意味着复位试过、还是开不起来,档位才是
63
+ * 剩下的嫌疑。要覆盖的是另一种失败:STREAMON 阶段就排不下高带宽等时档
64
+ * (libusb_set_interface_alt_setting 报 -ENOSPC),此时流根本不会启动,
65
+ * 光靠停摆那条路永远等不到。 */
66
+ #define OPEN_FAILURES_BEFORE_ALTSETTING_DOWNGRADE 3
67
+
68
+ /* 一段流稳定跑够这么久,就把「本档位停摆计数」清零。
69
+ * 要比实测的停摆间隔(45~130 秒)明显长,否则计数永远清不掉。 */
70
+ #define CLEAN_RUN_SECONDS 300.0
71
+
72
+ /* 复位 USB 设备(等价于拔插一次)。只在一个场合用:重开之后一帧都没有,
73
+ * 说明设备侧真的卡住了(典型是上一次服务被 SIGKILL、设备停在激活的等时
74
+ * alt setting 上),只重建上下文救不回来。
75
+ *
76
+ * 平时停摆恢复**不要**走这里:复位是 USB 端口级操作,会重新枚举整条链路,
77
+ * 连带打扰同一总线同一 Hub 上的另外两路 Sightac(实测每次复位两个 Sightac
78
+ * 都掉一批帧)。实测停摆 6 次只用「重建 libusb 上下文」就 6 次全恢复,复位
79
+ * 是白付的代价。
80
+ *
81
+ * libusb 是 libuvc 的依赖、进程里必然已加载,所以按符号名取而不是直接链接
82
+ * ——这样不给二进制新增 NEEDED,交付树里 libuvc/libusb 的解析结果不变。 */
83
+ typedef int (*libusb_reset_device_fn)(struct libusb_device_handle *);
84
+
85
+ static libusb_reset_device_fn resolve_libusb_reset_device(void) {
86
+ static libusb_reset_device_fn cached = NULL;
87
+ static int resolved = 0;
88
+ if (!resolved) {
89
+ cached = (libusb_reset_device_fn)dlsym(RTLD_DEFAULT,
90
+ "libusb_reset_device");
91
+ resolved = 1;
92
+ }
93
+ return cached;
94
+ }
95
+
96
+ static volatile sig_atomic_t g_stop = 0;
97
+ static int g_parent_pid = 0;
98
+
99
+ typedef struct {
100
+ char name[64];
101
+ int vid;
102
+ int pid;
103
+ int usb_bus;
104
+ char usb_port_path[64];
105
+ int streaming_interface;
106
+ /* 实际生效的等时档位。这两项不是「声明」——run_camera_once 打开设备后
107
+ * 会把它们交给 libuvc 的 uvc_set_altsetting_override(),由它同时决定
108
+ * COMMIT 的 payload 和 libusb 的等时传输几何。留空(-1)时退回 libuvc
109
+ * 的编译期兜底表。 */
110
+ int forced_altsetting;
111
+ int forced_payload;
112
+ int width;
113
+ int height;
114
+ int fps;
115
+ char format[16];
116
+ /* 相机的 USB 序列号、所在控制器的 PCI 路径、以及学习结果的存放目录。
117
+ * 三者只用来给「这台相机 × 这条物理路径」的档位选择建一个稳定的键,
118
+ * 见 mode_state_key()。控制器只进键、不参与选档。 */
119
+ char usb_serial[64];
120
+ char usb_controller[64];
121
+ char state_dir[PATH_MAX];
122
+ char socket_path[PATH_MAX];
123
+ } camera_config_t;
124
+
125
+ typedef struct {
126
+ uint32_t magic;
127
+ uint16_t version;
128
+ uint16_t header_bytes;
129
+ uint32_t sequence;
130
+ uint32_t width;
131
+ uint32_t height;
132
+ uint32_t fourcc;
133
+ uint32_t payload_bytes;
134
+ uint64_t timestamp_ns;
135
+ } ipc_frame_header_t;
136
+
137
+ typedef struct {
138
+ uint8_t *data;
139
+ size_t length;
140
+ uint32_t sequence;
141
+ uint64_t capture_timestamp_ns;
142
+ } frame_item_t;
143
+
144
+ typedef struct camera_state camera_state_t;
145
+
146
+ struct camera_state {
147
+ camera_config_t config;
148
+ pthread_t thread;
149
+ pthread_t writer_thread;
150
+ pthread_mutex_t mutex;
151
+ pthread_cond_t condition;
152
+ frame_item_t queue[FRAME_QUEUE_DEPTH];
153
+ size_t head;
154
+ size_t count;
155
+ int stopping;
156
+ int listen_fd;
157
+ int client_fd;
158
+ uint64_t frames_received;
159
+ uint64_t frames_output;
160
+ uint64_t frames_dropped;
161
+ uint64_t bad_jpeg_frames;
162
+ uint64_t bad_jpeg_logs;
163
+ uint64_t bad_jpeg_replaced;
164
+ uint64_t write_errors;
165
+ uint64_t reconnects;
166
+ uint64_t stalls;
167
+ /* 当前档位下已经停摆了几次,连着停够 STALLS_BEFORE_ALTSETTING_DOWNGRADE
168
+ * 次就降到下一档;中间只要有一段够长的稳定运行就清零(那次停摆是设备
169
+ * 自己抽了一下,不是档位撑不住)。 */
170
+ unsigned stalls_at_mode;
171
+ /* 当前档位下连着几次没能把流开起来(rc<0)。任何一次「开起来了」的证据
172
+ * 都会清零它——停摆也算,因为停摆说明设备是开得起来的。 */
173
+ unsigned open_failures_at_mode;
174
+ /* 连续「开不起来」的次数(rc<0)。与 stalls 分开计:停摆说明设备能开、
175
+ * 能出帧,只是中途死了;连续开不起来才是设备侧卡死的signature。 */
176
+ unsigned hard_failures;
177
+ unsigned usb_resets;
178
+
179
+ };
180
+
181
+ static int has_mjpeg_soi(const uint8_t *data, size_t length) {
182
+ return length >= 2 && data[0] == 0xff && data[1] == 0xd8;
183
+ }
184
+
185
+ static int has_mjpeg_eoi(const uint8_t *data, size_t length) {
186
+ /* Some firmware variants append padding after the EOI marker, so scan
187
+ * backwards instead of requiring the final two bytes to be exactly
188
+ * FF D9. A truncated scan will not contain the marker at all. */
189
+ for (size_t index = length; index >= 2; --index) {
190
+ if (data[index - 2] == 0xff && data[index - 1] == 0xd9) {
191
+ return 1;
192
+ }
193
+ }
194
+ return 0;
195
+ }
196
+
197
+ static int is_complete_mjpeg_payload(const uint8_t *data, size_t length) {
198
+ return has_mjpeg_soi(data, length) && has_mjpeg_eoi(data, length);
199
+ }
200
+
201
+ static void request_stop(int signal_number) {
202
+ (void)signal_number;
203
+ g_stop = 1;
204
+ }
205
+
206
+ static char *trim(char *value) {
207
+ char *end;
208
+ while (*value == ' ' || *value == '\t' || *value == '\r' ||
209
+ *value == '\n') {
210
+ ++value;
211
+ }
212
+ end = value + strlen(value);
213
+ while (end > value && (end[-1] == ' ' || end[-1] == '\t' ||
214
+ end[-1] == '\r' || end[-1] == '\n')) {
215
+ --end;
216
+ }
217
+ *end = '\0';
218
+ return value;
219
+ }
220
+
221
+ static int parse_int(const char *value, int *result) {
222
+ char *end = NULL;
223
+ long parsed;
224
+ errno = 0;
225
+ parsed = strtol(value, &end, 0);
226
+ if (errno != 0 || end == value || *trim(end) != '\0' ||
227
+ parsed < INT_MIN || parsed > INT_MAX) {
228
+ return -1;
229
+ }
230
+ *result = (int)parsed;
231
+ return 0;
232
+ }
233
+
234
+ static void set_defaults(camera_config_t *config) {
235
+ memset(config, 0, sizeof(*config));
236
+ config->usb_bus = -1;
237
+ config->streaming_interface = 1;
238
+ config->forced_altsetting = -1;
239
+ config->forced_payload = -1;
240
+ config->width = 640;
241
+ config->height = 480;
242
+ config->fps = 30;
243
+ snprintf(config->format, sizeof(config->format), "MJPEG");
244
+ }
245
+
246
+ static int assign_key(camera_config_t *config, const char *key,
247
+ const char *value) {
248
+ if (strcmp(key, "vid") == 0) {
249
+ return parse_int(value, &config->vid);
250
+ }
251
+ if (strcmp(key, "pid") == 0) {
252
+ return parse_int(value, &config->pid);
253
+ }
254
+ if (strcmp(key, "usb_bus") == 0) {
255
+ return parse_int(value, &config->usb_bus);
256
+ }
257
+ if (strcmp(key, "streaming_interface") == 0) {
258
+ return parse_int(value, &config->streaming_interface);
259
+ }
260
+ if (strcmp(key, "forced_altsetting") == 0) {
261
+ return parse_int(value, &config->forced_altsetting);
262
+ }
263
+ if (strcmp(key, "forced_payload") == 0) {
264
+ return parse_int(value, &config->forced_payload);
265
+ }
266
+ if (strcmp(key, "width") == 0) {
267
+ return parse_int(value, &config->width);
268
+ }
269
+ if (strcmp(key, "height") == 0) {
270
+ return parse_int(value, &config->height);
271
+ }
272
+ if (strcmp(key, "fps") == 0) {
273
+ return parse_int(value, &config->fps);
274
+ }
275
+ if (strcmp(key, "usb_port_path") == 0) {
276
+ snprintf(config->usb_port_path, sizeof(config->usb_port_path),
277
+ "%s", value);
278
+ return 0;
279
+ }
280
+ if (strcmp(key, "usb_serial") == 0) {
281
+ snprintf(config->usb_serial, sizeof(config->usb_serial), "%s", value);
282
+ return 0;
283
+ }
284
+ if (strcmp(key, "usb_controller") == 0) {
285
+ snprintf(config->usb_controller, sizeof(config->usb_controller),
286
+ "%s", value);
287
+ return 0;
288
+ }
289
+ if (strcmp(key, "state_dir") == 0) {
290
+ snprintf(config->state_dir, sizeof(config->state_dir), "%s", value);
291
+ return 0;
292
+ }
293
+ if (strcmp(key, "socket_path") == 0) {
294
+ snprintf(config->socket_path, sizeof(config->socket_path), "%s", value);
295
+ return 0;
296
+ }
297
+ if (strcmp(key, "format") == 0) {
298
+ snprintf(config->format, sizeof(config->format),
299
+ "%s", value);
300
+ return 0;
301
+ }
302
+ if (strcmp(key, "name") == 0) {
303
+ snprintf(config->name, sizeof(config->name), "%s", value);
304
+ return 0;
305
+ }
306
+ return 1;
307
+ }
308
+
309
+ static int is_supported_device(const camera_config_t *config) {
310
+ return (config->vid == 0x0c45 && config->pid == 0x636f) ||
311
+ (config->vid == 0x1bcf && config->pid == 0x2d4f);
312
+ }
313
+
314
+ /* 每个机型允许的「档位对」(altsetting, payload),按从好到差的顺序排列。
315
+ * 第 0 项是带宽最好的一档,停摆降级时往后走一格,走到最后一项就不再降
316
+ * ——**降级方向必须是从好到差,表序不能颠倒**。
317
+ *
318
+ * 这两张表必须与 libuvc 的编译期兜底表(third_party/libuvc/src/stream.c
319
+ * 的 ksq_altsetting_quirks)以及扫描程序(tools/discover_uvc_config.c 的
320
+ * profile_for)保持一致:libuvc 的表决定「没有覆盖值时的默认」,这里决定
321
+ * 「服务愿意接受哪些值」。
322
+ *
323
+ * **起始档位不在这张表里定**:起手用哪一档由 uvc_camera_service.py 的
324
+ * _starting_mode 写进 ini(表里最保守的一档,即最后一项),服务只负责接受
325
+ * 表内的值、并在反复停摆时降档。
326
+ *
327
+ * DECXIN 两档的账:alt7/1280 是 2 事务/微帧、10.24 MB/s,单帧上限 327680 B;
328
+ * alt6/944 是单事务档里最大的一档,8 transfer × 32 包 × 944 B = 241664 B 就是
329
+ * 单帧硬上限,而实测最大帧 234148 B——只剩 3% 余量。也就是说 alt7 的余量更
330
+ * 好看,但实测 alt7 在整机三路一起出流时每 45~130 秒必停摆一次,而 alt6 长跑
331
+ * 不停,**两档的出帧率完全一样(都 30.00fps)**——多出来的余量换不到任何看得
332
+ * 见的好处,所以默认就是 alt6。哪一档真的撑不住不靠推测,靠停摆实测往下走
333
+ * (见 maybe_downgrade_altsetting)。 */
334
+ typedef struct {
335
+ int altsetting;
336
+ int payload;
337
+ } altsetting_mode_t;
338
+
339
+ static const altsetting_mode_t kSightacModes[] = {
340
+ {3, 800},
341
+ };
342
+ static const altsetting_mode_t kDecxinModes[] = {
343
+ {7, 1280},
344
+ {6, 944},
345
+ };
346
+
347
+ static const altsetting_mode_t *mode_table_for(const camera_config_t *config,
348
+ size_t *count) {
349
+ if (config->vid == 0x0c45 && config->pid == 0x636f) {
350
+ *count = sizeof(kSightacModes) / sizeof(kSightacModes[0]);
351
+ return kSightacModes;
352
+ }
353
+ if (config->vid == 0x1bcf && config->pid == 0x2d4f) {
354
+ *count = sizeof(kDecxinModes) / sizeof(kDecxinModes[0]);
355
+ return kDecxinModes;
356
+ }
357
+ *count = 0;
358
+ return NULL;
359
+ }
360
+
361
+ static size_t mode_index_for(const camera_config_t *config) {
362
+ size_t count = 0;
363
+ const altsetting_mode_t *modes = mode_table_for(config, &count);
364
+ for (size_t i = 0; i < count; ++i) {
365
+ if (modes[i].altsetting == config->forced_altsetting &&
366
+ modes[i].payload == config->forced_payload) {
367
+ return i;
368
+ }
369
+ }
370
+ return count;
371
+ }
372
+
373
+ /* 「这台相机 × 这条物理路径」的落盘键。
374
+ *
375
+ * 刻意不用总线号/端口路径:机架插在哪个口、哪条总线都不是永久的(用户
376
+ * 2026-09-15 明确说过 bus 1 不是永久的),端口一变键就变,要么把上一台
377
+ * 机器的结论套到新拓扑上,要么白学一遍。序列号取自相机描述符、随相机走;
378
+ * 控制器取自 PCI 路径、随插槽走。换电脑 / 换 USB 口都会得到新键,也就是
379
+ * 重新学一次——取保守的那一边:结论严格绑在学它的那条物理路径上。控制器
380
+ * 本身是不是变量并无定论(2026-09-15 实测 alt7 在 74:00.4 与 0a:00.0 上都
381
+ * 停摆),所以它只进键、不参与选档。
382
+ *
383
+ * Python 侧 core/gripper/devices/uvc_camera_service.py 用同一套规则造键去
384
+ * 查这个目录,两边的清洗规则必须逐字一致。 */
385
+ static void mode_state_key(const camera_config_t *config, char *out,
386
+ size_t size) {
387
+ char raw[192];
388
+ size_t written = 0;
389
+
390
+ snprintf(raw, sizeof(raw), "%04x_%04x_%s_%s", config->vid, config->pid,
391
+ config->usb_controller[0] != '\0' ? config->usb_controller
392
+ : "unknown",
393
+ config->usb_serial[0] != '\0' ? config->usb_serial : "noserial");
394
+ for (const char *cursor = raw; *cursor != '\0' && written + 1 < size;
395
+ ++cursor) {
396
+ char c = *cursor;
397
+ int safe = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
398
+ (c >= '0' && c <= '9') || c == '-';
399
+ out[written++] = safe ? c : '_';
400
+ }
401
+ out[written] = '\0';
402
+ }
403
+
404
+ /* 把学到的档位写进 state_dir,下次开机直接用它,不必再赔一次停摆窗口。
405
+ * 尽力而为:目录建不出来、盘写不进去都只记日志,绝不能因此让相机起不来。 */
406
+ static void persist_mode_choice(const camera_state_t *camera) {
407
+ char key[200];
408
+ char path[PATH_MAX];
409
+ char temporary[PATH_MAX];
410
+ FILE *file;
411
+
412
+ if (camera->config.state_dir[0] == '\0') {
413
+ return;
414
+ }
415
+ mode_state_key(&camera->config, key, sizeof(key));
416
+ if (snprintf(path, sizeof(path), "%s/%s.mode", camera->config.state_dir,
417
+ key) >= (int)sizeof(path) ||
418
+ snprintf(temporary, sizeof(temporary), "%s.tmp.%d", path,
419
+ (int)getpid()) >= (int)sizeof(temporary)) {
420
+ fprintf(stderr, "[%s] state path too long; not persisting mode\n",
421
+ camera->config.name);
422
+ return;
423
+ }
424
+ if (mkdir(camera->config.state_dir, 0755) != 0 && errno != EEXIST) {
425
+ fprintf(stderr, "[%s] cannot create state dir %s: %s\n",
426
+ camera->config.name, camera->config.state_dir,
427
+ strerror(errno));
428
+ return;
429
+ }
430
+ file = fopen(temporary, "w");
431
+ if (file == NULL) {
432
+ fprintf(stderr, "[%s] cannot write %s: %s\n", camera->config.name,
433
+ temporary, strerror(errno));
434
+ return;
435
+ }
436
+ fprintf(file, "altsetting=%d\npayload=%d\n",
437
+ camera->config.forced_altsetting, camera->config.forced_payload);
438
+ fflush(file);
439
+ fsync(fileno(file));
440
+ fclose(file);
441
+ if (rename(temporary, path) != 0) {
442
+ fprintf(stderr, "[%s] cannot install %s: %s\n", camera->config.name,
443
+ path, strerror(errno));
444
+ unlink(temporary);
445
+ return;
446
+ }
447
+ fprintf(stderr, "[%s] remembered altsetting=%d payload=%d for this "
448
+ "camera/controller in %s\n", camera->config.name,
449
+ camera->config.forced_altsetting, camera->config.forced_payload,
450
+ path);
451
+ }
452
+
453
+ static int validate_config(const camera_config_t *config, size_t index) {
454
+ if (config->name[0] == '\0' || config->vid <= 0 || config->pid <= 0 ||
455
+ config->usb_bus < 0 || config->usb_port_path[0] == '\0' ||
456
+ config->socket_path[0] == '\0' || config->streaming_interface < 0 ||
457
+ config->forced_altsetting < 0 || config->forced_payload <= 0 ||
458
+ config->width <= 0 || config->height <= 0 || config->fps <= 0 ||
459
+ strcasecmp(config->format, "MJPEG") != 0) {
460
+ fprintf(stderr, "invalid camera config at index %zu\n", index);
461
+ return -1;
462
+ }
463
+ if (!is_supported_device(config)) {
464
+ fprintf(stderr, "%s: unsupported UVC device %04x:%04x; only Sightac "
465
+ "0c45:636f and DECXIN 1bcf:2d4f are supported\n",
466
+ config->name, config->vid, config->pid);
467
+ return -1;
468
+ }
469
+ if (config->vid == 0x0c45 && config->pid == 0x636f &&
470
+ (config->width != 640 || config->height != 480 || config->fps != 30)) {
471
+ fprintf(stderr, "%s: unsupported Sightac mode; expected 640x480 "
472
+ "MJPEG@30\n", config->name);
473
+ return -1;
474
+ }
475
+ if (config->vid == 0x1bcf && config->pid == 0x2d4f &&
476
+ (config->width != 1280 || config->height != 960 || config->fps != 30)) {
477
+ fprintf(stderr, "%s: unsupported DECXIN mode; expected 1280x960 "
478
+ "MJPEG@30\n", config->name);
479
+ return -1;
480
+ }
481
+ /* 档位对必须整体命中表里某一项。只查「alt 在表里」是不够的:alt 和
482
+ * payload 是一个整体(alt7 的端点就是 1280 B/包),把 7 和 944 拼在
483
+ * 一起会让 libuvc 用 alt7 的端点去跑 944 的预算,而 944 只是 COMMIT
484
+ * 上写的数——2026-09-15 主程序连不上夹爪就是这两项被拆开配出来的。 */
485
+ {
486
+ size_t count = 0;
487
+ mode_table_for(config, &count);
488
+ if (mode_index_for(config) < count) {
489
+ return 0;
490
+ }
491
+ }
492
+ fprintf(stderr, "%s: unsupported altsetting pair alt=%d payload=%d; this "
493
+ "camera accepts only the pairs in the service's mode table\n",
494
+ config->name, config->forced_altsetting, config->forced_payload);
495
+ return -1;
496
+ }
497
+
498
+ static int configs_conflict(const camera_config_t *left,
499
+ const camera_config_t *right) {
500
+ if (strcmp(left->socket_path, right->socket_path) == 0) {
501
+ return 1;
502
+ }
503
+ return left->vid == right->vid && left->pid == right->pid &&
504
+ left->usb_bus == right->usb_bus &&
505
+ strcmp(left->usb_port_path, right->usb_port_path) == 0;
506
+ }
507
+
508
+ static int load_config(const char *path, camera_config_t *configs,
509
+ size_t *count) {
510
+ FILE *file;
511
+ char line[MAX_LINE];
512
+ camera_config_t *current = NULL;
513
+ size_t index = 0;
514
+
515
+ file = fopen(path, "r");
516
+ if (file == NULL) {
517
+ fprintf(stderr, "cannot open config %s: %s\n", path, strerror(errno));
518
+ return -1;
519
+ }
520
+ while (fgets(line, sizeof(line), file) != NULL) {
521
+ char *text = trim(line);
522
+ char *equals;
523
+ if (*text == '\0' || *text == '#' || *text == ';') {
524
+ continue;
525
+ }
526
+ if (*text == '[') {
527
+ char *close = strchr(text, ']');
528
+ if (close == NULL || index >= MAX_CAMERAS) {
529
+ fclose(file);
530
+ return -1;
531
+ }
532
+ *close = '\0';
533
+ set_defaults(&configs[index]);
534
+ snprintf(configs[index].name, sizeof(configs[index].name),
535
+ "%s", trim(text + 1));
536
+ current = &configs[index++];
537
+ continue;
538
+ }
539
+ if (current == NULL || (equals = strchr(text, '=')) == NULL) {
540
+ fclose(file);
541
+ return -1;
542
+ }
543
+ *equals = '\0';
544
+ {
545
+ char *key = trim(text);
546
+ char *value = trim(equals + 1);
547
+ char *comment = strchr(value, '#');
548
+ if (comment != NULL) {
549
+ *comment = '\0';
550
+ value = trim(value);
551
+ }
552
+ if (assign_key(current, key, value) < 0) {
553
+ fprintf(stderr, "invalid config value %s=%s\n", key, value);
554
+ fclose(file);
555
+ return -1;
556
+ }
557
+ }
558
+ }
559
+ fclose(file);
560
+ if (index == 0 || index > MAX_CAMERAS) {
561
+ return -1;
562
+ }
563
+ for (size_t i = 0; i < index; ++i) {
564
+ if (validate_config(&configs[i], i) != 0) {
565
+ return -1;
566
+ }
567
+ for (size_t j = 0; j < i; ++j) {
568
+ if (configs_conflict(&configs[i], &configs[j])) {
569
+ fprintf(stderr,
570
+ "camera config conflict between %s and %s "
571
+ "(duplicate output or USB identity)\n",
572
+ configs[j].name, configs[i].name);
573
+ return -1;
574
+ }
575
+ }
576
+ }
577
+ *count = index;
578
+ return 0;
579
+ }
580
+
581
+ static int uvc_port_path(uvc_device_t *device, char *buffer,
582
+ size_t buffer_size) {
583
+ uint8_t ports[8];
584
+ int count;
585
+ size_t used = 0;
586
+ count = uvc_get_port_numbers(device, ports, sizeof(ports));
587
+ if (count < 0) {
588
+ return -1;
589
+ }
590
+ buffer[0] = '\0';
591
+ for (int i = 0; i < count; ++i) {
592
+ int written = snprintf(buffer + used, buffer_size - used, "%s%u",
593
+ i == 0 ? "" : ".", ports[i]);
594
+ if (written < 0 || (size_t)written >= buffer_size - used) {
595
+ return -1;
596
+ }
597
+ used += (size_t)written;
598
+ }
599
+ return 0;
600
+ }
601
+
602
+ static uvc_error_t open_matching_device(uvc_context_t *context,
603
+ const camera_config_t *config,
604
+ uvc_device_handle_t **result,
605
+ char *actual_path,
606
+ size_t actual_path_size) {
607
+ uvc_device_t **list = NULL;
608
+ uvc_error_t error;
609
+ *result = NULL;
610
+ error = uvc_get_device_list(context, &list);
611
+ if (error != UVC_SUCCESS) {
612
+ return error;
613
+ }
614
+ for (size_t i = 0; list[i] != NULL; ++i) {
615
+ uvc_device_descriptor_t *descriptor = NULL;
616
+ uvc_device_handle_t *candidate = NULL;
617
+ error = uvc_get_device_descriptor(list[i], &descriptor);
618
+ if (error != UVC_SUCCESS || descriptor == NULL ||
619
+ descriptor->idVendor != (uint16_t)config->vid ||
620
+ descriptor->idProduct != (uint16_t)config->pid ||
621
+ (int)uvc_get_bus_number(list[i]) != config->usb_bus) {
622
+ uvc_free_device_descriptor(descriptor);
623
+ continue;
624
+ }
625
+ if (uvc_port_path(list[i], actual_path, actual_path_size) != 0 ||
626
+ strcmp(actual_path, config->usb_port_path) != 0) {
627
+ uvc_free_device_descriptor(descriptor);
628
+ continue;
629
+ }
630
+ error = uvc_open(list[i], &candidate);
631
+ uvc_free_device_descriptor(descriptor);
632
+ if (error != UVC_SUCCESS || candidate == NULL) {
633
+ fprintf(stderr, "[%s] matched bus=%d port=%s open failed: %s (%d)\n",
634
+ config->name, config->usb_bus, actual_path,
635
+ uvc_strerror(error), error);
636
+ uvc_free_device_list(list, 1);
637
+ return error == UVC_SUCCESS ? UVC_ERROR_IO : error;
638
+ }
639
+ *result = candidate;
640
+ uvc_free_device_list(list, 1);
641
+ return UVC_SUCCESS;
642
+ }
643
+ uvc_free_device_list(list, 1);
644
+ return UVC_ERROR_NO_DEVICE;
645
+ }
646
+
647
+ static uint64_t timespec_nanoseconds(struct timespec value) {
648
+ if (value.tv_sec < 0 || value.tv_nsec < 0 || value.tv_nsec >= 1000000000L) {
649
+ return 0;
650
+ }
651
+ return (uint64_t)value.tv_sec * 1000000000ull +
652
+ (uint64_t)value.tv_nsec;
653
+ }
654
+
655
+ static int configure_ipc(camera_state_t *camera) {
656
+ struct sockaddr_un address;
657
+ mode_t old_umask;
658
+ size_t path_length = strlen(camera->config.socket_path);
659
+
660
+ if (path_length >= sizeof(address.sun_path)) {
661
+ fprintf(stderr, "[%s] Unix socket path is too long: %s\n",
662
+ camera->config.name, camera->config.socket_path);
663
+ return -1;
664
+ }
665
+ /*
666
+ * Use a byte-stream Unix socket instead of SOCK_SEQPACKET. A DECXIN
667
+ * MJPEG frame can exceed the kernel's AF_UNIX packet-size limit; a
668
+ * length-bearing stream header avoids EMSGSIZE while retaining one
669
+ * complete frame per read_packet() at the protocol level.
670
+ */
671
+ camera->listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
672
+ if (camera->listen_fd < 0) {
673
+ fprintf(stderr, "[%s] create Unix socket failed: %s\n",
674
+ camera->config.name, strerror(errno));
675
+ return -1;
676
+ }
677
+ memset(&address, 0, sizeof(address));
678
+ address.sun_family = AF_UNIX;
679
+ memcpy(address.sun_path, camera->config.socket_path, path_length + 1);
680
+ unlink(camera->config.socket_path);
681
+ old_umask = umask(0);
682
+ if (bind(camera->listen_fd, (struct sockaddr *)&address,
683
+ sizeof(address)) < 0) {
684
+ umask(old_umask);
685
+ fprintf(stderr, "[%s] bind Unix socket %s failed: %s\n",
686
+ camera->config.name, camera->config.socket_path,
687
+ strerror(errno));
688
+ close(camera->listen_fd);
689
+ camera->listen_fd = -1;
690
+ return -1;
691
+ }
692
+ umask(old_umask);
693
+ if (chmod(camera->config.socket_path, 0666) != 0 ||
694
+ listen(camera->listen_fd, 1) != 0) {
695
+ fprintf(stderr, "[%s] prepare Unix socket %s failed: %s\n",
696
+ camera->config.name, camera->config.socket_path,
697
+ strerror(errno));
698
+ close(camera->listen_fd);
699
+ camera->listen_fd = -1;
700
+ unlink(camera->config.socket_path);
701
+ return -1;
702
+ }
703
+ fprintf(stderr, "[%s] IPC socket=%s format=MJPEG size=%dx%d fps=%d\n",
704
+ camera->config.name, camera->config.socket_path,
705
+ camera->config.width, camera->config.height, camera->config.fps);
706
+ return 0;
707
+ }
708
+
709
+ static int accept_ipc_client(camera_state_t *camera) {
710
+ while (!g_stop && camera->client_fd < 0) {
711
+ struct pollfd descriptor = {
712
+ .fd = camera->listen_fd,
713
+ .events = POLLIN,
714
+ .revents = 0,
715
+ };
716
+ int ready = poll(&descriptor, 1, 500);
717
+ if (ready < 0 && errno == EINTR) {
718
+ continue;
719
+ }
720
+ if (ready <= 0) {
721
+ continue;
722
+ }
723
+ camera->client_fd = accept(camera->listen_fd, NULL, NULL);
724
+ if (camera->client_fd < 0 && errno != EINTR) {
725
+ return errno;
726
+ }
727
+ }
728
+ return camera->client_fd >= 0 ? 0 : ECANCELED;
729
+ }
730
+
731
+ static int send_all(int fd, const void *data, size_t length) {
732
+ const uint8_t *cursor = (const uint8_t *)data;
733
+ while (length > 0) {
734
+ ssize_t sent = send(fd, cursor, length, MSG_NOSIGNAL);
735
+ if (sent < 0) {
736
+ if (errno == EINTR) {
737
+ continue;
738
+ }
739
+ return errno;
740
+ }
741
+ if (sent == 0) {
742
+ return EPIPE;
743
+ }
744
+ cursor += (size_t)sent;
745
+ length -= (size_t)sent;
746
+ }
747
+ return 0;
748
+ }
749
+
750
+ static int write_frame(camera_state_t *camera, const frame_item_t *item) {
751
+ ipc_frame_header_t header;
752
+ int error;
753
+
754
+ if (accept_ipc_client(camera) != 0) {
755
+ return g_stop ? ECANCELED : ENOTCONN;
756
+ }
757
+ memset(&header, 0, sizeof(header));
758
+ header.magic = IPC_MAGIC;
759
+ header.version = IPC_VERSION;
760
+ header.header_bytes = (uint16_t)sizeof(header);
761
+ header.sequence = item->sequence;
762
+ header.width = (uint32_t)camera->config.width;
763
+ header.height = (uint32_t)camera->config.height;
764
+ header.fourcc = (uint32_t)('M' | ('J' << 8) | ('P' << 16) | ('G' << 24));
765
+ header.payload_bytes = (uint32_t)item->length;
766
+ /*
767
+ * Preserve the timestamp assigned by libuvc when the complete UVC frame
768
+ * was received. The socket writer can run later (or burst after a
769
+ * client connects), so send time would measure IPC scheduling rather than
770
+ * camera acquisition cadence.
771
+ */
772
+ header.timestamp_ns = item->capture_timestamp_ns;
773
+
774
+ error = send_all(camera->client_fd, &header, sizeof(header));
775
+ if (error == 0) {
776
+ error = send_all(camera->client_fd, item->data, item->length);
777
+ }
778
+ /* Any partial write invalidates byte-stream framing, including timeout. */
779
+ if (error != 0) {
780
+ close(camera->client_fd);
781
+ camera->client_fd = -1;
782
+ }
783
+ return error;
784
+ }
785
+
786
+ static void enqueue_frame(uvc_frame_t *frame, camera_state_t *camera) {
787
+ uint8_t *copy;
788
+ size_t tail;
789
+ uint64_t capture_timestamp_ns;
790
+ uint8_t *source = NULL;
791
+ size_t source_length = 0;
792
+ uint32_t source_sequence = 0;
793
+ if (frame == NULL || frame->data == NULL || frame->data_bytes == 0 ||
794
+ frame->frame_format != UVC_FRAME_FORMAT_MJPEG) {
795
+ return;
796
+ }
797
+ if (!is_complete_mjpeg_payload(frame->data, frame->data_bytes)) {
798
+ int should_log;
799
+ uint64_t bad_count;
800
+ pthread_mutex_lock(&camera->mutex);
801
+ camera->bad_jpeg_frames++;
802
+ camera->bad_jpeg_logs++;
803
+ camera->frames_dropped++;
804
+ bad_count = camera->bad_jpeg_frames;
805
+ should_log = bad_count == 1 || camera->bad_jpeg_logs % 100 == 0;
806
+ pthread_mutex_unlock(&camera->mutex);
807
+ if (should_log) {
808
+ fprintf(stderr,
809
+ "[%s] dropped incomplete MJPEG sequence=%u bytes=%zu "
810
+ "bad=%llu\n",
811
+ camera->config.name, frame->sequence, frame->data_bytes,
812
+ (unsigned long long)bad_count);
813
+ }
814
+ /* Never fabricate a new sample from an older image. The sequence
815
+ * gap is intentional and preserves honest acquisition timestamps. */
816
+ return;
817
+ }
818
+ source = frame->data;
819
+ source_length = frame->data_bytes;
820
+ source_sequence = frame->sequence;
821
+ capture_timestamp_ns = timespec_nanoseconds(frame->capture_time_finished);
822
+ if (capture_timestamp_ns == 0) {
823
+ pthread_mutex_lock(&camera->mutex);
824
+ camera->frames_dropped++;
825
+ pthread_mutex_unlock(&camera->mutex);
826
+ return;
827
+ }
828
+ copy = malloc(source_length);
829
+ if (copy == NULL) {
830
+ pthread_mutex_lock(&camera->mutex);
831
+ camera->frames_dropped++;
832
+ pthread_mutex_unlock(&camera->mutex);
833
+ return;
834
+ }
835
+ memcpy(copy, source, source_length);
836
+ pthread_mutex_lock(&camera->mutex);
837
+ if (camera->stopping) {
838
+ free(copy);
839
+ pthread_mutex_unlock(&camera->mutex);
840
+ return;
841
+ }
842
+ if (camera->count == FRAME_QUEUE_DEPTH) {
843
+ free(camera->queue[camera->head].data);
844
+ camera->head = (camera->head + 1) % FRAME_QUEUE_DEPTH;
845
+ camera->count--;
846
+ camera->frames_dropped++;
847
+ }
848
+ tail = (camera->head + camera->count) % FRAME_QUEUE_DEPTH;
849
+ camera->queue[tail].data = copy;
850
+ camera->queue[tail].length = source_length;
851
+ camera->queue[tail].sequence = source_sequence;
852
+ camera->queue[tail].capture_timestamp_ns = capture_timestamp_ns;
853
+ camera->count++;
854
+ camera->frames_received++;
855
+
856
+ pthread_cond_signal(&camera->condition);
857
+ pthread_mutex_unlock(&camera->mutex);
858
+ }
859
+
860
+ static void frame_callback(uvc_frame_t *frame, void *user_ptr) {
861
+ enqueue_frame(frame, (camera_state_t *)user_ptr);
862
+ }
863
+
864
+ static void *writer_main(void *user_ptr) {
865
+ camera_state_t *camera = (camera_state_t *)user_ptr;
866
+ for (;;) {
867
+ frame_item_t item;
868
+ memset(&item, 0, sizeof(item));
869
+ pthread_mutex_lock(&camera->mutex);
870
+ while (camera->count == 0 && !camera->stopping) {
871
+ pthread_cond_wait(&camera->condition, &camera->mutex);
872
+ }
873
+ if (camera->count == 0 && camera->stopping) {
874
+ pthread_mutex_unlock(&camera->mutex);
875
+ break;
876
+ }
877
+ item = camera->queue[camera->head];
878
+ camera->queue[camera->head].data = NULL;
879
+ camera->head = (camera->head + 1) % FRAME_QUEUE_DEPTH;
880
+ camera->count--;
881
+ pthread_mutex_unlock(&camera->mutex);
882
+
883
+ int write_error = write_frame(camera, &item);
884
+ if (write_error == 0) {
885
+ pthread_mutex_lock(&camera->mutex);
886
+ camera->frames_output++;
887
+ pthread_mutex_unlock(&camera->mutex);
888
+ } else if (write_error == ECANCELED && g_stop) {
889
+ /* Normal shutdown: do not report queued frames canceled by the
890
+ * stop signal as an output failure. */
891
+ } else {
892
+ pthread_mutex_lock(&camera->mutex);
893
+ camera->write_errors++;
894
+ pthread_mutex_unlock(&camera->mutex);
895
+ fprintf(stderr, "[%s] output write failed: %s (%d)\n",
896
+ camera->config.name, strerror(write_error), write_error);
897
+ }
898
+ free(item.data);
899
+ }
900
+ return NULL;
901
+ }
902
+
903
+ static double monotonic_seconds(void) {
904
+ struct timespec now;
905
+ if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
906
+ return 0.0;
907
+ }
908
+ return (double)now.tv_sec + (double)now.tv_nsec / 1000000000.0;
909
+ }
910
+
911
+ static void report_stats(camera_state_t *camera, double elapsed,
912
+ uint64_t previous_received,
913
+ uint64_t previous_output,
914
+ uint64_t previous_dropped,
915
+ uint64_t previous_bad_jpeg) {
916
+ uint64_t received;
917
+ uint64_t output;
918
+ uint64_t dropped;
919
+ uint64_t bad_jpeg;
920
+ uint64_t bad_replaced;
921
+ uint64_t write_errors;
922
+ size_t queued;
923
+
924
+ pthread_mutex_lock(&camera->mutex);
925
+ received = camera->frames_received;
926
+ output = camera->frames_output;
927
+ dropped = camera->frames_dropped;
928
+ bad_jpeg = camera->bad_jpeg_frames;
929
+ bad_replaced = camera->bad_jpeg_replaced;
930
+ write_errors = camera->write_errors;
931
+ queued = camera->count;
932
+ pthread_mutex_unlock(&camera->mutex);
933
+ if (elapsed <= 0.0) {
934
+ return;
935
+ }
936
+ fprintf(stderr,
937
+ "[%s] fps_in=%.2f fps_out=%.2f received=%llu output=%llu "
938
+ "dropped=%llu (+%llu) bad_jpeg=%llu (+%llu) "
939
+ "bad_replaced=%llu write_errors=%llu queue=%zu\n",
940
+ camera->config.name,
941
+ (double)(received - previous_received) / elapsed,
942
+ (double)(output - previous_output) / elapsed,
943
+ (unsigned long long)received, (unsigned long long)output,
944
+ (unsigned long long)dropped,
945
+ (unsigned long long)(dropped - previous_dropped),
946
+ (unsigned long long)bad_jpeg,
947
+ (unsigned long long)(bad_jpeg - previous_bad_jpeg),
948
+ (unsigned long long)bad_replaced,
949
+ (unsigned long long)write_errors, queued);
950
+ }
951
+
952
+ static void close_ipc(camera_state_t *camera) {
953
+ pthread_mutex_lock(&camera->mutex);
954
+ camera->stopping = 1;
955
+ pthread_cond_broadcast(&camera->condition);
956
+ pthread_mutex_unlock(&camera->mutex);
957
+ if (camera->writer_thread != 0) {
958
+ pthread_join(camera->writer_thread, NULL);
959
+ camera->writer_thread = 0;
960
+ }
961
+ for (size_t i = 0; i < FRAME_QUEUE_DEPTH; ++i) {
962
+ free(camera->queue[i].data);
963
+ camera->queue[i].data = NULL;
964
+ }
965
+ camera->head = 0;
966
+ camera->count = 0;
967
+ if (camera->client_fd >= 0) {
968
+ close(camera->client_fd);
969
+ camera->client_fd = -1;
970
+ }
971
+ if (camera->listen_fd >= 0) {
972
+ close(camera->listen_fd);
973
+ camera->listen_fd = -1;
974
+ }
975
+ unlink(camera->config.socket_path);
976
+ }
977
+
978
+ static void reset_usb_device(camera_state_t *camera,
979
+ uvc_device_handle_t *device) {
980
+ struct libusb_device_handle *usb_handle = uvc_get_libusb_handle(device);
981
+ libusb_reset_device_fn reset_device = resolve_libusb_reset_device();
982
+ if (usb_handle == NULL || reset_device == NULL) {
983
+ fprintf(stderr,
984
+ "[%s] cannot reset device (handle=%p symbol=%p)\n",
985
+ camera->config.name, (void *)usb_handle, (void *)reset_device);
986
+ return;
987
+ }
988
+ int reset_rc = reset_device(usb_handle);
989
+ fprintf(stderr, "[%s] usb reset: rc=%d (%s)\n", camera->config.name,
990
+ reset_rc, uvc_strerror(reset_rc));
991
+ }
992
+
993
+ /* 上一次复位之后留给客户端的余量:客户端只等 10 秒就把服务收掉,所以
994
+ * 「第几次失败才升级成复位」是拿这个窗口倒推出来的,不是拍的。
995
+ * 实测卡死设备的失败很快(每次约 0.3 秒 + 1 秒间隔),第 2 次失败触发
996
+ * 复位的时刻在 t≈2 秒,重枚举加重开约 1 秒,t≈3 秒就能出帧——10 秒够用。
997
+ * 门槛设成「连续 2 次」而不是「1 次」:单次失败往往只是设备还没缓过来
998
+ * (那种情况重建上下文就够,实测 6/6 全恢复),一失败就复位会白白打扰
999
+ * 同 Hub 的另外两路。
1000
+ *
1001
+ * 上限 USB_RESET_LIMIT 次:设备真坏了的时候,不设上限会变成每 2 秒复位
1002
+ * 一次、把另外两路一直按在地上。打满就不再复位,退回普通重试。 */
1003
+ #define HARD_FAILURES_BEFORE_RESET 1
1004
+ #define USB_RESET_LIMIT 3
1005
+
1006
+ /* 停摆够次数就退一档,并记住这次选择。
1007
+ *
1008
+ * 为什么要有这条路(而不是起手就用最保守档、或者按机器写死):起手档已经
1009
+ * 是最保守的那一档了,这条路是给**操作者手动把 ini 改成高带宽档**兜底的
1010
+ * ——想要 alt7 那点每帧余量就改,真撑不住时服务停两次自己退回 alt6 并把结论
1011
+ * 落盘,下次开机直接用,不用人去记哪台机器该用哪档。按机器写死则是另一回事:
1012
+ * 机架插在哪条总线、哪台机器都不固定,写死要每台各配一份,而且写死的那个
1013
+ * 判断(「这台控制器扛不扛得住」)本身就没被测准过——试错要便宜得多。
1014
+ *
1015
+ * 返回 1 表示已降档。 */
1016
+ static int maybe_downgrade_altsetting(camera_state_t *camera) {
1017
+ size_t count = 0;
1018
+ const altsetting_mode_t *modes = mode_table_for(&camera->config, &count);
1019
+ size_t index = mode_index_for(&camera->config);
1020
+
1021
+ if (modes == NULL || index + 1 >= count) {
1022
+ return 0;
1023
+ }
1024
+ camera->config.forced_altsetting = modes[index + 1].altsetting;
1025
+ camera->config.forced_payload = modes[index + 1].payload;
1026
+ /* 两个计数都要归零,各自对应一条降档触发路径。漏掉哪个,那条路就
1027
+ * 只能降一次:stalls 由本函数清零,open_failures 若不清零,判等
1028
+ * (== 门槛)在降档后永远不再成立,梯子在「开不起来」那条路上走
1029
+ * 完一格就卡死,后两档形同不存在。 */
1030
+ camera->stalls_at_mode = 0;
1031
+ camera->open_failures_at_mode = 0;
1032
+ persist_mode_choice(camera);
1033
+ return 1;
1034
+ }
1035
+
1036
+ static void escalate_to_usb_reset(camera_state_t *camera,
1037
+ uvc_device_handle_t *device) {
1038
+ if (camera->hard_failures < HARD_FAILURES_BEFORE_RESET) {
1039
+ return;
1040
+ }
1041
+ if (camera->usb_resets >= USB_RESET_LIMIT) {
1042
+ return;
1043
+ }
1044
+ camera->usb_resets++;
1045
+ reset_usb_device(camera, device);
1046
+ }
1047
+
1048
+ /* 失败路径的收尾。复位要抢在 uvc_stop_streaming 之前:
1049
+ * 卡死的设备上 uvc_stop_streaming 会一直等它那批永远回不来的等时传输,
1050
+ * 实测能卡满客户端那 2 秒宽限期、被 SIGKILL 打断——进程死在这中间,
1051
+ * 设备就停在激活的 alt setting 上,下一轮启动照样起不来(用户 09:24
1052
+ * 的日志正是断在 startup failed 与 usb reset 之间)。复位会取消在途
1053
+ * 传输,先复位再停流,这条路径才走得完。 */
1054
+ static void teardown_failed_open(camera_state_t *camera,
1055
+ uvc_device_handle_t *device) {
1056
+ escalate_to_usb_reset(camera, device);
1057
+ uvc_stop_streaming(device);
1058
+ uvc_close(device);
1059
+ close_ipc(camera);
1060
+ }
1061
+
1062
+ static int run_camera_once(camera_state_t *camera, uvc_context_t *context) {
1063
+ uvc_device_handle_t *device = NULL;
1064
+ uvc_stream_ctrl_t control;
1065
+ char actual_path[64] = {0};
1066
+ uvc_error_t error;
1067
+ double previous_report = monotonic_seconds();
1068
+ uint64_t previous_received = 0;
1069
+ uint64_t previous_output = 0;
1070
+ uint64_t previous_dropped = 0;
1071
+ uint64_t previous_bad_jpeg = 0;
1072
+
1073
+ pthread_mutex_lock(&camera->mutex);
1074
+ uint64_t initial_received = camera->frames_received;
1075
+ /* 每次重开都要把上报基线对齐到当前累计值。留在 0 会让重开后的第一次
1076
+ * 上报把「进程启动至今的全部帧数」当成本窗口的增量,算出 200+fps 这种
1077
+ * 假速率(纯日志问题,不影响出帧,但会把人带偏)。 */
1078
+ previous_received = camera->frames_received;
1079
+ previous_output = camera->frames_output;
1080
+ previous_dropped = camera->frames_dropped;
1081
+ previous_bad_jpeg = camera->bad_jpeg_frames;
1082
+ camera->stopping = 0;
1083
+ pthread_mutex_unlock(&camera->mutex);
1084
+ error = open_matching_device(context, &camera->config, &device,
1085
+ actual_path, sizeof(actual_path));
1086
+ if (error != UVC_SUCCESS) {
1087
+ fprintf(stderr, "[%s] device %04x:%04x bus=%d port=%s unavailable: %s\n",
1088
+ camera->config.name, camera->config.vid, camera->config.pid,
1089
+ camera->config.usb_bus, camera->config.usb_port_path,
1090
+ uvc_strerror(error));
1091
+ close_ipc(camera);
1092
+ return -1;
1093
+ }
1094
+ /* 在协商之前把 ini 里的档位钉到设备句柄上。libuvc 自己的编译期表只是
1095
+ * 兜底:真正决定用哪一档的是这份 ini,而 ini 里的值来自扫描程序实测的
1096
+ * 端点描述符、或者上一轮学到的结论。 */
1097
+ error = uvc_set_altsetting_override(device, camera->config.forced_altsetting,
1098
+ (unsigned int)camera->config.forced_payload);
1099
+ if (error != UVC_SUCCESS) {
1100
+ fprintf(stderr, "[%s] cannot apply altsetting override alt=%d payload=%d: %s\n",
1101
+ camera->config.name, camera->config.forced_altsetting,
1102
+ camera->config.forced_payload, uvc_strerror(error));
1103
+ teardown_failed_open(camera, device);
1104
+ return -1;
1105
+ }
1106
+ memset(&control, 0, sizeof(control));
1107
+ error = uvc_get_stream_ctrl_format_size(
1108
+ device, &control, UVC_FRAME_FORMAT_MJPEG,
1109
+ camera->config.width, camera->config.height, camera->config.fps);
1110
+ if (error != UVC_SUCCESS ||
1111
+ control.bInterfaceNumber != camera->config.streaming_interface) {
1112
+ fprintf(stderr, "[%s] UVC format/interface negotiation failed: %s interface=%u expected=%d\n",
1113
+ camera->config.name, uvc_strerror(error),
1114
+ control.bInterfaceNumber, camera->config.streaming_interface);
1115
+ teardown_failed_open(camera, device);
1116
+ return -1;
1117
+ }
1118
+ fprintf(stderr,
1119
+ "[%s] vidpid=%04x:%04x bus=%d port=%s interface=%u alt=%d payload=%d "
1120
+ "format=MJPEG size=%dx%d fps=%d socket=%s negotiated_payload=%u\n",
1121
+ camera->config.name, camera->config.vid, camera->config.pid,
1122
+ camera->config.usb_bus, actual_path, control.bInterfaceNumber,
1123
+ camera->config.forced_altsetting, camera->config.forced_payload,
1124
+ camera->config.width, camera->config.height, camera->config.fps,
1125
+ camera->config.socket_path, control.dwMaxPayloadTransferSize);
1126
+ error = uvc_start_streaming(device, &control, frame_callback, camera, 0);
1127
+ if (error != UVC_SUCCESS) {
1128
+ fprintf(stderr, "[%s] uvc_start_streaming failed: %s\n",
1129
+ camera->config.name, uvc_strerror(error));
1130
+ teardown_failed_open(camera, device);
1131
+ return -1;
1132
+ }
1133
+ /* Publish IPC only once MJPG negotiation, STREAMON and a valid frame
1134
+ * have succeeded. Socket existence is a readiness promise to the parent. */
1135
+ int first_frame = 0;
1136
+ int restarting = camera->reconnects > 0;
1137
+ double first_frame_timeout = restarting
1138
+ ? RESTART_FIRST_FRAME_TIMEOUT_SECONDS : FIRST_FRAME_TIMEOUT_SECONDS;
1139
+ double deadline = monotonic_seconds() + first_frame_timeout;
1140
+ while (!g_stop && monotonic_seconds() < deadline) {
1141
+ pthread_mutex_lock(&camera->mutex);
1142
+ first_frame = camera->frames_received > initial_received;
1143
+ pthread_mutex_unlock(&camera->mutex);
1144
+ if (first_frame) break;
1145
+ usleep(10000);
1146
+ }
1147
+ if (!first_frame || configure_ipc(camera) != 0) {
1148
+ fprintf(stderr, "[%s] startup failed: no valid MJPG frame or IPC unavailable\n", camera->config.name);
1149
+ teardown_failed_open(camera, device);
1150
+ return -1;
1151
+ }
1152
+ if (pthread_create(&camera->writer_thread, NULL, writer_main, camera) != 0) {
1153
+ fprintf(stderr, "[%s] writer thread creation failed\n", camera->config.name);
1154
+ uvc_stop_streaming(device);
1155
+ uvc_close(device);
1156
+ close_ipc(camera);
1157
+ return -1;
1158
+ }
1159
+ int stalled = 0;
1160
+ double last_progress = monotonic_seconds();
1161
+ double stream_started = last_progress;
1162
+ int clean_run_credited = 0;
1163
+ uint64_t last_received = 0;
1164
+ pthread_mutex_lock(&camera->mutex);
1165
+ last_received = camera->frames_received;
1166
+ pthread_mutex_unlock(&camera->mutex);
1167
+
1168
+ while (!g_stop) {
1169
+ sleep(1);
1170
+ if (g_parent_pid > 1 && getppid() != g_parent_pid) {
1171
+ fprintf(stderr,
1172
+ "[%s] parent %d exited; stopping stream\n",
1173
+ camera->config.name, g_parent_pid);
1174
+ g_stop = 1;
1175
+ break;
1176
+ }
1177
+ double now = monotonic_seconds();
1178
+ if (now - previous_report >= 5.0) {
1179
+ report_stats(camera, now - previous_report,
1180
+ previous_received, previous_output,
1181
+ previous_dropped, previous_bad_jpeg);
1182
+ pthread_mutex_lock(&camera->mutex);
1183
+ previous_received = camera->frames_received;
1184
+ previous_output = camera->frames_output;
1185
+ previous_dropped = camera->frames_dropped;
1186
+ previous_bad_jpeg = camera->bad_jpeg_frames;
1187
+ pthread_mutex_unlock(&camera->mutex);
1188
+ previous_report = now;
1189
+ }
1190
+ /* 停滞看门狗:见 STREAM_STALL_TIMEOUT_SECONDS 的注释。这里不能
1191
+ * 只等 g_stop——流死了 g_stop 永远不会置位,重试循环也就永远
1192
+ * 轮不到,整路相机就此静默报废。 */
1193
+ pthread_mutex_lock(&camera->mutex);
1194
+ uint64_t received_now = camera->frames_received;
1195
+ pthread_mutex_unlock(&camera->mutex);
1196
+ /* 稳定跑够 CLEAN_RUN_SECONDS 就把本档位的停摆计数清零:说明这个档位
1197
+ * 是撑得住的,之前那次停摆是设备自己抽了一下。 */
1198
+ if (!clean_run_credited && now - stream_started >= CLEAN_RUN_SECONDS) {
1199
+ clean_run_credited = 1;
1200
+ camera->stalls_at_mode = 0;
1201
+ }
1202
+ if (received_now != last_received) {
1203
+ last_received = received_now;
1204
+ last_progress = now;
1205
+ } else if (now - last_progress >= STREAM_STALL_TIMEOUT_SECONDS) {
1206
+ pthread_mutex_lock(&camera->mutex);
1207
+ camera->stalls++;
1208
+ pthread_mutex_unlock(&camera->mutex);
1209
+ fprintf(stderr,
1210
+ "[%s] stream stalled: no frame for %.1fs "
1211
+ "(received=%llu); restarting UVC stream\n",
1212
+ camera->config.name, now - last_progress,
1213
+ (unsigned long long)received_now);
1214
+ stalled = 1;
1215
+ break;
1216
+ }
1217
+ }
1218
+ uvc_stop_streaming(device);
1219
+ uvc_close(device);
1220
+ close_ipc(camera);
1221
+ /* 返回 0 会被 camera_main 当成正常收尾而退出重试循环;停摆用 +1 单独
1222
+ * 标记,让 camera_main 知道还要重建 libusb 上下文。 */
1223
+ return stalled ? 1 : 0;
1224
+ }
1225
+
1226
+ static void *camera_main(void *user_ptr) {
1227
+ camera_state_t *camera = (camera_state_t *)user_ptr;
1228
+ uvc_context_t *context = NULL;
1229
+ uvc_error_t error = uvc_init(&context, NULL);
1230
+ if (error != UVC_SUCCESS) {
1231
+ fprintf(stderr, "[%s] uvc_init failed: %s\n", camera->config.name,
1232
+ uvc_strerror(error));
1233
+ return NULL;
1234
+ }
1235
+ while (!g_stop) {
1236
+ if (g_parent_pid > 1 && getppid() != g_parent_pid) {
1237
+ fprintf(stderr,
1238
+ "[SUPERVISION] parent %d exited; stopping service\n",
1239
+ g_parent_pid);
1240
+ g_stop = 1;
1241
+ break;
1242
+ }
1243
+ int rc = run_camera_once(camera, context);
1244
+ if (rc == 0) {
1245
+ break;
1246
+ }
1247
+ camera->reconnects++;
1248
+ if (rc > 0) {
1249
+ /* 停摆那次是开得起来、出过帧的,设备侧没卡死;把连续失败清零,
1250
+ * 免得几次停摆的失败凑够数、误触发 USB 复位去打扰另���两路。 */
1251
+ camera->hard_failures = 0;
1252
+ /* 开得起来 ⇒ 这个档位至少被控制器接受了,清掉开不起来的计数。 */
1253
+ camera->open_failures_at_mode = 0;
1254
+ /* 当前档位连着停够次数就退一档(并落盘)。降档要在重建上下文
1255
+ * 之前生效——重开的流才会用新的 alt/payload。 */
1256
+ camera->stalls_at_mode++;
1257
+ if (camera->stalls_at_mode == STALLS_BEFORE_ALTSETTING_DOWNGRADE) {
1258
+ /* 计数要在降档之前抓下来:maybe_downgrade_altsetting 成功时
1259
+ * 会把它清零,之后再读就只能打出「0 stalls」,正好把最该
1260
+ * 看的那次降级说成没有依据。 */
1261
+ unsigned stalls = camera->stalls_at_mode;
1262
+ int previous_alt = camera->config.forced_altsetting;
1263
+ if (maybe_downgrade_altsetting(camera)) {
1264
+ fprintf(stderr,
1265
+ "[%s] %u stalls at alt=%d; dropping to alt=%d "
1266
+ "payload=%d\n",
1267
+ camera->config.name, stalls, previous_alt,
1268
+ camera->config.forced_altsetting,
1269
+ camera->config.forced_payload);
1270
+ } else {
1271
+ fprintf(stderr,
1272
+ "[%s] %u stalls but alt=%d is already the lowest "
1273
+ "setting for this camera; staying put\n",
1274
+ camera->config.name, stalls,
1275
+ camera->config.forced_altsetting);
1276
+ }
1277
+ }
1278
+ /* 停摆:同一个 libusb 上下文里的设备对象在复位后已经失效,
1279
+ * 用它重开只会拿到一个永远不出帧的死句柄(表现为
1280
+ * 「negotiated OK 但 20 秒一帧没有」)。新进程能恢复、同进程
1281
+ * 重开不能,差别就在这里——重建上下文=拿到与「新进程」等价
1282
+ * 的干净枚举。 */
1283
+ fprintf(stderr, "[%s] rebuilding libusb context after stall\n",
1284
+ camera->config.name);
1285
+ uvc_exit(context);
1286
+ context = NULL;
1287
+ if (uvc_init(&context, NULL) != UVC_SUCCESS) {
1288
+ fprintf(stderr, "[%s] uvc_init failed after stall; "
1289
+ "camera thread exiting\n", camera->config.name);
1290
+ return NULL;
1291
+ }
1292
+ } else {
1293
+ /* 开不起来(rc<0):计数到第 2 次就升级成 USB 复位,见
1294
+ * escalate_to_usb_reset。 */
1295
+ camera->hard_failures++;
1296
+ /* 复位也救不回来时,档位是剩下的嫌疑——可能在 STREAMON 阶段就
1297
+ * 排不下这个等时档,那样流根本不会启动,停摆那条路永远等不到。 */
1298
+ camera->open_failures_at_mode++;
1299
+ if (camera->open_failures_at_mode ==
1300
+ OPEN_FAILURES_BEFORE_ALTSETTING_DOWNGRADE) {
1301
+ /* 和停摆那条路一样,计数要在降档之前抓下来:成功降档会把
1302
+ * 它清零,之后再读就打不出触发这次降级的次数。 */
1303
+ unsigned failed = camera->open_failures_at_mode;
1304
+ int previous_alt = camera->config.forced_altsetting;
1305
+ if (maybe_downgrade_altsetting(camera)) {
1306
+ fprintf(stderr,
1307
+ "[%s] %u failed opens at alt=%d; dropping to "
1308
+ "alt=%d payload=%d\n",
1309
+ camera->config.name, failed, previous_alt,
1310
+ camera->config.forced_altsetting,
1311
+ camera->config.forced_payload);
1312
+ } else {
1313
+ fprintf(stderr,
1314
+ "[%s] %u failed opens but alt=%d is already the "
1315
+ "lowest setting for this camera; staying put\n",
1316
+ camera->config.name, failed,
1317
+ camera->config.forced_altsetting);
1318
+ }
1319
+ }
1320
+ }
1321
+ if (!g_stop) {
1322
+ sleep(1);
1323
+ }
1324
+ }
1325
+ uvc_exit(context);
1326
+ return NULL;
1327
+ }
1328
+
1329
+ static void print_usage(const char *program) {
1330
+ fprintf(stderr,
1331
+ "usage: %s --config FILE [--validate-only] "
1332
+ "[--parent-pid PID]\n",
1333
+ program);
1334
+ }
1335
+
1336
+ /* SIGTERM 之后必须退得掉。客户端(uvc_camera_service.py)只给 2 秒宽限:
1337
+ * terminate() → 等 2 秒 → kill()。超了就是 SIGKILL,进程死在 libusb 调用
1338
+ * 中间、设备停在激活的 alt setting 上,下一轮照样起不来——正是 2026-09-15
1339
+ * 09:24 那次事故的形状。
1340
+ *
1341
+ * 光置 g_stop 不够:相机线程可能正陷在 uvc_open 的同步 libusb 调用里(卡死
1342
+ * 的设备上它不返回),永远走不到循环头那个 g_stop 判断,pthread_join 于是
1343
+ * 永远等下去。实测:生产二进制收到 SIGTERM 后 3 分钟不退,只攥着 DECXIN 的
1344
+ * fd,left/right 都已干净释放,日志停在断流那一刻——连
1345
+ * [SUPERVISION] parent exited 都没打出来。
1346
+ *
1347
+ * 所以 join 必须有界:整体 1.5 秒、单路 0.8 秒(健康时三路是并行收尾的,
1348
+ * 实测全程 0.56 秒,留足余量)。超时就 detach、继续走,main 一返回进程即
1349
+ * 结束——至少把能收的收干净了,跟客户端硬杀不是一回事。
1350
+ *
1351
+ * 注意 join 循环同时就是主运行循环,所以正常运行时不能套这个截止时间,
1352
+ * 只能短超时轮询着等 g_stop(见 main 里那段说明)。 */
1353
+ #define SHUTDOWN_JOIN_TOTAL_MS 1500
1354
+ #define SHUTDOWN_JOIN_PER_CAMERA_MS 800
1355
+ #define SHUTDOWN_JOIN_POLL_MS 200
1356
+
1357
+ /* 距 deadline 还有多少毫秒(≤0 表示已过期)。 */
1358
+ static long ms_until(const struct timespec *deadline) {
1359
+ struct timespec now;
1360
+ clock_gettime(CLOCK_REALTIME, &now);
1361
+ return (long)(deadline->tv_sec - now.tv_sec) * 1000L +
1362
+ (long)(deadline->tv_nsec - now.tv_nsec) / 1000000L;
1363
+ }
1364
+
1365
+ /* 现在起 ms 毫秒之后的时刻。pthread_timedjoin_np 按 CLOCK_REALTIME 算。 */
1366
+ static struct timespec deadline_after_ms(long ms) {
1367
+ struct timespec t;
1368
+ clock_gettime(CLOCK_REALTIME, &t);
1369
+ t.tv_sec += ms / 1000;
1370
+ t.tv_nsec += (ms % 1000) * 1000000L;
1371
+ if (t.tv_nsec >= 1000000000L) {
1372
+ t.tv_sec += 1;
1373
+ t.tv_nsec -= 1000000000L;
1374
+ }
1375
+ return t;
1376
+ }
1377
+
1378
+ int main(int argc, char **argv) {
1379
+ const char *config_path = NULL;
1380
+ int validate_only = 0;
1381
+ camera_config_t configs[MAX_CAMERAS];
1382
+ camera_state_t cameras[MAX_CAMERAS];
1383
+ size_t camera_count = 0;
1384
+ size_t started = 0;
1385
+ struct sigaction action;
1386
+
1387
+ for (int i = 1; i < argc; ++i) {
1388
+ if (strcmp(argv[i], "--config") == 0 && i + 1 < argc) {
1389
+ config_path = argv[++i];
1390
+ } else if (strcmp(argv[i], "--validate-only") == 0) {
1391
+ validate_only = 1;
1392
+ } else if (strcmp(argv[i], "--parent-pid") == 0 &&
1393
+ i + 1 < argc) {
1394
+ if (parse_int(argv[++i], &g_parent_pid) != 0 ||
1395
+ g_parent_pid <= 1) {
1396
+ fprintf(stderr, "invalid --parent-pid\n");
1397
+ return 2;
1398
+ }
1399
+ } else {
1400
+ print_usage(argv[0]);
1401
+ return 2;
1402
+ }
1403
+ }
1404
+ if (config_path == NULL || load_config(config_path, configs,
1405
+ &camera_count) != 0) {
1406
+ print_usage(argv[0]);
1407
+ return 2;
1408
+ }
1409
+ if (validate_only) {
1410
+ for (size_t i = 0; i < camera_count; ++i) {
1411
+ fprintf(stdout,
1412
+ "valid[%zu] name=%s vidpid=%04x:%04x bus=%d port=%s "
1413
+ "interface=%d alt=%d payload=%d mode=%dx%d MJPEG@%d "
1414
+ "socket=%s\n",
1415
+ i, configs[i].name, configs[i].vid, configs[i].pid,
1416
+ configs[i].usb_bus, configs[i].usb_port_path,
1417
+ configs[i].streaming_interface,
1418
+ configs[i].forced_altsetting, configs[i].forced_payload,
1419
+ configs[i].width, configs[i].height, configs[i].fps,
1420
+ configs[i].socket_path);
1421
+ }
1422
+ return 0;
1423
+ }
1424
+ memset(&action, 0, sizeof(action));
1425
+ action.sa_handler = request_stop;
1426
+ sigemptyset(&action.sa_mask);
1427
+ sigaction(SIGINT, &action, NULL);
1428
+ sigaction(SIGTERM, &action, NULL);
1429
+
1430
+ memset(cameras, 0, sizeof(cameras));
1431
+ for (size_t i = 0; i < camera_count; ++i) {
1432
+ cameras[i].config = configs[i];
1433
+ cameras[i].listen_fd = -1;
1434
+ cameras[i].client_fd = -1;
1435
+ pthread_mutex_init(&cameras[i].mutex, NULL);
1436
+ pthread_cond_init(&cameras[i].condition, NULL);
1437
+ if (pthread_create(&cameras[i].thread, NULL, camera_main,
1438
+ &cameras[i]) != 0) {
1439
+ fprintf(stderr, "[%s] capture thread creation failed\n",
1440
+ cameras[i].config.name);
1441
+ g_stop = 1;
1442
+ break;
1443
+ }
1444
+ started++;
1445
+ }
1446
+ /* 这个 join 循环**就是服务的主运行循环**——它在启动时进入、一直跑到
1447
+ * g_stop,不是「收尾时才走的一段」。所以截止时间不能在进循环前就算好
1448
+ * (那样正常运行时也会到点超时、服务自己退出),要等 g_stop 真置位时
1449
+ * 才开始计时。没置位时只用 200ms 短超时轮询,成本可忽略。 */
1450
+ int shutdown_started = 0;
1451
+ struct timespec shutdown_deadline = {0, 0};
1452
+ for (size_t i = 0; i < started; ++i) {
1453
+ int join_rc;
1454
+ for (;;) {
1455
+ long budget = SHUTDOWN_JOIN_POLL_MS;
1456
+ if (g_stop) {
1457
+ if (!shutdown_started) {
1458
+ shutdown_deadline =
1459
+ deadline_after_ms(SHUTDOWN_JOIN_TOTAL_MS);
1460
+ shutdown_started = 1;
1461
+ }
1462
+ long left = ms_until(&shutdown_deadline);
1463
+ budget = left < SHUTDOWN_JOIN_PER_CAMERA_MS
1464
+ ? left : SHUTDOWN_JOIN_PER_CAMERA_MS;
1465
+ /* 总预算已用尽:不再等,但还是要问一次——线程可能早就退了
1466
+ * (健康的那几路是并行收尾的),0 超时的 join 会立刻返回。 */
1467
+ if (budget < 0) {
1468
+ budget = 0;
1469
+ }
1470
+ }
1471
+ struct timespec limit = deadline_after_ms(budget);
1472
+ join_rc = pthread_timedjoin_np(cameras[i].thread, NULL, &limit);
1473
+ if (join_rc != ETIMEDOUT) {
1474
+ break;
1475
+ }
1476
+ if (!g_stop) {
1477
+ continue; /* 正常运行中的轮询到期,接着等 */
1478
+ }
1479
+ if (budget == 0) {
1480
+ break; /* 预算已尽,放弃这一路 */
1481
+ }
1482
+ }
1483
+ if (join_rc == ETIMEDOUT) {
1484
+ /* 线程没在预算内退出——多半还陷在设备调用里。不能为它把整个
1485
+ * 进程陪进去,否则客户端 2 秒宽限一到就是 SIGKILL、设备留脏。
1486
+ * detach 后 main 一返回进程即结束,内核会替我们释放设备句柄。
1487
+ * 跳过下面的统计与销毁:那些结构线程可能还在用,销毁它们是
1488
+ * use-after-free。 */
1489
+ fprintf(stderr,
1490
+ "[%s] 收尾超时:线程未在预算内退出(多半卡在设备调用里),"
1491
+ "不再等它\n", cameras[i].config.name);
1492
+ pthread_detach(cameras[i].thread);
1493
+ continue;
1494
+ }
1495
+ pthread_mutex_lock(&cameras[i].mutex);
1496
+ fprintf(stderr, "[%s] received=%llu output=%llu dropped=%llu "
1497
+ "bad_jpeg=%llu bad_replaced=%llu write_errors=%llu "
1498
+ "retries=%llu stalls=%llu usb_resets=%u\n",
1499
+ cameras[i].config.name,
1500
+ (unsigned long long)cameras[i].frames_received,
1501
+ (unsigned long long)cameras[i].frames_output,
1502
+ (unsigned long long)cameras[i].frames_dropped,
1503
+ (unsigned long long)cameras[i].bad_jpeg_frames,
1504
+ (unsigned long long)cameras[i].bad_jpeg_replaced,
1505
+ (unsigned long long)cameras[i].write_errors,
1506
+ (unsigned long long)cameras[i].reconnects,
1507
+ (unsigned long long)cameras[i].stalls,
1508
+ cameras[i].usb_resets);
1509
+ pthread_mutex_unlock(&cameras[i].mutex);
1510
+ pthread_cond_destroy(&cameras[i].condition);
1511
+ pthread_mutex_destroy(&cameras[i].mutex);
1512
+ }
1513
+ return started == camera_count ? 0 : 1;
1514
+ }
collector/core/gripper/camera_service_src/tests/test_altsetting_ladder.c ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Deterministic tests for the altsetting ladder. No USB devices involved.
2
+ *
3
+ * The ladder is the thing that lets one binary work both on controllers that
4
+ * can carry DECXIN's high-bandwidth isochronous setting and on those that
5
+ * cannot, so its two failure modes are worth pinning down:
6
+ *
7
+ * - silently accepting a pair the camera cannot do. alt and payload are one
8
+ * unit (alt7's endpoint *is* 1280 B/packet); pairing 7 with 944 is exactly
9
+ * the configuration that took the whole gripper down on 2026-09-15 with
10
+ * "unsupported DECXIN mode" -> rc=2.
11
+ * - silently refusing to step down, which leaves the camera wedged at a
12
+ * setting its controller cannot carry.
13
+ * - stepping down once and then jamming, because the counter that triggered
14
+ * the step is never cleared back below its threshold: the comparison is an
15
+ * equality against the threshold, so a counter left standing on it never
16
+ * fires again and every rung below the second is unreachable.
17
+ *
18
+ * The state-file name is also pinned, because uvc_camera_service.py has to
19
+ * derive the same key in Python to read the result back; the two are only kept
20
+ * in step by this assertion and its Python counterpart.
21
+ */
22
+ #undef NDEBUG
23
+ #include <assert.h>
24
+ #include <dirent.h>
25
+ #include <sys/stat.h>
26
+ #include <unistd.h>
27
+
28
+ #define main camera_service_main
29
+ #include "../src/camera_service.c"
30
+ #undef main
31
+
32
+ static camera_config_t make_camera(int vid, int pid, int width, int height) {
33
+ camera_config_t config;
34
+ set_defaults(&config);
35
+ snprintf(config.name, sizeof(config.name), "unit_1_test");
36
+ config.vid = vid;
37
+ config.pid = pid;
38
+ config.usb_bus = 1;
39
+ snprintf(config.usb_port_path, sizeof(config.usb_port_path), "2.2.2");
40
+ config.width = width;
41
+ config.height = height;
42
+ config.fps = 30;
43
+ snprintf(config.format, sizeof(config.format), "MJPEG");
44
+ snprintf(config.socket_path, sizeof(config.socket_path), "/tmp/x.sock");
45
+ snprintf(config.usb_serial, sizeof(config.usb_serial), "DECXIN-01");
46
+ snprintf(config.usb_controller, sizeof(config.usb_controller),
47
+ "0000:74:00.4");
48
+ return config;
49
+ }
50
+
51
+ static camera_config_t make_decxin(void) {
52
+ camera_config_t config = make_camera(0x1bcf, 0x2d4f, 1280, 960);
53
+ config.forced_altsetting = 7;
54
+ config.forced_payload = 1280;
55
+ return config;
56
+ }
57
+
58
+ static void test_accepts_every_rung_and_nothing_else(void) {
59
+ camera_config_t config = make_decxin();
60
+
61
+ assert(validate_config(&config, 0) == 0); /* alt7/1280, the preferred rung */
62
+ config.forced_altsetting = 6;
63
+ config.forced_payload = 944;
64
+ assert(validate_config(&config, 0) == 0); /* alt6/944, the fallback rung */
65
+
66
+ /* Alt and payload are a matched pair, so a mixed pair must be refused even
67
+ * though both numbers appear in the table on their own. */
68
+ config.forced_altsetting = 7;
69
+ config.forced_payload = 944;
70
+ assert(validate_config(&config, 0) == -1);
71
+ config.forced_altsetting = 6;
72
+ config.forced_payload = 1280;
73
+ assert(validate_config(&config, 0) == -1);
74
+ /* A pair nobody has measured must not be accepted on faith either. */
75
+ config.forced_altsetting = 5;
76
+ config.forced_payload = 800;
77
+ assert(validate_config(&config, 0) == -1);
78
+
79
+ config = make_camera(0x0c45, 0x636f, 640, 480);
80
+ config.forced_altsetting = 3;
81
+ config.forced_payload = 800;
82
+ assert(validate_config(&config, 0) == 0);
83
+ config.forced_altsetting = 4; /* the pre-2026-08-28 1600 B setting */
84
+ config.forced_payload = 1600;
85
+ assert(validate_config(&config, 0) == -1);
86
+ }
87
+
88
+ static void test_steps_down_one_rung_and_then_stops(void) {
89
+ camera_state_t camera;
90
+ memset(&camera, 0, sizeof(camera));
91
+ camera.config = make_decxin();
92
+
93
+ assert(mode_index_for(&camera.config) == 0);
94
+ /* Both counters are driven to non-zero first: stepping down has to clear
95
+ * *each* of them. The thresholds are tested with ==, so a counter left
96
+ * standing at the threshold never fires again and that whole trigger path
97
+ * gets one step and then jams -- the rungs below it might as well not
98
+ * exist. Stalls and failed opens are separate paths and each clears its
99
+ * own; a downgrade is a fresh start for both. */
100
+ camera.stalls_at_mode = 99;
101
+ camera.open_failures_at_mode = 99;
102
+ assert(maybe_downgrade_altsetting(&camera) == 1);
103
+ assert(camera.config.forced_altsetting == 6);
104
+ assert(camera.config.forced_payload == 944);
105
+ assert(mode_index_for(&camera.config) == 1);
106
+ assert(camera.stalls_at_mode == 0);
107
+ assert(camera.open_failures_at_mode == 0);
108
+
109
+ /* alt6 is the last rung: a further stall must not invent a worse one. */
110
+ assert(maybe_downgrade_altsetting(&camera) == 0);
111
+ assert(camera.config.forced_altsetting == 6);
112
+ assert(camera.config.forced_payload == 944);
113
+
114
+ /* Sightac has a single rung, so it never steps anywhere. */
115
+ camera.config = make_camera(0x0c45, 0x636f, 640, 480);
116
+ camera.config.forced_altsetting = 3;
117
+ camera.config.forced_payload = 800;
118
+ assert(maybe_downgrade_altsetting(&camera) == 0);
119
+ assert(camera.config.forced_altsetting == 3);
120
+
121
+ /* A pair that is in no table at all must not be walked off the end. */
122
+ camera.config = make_decxin();
123
+ camera.config.forced_payload = 944; /* 7/944: refused by validate_config */
124
+ assert(mode_index_for(&camera.config) == 2);
125
+ assert(maybe_downgrade_altsetting(&camera) == 0);
126
+ }
127
+
128
+ static void test_downgrade_is_remembered_under_a_stable_key(void) {
129
+ char parent[] = "/tmp/ksq-ladder-test-XXXXXX";
130
+ char state_dir[PATH_MAX];
131
+ char expected[PATH_MAX];
132
+ char contents[128];
133
+ camera_state_t camera;
134
+ FILE *file;
135
+ size_t read_bytes;
136
+
137
+ assert(mkdtemp(parent) != NULL);
138
+ /* A subdirectory that does not exist yet: persist_mode_choice creates it. */
139
+ snprintf(state_dir, sizeof(state_dir), "%s/camera_modes", parent);
140
+ memset(&camera, 0, sizeof(camera));
141
+ camera.config = make_decxin();
142
+ snprintf(camera.config.state_dir, sizeof(camera.config.state_dir), "%s",
143
+ state_dir);
144
+
145
+ assert(maybe_downgrade_altsetting(&camera) == 1);
146
+
147
+ /* Key = vid_pid_controller_serial with everything outside [A-Za-z0-9-]
148
+ * replaced by '_'. uvc_camera_service._mode_state_key must produce this
149
+ * exact string for the learned value to be read back. */
150
+ snprintf(expected, sizeof(expected), "%s/1bcf_2d4f_0000_74_00_4_DECXIN-01.mode",
151
+ state_dir);
152
+ file = fopen(expected, "r");
153
+ assert(file != NULL);
154
+ read_bytes = fread(contents, 1, sizeof(contents) - 1, file);
155
+ contents[read_bytes] = '\0';
156
+ fclose(file);
157
+ assert(strcmp(contents, "altsetting=6\npayload=944\n") == 0);
158
+
159
+ /* No temp file may be left behind next to the result. */
160
+ {
161
+ DIR *dir = opendir(state_dir);
162
+ struct dirent *entry;
163
+ int seen = 0;
164
+ assert(dir != NULL);
165
+ while ((entry = readdir(dir)) != NULL) {
166
+ if (entry->d_name[0] == '.') {
167
+ continue;
168
+ }
169
+ ++seen;
170
+ assert(strstr(entry->d_name, ".tmp.") == NULL);
171
+ }
172
+ closedir(dir);
173
+ assert(seen == 1);
174
+ }
175
+
176
+ unlink(expected);
177
+ rmdir(state_dir);
178
+ rmdir(parent);
179
+ }
180
+
181
+ static void test_missing_state_dir_is_not_fatal(void) {
182
+ camera_state_t camera;
183
+ memset(&camera, 0, sizeof(camera));
184
+ camera.config = make_decxin();
185
+ /* Empty state_dir means "do not remember anything" and must still step
186
+ * down in memory for the rest of this session. */
187
+ assert(camera.config.state_dir[0] == '\0');
188
+ assert(maybe_downgrade_altsetting(&camera) == 1);
189
+ assert(camera.config.forced_altsetting == 6);
190
+ }
191
+
192
+ int main(void) {
193
+ /* validate_config reports refusals on stderr; that is the production
194
+ * behaviour and is expected here, so keep the test output readable. */
195
+ freopen("/dev/null", "w", stderr);
196
+ test_accepts_every_rung_and_nothing_else();
197
+ test_steps_down_one_rung_and_then_stops();
198
+ test_downgrade_is_remembered_under_a_stable_key();
199
+ test_missing_state_dir_is_not_fatal();
200
+ printf("altsetting ladder: all assertions passed\n");
201
+ return 0;
202
+ }
collector/core/gripper/camera_service_src/tests/test_frame_integrity.c ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Test the actual callback and queue without opening USB devices. */
2
+ #undef NDEBUG
3
+ #include <assert.h>
4
+ #define main camera_service_main
5
+ #include "../src/camera_service.c"
6
+ #undef main
7
+
8
+ int main(void) {
9
+ camera_state_t camera = {0};
10
+ uint8_t good[] = {0xff, 0xd8, 0x01, 0x02, 0xff, 0xd9};
11
+ uint8_t short_frame[] = {0xff};
12
+ uvc_frame_t frame = {0};
13
+ pthread_mutex_init(&camera.mutex, NULL);
14
+ pthread_cond_init(&camera.condition, NULL);
15
+ frame.frame_format = UVC_FRAME_FORMAT_MJPEG;
16
+ frame.data = good;
17
+ frame.data_bytes = sizeof(good);
18
+ frame.sequence = 1;
19
+ frame.capture_time_finished.tv_sec = 2;
20
+ enqueue_frame(&frame, &camera);
21
+ assert(camera.count == 1);
22
+ assert(camera.queue[0].sequence == 1);
23
+ assert(camera.queue[0].capture_timestamp_ns == 2000000000ull);
24
+ frame.data = short_frame;
25
+ frame.data_bytes = sizeof(short_frame);
26
+ frame.sequence = 2;
27
+ frame.capture_time_finished.tv_sec = 3;
28
+ enqueue_frame(&frame, &camera);
29
+ assert(camera.count == 1); /* No old image under a new timestamp. */
30
+ assert(camera.bad_jpeg_frames == 1);
31
+ assert(camera.frames_dropped == 1);
32
+ assert(camera.bad_jpeg_replaced == 0);
33
+ assert(camera.queue[0].capture_timestamp_ns == 2000000000ull);
34
+ frame.data = good;
35
+ frame.data_bytes = sizeof(good);
36
+ frame.sequence = 3;
37
+ enqueue_frame(&frame, &camera);
38
+ assert(camera.count == 2);
39
+ assert(camera.queue[1].sequence == 3);
40
+ assert(camera.queue[1].capture_timestamp_ns == 3000000000ull);
41
+ for (size_t i = 0; i < FRAME_QUEUE_DEPTH; ++i) free(camera.queue[i].data);
42
+ pthread_mutex_destroy(&camera.mutex);
43
+ pthread_cond_destroy(&camera.condition);
44
+ return 0;
45
+ }
collector/core/gripper/camera_service_src/third_party/libuvc/CMakeLists.txt ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.1)
2
+ project(libuvc
3
+ VERSION 0.0.7
4
+ LANGUAGES C
5
+ )
6
+
7
+ # Additional search scripts path for libusb-1.0, libjpeg, OpenCV
8
+ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
9
+
10
+ # Xcode and Visual Studio do not using CMAKE_BUILD_TYPE cache variable
11
+ # so we use Release build type only with single configuration generators.
12
+ if (NOT CMAKE_CONFIGURATION_TYPES)
13
+ if(NOT CMAKE_BUILD_TYPE)
14
+ message(STATUS "No build type selected, default to Release")
15
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
16
+ endif()
17
+ endif()
18
+
19
+ if(NOT CMAKE_BUILD_TARGET)
20
+ message(STATUS "No target type selected, default to both shared and static library")
21
+ set(CMAKE_BUILD_TARGET "Both" CACHE STRING "" FORCE)
22
+ endif()
23
+
24
+ option(BUILD_EXAMPLE "Build example program" ON)
25
+ option(BUILD_TEST "Build test program" OFF)
26
+ option(ENABLE_UVC_DEBUGGING "Enable UVC debugging" OFF)
27
+
28
+ set(libuvc_DESCRIPTION "A cross-platform library for USB video devices")
29
+ set(libuvc_URL "https://github.com/libuvc/libuvc")
30
+
31
+ set(SOURCES
32
+ src/ctrl.c
33
+ src/ctrl-gen.c
34
+ src/device.c
35
+ src/diag.c
36
+ src/frame.c
37
+ src/init.c
38
+ src/stream.c
39
+ src/misc.c
40
+ )
41
+
42
+ find_package(LibUSB)
43
+
44
+ # JpegPkg name to differ from shipped with CMake
45
+ find_package(JpegPkg QUIET)
46
+ if(JPEG_FOUND)
47
+ message(STATUS "Building libuvc with JPEG support.")
48
+ set(LIBUVC_HAS_JPEG TRUE)
49
+ list(APPEND SOURCES src/frame-mjpeg.c)
50
+ else()
51
+ message(WARNING "JPEG not found. libuvc will not support JPEG decoding.")
52
+ endif()
53
+
54
+ if((UNIX AND NOT APPLE) OR MINGW OR WIN32)
55
+ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
56
+ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
57
+ find_package(Threads REQUIRED)
58
+ set(threads Threads::Threads)
59
+ endif()
60
+
61
+ if(${CMAKE_BUILD_TARGET} MATCHES "Shared")
62
+ set(BUILD_UVC_SHARED TRUE)
63
+ elseif(${CMAKE_BUILD_TARGET} MATCHES "Static")
64
+ set(BUILD_UVC_STATIC TRUE)
65
+ elseif(${CMAKE_BUILD_TARGET} MATCHES "Both")
66
+ set(BUILD_UVC_SHARED TRUE)
67
+ set(BUILD_UVC_STATIC TRUE)
68
+ else()
69
+ message(FATAL_ERROR "Invalid build type ${CMAKE_BUILD_TARGET}" )
70
+ endif()
71
+
72
+ if(BUILD_UVC_SHARED)
73
+ add_library(uvc SHARED ${SOURCES})
74
+ set_target_properties(uvc PROPERTIES
75
+ VERSION ${libuvc_VERSION}
76
+ SOVERSION ${libuvc_VERSION_MAJOR}
77
+ # Exported name of target within namespace LibUVC
78
+ EXPORT_NAME UVCShared
79
+ )
80
+ list(APPEND UVC_TARGETS uvc)
81
+ if(NOT LibUVC_STATIC)
82
+ add_library(LibUVC::UVC ALIAS uvc)
83
+ endif()
84
+ # Aliases defined here available only if project included
85
+ # via addsubdirectory
86
+ add_library(LibUVC::UVCShared ALIAS uvc)
87
+ endif()
88
+
89
+ if(BUILD_UVC_STATIC)
90
+ add_library(uvc_static STATIC ${SOURCES})
91
+ set_target_properties(uvc_static PROPERTIES
92
+ OUTPUT_NAME uvc
93
+ # Exported name of target within namespace LibUVC
94
+ EXPORT_NAME UVCStatic
95
+ )
96
+ list(APPEND UVC_TARGETS uvc_static)
97
+ add_library(LibUVC::UVCStatic ALIAS uvc_static)
98
+ if(LibUVC_STATIC)
99
+ add_library(LibUVC::UVC ALIAS uvc_static)
100
+ endif()
101
+ endif()
102
+
103
+ configure_file(include/libuvc/libuvc_config.h.in
104
+ include/libuvc/libuvc_config.h
105
+ @ONLY
106
+ )
107
+
108
+ foreach(target_name IN LISTS UVC_TARGETS)
109
+ target_include_directories(${target_name}
110
+ PUBLIC
111
+ # Different paths for includes for build and install phase supported
112
+ # via INSTALL_INTERFACE and BUILD_INTERFACE generator expressions.
113
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
114
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
115
+ $<INSTALL_INTERFACE:include>
116
+ )
117
+ target_link_libraries(${target_name}
118
+ # libusb-1.0 used internally so we link to it privately.
119
+ PRIVATE LibUSB::LibUSB ${threads}
120
+ )
121
+ if(JPEG_FOUND)
122
+ target_link_libraries(${target_name}
123
+ PRIVATE JPEG::JPEG
124
+ )
125
+ endif()
126
+ set_target_properties(${target_name} PROPERTIES
127
+ PUBLIC_HEADER "include/libuvc/libuvc.h;${CMAKE_CURRENT_BINARY_DIR}/include/libuvc/libuvc_config.h"
128
+ )
129
+ if(ENABLE_UVC_DEBUGGING)
130
+ target_compile_definitions(${target_name}
131
+ PRIVATE
132
+ UVC_DEBUGGING
133
+ )
134
+ find_library(
135
+ log-lib
136
+ log
137
+ )
138
+ target_link_libraries(
139
+ ${target_name}
140
+ PRIVATE
141
+ ${log-lib}
142
+ )
143
+ endif()
144
+ endforeach()
145
+
146
+ if(BUILD_EXAMPLE)
147
+ add_executable(example src/example.c)
148
+ find_package(Threads)
149
+ target_link_libraries(example
150
+ PRIVATE
151
+ LibUVC::UVC
152
+ Threads::Threads
153
+ )
154
+ endif()
155
+
156
+ if(BUILD_TEST)
157
+ # OpenCV defines targets with transitive dependencies not with namespaces but using opencv_ prefix.
158
+ # This targets provide necessary include directories and linked flags.
159
+ find_package(OpenCVPkg REQUIRED
160
+ COMPONENTS
161
+ opencv_core
162
+ opencv_highgui
163
+ )
164
+
165
+ add_executable(uvc_test src/test.c)
166
+ target_link_libraries(uvc_test
167
+ PRIVATE
168
+ LibUVC::UVC
169
+ opencv_core
170
+ opencv_highgui
171
+ )
172
+ endif()
173
+
174
+
175
+ include(GNUInstallDirs)
176
+ set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/libuvc)
177
+
178
+ install(
179
+ TARGETS ${UVC_TARGETS}
180
+ EXPORT libuvcTargets
181
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
182
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
183
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
184
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
185
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libuvc
186
+ )
187
+
188
+ install(EXPORT libuvcTargets
189
+ FILE libuvcTargets.cmake
190
+ NAMESPACE LibUVC::
191
+ DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
192
+ )
193
+
194
+ install(FILES
195
+ cmake/FindLibUSB.cmake
196
+ cmake/FindJpegPkg.cmake
197
+ DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
198
+ )
199
+
200
+ include(CMakePackageConfigHelpers)
201
+ write_basic_package_version_file(libuvcConfigVersion.cmake
202
+ COMPATIBILITY AnyNewerVersion
203
+ )
204
+
205
+ install(FILES
206
+ ${CMAKE_CURRENT_BINARY_DIR}/libuvcConfigVersion.cmake
207
+ DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
208
+ )
209
+
210
+ if(JPEG_FOUND)
211
+ # If we have used JPEG library we need to
212
+ # add linker flag for it in config file for pkgconfig
213
+ set(PKGCONFIG_JPEG_LDFLAG "-ljpeg")
214
+ endif()
215
+
216
+ configure_file(libuvc.pc.in
217
+ ${PROJECT_BINARY_DIR}/libuvc.pc
218
+ @ONLY
219
+ )
220
+
221
+ install(FILES
222
+ ${CMAKE_CURRENT_BINARY_DIR}/libuvc.pc
223
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
224
+ )
225
+
226
+ install(FILES libuvcConfig.cmake
227
+ DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
228
+ )
229
+
230
+
collector/core/gripper/camera_service_src/third_party/libuvc/LICENSE.txt ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Software License Agreement (BSD License)
2
+
3
+ Copyright (C) 2010-2015 Ken Tossell
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions
8
+ are met:
9
+
10
+ * Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+ * Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following
14
+ disclaimer in the documentation and/or other materials provided
15
+ with the distribution.
16
+ * Neither the name of the author nor other contributors may be
17
+ used to endorse or promote products derived from this software
18
+ without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE.
collector/core/gripper/camera_service_src/third_party/libuvc/README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ `libuvc` is a cross-platform library for USB video devices, built atop `libusb`.
2
+ It enables fine-grained control over USB video devices exporting the standard USB Video Class
3
+ (UVC) interface, enabling developers to write drivers for previously unsupported devices,
4
+ or just access UVC devices in a generic fashion.
5
+
6
+ ## Getting and Building libuvc
7
+
8
+ Prerequisites: You will need `libusb` and [CMake](http://www.cmake.org/) installed.
9
+
10
+ To build, you can just run these shell commands:
11
+
12
+ git clone https://github.com/libuvc/libuvc
13
+ cd libuvc
14
+ mkdir build
15
+ cd build
16
+ cmake ..
17
+ make && sudo make install
18
+
19
+ and you're set! If you want to change the build configuration, you can edit `CMakeCache.txt`
20
+ in the build directory, or use a CMake GUI to make the desired changes.
21
+
22
+ There is also `BUILD_EXAMPLE` and `BUILD_TEST` options to enable the compilation of `example` and `uvc_test` programs. To use them, replace the `cmake ..` command above with `cmake .. -DBUILD_TEST=ON -DBUILD_EXAMPLE=ON`.
23
+ Then you can start them with `./example` and `./uvc_test` respectively. Note that you need OpenCV to build the later (for displaying image).
24
+
25
+ ## Developing with libuvc
26
+
27
+ The documentation for `libuvc` can currently be found at https://libuvc.github.io/.
28
+
29
+ Happy hacking!
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_imac.txt ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Bus 001 Device 007: ID 05ac:8501 Apple, Inc. Built-in iSight [Micron]
3
+ Device Descriptor:
4
+ bLength 18
5
+ bDescriptorType 1
6
+ bcdUSB 2.00
7
+ bDeviceClass 239 Miscellaneous Device
8
+ bDeviceSubClass 2 ?
9
+ bDeviceProtocol 1 Interface Association
10
+ bMaxPacketSize0 64
11
+ idVendor 0x05ac Apple, Inc.
12
+ idProduct 0x8501 Built-in iSight [Micron]
13
+ bcdDevice 1.89
14
+ iManufacturer 1 Micron
15
+ iProduct 2 Built-in iSight
16
+ iSerial 0
17
+ bNumConfigurations 1
18
+ Configuration Descriptor:
19
+ bLength 9
20
+ bDescriptorType 2
21
+ wTotalLength 267
22
+ bNumInterfaces 2
23
+ bConfigurationValue 1
24
+ iConfiguration 0
25
+ bmAttributes 0x80
26
+ (Bus Powered)
27
+ MaxPower 100mA
28
+ Interface Association:
29
+ bLength 8
30
+ bDescriptorType 11
31
+ bFirstInterface 0
32
+ bInterfaceCount 2
33
+ bFunctionClass 14 Video
34
+ bFunctionSubClass 3 Video Interface Collection
35
+ bFunctionProtocol 0
36
+ iFunction 0
37
+ Interface Descriptor:
38
+ bLength 9
39
+ bDescriptorType 4
40
+ bInterfaceNumber 0
41
+ bAlternateSetting 0
42
+ bNumEndpoints 1
43
+ bInterfaceClass 14 Video
44
+ bInterfaceSubClass 1 Video Control
45
+ bInterfaceProtocol 0
46
+ iInterface 0
47
+ VideoControl Interface Descriptor:
48
+ bLength 13
49
+ bDescriptorType 36
50
+ bDescriptorSubtype 1 (HEADER)
51
+ bcdUVC 1.00
52
+ wTotalLength 49
53
+ dwClockFrequency 13.500000MHz
54
+ bInCollection 1
55
+ baInterfaceNr( 0) 1
56
+ VideoControl Interface Descriptor:
57
+ bLength 16
58
+ bDescriptorType 36
59
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
60
+ bTerminalID 1
61
+ wTerminalType 0x0201 Camera Sensor
62
+ bAssocTerminal 0
63
+ iTerminal 0
64
+ wObjectiveFocalLengthMin 0
65
+ wObjectiveFocalLengthMax 0
66
+ wOcularFocalLength 0
67
+ bControlSize 1
68
+ bmControls 0x00000000
69
+ VideoControl Interface Descriptor:
70
+ bLength 11
71
+ bDescriptorType 36
72
+ bDescriptorSubtype 5 (PROCESSING_UNIT)
73
+ Warning: Descriptor too short
74
+ bUnitID 2
75
+ bSourceID 1
76
+ wMaxMultiplier 0
77
+ bControlSize 2
78
+ bmControls 0x00000039
79
+ Brightness
80
+ Saturation
81
+ Sharpness
82
+ Gamma
83
+ iProcessing 0
84
+ bmVideoStandards 0x 9
85
+ None
86
+ SECAM - 625/50
87
+ VideoControl Interface Descriptor:
88
+ bLength 9
89
+ bDescriptorType 36
90
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
91
+ bTerminalID 3
92
+ wTerminalType 0x0101 USB Streaming
93
+ bAssocTerminal 0
94
+ bSourceID 2
95
+ iTerminal 0
96
+ Endpoint Descriptor:
97
+ bLength 7
98
+ bDescriptorType 5
99
+ bEndpointAddress 0x81 EP 1 IN
100
+ bmAttributes 3
101
+ Transfer Type Interrupt
102
+ Synch Type None
103
+ Usage Type Data
104
+ wMaxPacketSize 0x0008 1x 8 bytes
105
+ bInterval 10
106
+ Interface Descriptor:
107
+ bLength 9
108
+ bDescriptorType 4
109
+ bInterfaceNumber 1
110
+ bAlternateSetting 0
111
+ bNumEndpoints 0
112
+ bInterfaceClass 14 Video
113
+ bInterfaceSubClass 2 Video Streaming
114
+ bInterfaceProtocol 0
115
+ iInterface 0
116
+ VideoStreaming Interface Descriptor:
117
+ bLength 14
118
+ bDescriptorType 36
119
+ bDescriptorSubtype 1 (INPUT_HEADER)
120
+ bNumFormats 1
121
+ wTotalLength 155
122
+ bEndPointAddress 130
123
+ bmInfo 0
124
+ bTerminalLink 3
125
+ bStillCaptureMethod 0
126
+ bTriggerSupport 0
127
+ bTriggerUsage 0
128
+ bControlSize 1
129
+ bmaControls( 0) 27
130
+ VideoStreaming Interface Descriptor:
131
+ bLength 27
132
+ bDescriptorType 36
133
+ bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
134
+ bFormatIndex 1
135
+ bNumFrameDescriptors 3
136
+ guidFormat {55595659-0000-1000-8000-00aa00389b71}
137
+ bBitsPerPixel 16
138
+ bDefaultFrameIndex 1
139
+ bAspectRatioX 0
140
+ bAspectRatioY 0
141
+ bmInterlaceFlags 0x00
142
+ Interlaced stream or variable: No
143
+ Fields per frame: 1 fields
144
+ Field 1 first: No
145
+ Field pattern: Field 1 only
146
+ bCopyProtect 0
147
+ VideoStreaming Interface Descriptor:
148
+ bLength 38
149
+ bDescriptorType 36
150
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
151
+ bFrameIndex 1
152
+ bmCapabilities 0x00
153
+ Still image unsupported
154
+ wWidth 640
155
+ wHeight 480
156
+ dwMinBitRate 383976960
157
+ dwMaxBitRate 383976960
158
+ dwMaxVideoFrameBufferSize 614400
159
+ dwDefaultFrameInterval 333333
160
+ bFrameIntervalType 0
161
+ dwMinFrameInterval 333333
162
+ dwMaxFrameInterval 333333
163
+ dwFrameIntervalStep 0
164
+ VideoStreaming Interface Descriptor:
165
+ bLength 38
166
+ bDescriptorType 36
167
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
168
+ bFrameIndex 2
169
+ bmCapabilities 0x00
170
+ Still image unsupported
171
+ wWidth 352
172
+ wHeight 288
173
+ dwMinBitRate 383976960
174
+ dwMaxBitRate 383976960
175
+ dwMaxVideoFrameBufferSize 202752
176
+ dwDefaultFrameInterval 333333
177
+ bFrameIntervalType 0
178
+ dwMinFrameInterval 333333
179
+ dwMaxFrameInterval 333333
180
+ dwFrameIntervalStep 0
181
+ VideoStreaming Interface Descriptor:
182
+ bLength 38
183
+ bDescriptorType 36
184
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
185
+ bFrameIndex 3
186
+ bmCapabilities 0x00
187
+ Still image unsupported
188
+ wWidth 320
189
+ wHeight 240
190
+ dwMinBitRate 383976960
191
+ dwMaxBitRate 383976960
192
+ dwMaxVideoFrameBufferSize 153600
193
+ dwDefaultFrameInterval 333333
194
+ bFrameIntervalType 0
195
+ dwMinFrameInterval 333333
196
+ dwMaxFrameInterval 333333
197
+ dwFrameIntervalStep 0
198
+ Interface Descriptor:
199
+ bLength 9
200
+ bDescriptorType 4
201
+ bInterfaceNumber 1
202
+ bAlternateSetting 1
203
+ bNumEndpoints 1
204
+ bInterfaceClass 14 Video
205
+ bInterfaceSubClass 2 Video Streaming
206
+ bInterfaceProtocol 0
207
+ iInterface 0
208
+ Endpoint Descriptor:
209
+ bLength 7
210
+ bDescriptorType 5
211
+ bEndpointAddress 0x82 EP 2 IN
212
+ bmAttributes 5
213
+ Transfer Type Isochronous
214
+ Synch Type Asynchronous
215
+ Usage Type Data
216
+ wMaxPacketSize 0x1400 3x 1024 bytes
217
+ bInterval 1
218
+ Device Qualifier (for other device speed):
219
+ bLength 10
220
+ bDescriptorType 6
221
+ bcdUSB 2.00
222
+ bDeviceClass 14 Video
223
+ bDeviceSubClass 2 Video Streaming
224
+ bDeviceProtocol 0
225
+ bMaxPacketSize0 8
226
+ bNumConfigurations 1
227
+ Device Status: 0x0000
228
+ (Bus Powered)
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_macbook.txt ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Bus 001 Device 010: ID 05ac:8501 Apple, Inc. Built-in iSight [Micron]
3
+ Device Descriptor:
4
+ bLength 18
5
+ bDescriptorType 1
6
+ bcdUSB 2.00
7
+ bDeviceClass 239 Miscellaneous Device
8
+ bDeviceSubClass 2 ?
9
+ bDeviceProtocol 1 Interface Association
10
+ bMaxPacketSize0 64
11
+ idVendor 0x05ac Apple, Inc.
12
+ idProduct 0x8501 Built-in iSight [Micron]
13
+ bcdDevice 1.89
14
+ iManufacturer 1 Micron
15
+ iProduct 2 Built-in iSight
16
+ iSerial 0
17
+ bNumConfigurations 1
18
+ Configuration Descriptor:
19
+ bLength 9
20
+ bDescriptorType 2
21
+ wTotalLength 267
22
+ bNumInterfaces 2
23
+ bConfigurationValue 1
24
+ iConfiguration 0
25
+ bmAttributes 0x80
26
+ (Bus Powered)
27
+ MaxPower 100mA
28
+ Interface Association:
29
+ bLength 8
30
+ bDescriptorType 11
31
+ bFirstInterface 0
32
+ bInterfaceCount 2
33
+ bFunctionClass 14 Video
34
+ bFunctionSubClass 3 Video Interface Collection
35
+ bFunctionProtocol 0
36
+ iFunction 0
37
+ Interface Descriptor:
38
+ bLength 9
39
+ bDescriptorType 4
40
+ bInterfaceNumber 0
41
+ bAlternateSetting 0
42
+ bNumEndpoints 1
43
+ bInterfaceClass 14 Video
44
+ bInterfaceSubClass 1 Video Control
45
+ bInterfaceProtocol 0
46
+ iInterface 0
47
+ VideoControl Interface Descriptor:
48
+ bLength 13
49
+ bDescriptorType 36
50
+ bDescriptorSubtype 1 (HEADER)
51
+ bcdUVC 1.00
52
+ wTotalLength 49
53
+ dwClockFrequency 13.500000MHz
54
+ bInCollection 1
55
+ baInterfaceNr( 0) 1
56
+ VideoControl Interface Descriptor:
57
+ bLength 16
58
+ bDescriptorType 36
59
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
60
+ bTerminalID 1
61
+ wTerminalType 0x0201 Camera Sensor
62
+ bAssocTerminal 0
63
+ iTerminal 0
64
+ wObjectiveFocalLengthMin 0
65
+ wObjectiveFocalLengthMax 0
66
+ wOcularFocalLength 0
67
+ bControlSize 1
68
+ bmControls 0x00000000
69
+ VideoControl Interface Descriptor:
70
+ bLength 11
71
+ bDescriptorType 36
72
+ bDescriptorSubtype 5 (PROCESSING_UNIT)
73
+ Warning: Descriptor too short
74
+ bUnitID 2
75
+ bSourceID 1
76
+ wMaxMultiplier 0
77
+ bControlSize 2
78
+ bmControls 0x00000039
79
+ Brightness
80
+ Saturation
81
+ Sharpness
82
+ Gamma
83
+ iProcessing 0
84
+ bmVideoStandards 0x 9
85
+ None
86
+ SECAM - 625/50
87
+ VideoControl Interface Descriptor:
88
+ bLength 9
89
+ bDescriptorType 36
90
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
91
+ bTerminalID 3
92
+ wTerminalType 0x0101 USB Streaming
93
+ bAssocTerminal 0
94
+ bSourceID 2
95
+ iTerminal 0
96
+ Endpoint Descriptor:
97
+ bLength 7
98
+ bDescriptorType 5
99
+ bEndpointAddress 0x81 EP 1 IN
100
+ bmAttributes 3
101
+ Transfer Type Interrupt
102
+ Synch Type None
103
+ Usage Type Data
104
+ wMaxPacketSize 0x0008 1x 8 bytes
105
+ bInterval 10
106
+ Interface Descriptor:
107
+ bLength 9
108
+ bDescriptorType 4
109
+ bInterfaceNumber 1
110
+ bAlternateSetting 0
111
+ bNumEndpoints 0
112
+ bInterfaceClass 14 Video
113
+ bInterfaceSubClass 2 Video Streaming
114
+ bInterfaceProtocol 0
115
+ iInterface 0
116
+ VideoStreaming Interface Descriptor:
117
+ bLength 14
118
+ bDescriptorType 36
119
+ bDescriptorSubtype 1 (INPUT_HEADER)
120
+ bNumFormats 1
121
+ wTotalLength 155
122
+ bEndPointAddress 130
123
+ bmInfo 0
124
+ bTerminalLink 3
125
+ bStillCaptureMethod 0
126
+ bTriggerSupport 0
127
+ bTriggerUsage 0
128
+ bControlSize 1
129
+ bmaControls( 0) 27
130
+ VideoStreaming Interface Descriptor:
131
+ bLength 27
132
+ bDescriptorType 36
133
+ bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
134
+ bFormatIndex 1
135
+ bNumFrameDescriptors 3
136
+ guidFormat {55595659-0000-1000-8000-00aa00389b71}
137
+ bBitsPerPixel 16
138
+ bDefaultFrameIndex 1
139
+ bAspectRatioX 0
140
+ bAspectRatioY 0
141
+ bmInterlaceFlags 0x00
142
+ Interlaced stream or variable: No
143
+ Fields per frame: 1 fields
144
+ Field 1 first: No
145
+ Field pattern: Field 1 only
146
+ bCopyProtect 0
147
+ VideoStreaming Interface Descriptor:
148
+ bLength 38
149
+ bDescriptorType 36
150
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
151
+ bFrameIndex 1
152
+ bmCapabilities 0x00
153
+ Still image unsupported
154
+ wWidth 640
155
+ wHeight 480
156
+ dwMinBitRate 383976960
157
+ dwMaxBitRate 383976960
158
+ dwMaxVideoFrameBufferSize 614400
159
+ dwDefaultFrameInterval 333333
160
+ bFrameIntervalType 0
161
+ dwMinFrameInterval 333333
162
+ dwMaxFrameInterval 333333
163
+ dwFrameIntervalStep 0
164
+ VideoStreaming Interface Descriptor:
165
+ bLength 38
166
+ bDescriptorType 36
167
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
168
+ bFrameIndex 2
169
+ bmCapabilities 0x00
170
+ Still image unsupported
171
+ wWidth 352
172
+ wHeight 288
173
+ dwMinBitRate 383976960
174
+ dwMaxBitRate 383976960
175
+ dwMaxVideoFrameBufferSize 202752
176
+ dwDefaultFrameInterval 333333
177
+ bFrameIntervalType 0
178
+ dwMinFrameInterval 333333
179
+ dwMaxFrameInterval 333333
180
+ dwFrameIntervalStep 0
181
+ VideoStreaming Interface Descriptor:
182
+ bLength 38
183
+ bDescriptorType 36
184
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
185
+ bFrameIndex 3
186
+ bmCapabilities 0x00
187
+ Still image unsupported
188
+ wWidth 320
189
+ wHeight 240
190
+ dwMinBitRate 383976960
191
+ dwMaxBitRate 383976960
192
+ dwMaxVideoFrameBufferSize 153600
193
+ dwDefaultFrameInterval 333333
194
+ bFrameIntervalType 0
195
+ dwMinFrameInterval 333333
196
+ dwMaxFrameInterval 333333
197
+ dwFrameIntervalStep 0
198
+ Interface Descriptor:
199
+ bLength 9
200
+ bDescriptorType 4
201
+ bInterfaceNumber 1
202
+ bAlternateSetting 1
203
+ bNumEndpoints 1
204
+ bInterfaceClass 14 Video
205
+ bInterfaceSubClass 2 Video Streaming
206
+ bInterfaceProtocol 0
207
+ iInterface 0
208
+ Endpoint Descriptor:
209
+ bLength 7
210
+ bDescriptorType 5
211
+ bEndpointAddress 0x82 EP 2 IN
212
+ bmAttributes 5
213
+ Transfer Type Isochronous
214
+ Synch Type Asynchronous
215
+ Usage Type Data
216
+ wMaxPacketSize 0x1400 3x 1024 bytes
217
+ bInterval 1
218
+ Device Qualifier (for other device speed):
219
+ bLength 10
220
+ bDescriptorType 6
221
+ bcdUSB 2.00
222
+ bDeviceClass 14 Video
223
+ bDeviceSubClass 2 Video Streaming
224
+ bDeviceProtocol 0
225
+ bMaxPacketSize0 8
226
+ bNumConfigurations 1
227
+ Device Status: 0x0000
228
+ (Bus Powered)
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/logitech_hd_pro_920.txt ADDED
@@ -0,0 +1,1817 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Bus 001 Device 018: ID 046d:082d Logitech, Inc. HD Pro Webcam C920
3
+ Device Descriptor:
4
+ bLength 18
5
+ bDescriptorType 1
6
+ bcdUSB 2.00
7
+ bDeviceClass 239 Miscellaneous Device
8
+ bDeviceSubClass 2 ?
9
+ bDeviceProtocol 1 Interface Association
10
+ bMaxPacketSize0 64
11
+ idVendor 0x046d Logitech, Inc.
12
+ idProduct 0x082d HD Pro Webcam C920
13
+ bcdDevice 0.11
14
+ iManufacturer 0
15
+ iProduct 2 HD Pro Webcam C920
16
+ iSerial 1 E1CA2A7F
17
+ bNumConfigurations 1
18
+ Configuration Descriptor:
19
+ bLength 9
20
+ bDescriptorType 2
21
+ wTotalLength 3452
22
+ bNumInterfaces 4
23
+ bConfigurationValue 1
24
+ iConfiguration 0
25
+ bmAttributes 0x80
26
+ (Bus Powered)
27
+ MaxPower 500mA
28
+ Interface Association:
29
+ bLength 8
30
+ bDescriptorType 11
31
+ bFirstInterface 0
32
+ bInterfaceCount 2
33
+ bFunctionClass 14 Video
34
+ bFunctionSubClass 3 Video Interface Collection
35
+ bFunctionProtocol 0
36
+ iFunction 0
37
+ Interface Descriptor:
38
+ bLength 9
39
+ bDescriptorType 4
40
+ bInterfaceNumber 0
41
+ bAlternateSetting 0
42
+ bNumEndpoints 1
43
+ bInterfaceClass 14 Video
44
+ bInterfaceSubClass 1 Video Control
45
+ bInterfaceProtocol 0
46
+ iInterface 0
47
+ VideoControl Interface Descriptor:
48
+ bLength 13
49
+ bDescriptorType 36
50
+ bDescriptorSubtype 1 (HEADER)
51
+ bcdUVC 1.00
52
+ wTotalLength 214
53
+ dwClockFrequency 300.000000MHz
54
+ bInCollection 1
55
+ baInterfaceNr( 0) 1
56
+ VideoControl Interface Descriptor:
57
+ bLength 18
58
+ bDescriptorType 36
59
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
60
+ bTerminalID 1
61
+ wTerminalType 0x0201 Camera Sensor
62
+ bAssocTerminal 0
63
+ iTerminal 0
64
+ wObjectiveFocalLengthMin 0
65
+ wObjectiveFocalLengthMax 0
66
+ wOcularFocalLength 0
67
+ bControlSize 3
68
+ bmControls 0x00020a2e
69
+ Auto-Exposure Mode
70
+ Auto-Exposure Priority
71
+ Exposure Time (Absolute)
72
+ Focus (Absolute)
73
+ Zoom (Absolute)
74
+ PanTilt (Absolute)
75
+ Focus, Auto
76
+ VideoControl Interface Descriptor:
77
+ bLength 11
78
+ bDescriptorType 36
79
+ bDescriptorSubtype 5 (PROCESSING_UNIT)
80
+ Warning: Descriptor too short
81
+ bUnitID 3
82
+ bSourceID 1
83
+ wMaxMultiplier 16384
84
+ bControlSize 2
85
+ bmControls 0x0000175b
86
+ Brightness
87
+ Contrast
88
+ Saturation
89
+ Sharpness
90
+ White Balance Temperature
91
+ Backlight Compensation
92
+ Gain
93
+ Power Line Frequency
94
+ White Balance Temperature, Auto
95
+ iProcessing 0
96
+ bmVideoStandards 0x1b
97
+ None
98
+ NTSC - 525/60
99
+ SECAM - 625/50
100
+ NTSC - 625/50
101
+ VideoControl Interface Descriptor:
102
+ bLength 27
103
+ bDescriptorType 36
104
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
105
+ bUnitID 6
106
+ guidExtensionCode {d09ee423-7811-314f-ae52-d2fb8a8d3b48}
107
+ bNumControl 10
108
+ bNrPins 1
109
+ baSourceID( 0) 3
110
+ bControlSize 2
111
+ bmControls( 0) 0xff
112
+ bmControls( 1) 0x03
113
+ iExtension 0
114
+ VideoControl Interface Descriptor:
115
+ bLength 27
116
+ bDescriptorType 36
117
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
118
+ bUnitID 8
119
+ guidExtensionCode {e48e6769-0f41-db40-a850-7420d7d8240e}
120
+ bNumControl 7
121
+ bNrPins 1
122
+ baSourceID( 0) 1
123
+ bControlSize 2
124
+ bmControls( 0) 0x3b
125
+ bmControls( 1) 0x03
126
+ iExtension 0
127
+ VideoControl Interface Descriptor:
128
+ bLength 28
129
+ bDescriptorType 36
130
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
131
+ bUnitID 9
132
+ guidExtensionCode {a94c5d1f-11de-8744-840d-50933c8ec8d1}
133
+ bNumControl 17
134
+ bNrPins 1
135
+ baSourceID( 0) 1
136
+ bControlSize 3
137
+ bmControls( 0) 0xf3
138
+ bmControls( 1) 0xff
139
+ bmControls( 2) 0x23
140
+ iExtension 0
141
+ VideoControl Interface Descriptor:
142
+ bLength 27
143
+ bDescriptorType 36
144
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
145
+ bUnitID 10
146
+ guidExtensionCode {1502e449-34f4-fe47-b158-0e885023e51b}
147
+ bNumControl 7
148
+ bNrPins 1
149
+ baSourceID( 0) 1
150
+ bControlSize 2
151
+ bmControls( 0) 0xaa
152
+ bmControls( 1) 0x07
153
+ iExtension 0
154
+ VideoControl Interface Descriptor:
155
+ bLength 27
156
+ bDescriptorType 36
157
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
158
+ bUnitID 11
159
+ guidExtensionCode {212de5ff-3080-2c4e-82d9-f587d00540bd}
160
+ bNumControl 2
161
+ bNrPins 1
162
+ baSourceID( 0) 1
163
+ bControlSize 2
164
+ bmControls( 0) 0x00
165
+ bmControls( 1) 0x41
166
+ iExtension 0
167
+ VideoControl Interface Descriptor:
168
+ bLength 27
169
+ bDescriptorType 36
170
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
171
+ bUnitID 12
172
+ guidExtensionCode {41769ea2-04de-e347-8b2b-f4341aff003b}
173
+ bNumControl 11
174
+ bNrPins 1
175
+ baSourceID( 0) 3
176
+ bControlSize 2
177
+ bmControls( 0) 0x07
178
+ bmControls( 1) 0x7f
179
+ iExtension 0
180
+ VideoControl Interface Descriptor:
181
+ bLength 9
182
+ bDescriptorType 36
183
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
184
+ bTerminalID 4
185
+ wTerminalType 0x0101 USB Streaming
186
+ bAssocTerminal 0
187
+ bSourceID 3
188
+ iTerminal 0
189
+ Endpoint Descriptor:
190
+ bLength 7
191
+ bDescriptorType 5
192
+ bEndpointAddress 0x83 EP 3 IN
193
+ bmAttributes 3
194
+ Transfer Type Interrupt
195
+ Synch Type None
196
+ Usage Type Data
197
+ wMaxPacketSize 0x0040 1x 64 bytes
198
+ bInterval 8
199
+ Interface Descriptor:
200
+ bLength 9
201
+ bDescriptorType 4
202
+ bInterfaceNumber 1
203
+ bAlternateSetting 0
204
+ bNumEndpoints 0
205
+ bInterfaceClass 14 Video
206
+ bInterfaceSubClass 2 Video Streaming
207
+ bInterfaceProtocol 0
208
+ iInterface 0
209
+ VideoStreaming Interface Descriptor:
210
+ bLength 16
211
+ bDescriptorType 36
212
+ bDescriptorSubtype 1 (INPUT_HEADER)
213
+ bNumFormats 3
214
+ wTotalLength 2822
215
+ bEndPointAddress 129
216
+ bmInfo 0
217
+ bTerminalLink 4
218
+ bStillCaptureMethod 0
219
+ bTriggerSupport 0
220
+ bTriggerUsage 0
221
+ bControlSize 1
222
+ bmaControls( 0) 27
223
+ bmaControls( 1) 27
224
+ bmaControls( 2) 27
225
+ VideoStreaming Interface Descriptor:
226
+ bLength 27
227
+ bDescriptorType 36
228
+ bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
229
+ bFormatIndex 1
230
+ bNumFrameDescriptors 19
231
+ guidFormat {59555932-0000-1000-8000-00aa00389b71}
232
+ bBitsPerPixel 16
233
+ bDefaultFrameIndex 1
234
+ bAspectRatioX 0
235
+ bAspectRatioY 0
236
+ bmInterlaceFlags 0x00
237
+ Interlaced stream or variable: No
238
+ Fields per frame: 2 fields
239
+ Field 1 first: No
240
+ Field pattern: Field 1 only
241
+ bCopyProtect 0
242
+ VideoStreaming Interface Descriptor:
243
+ bLength 54
244
+ bDescriptorType 36
245
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
246
+ bFrameIndex 1
247
+ bmCapabilities 0x00
248
+ Still image unsupported
249
+ wWidth 640
250
+ wHeight 480
251
+ dwMinBitRate 24576000
252
+ dwMaxBitRate 147456000
253
+ dwMaxVideoFrameBufferSize 614400
254
+ dwDefaultFrameInterval 333333
255
+ bFrameIntervalType 7
256
+ dwFrameInterval( 0) 333333
257
+ dwFrameInterval( 1) 416666
258
+ dwFrameInterval( 2) 500000
259
+ dwFrameInterval( 3) 666666
260
+ dwFrameInterval( 4) 1000000
261
+ dwFrameInterval( 5) 1333333
262
+ dwFrameInterval( 6) 2000000
263
+ VideoStreaming Interface Descriptor:
264
+ bLength 54
265
+ bDescriptorType 36
266
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
267
+ bFrameIndex 2
268
+ bmCapabilities 0x00
269
+ Still image unsupported
270
+ wWidth 160
271
+ wHeight 90
272
+ dwMinBitRate 1152000
273
+ dwMaxBitRate 6912000
274
+ dwMaxVideoFrameBufferSize 28800
275
+ dwDefaultFrameInterval 333333
276
+ bFrameIntervalType 7
277
+ dwFrameInterval( 0) 333333
278
+ dwFrameInterval( 1) 416666
279
+ dwFrameInterval( 2) 500000
280
+ dwFrameInterval( 3) 666666
281
+ dwFrameInterval( 4) 1000000
282
+ dwFrameInterval( 5) 1333333
283
+ dwFrameInterval( 6) 2000000
284
+ VideoStreaming Interface Descriptor:
285
+ bLength 54
286
+ bDescriptorType 36
287
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
288
+ bFrameIndex 3
289
+ bmCapabilities 0x00
290
+ Still image unsupported
291
+ wWidth 160
292
+ wHeight 120
293
+ dwMinBitRate 1536000
294
+ dwMaxBitRate 9216000
295
+ dwMaxVideoFrameBufferSize 38400
296
+ dwDefaultFrameInterval 333333
297
+ bFrameIntervalType 7
298
+ dwFrameInterval( 0) 333333
299
+ dwFrameInterval( 1) 416666
300
+ dwFrameInterval( 2) 500000
301
+ dwFrameInterval( 3) 666666
302
+ dwFrameInterval( 4) 1000000
303
+ dwFrameInterval( 5) 1333333
304
+ dwFrameInterval( 6) 2000000
305
+ VideoStreaming Interface Descriptor:
306
+ bLength 54
307
+ bDescriptorType 36
308
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
309
+ bFrameIndex 4
310
+ bmCapabilities 0x00
311
+ Still image unsupported
312
+ wWidth 176
313
+ wHeight 144
314
+ dwMinBitRate 2027520
315
+ dwMaxBitRate 12165120
316
+ dwMaxVideoFrameBufferSize 50688
317
+ dwDefaultFrameInterval 333333
318
+ bFrameIntervalType 7
319
+ dwFrameInterval( 0) 333333
320
+ dwFrameInterval( 1) 416666
321
+ dwFrameInterval( 2) 500000
322
+ dwFrameInterval( 3) 666666
323
+ dwFrameInterval( 4) 1000000
324
+ dwFrameInterval( 5) 1333333
325
+ dwFrameInterval( 6) 2000000
326
+ VideoStreaming Interface Descriptor:
327
+ bLength 54
328
+ bDescriptorType 36
329
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
330
+ bFrameIndex 5
331
+ bmCapabilities 0x00
332
+ Still image unsupported
333
+ wWidth 320
334
+ wHeight 180
335
+ dwMinBitRate 4608000
336
+ dwMaxBitRate 27648000
337
+ dwMaxVideoFrameBufferSize 115200
338
+ dwDefaultFrameInterval 333333
339
+ bFrameIntervalType 7
340
+ dwFrameInterval( 0) 333333
341
+ dwFrameInterval( 1) 416666
342
+ dwFrameInterval( 2) 500000
343
+ dwFrameInterval( 3) 666666
344
+ dwFrameInterval( 4) 1000000
345
+ dwFrameInterval( 5) 1333333
346
+ dwFrameInterval( 6) 2000000
347
+ VideoStreaming Interface Descriptor:
348
+ bLength 54
349
+ bDescriptorType 36
350
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
351
+ bFrameIndex 6
352
+ bmCapabilities 0x00
353
+ Still image unsupported
354
+ wWidth 320
355
+ wHeight 240
356
+ dwMinBitRate 6144000
357
+ dwMaxBitRate 36864000
358
+ dwMaxVideoFrameBufferSize 153600
359
+ dwDefaultFrameInterval 333333
360
+ bFrameIntervalType 7
361
+ dwFrameInterval( 0) 333333
362
+ dwFrameInterval( 1) 416666
363
+ dwFrameInterval( 2) 500000
364
+ dwFrameInterval( 3) 666666
365
+ dwFrameInterval( 4) 1000000
366
+ dwFrameInterval( 5) 1333333
367
+ dwFrameInterval( 6) 2000000
368
+ VideoStreaming Interface Descriptor:
369
+ bLength 54
370
+ bDescriptorType 36
371
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
372
+ bFrameIndex 7
373
+ bmCapabilities 0x00
374
+ Still image unsupported
375
+ wWidth 352
376
+ wHeight 288
377
+ dwMinBitRate 8110080
378
+ dwMaxBitRate 48660480
379
+ dwMaxVideoFrameBufferSize 202752
380
+ dwDefaultFrameInterval 333333
381
+ bFrameIntervalType 7
382
+ dwFrameInterval( 0) 333333
383
+ dwFrameInterval( 1) 416666
384
+ dwFrameInterval( 2) 500000
385
+ dwFrameInterval( 3) 666666
386
+ dwFrameInterval( 4) 1000000
387
+ dwFrameInterval( 5) 1333333
388
+ dwFrameInterval( 6) 2000000
389
+ VideoStreaming Interface Descriptor:
390
+ bLength 54
391
+ bDescriptorType 36
392
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
393
+ bFrameIndex 8
394
+ bmCapabilities 0x00
395
+ Still image unsupported
396
+ wWidth 432
397
+ wHeight 240
398
+ dwMinBitRate 8294400
399
+ dwMaxBitRate 49766400
400
+ dwMaxVideoFrameBufferSize 207360
401
+ dwDefaultFrameInterval 333333
402
+ bFrameIntervalType 7
403
+ dwFrameInterval( 0) 333333
404
+ dwFrameInterval( 1) 416666
405
+ dwFrameInterval( 2) 500000
406
+ dwFrameInterval( 3) 666666
407
+ dwFrameInterval( 4) 1000000
408
+ dwFrameInterval( 5) 1333333
409
+ dwFrameInterval( 6) 2000000
410
+ VideoStreaming Interface Descriptor:
411
+ bLength 54
412
+ bDescriptorType 36
413
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
414
+ bFrameIndex 9
415
+ bmCapabilities 0x00
416
+ Still image unsupported
417
+ wWidth 640
418
+ wHeight 360
419
+ dwMinBitRate 18432000
420
+ dwMaxBitRate 110592000
421
+ dwMaxVideoFrameBufferSize 460800
422
+ dwDefaultFrameInterval 333333
423
+ bFrameIntervalType 7
424
+ dwFrameInterval( 0) 333333
425
+ dwFrameInterval( 1) 416666
426
+ dwFrameInterval( 2) 500000
427
+ dwFrameInterval( 3) 666666
428
+ dwFrameInterval( 4) 1000000
429
+ dwFrameInterval( 5) 1333333
430
+ dwFrameInterval( 6) 2000000
431
+ VideoStreaming Interface Descriptor:
432
+ bLength 54
433
+ bDescriptorType 36
434
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
435
+ bFrameIndex 10
436
+ bmCapabilities 0x00
437
+ Still image unsupported
438
+ wWidth 800
439
+ wHeight 448
440
+ dwMinBitRate 28672000
441
+ dwMaxBitRate 172032000
442
+ dwMaxVideoFrameBufferSize 716800
443
+ dwDefaultFrameInterval 333333
444
+ bFrameIntervalType 7
445
+ dwFrameInterval( 0) 333333
446
+ dwFrameInterval( 1) 416666
447
+ dwFrameInterval( 2) 500000
448
+ dwFrameInterval( 3) 666666
449
+ dwFrameInterval( 4) 1000000
450
+ dwFrameInterval( 5) 1333333
451
+ dwFrameInterval( 6) 2000000
452
+ VideoStreaming Interface Descriptor:
453
+ bLength 50
454
+ bDescriptorType 36
455
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
456
+ bFrameIndex 11
457
+ bmCapabilities 0x00
458
+ Still image unsupported
459
+ wWidth 800
460
+ wHeight 600
461
+ dwMinBitRate 38400000
462
+ dwMaxBitRate 184320000
463
+ dwMaxVideoFrameBufferSize 960000
464
+ dwDefaultFrameInterval 416666
465
+ bFrameIntervalType 6
466
+ dwFrameInterval( 0) 416666
467
+ dwFrameInterval( 1) 500000
468
+ dwFrameInterval( 2) 666666
469
+ dwFrameInterval( 3) 1000000
470
+ dwFrameInterval( 4) 1333333
471
+ dwFrameInterval( 5) 2000000
472
+ VideoStreaming Interface Descriptor:
473
+ bLength 50
474
+ bDescriptorType 36
475
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
476
+ bFrameIndex 12
477
+ bmCapabilities 0x00
478
+ Still image unsupported
479
+ wWidth 864
480
+ wHeight 480
481
+ dwMinBitRate 33177600
482
+ dwMaxBitRate 159252480
483
+ dwMaxVideoFrameBufferSize 829440
484
+ dwDefaultFrameInterval 416666
485
+ bFrameIntervalType 6
486
+ dwFrameInterval( 0) 416666
487
+ dwFrameInterval( 1) 500000
488
+ dwFrameInterval( 2) 666666
489
+ dwFrameInterval( 3) 1000000
490
+ dwFrameInterval( 4) 1333333
491
+ dwFrameInterval( 5) 2000000
492
+ VideoStreaming Interface Descriptor:
493
+ bLength 42
494
+ bDescriptorType 36
495
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
496
+ bFrameIndex 13
497
+ bmCapabilities 0x00
498
+ Still image unsupported
499
+ wWidth 960
500
+ wHeight 720
501
+ dwMinBitRate 55296000
502
+ dwMaxBitRate 165888000
503
+ dwMaxVideoFrameBufferSize 1382400
504
+ dwDefaultFrameInterval 666666
505
+ bFrameIntervalType 4
506
+ dwFrameInterval( 0) 666666
507
+ dwFrameInterval( 1) 1000000
508
+ dwFrameInterval( 2) 1333333
509
+ dwFrameInterval( 3) 2000000
510
+ VideoStreaming Interface Descriptor:
511
+ bLength 42
512
+ bDescriptorType 36
513
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
514
+ bFrameIndex 14
515
+ bmCapabilities 0x00
516
+ Still image unsupported
517
+ wWidth 1024
518
+ wHeight 576
519
+ dwMinBitRate 47185920
520
+ dwMaxBitRate 141557760
521
+ dwMaxVideoFrameBufferSize 1179648
522
+ dwDefaultFrameInterval 666666
523
+ bFrameIntervalType 4
524
+ dwFrameInterval( 0) 666666
525
+ dwFrameInterval( 1) 1000000
526
+ dwFrameInterval( 2) 1333333
527
+ dwFrameInterval( 3) 2000000
528
+ VideoStreaming Interface Descriptor:
529
+ bLength 38
530
+ bDescriptorType 36
531
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
532
+ bFrameIndex 15
533
+ bmCapabilities 0x00
534
+ Still image unsupported
535
+ wWidth 1280
536
+ wHeight 720
537
+ dwMinBitRate 73728000
538
+ dwMaxBitRate 147456000
539
+ dwMaxVideoFrameBufferSize 1843200
540
+ dwDefaultFrameInterval 1000000
541
+ bFrameIntervalType 3
542
+ dwFrameInterval( 0) 1000000
543
+ dwFrameInterval( 1) 1333333
544
+ dwFrameInterval( 2) 2000000
545
+ VideoStreaming Interface Descriptor:
546
+ bLength 34
547
+ bDescriptorType 36
548
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
549
+ bFrameIndex 16
550
+ bmCapabilities 0x00
551
+ Still image unsupported
552
+ wWidth 1600
553
+ wHeight 896
554
+ dwMinBitRate 114688000
555
+ dwMaxBitRate 172032000
556
+ dwMaxVideoFrameBufferSize 2867200
557
+ dwDefaultFrameInterval 1333333
558
+ bFrameIntervalType 2
559
+ dwFrameInterval( 0) 1333333
560
+ dwFrameInterval( 1) 2000000
561
+ VideoStreaming Interface Descriptor:
562
+ bLength 30
563
+ bDescriptorType 36
564
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
565
+ bFrameIndex 17
566
+ bmCapabilities 0x00
567
+ Still image unsupported
568
+ wWidth 1920
569
+ wHeight 1080
570
+ dwMinBitRate 165888000
571
+ dwMaxBitRate 165888000
572
+ dwMaxVideoFrameBufferSize 4147200
573
+ dwDefaultFrameInterval 2000000
574
+ bFrameIntervalType 1
575
+ dwFrameInterval( 0) 2000000
576
+ VideoStreaming Interface Descriptor:
577
+ bLength 30
578
+ bDescriptorType 36
579
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
580
+ bFrameIndex 18
581
+ bmCapabilities 0x00
582
+ Still image unsupported
583
+ wWidth 2304
584
+ wHeight 1296
585
+ dwMinBitRate 238878720
586
+ dwMaxBitRate 238878720
587
+ dwMaxVideoFrameBufferSize 5971968
588
+ dwDefaultFrameInterval 4999998
589
+ bFrameIntervalType 1
590
+ dwFrameInterval( 0) 4999998
591
+ VideoStreaming Interface Descriptor:
592
+ bLength 30
593
+ bDescriptorType 36
594
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
595
+ bFrameIndex 19
596
+ bmCapabilities 0x00
597
+ Still image unsupported
598
+ wWidth 2304
599
+ wHeight 1536
600
+ dwMinBitRate 283115520
601
+ dwMaxBitRate 283115520
602
+ dwMaxVideoFrameBufferSize 7077888
603
+ dwDefaultFrameInterval 4999998
604
+ bFrameIntervalType 1
605
+ dwFrameInterval( 0) 4999998
606
+ VideoStreaming Interface Descriptor:
607
+ bLength 6
608
+ bDescriptorType 36
609
+ bDescriptorSubtype 13 (COLORFORMAT)
610
+ bColorPrimaries 1 (BT.709,sRGB)
611
+ bTransferCharacteristics 1 (BT.709)
612
+ bMatrixCoefficients 4 (SMPTE 170M (BT.601))
613
+ VideoStreaming Interface Descriptor:
614
+ bLength 28
615
+ bDescriptorType 36
616
+ bDescriptorSubtype 16 (FORMAT_FRAME_BASED)
617
+ bFormatIndex 2
618
+ bNumFrameDescriptors 17
619
+ guidFormat {48323634-0000-1000-8000-00aa00389b71}
620
+ bBitsPerPixel 16
621
+ bDefaultFrameIndex 1
622
+ bAspectRatioX 0
623
+ bAspectRatioY 0
624
+ bmInterlaceFlags 0x00
625
+ Interlaced stream or variable: No
626
+ Fields per frame: 2 fields
627
+ Field 1 first: No
628
+ Field pattern: Field 1 only
629
+ bCopyProtect 0
630
+ bVariableSize 1
631
+ VideoStreaming Interface Descriptor:
632
+ bLength 54
633
+ bDescriptorType 36
634
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
635
+ bFrameIndex 1
636
+ bmCapabilities 0x00
637
+ Still image unsupported
638
+ wWidth 640
639
+ wHeight 480
640
+ dwMinBitRate 24576000
641
+ dwMaxBitRate 147456000
642
+ dwDefaultFrameInterval 333333
643
+ bFrameIntervalType 7
644
+ dwBytesPerLine 0
645
+ dwFrameInterval( 0) 333333
646
+ dwFrameInterval( 1) 416666
647
+ dwFrameInterval( 2) 500000
648
+ dwFrameInterval( 3) 666666
649
+ dwFrameInterval( 4) 1000000
650
+ dwFrameInterval( 5) 1333333
651
+ dwFrameInterval( 6) 2000000
652
+ VideoStreaming Interface Descriptor:
653
+ bLength 54
654
+ bDescriptorType 36
655
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
656
+ bFrameIndex 2
657
+ bmCapabilities 0x00
658
+ Still image unsupported
659
+ wWidth 160
660
+ wHeight 90
661
+ dwMinBitRate 1152000
662
+ dwMaxBitRate 6912000
663
+ dwDefaultFrameInterval 333333
664
+ bFrameIntervalType 7
665
+ dwBytesPerLine 0
666
+ dwFrameInterval( 0) 333333
667
+ dwFrameInterval( 1) 416666
668
+ dwFrameInterval( 2) 500000
669
+ dwFrameInterval( 3) 666666
670
+ dwFrameInterval( 4) 1000000
671
+ dwFrameInterval( 5) 1333333
672
+ dwFrameInterval( 6) 2000000
673
+ VideoStreaming Interface Descriptor:
674
+ bLength 54
675
+ bDescriptorType 36
676
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
677
+ bFrameIndex 3
678
+ bmCapabilities 0x00
679
+ Still image unsupported
680
+ wWidth 160
681
+ wHeight 120
682
+ dwMinBitRate 1536000
683
+ dwMaxBitRate 9216000
684
+ dwDefaultFrameInterval 333333
685
+ bFrameIntervalType 7
686
+ dwBytesPerLine 0
687
+ dwFrameInterval( 0) 333333
688
+ dwFrameInterval( 1) 416666
689
+ dwFrameInterval( 2) 500000
690
+ dwFrameInterval( 3) 666666
691
+ dwFrameInterval( 4) 1000000
692
+ dwFrameInterval( 5) 1333333
693
+ dwFrameInterval( 6) 2000000
694
+ VideoStreaming Interface Descriptor:
695
+ bLength 54
696
+ bDescriptorType 36
697
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
698
+ bFrameIndex 4
699
+ bmCapabilities 0x00
700
+ Still image unsupported
701
+ wWidth 176
702
+ wHeight 144
703
+ dwMinBitRate 2027520
704
+ dwMaxBitRate 12165120
705
+ dwDefaultFrameInterval 333333
706
+ bFrameIntervalType 7
707
+ dwBytesPerLine 0
708
+ dwFrameInterval( 0) 333333
709
+ dwFrameInterval( 1) 416666
710
+ dwFrameInterval( 2) 500000
711
+ dwFrameInterval( 3) 666666
712
+ dwFrameInterval( 4) 1000000
713
+ dwFrameInterval( 5) 1333333
714
+ dwFrameInterval( 6) 2000000
715
+ VideoStreaming Interface Descriptor:
716
+ bLength 54
717
+ bDescriptorType 36
718
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
719
+ bFrameIndex 5
720
+ bmCapabilities 0x00
721
+ Still image unsupported
722
+ wWidth 320
723
+ wHeight 180
724
+ dwMinBitRate 4608000
725
+ dwMaxBitRate 27648000
726
+ dwDefaultFrameInterval 333333
727
+ bFrameIntervalType 7
728
+ dwBytesPerLine 0
729
+ dwFrameInterval( 0) 333333
730
+ dwFrameInterval( 1) 416666
731
+ dwFrameInterval( 2) 500000
732
+ dwFrameInterval( 3) 666666
733
+ dwFrameInterval( 4) 1000000
734
+ dwFrameInterval( 5) 1333333
735
+ dwFrameInterval( 6) 2000000
736
+ VideoStreaming Interface Descriptor:
737
+ bLength 54
738
+ bDescriptorType 36
739
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
740
+ bFrameIndex 6
741
+ bmCapabilities 0x00
742
+ Still image unsupported
743
+ wWidth 320
744
+ wHeight 240
745
+ dwMinBitRate 6144000
746
+ dwMaxBitRate 36864000
747
+ dwDefaultFrameInterval 333333
748
+ bFrameIntervalType 7
749
+ dwBytesPerLine 0
750
+ dwFrameInterval( 0) 333333
751
+ dwFrameInterval( 1) 416666
752
+ dwFrameInterval( 2) 500000
753
+ dwFrameInterval( 3) 666666
754
+ dwFrameInterval( 4) 1000000
755
+ dwFrameInterval( 5) 1333333
756
+ dwFrameInterval( 6) 2000000
757
+ VideoStreaming Interface Descriptor:
758
+ bLength 54
759
+ bDescriptorType 36
760
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
761
+ bFrameIndex 7
762
+ bmCapabilities 0x00
763
+ Still image unsupported
764
+ wWidth 352
765
+ wHeight 288
766
+ dwMinBitRate 8110080
767
+ dwMaxBitRate 48660480
768
+ dwDefaultFrameInterval 333333
769
+ bFrameIntervalType 7
770
+ dwBytesPerLine 0
771
+ dwFrameInterval( 0) 333333
772
+ dwFrameInterval( 1) 416666
773
+ dwFrameInterval( 2) 500000
774
+ dwFrameInterval( 3) 666666
775
+ dwFrameInterval( 4) 1000000
776
+ dwFrameInterval( 5) 1333333
777
+ dwFrameInterval( 6) 2000000
778
+ VideoStreaming Interface Descriptor:
779
+ bLength 54
780
+ bDescriptorType 36
781
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
782
+ bFrameIndex 8
783
+ bmCapabilities 0x00
784
+ Still image unsupported
785
+ wWidth 432
786
+ wHeight 240
787
+ dwMinBitRate 8294400
788
+ dwMaxBitRate 49766400
789
+ dwDefaultFrameInterval 333333
790
+ bFrameIntervalType 7
791
+ dwBytesPerLine 0
792
+ dwFrameInterval( 0) 333333
793
+ dwFrameInterval( 1) 416666
794
+ dwFrameInterval( 2) 500000
795
+ dwFrameInterval( 3) 666666
796
+ dwFrameInterval( 4) 1000000
797
+ dwFrameInterval( 5) 1333333
798
+ dwFrameInterval( 6) 2000000
799
+ VideoStreaming Interface Descriptor:
800
+ bLength 54
801
+ bDescriptorType 36
802
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
803
+ bFrameIndex 9
804
+ bmCapabilities 0x00
805
+ Still image unsupported
806
+ wWidth 640
807
+ wHeight 360
808
+ dwMinBitRate 18432000
809
+ dwMaxBitRate 110592000
810
+ dwDefaultFrameInterval 333333
811
+ bFrameIntervalType 7
812
+ dwBytesPerLine 0
813
+ dwFrameInterval( 0) 333333
814
+ dwFrameInterval( 1) 416666
815
+ dwFrameInterval( 2) 500000
816
+ dwFrameInterval( 3) 666666
817
+ dwFrameInterval( 4) 1000000
818
+ dwFrameInterval( 5) 1333333
819
+ dwFrameInterval( 6) 2000000
820
+ VideoStreaming Interface Descriptor:
821
+ bLength 54
822
+ bDescriptorType 36
823
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
824
+ bFrameIndex 10
825
+ bmCapabilities 0x00
826
+ Still image unsupported
827
+ wWidth 800
828
+ wHeight 448
829
+ dwMinBitRate 28672000
830
+ dwMaxBitRate 172032000
831
+ dwDefaultFrameInterval 333333
832
+ bFrameIntervalType 7
833
+ dwBytesPerLine 0
834
+ dwFrameInterval( 0) 333333
835
+ dwFrameInterval( 1) 416666
836
+ dwFrameInterval( 2) 500000
837
+ dwFrameInterval( 3) 666666
838
+ dwFrameInterval( 4) 1000000
839
+ dwFrameInterval( 5) 1333333
840
+ dwFrameInterval( 6) 2000000
841
+ VideoStreaming Interface Descriptor:
842
+ bLength 54
843
+ bDescriptorType 36
844
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
845
+ bFrameIndex 11
846
+ bmCapabilities 0x00
847
+ Still image unsupported
848
+ wWidth 800
849
+ wHeight 600
850
+ dwMinBitRate 38400000
851
+ dwMaxBitRate 230400000
852
+ dwDefaultFrameInterval 333333
853
+ bFrameIntervalType 7
854
+ dwBytesPerLine 0
855
+ dwFrameInterval( 0) 333333
856
+ dwFrameInterval( 1) 416666
857
+ dwFrameInterval( 2) 500000
858
+ dwFrameInterval( 3) 666666
859
+ dwFrameInterval( 4) 1000000
860
+ dwFrameInterval( 5) 1333333
861
+ dwFrameInterval( 6) 2000000
862
+ VideoStreaming Interface Descriptor:
863
+ bLength 54
864
+ bDescriptorType 36
865
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
866
+ bFrameIndex 12
867
+ bmCapabilities 0x00
868
+ Still image unsupported
869
+ wWidth 864
870
+ wHeight 480
871
+ dwMinBitRate 33177600
872
+ dwMaxBitRate 199065600
873
+ dwDefaultFrameInterval 333333
874
+ bFrameIntervalType 7
875
+ dwBytesPerLine 0
876
+ dwFrameInterval( 0) 333333
877
+ dwFrameInterval( 1) 416666
878
+ dwFrameInterval( 2) 500000
879
+ dwFrameInterval( 3) 666666
880
+ dwFrameInterval( 4) 1000000
881
+ dwFrameInterval( 5) 1333333
882
+ dwFrameInterval( 6) 2000000
883
+ VideoStreaming Interface Descriptor:
884
+ bLength 54
885
+ bDescriptorType 36
886
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
887
+ bFrameIndex 13
888
+ bmCapabilities 0x00
889
+ Still image unsupported
890
+ wWidth 960
891
+ wHeight 720
892
+ dwMinBitRate 55296000
893
+ dwMaxBitRate 331776000
894
+ dwDefaultFrameInterval 333333
895
+ bFrameIntervalType 7
896
+ dwBytesPerLine 0
897
+ dwFrameInterval( 0) 333333
898
+ dwFrameInterval( 1) 416666
899
+ dwFrameInterval( 2) 500000
900
+ dwFrameInterval( 3) 666666
901
+ dwFrameInterval( 4) 1000000
902
+ dwFrameInterval( 5) 1333333
903
+ dwFrameInterval( 6) 2000000
904
+ VideoStreaming Interface Descriptor:
905
+ bLength 54
906
+ bDescriptorType 36
907
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
908
+ bFrameIndex 14
909
+ bmCapabilities 0x00
910
+ Still image unsupported
911
+ wWidth 1024
912
+ wHeight 576
913
+ dwMinBitRate 47185920
914
+ dwMaxBitRate 283115520
915
+ dwDefaultFrameInterval 333333
916
+ bFrameIntervalType 7
917
+ dwBytesPerLine 0
918
+ dwFrameInterval( 0) 333333
919
+ dwFrameInterval( 1) 416666
920
+ dwFrameInterval( 2) 500000
921
+ dwFrameInterval( 3) 666666
922
+ dwFrameInterval( 4) 1000000
923
+ dwFrameInterval( 5) 1333333
924
+ dwFrameInterval( 6) 2000000
925
+ VideoStreaming Interface Descriptor:
926
+ bLength 54
927
+ bDescriptorType 36
928
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
929
+ bFrameIndex 15
930
+ bmCapabilities 0x00
931
+ Still image unsupported
932
+ wWidth 1280
933
+ wHeight 720
934
+ dwMinBitRate 73728000
935
+ dwMaxBitRate 442368000
936
+ dwDefaultFrameInterval 333333
937
+ bFrameIntervalType 7
938
+ dwBytesPerLine 0
939
+ dwFrameInterval( 0) 333333
940
+ dwFrameInterval( 1) 416666
941
+ dwFrameInterval( 2) 500000
942
+ dwFrameInterval( 3) 666666
943
+ dwFrameInterval( 4) 1000000
944
+ dwFrameInterval( 5) 1333333
945
+ dwFrameInterval( 6) 2000000
946
+ VideoStreaming Interface Descriptor:
947
+ bLength 54
948
+ bDescriptorType 36
949
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
950
+ bFrameIndex 16
951
+ bmCapabilities 0x00
952
+ Still image unsupported
953
+ wWidth 1600
954
+ wHeight 896
955
+ dwMinBitRate 114688000
956
+ dwMaxBitRate 688128000
957
+ dwDefaultFrameInterval 333333
958
+ bFrameIntervalType 7
959
+ dwBytesPerLine 0
960
+ dwFrameInterval( 0) 333333
961
+ dwFrameInterval( 1) 416666
962
+ dwFrameInterval( 2) 500000
963
+ dwFrameInterval( 3) 666666
964
+ dwFrameInterval( 4) 1000000
965
+ dwFrameInterval( 5) 1333333
966
+ dwFrameInterval( 6) 2000000
967
+ VideoStreaming Interface Descriptor:
968
+ bLength 54
969
+ bDescriptorType 36
970
+ bDescriptorSubtype 17 (FRAME_FRAME_BASED)
971
+ bFrameIndex 17
972
+ bmCapabilities 0x00
973
+ Still image unsupported
974
+ wWidth 1920
975
+ wHeight 1080
976
+ dwMinBitRate 165888000
977
+ dwMaxBitRate 995328000
978
+ dwDefaultFrameInterval 333333
979
+ bFrameIntervalType 7
980
+ dwBytesPerLine 0
981
+ dwFrameInterval( 0) 333333
982
+ dwFrameInterval( 1) 416666
983
+ dwFrameInterval( 2) 500000
984
+ dwFrameInterval( 3) 666666
985
+ dwFrameInterval( 4) 1000000
986
+ dwFrameInterval( 5) 1333333
987
+ dwFrameInterval( 6) 2000000
988
+ VideoStreaming Interface Descriptor:
989
+ bLength 6
990
+ bDescriptorType 36
991
+ bDescriptorSubtype 13 (COLORFORMAT)
992
+ bColorPrimaries 1 (BT.709,sRGB)
993
+ bTransferCharacteristics 1 (BT.709)
994
+ bMatrixCoefficients 4 (SMPTE 170M (BT.601))
995
+ VideoStreaming Interface Descriptor:
996
+ bLength 11
997
+ bDescriptorType 36
998
+ bDescriptorSubtype 6 (FORMAT_MJPEG)
999
+ bFormatIndex 3
1000
+ bNumFrameDescriptors 17
1001
+ bFlags 1
1002
+ Fixed-size samples: Yes
1003
+ bDefaultFrameIndex 1
1004
+ bAspectRatioX 0
1005
+ bAspectRatioY 0
1006
+ bmInterlaceFlags 0x00
1007
+ Interlaced stream or variable: No
1008
+ Fields per frame: 1 fields
1009
+ Field 1 first: No
1010
+ Field pattern: Field 1 only
1011
+ bCopyProtect 0
1012
+ VideoStreaming Interface Descriptor:
1013
+ bLength 54
1014
+ bDescriptorType 36
1015
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1016
+ bFrameIndex 1
1017
+ bmCapabilities 0x00
1018
+ Still image unsupported
1019
+ wWidth 640
1020
+ wHeight 480
1021
+ dwMinBitRate 24576000
1022
+ dwMaxBitRate 147456000
1023
+ dwMaxVideoFrameBufferSize 614400
1024
+ dwDefaultFrameInterval 333333
1025
+ bFrameIntervalType 7
1026
+ dwFrameInterval( 0) 333333
1027
+ dwFrameInterval( 1) 416666
1028
+ dwFrameInterval( 2) 500000
1029
+ dwFrameInterval( 3) 666666
1030
+ dwFrameInterval( 4) 1000000
1031
+ dwFrameInterval( 5) 1333333
1032
+ dwFrameInterval( 6) 2000000
1033
+ VideoStreaming Interface Descriptor:
1034
+ bLength 54
1035
+ bDescriptorType 36
1036
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1037
+ bFrameIndex 2
1038
+ bmCapabilities 0x00
1039
+ Still image unsupported
1040
+ wWidth 160
1041
+ wHeight 90
1042
+ dwMinBitRate 1152000
1043
+ dwMaxBitRate 6912000
1044
+ dwMaxVideoFrameBufferSize 28800
1045
+ dwDefaultFrameInterval 333333
1046
+ bFrameIntervalType 7
1047
+ dwFrameInterval( 0) 333333
1048
+ dwFrameInterval( 1) 416666
1049
+ dwFrameInterval( 2) 500000
1050
+ dwFrameInterval( 3) 666666
1051
+ dwFrameInterval( 4) 1000000
1052
+ dwFrameInterval( 5) 1333333
1053
+ dwFrameInterval( 6) 2000000
1054
+ VideoStreaming Interface Descriptor:
1055
+ bLength 54
1056
+ bDescriptorType 36
1057
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1058
+ bFrameIndex 3
1059
+ bmCapabilities 0x00
1060
+ Still image unsupported
1061
+ wWidth 160
1062
+ wHeight 120
1063
+ dwMinBitRate 1536000
1064
+ dwMaxBitRate 9216000
1065
+ dwMaxVideoFrameBufferSize 38400
1066
+ dwDefaultFrameInterval 333333
1067
+ bFrameIntervalType 7
1068
+ dwFrameInterval( 0) 333333
1069
+ dwFrameInterval( 1) 416666
1070
+ dwFrameInterval( 2) 500000
1071
+ dwFrameInterval( 3) 666666
1072
+ dwFrameInterval( 4) 1000000
1073
+ dwFrameInterval( 5) 1333333
1074
+ dwFrameInterval( 6) 2000000
1075
+ VideoStreaming Interface Descriptor:
1076
+ bLength 54
1077
+ bDescriptorType 36
1078
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1079
+ bFrameIndex 4
1080
+ bmCapabilities 0x00
1081
+ Still image unsupported
1082
+ wWidth 176
1083
+ wHeight 144
1084
+ dwMinBitRate 2027520
1085
+ dwMaxBitRate 12165120
1086
+ dwMaxVideoFrameBufferSize 50688
1087
+ dwDefaultFrameInterval 333333
1088
+ bFrameIntervalType 7
1089
+ dwFrameInterval( 0) 333333
1090
+ dwFrameInterval( 1) 416666
1091
+ dwFrameInterval( 2) 500000
1092
+ dwFrameInterval( 3) 666666
1093
+ dwFrameInterval( 4) 1000000
1094
+ dwFrameInterval( 5) 1333333
1095
+ dwFrameInterval( 6) 2000000
1096
+ VideoStreaming Interface Descriptor:
1097
+ bLength 54
1098
+ bDescriptorType 36
1099
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1100
+ bFrameIndex 5
1101
+ bmCapabilities 0x00
1102
+ Still image unsupported
1103
+ wWidth 320
1104
+ wHeight 180
1105
+ dwMinBitRate 4608000
1106
+ dwMaxBitRate 27648000
1107
+ dwMaxVideoFrameBufferSize 115200
1108
+ dwDefaultFrameInterval 333333
1109
+ bFrameIntervalType 7
1110
+ dwFrameInterval( 0) 333333
1111
+ dwFrameInterval( 1) 416666
1112
+ dwFrameInterval( 2) 500000
1113
+ dwFrameInterval( 3) 666666
1114
+ dwFrameInterval( 4) 1000000
1115
+ dwFrameInterval( 5) 1333333
1116
+ dwFrameInterval( 6) 2000000
1117
+ VideoStreaming Interface Descriptor:
1118
+ bLength 54
1119
+ bDescriptorType 36
1120
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1121
+ bFrameIndex 6
1122
+ bmCapabilities 0x00
1123
+ Still image unsupported
1124
+ wWidth 320
1125
+ wHeight 240
1126
+ dwMinBitRate 6144000
1127
+ dwMaxBitRate 36864000
1128
+ dwMaxVideoFrameBufferSize 153600
1129
+ dwDefaultFrameInterval 333333
1130
+ bFrameIntervalType 7
1131
+ dwFrameInterval( 0) 333333
1132
+ dwFrameInterval( 1) 416666
1133
+ dwFrameInterval( 2) 500000
1134
+ dwFrameInterval( 3) 666666
1135
+ dwFrameInterval( 4) 1000000
1136
+ dwFrameInterval( 5) 1333333
1137
+ dwFrameInterval( 6) 2000000
1138
+ VideoStreaming Interface Descriptor:
1139
+ bLength 54
1140
+ bDescriptorType 36
1141
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1142
+ bFrameIndex 7
1143
+ bmCapabilities 0x00
1144
+ Still image unsupported
1145
+ wWidth 352
1146
+ wHeight 288
1147
+ dwMinBitRate 8110080
1148
+ dwMaxBitRate 48660480
1149
+ dwMaxVideoFrameBufferSize 202752
1150
+ dwDefaultFrameInterval 333333
1151
+ bFrameIntervalType 7
1152
+ dwFrameInterval( 0) 333333
1153
+ dwFrameInterval( 1) 416666
1154
+ dwFrameInterval( 2) 500000
1155
+ dwFrameInterval( 3) 666666
1156
+ dwFrameInterval( 4) 1000000
1157
+ dwFrameInterval( 5) 1333333
1158
+ dwFrameInterval( 6) 2000000
1159
+ VideoStreaming Interface Descriptor:
1160
+ bLength 54
1161
+ bDescriptorType 36
1162
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1163
+ bFrameIndex 8
1164
+ bmCapabilities 0x00
1165
+ Still image unsupported
1166
+ wWidth 432
1167
+ wHeight 240
1168
+ dwMinBitRate 8294400
1169
+ dwMaxBitRate 49766400
1170
+ dwMaxVideoFrameBufferSize 207360
1171
+ dwDefaultFrameInterval 333333
1172
+ bFrameIntervalType 7
1173
+ dwFrameInterval( 0) 333333
1174
+ dwFrameInterval( 1) 416666
1175
+ dwFrameInterval( 2) 500000
1176
+ dwFrameInterval( 3) 666666
1177
+ dwFrameInterval( 4) 1000000
1178
+ dwFrameInterval( 5) 1333333
1179
+ dwFrameInterval( 6) 2000000
1180
+ VideoStreaming Interface Descriptor:
1181
+ bLength 54
1182
+ bDescriptorType 36
1183
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1184
+ bFrameIndex 9
1185
+ bmCapabilities 0x00
1186
+ Still image unsupported
1187
+ wWidth 640
1188
+ wHeight 360
1189
+ dwMinBitRate 18432000
1190
+ dwMaxBitRate 110592000
1191
+ dwMaxVideoFrameBufferSize 460800
1192
+ dwDefaultFrameInterval 333333
1193
+ bFrameIntervalType 7
1194
+ dwFrameInterval( 0) 333333
1195
+ dwFrameInterval( 1) 416666
1196
+ dwFrameInterval( 2) 500000
1197
+ dwFrameInterval( 3) 666666
1198
+ dwFrameInterval( 4) 1000000
1199
+ dwFrameInterval( 5) 1333333
1200
+ dwFrameInterval( 6) 2000000
1201
+ VideoStreaming Interface Descriptor:
1202
+ bLength 54
1203
+ bDescriptorType 36
1204
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1205
+ bFrameIndex 10
1206
+ bmCapabilities 0x00
1207
+ Still image unsupported
1208
+ wWidth 800
1209
+ wHeight 448
1210
+ dwMinBitRate 28672000
1211
+ dwMaxBitRate 172032000
1212
+ dwMaxVideoFrameBufferSize 716800
1213
+ dwDefaultFrameInterval 333333
1214
+ bFrameIntervalType 7
1215
+ dwFrameInterval( 0) 333333
1216
+ dwFrameInterval( 1) 416666
1217
+ dwFrameInterval( 2) 500000
1218
+ dwFrameInterval( 3) 666666
1219
+ dwFrameInterval( 4) 1000000
1220
+ dwFrameInterval( 5) 1333333
1221
+ dwFrameInterval( 6) 2000000
1222
+ VideoStreaming Interface Descriptor:
1223
+ bLength 54
1224
+ bDescriptorType 36
1225
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1226
+ bFrameIndex 11
1227
+ bmCapabilities 0x00
1228
+ Still image unsupported
1229
+ wWidth 800
1230
+ wHeight 600
1231
+ dwMinBitRate 38400000
1232
+ dwMaxBitRate 230400000
1233
+ dwMaxVideoFrameBufferSize 960000
1234
+ dwDefaultFrameInterval 333333
1235
+ bFrameIntervalType 7
1236
+ dwFrameInterval( 0) 333333
1237
+ dwFrameInterval( 1) 416666
1238
+ dwFrameInterval( 2) 500000
1239
+ dwFrameInterval( 3) 666666
1240
+ dwFrameInterval( 4) 1000000
1241
+ dwFrameInterval( 5) 1333333
1242
+ dwFrameInterval( 6) 2000000
1243
+ VideoStreaming Interface Descriptor:
1244
+ bLength 54
1245
+ bDescriptorType 36
1246
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1247
+ bFrameIndex 12
1248
+ bmCapabilities 0x00
1249
+ Still image unsupported
1250
+ wWidth 864
1251
+ wHeight 480
1252
+ dwMinBitRate 33177600
1253
+ dwMaxBitRate 199065600
1254
+ dwMaxVideoFrameBufferSize 829440
1255
+ dwDefaultFrameInterval 333333
1256
+ bFrameIntervalType 7
1257
+ dwFrameInterval( 0) 333333
1258
+ dwFrameInterval( 1) 416666
1259
+ dwFrameInterval( 2) 500000
1260
+ dwFrameInterval( 3) 666666
1261
+ dwFrameInterval( 4) 1000000
1262
+ dwFrameInterval( 5) 1333333
1263
+ dwFrameInterval( 6) 2000000
1264
+ VideoStreaming Interface Descriptor:
1265
+ bLength 54
1266
+ bDescriptorType 36
1267
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1268
+ bFrameIndex 13
1269
+ bmCapabilities 0x00
1270
+ Still image unsupported
1271
+ wWidth 960
1272
+ wHeight 720
1273
+ dwMinBitRate 55296000
1274
+ dwMaxBitRate 331776000
1275
+ dwMaxVideoFrameBufferSize 1382400
1276
+ dwDefaultFrameInterval 333333
1277
+ bFrameIntervalType 7
1278
+ dwFrameInterval( 0) 333333
1279
+ dwFrameInterval( 1) 416666
1280
+ dwFrameInterval( 2) 500000
1281
+ dwFrameInterval( 3) 666666
1282
+ dwFrameInterval( 4) 1000000
1283
+ dwFrameInterval( 5) 1333333
1284
+ dwFrameInterval( 6) 2000000
1285
+ VideoStreaming Interface Descriptor:
1286
+ bLength 54
1287
+ bDescriptorType 36
1288
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1289
+ bFrameIndex 14
1290
+ bmCapabilities 0x00
1291
+ Still image unsupported
1292
+ wWidth 1024
1293
+ wHeight 576
1294
+ dwMinBitRate 47185920
1295
+ dwMaxBitRate 283115520
1296
+ dwMaxVideoFrameBufferSize 1179648
1297
+ dwDefaultFrameInterval 333333
1298
+ bFrameIntervalType 7
1299
+ dwFrameInterval( 0) 333333
1300
+ dwFrameInterval( 1) 416666
1301
+ dwFrameInterval( 2) 500000
1302
+ dwFrameInterval( 3) 666666
1303
+ dwFrameInterval( 4) 1000000
1304
+ dwFrameInterval( 5) 1333333
1305
+ dwFrameInterval( 6) 2000000
1306
+ VideoStreaming Interface Descriptor:
1307
+ bLength 54
1308
+ bDescriptorType 36
1309
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1310
+ bFrameIndex 15
1311
+ bmCapabilities 0x00
1312
+ Still image unsupported
1313
+ wWidth 1280
1314
+ wHeight 720
1315
+ dwMinBitRate 73728000
1316
+ dwMaxBitRate 442368000
1317
+ dwMaxVideoFrameBufferSize 1843200
1318
+ dwDefaultFrameInterval 333333
1319
+ bFrameIntervalType 7
1320
+ dwFrameInterval( 0) 333333
1321
+ dwFrameInterval( 1) 416666
1322
+ dwFrameInterval( 2) 500000
1323
+ dwFrameInterval( 3) 666666
1324
+ dwFrameInterval( 4) 1000000
1325
+ dwFrameInterval( 5) 1333333
1326
+ dwFrameInterval( 6) 2000000
1327
+ VideoStreaming Interface Descriptor:
1328
+ bLength 54
1329
+ bDescriptorType 36
1330
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1331
+ bFrameIndex 16
1332
+ bmCapabilities 0x00
1333
+ Still image unsupported
1334
+ wWidth 1600
1335
+ wHeight 896
1336
+ dwMinBitRate 114688000
1337
+ dwMaxBitRate 688128000
1338
+ dwMaxVideoFrameBufferSize 2867200
1339
+ dwDefaultFrameInterval 333333
1340
+ bFrameIntervalType 7
1341
+ dwFrameInterval( 0) 333333
1342
+ dwFrameInterval( 1) 416666
1343
+ dwFrameInterval( 2) 500000
1344
+ dwFrameInterval( 3) 666666
1345
+ dwFrameInterval( 4) 1000000
1346
+ dwFrameInterval( 5) 1333333
1347
+ dwFrameInterval( 6) 2000000
1348
+ VideoStreaming Interface Descriptor:
1349
+ bLength 54
1350
+ bDescriptorType 36
1351
+ bDescriptorSubtype 7 (FRAME_MJPEG)
1352
+ bFrameIndex 17
1353
+ bmCapabilities 0x00
1354
+ Still image unsupported
1355
+ wWidth 1920
1356
+ wHeight 1080
1357
+ dwMinBitRate 165888000
1358
+ dwMaxBitRate 995328000
1359
+ dwMaxVideoFrameBufferSize 4147200
1360
+ dwDefaultFrameInterval 333333
1361
+ bFrameIntervalType 7
1362
+ dwFrameInterval( 0) 333333
1363
+ dwFrameInterval( 1) 416666
1364
+ dwFrameInterval( 2) 500000
1365
+ dwFrameInterval( 3) 666666
1366
+ dwFrameInterval( 4) 1000000
1367
+ dwFrameInterval( 5) 1333333
1368
+ dwFrameInterval( 6) 2000000
1369
+ VideoStreaming Interface Descriptor:
1370
+ bLength 6
1371
+ bDescriptorType 36
1372
+ bDescriptorSubtype 13 (COLORFORMAT)
1373
+ bColorPrimaries 1 (BT.709,sRGB)
1374
+ bTransferCharacteristics 1 (BT.709)
1375
+ bMatrixCoefficients 4 (SMPTE 170M (BT.601))
1376
+ Interface Descriptor:
1377
+ bLength 9
1378
+ bDescriptorType 4
1379
+ bInterfaceNumber 1
1380
+ bAlternateSetting 1
1381
+ bNumEndpoints 1
1382
+ bInterfaceClass 14 Video
1383
+ bInterfaceSubClass 2 Video Streaming
1384
+ bInterfaceProtocol 0
1385
+ iInterface 0
1386
+ Endpoint Descriptor:
1387
+ bLength 7
1388
+ bDescriptorType 5
1389
+ bEndpointAddress 0x81 EP 1 IN
1390
+ bmAttributes 5
1391
+ Transfer Type Isochronous
1392
+ Synch Type Asynchronous
1393
+ Usage Type Data
1394
+ wMaxPacketSize 0x00c0 1x 192 bytes
1395
+ bInterval 1
1396
+ Interface Descriptor:
1397
+ bLength 9
1398
+ bDescriptorType 4
1399
+ bInterfaceNumber 1
1400
+ bAlternateSetting 2
1401
+ bNumEndpoints 1
1402
+ bInterfaceClass 14 Video
1403
+ bInterfaceSubClass 2 Video Streaming
1404
+ bInterfaceProtocol 0
1405
+ iInterface 0
1406
+ Endpoint Descriptor:
1407
+ bLength 7
1408
+ bDescriptorType 5
1409
+ bEndpointAddress 0x81 EP 1 IN
1410
+ bmAttributes 5
1411
+ Transfer Type Isochronous
1412
+ Synch Type Asynchronous
1413
+ Usage Type Data
1414
+ wMaxPacketSize 0x0180 1x 384 bytes
1415
+ bInterval 1
1416
+ Interface Descriptor:
1417
+ bLength 9
1418
+ bDescriptorType 4
1419
+ bInterfaceNumber 1
1420
+ bAlternateSetting 3
1421
+ bNumEndpoints 1
1422
+ bInterfaceClass 14 Video
1423
+ bInterfaceSubClass 2 Video Streaming
1424
+ bInterfaceProtocol 0
1425
+ iInterface 0
1426
+ Endpoint Descriptor:
1427
+ bLength 7
1428
+ bDescriptorType 5
1429
+ bEndpointAddress 0x81 EP 1 IN
1430
+ bmAttributes 5
1431
+ Transfer Type Isochronous
1432
+ Synch Type Asynchronous
1433
+ Usage Type Data
1434
+ wMaxPacketSize 0x0200 1x 512 bytes
1435
+ bInterval 1
1436
+ Interface Descriptor:
1437
+ bLength 9
1438
+ bDescriptorType 4
1439
+ bInterfaceNumber 1
1440
+ bAlternateSetting 4
1441
+ bNumEndpoints 1
1442
+ bInterfaceClass 14 Video
1443
+ bInterfaceSubClass 2 Video Streaming
1444
+ bInterfaceProtocol 0
1445
+ iInterface 0
1446
+ Endpoint Descriptor:
1447
+ bLength 7
1448
+ bDescriptorType 5
1449
+ bEndpointAddress 0x81 EP 1 IN
1450
+ bmAttributes 5
1451
+ Transfer Type Isochronous
1452
+ Synch Type Asynchronous
1453
+ Usage Type Data
1454
+ wMaxPacketSize 0x0280 1x 640 bytes
1455
+ bInterval 1
1456
+ Interface Descriptor:
1457
+ bLength 9
1458
+ bDescriptorType 4
1459
+ bInterfaceNumber 1
1460
+ bAlternateSetting 5
1461
+ bNumEndpoints 1
1462
+ bInterfaceClass 14 Video
1463
+ bInterfaceSubClass 2 Video Streaming
1464
+ bInterfaceProtocol 0
1465
+ iInterface 0
1466
+ Endpoint Descriptor:
1467
+ bLength 7
1468
+ bDescriptorType 5
1469
+ bEndpointAddress 0x81 EP 1 IN
1470
+ bmAttributes 5
1471
+ Transfer Type Isochronous
1472
+ Synch Type Asynchronous
1473
+ Usage Type Data
1474
+ wMaxPacketSize 0x0320 1x 800 bytes
1475
+ bInterval 1
1476
+ Interface Descriptor:
1477
+ bLength 9
1478
+ bDescriptorType 4
1479
+ bInterfaceNumber 1
1480
+ bAlternateSetting 6
1481
+ bNumEndpoints 1
1482
+ bInterfaceClass 14 Video
1483
+ bInterfaceSubClass 2 Video Streaming
1484
+ bInterfaceProtocol 0
1485
+ iInterface 0
1486
+ Endpoint Descriptor:
1487
+ bLength 7
1488
+ bDescriptorType 5
1489
+ bEndpointAddress 0x81 EP 1 IN
1490
+ bmAttributes 5
1491
+ Transfer Type Isochronous
1492
+ Synch Type Asynchronous
1493
+ Usage Type Data
1494
+ wMaxPacketSize 0x03b0 1x 944 bytes
1495
+ bInterval 1
1496
+ Interface Descriptor:
1497
+ bLength 9
1498
+ bDescriptorType 4
1499
+ bInterfaceNumber 1
1500
+ bAlternateSetting 7
1501
+ bNumEndpoints 1
1502
+ bInterfaceClass 14 Video
1503
+ bInterfaceSubClass 2 Video Streaming
1504
+ bInterfaceProtocol 0
1505
+ iInterface 0
1506
+ Endpoint Descriptor:
1507
+ bLength 7
1508
+ bDescriptorType 5
1509
+ bEndpointAddress 0x81 EP 1 IN
1510
+ bmAttributes 5
1511
+ Transfer Type Isochronous
1512
+ Synch Type Asynchronous
1513
+ Usage Type Data
1514
+ wMaxPacketSize 0x0a80 2x 640 bytes
1515
+ bInterval 1
1516
+ Interface Descriptor:
1517
+ bLength 9
1518
+ bDescriptorType 4
1519
+ bInterfaceNumber 1
1520
+ bAlternateSetting 8
1521
+ bNumEndpoints 1
1522
+ bInterfaceClass 14 Video
1523
+ bInterfaceSubClass 2 Video Streaming
1524
+ bInterfaceProtocol 0
1525
+ iInterface 0
1526
+ Endpoint Descriptor:
1527
+ bLength 7
1528
+ bDescriptorType 5
1529
+ bEndpointAddress 0x81 EP 1 IN
1530
+ bmAttributes 5
1531
+ Transfer Type Isochronous
1532
+ Synch Type Asynchronous
1533
+ Usage Type Data
1534
+ wMaxPacketSize 0x0b20 2x 800 bytes
1535
+ bInterval 1
1536
+ Interface Descriptor:
1537
+ bLength 9
1538
+ bDescriptorType 4
1539
+ bInterfaceNumber 1
1540
+ bAlternateSetting 9
1541
+ bNumEndpoints 1
1542
+ bInterfaceClass 14 Video
1543
+ bInterfaceSubClass 2 Video Streaming
1544
+ bInterfaceProtocol 0
1545
+ iInterface 0
1546
+ Endpoint Descriptor:
1547
+ bLength 7
1548
+ bDescriptorType 5
1549
+ bEndpointAddress 0x81 EP 1 IN
1550
+ bmAttributes 5
1551
+ Transfer Type Isochronous
1552
+ Synch Type Asynchronous
1553
+ Usage Type Data
1554
+ wMaxPacketSize 0x0be0 2x 992 bytes
1555
+ bInterval 1
1556
+ Interface Descriptor:
1557
+ bLength 9
1558
+ bDescriptorType 4
1559
+ bInterfaceNumber 1
1560
+ bAlternateSetting 10
1561
+ bNumEndpoints 1
1562
+ bInterfaceClass 14 Video
1563
+ bInterfaceSubClass 2 Video Streaming
1564
+ bInterfaceProtocol 0
1565
+ iInterface 0
1566
+ Endpoint Descriptor:
1567
+ bLength 7
1568
+ bDescriptorType 5
1569
+ bEndpointAddress 0x81 EP 1 IN
1570
+ bmAttributes 5
1571
+ Transfer Type Isochronous
1572
+ Synch Type Asynchronous
1573
+ Usage Type Data
1574
+ wMaxPacketSize 0x1380 3x 896 bytes
1575
+ bInterval 1
1576
+ Interface Descriptor:
1577
+ bLength 9
1578
+ bDescriptorType 4
1579
+ bInterfaceNumber 1
1580
+ bAlternateSetting 11
1581
+ bNumEndpoints 1
1582
+ bInterfaceClass 14 Video
1583
+ bInterfaceSubClass 2 Video Streaming
1584
+ bInterfaceProtocol 0
1585
+ iInterface 0
1586
+ Endpoint Descriptor:
1587
+ bLength 7
1588
+ bDescriptorType 5
1589
+ bEndpointAddress 0x81 EP 1 IN
1590
+ bmAttributes 5
1591
+ Transfer Type Isochronous
1592
+ Synch Type Asynchronous
1593
+ Usage Type Data
1594
+ wMaxPacketSize 0x13fc 3x 1020 bytes
1595
+ bInterval 1
1596
+ Interface Association:
1597
+ bLength 8
1598
+ bDescriptorType 11
1599
+ bFirstInterface 2
1600
+ bInterfaceCount 2
1601
+ bFunctionClass 1 Audio
1602
+ bFunctionSubClass 2 Streaming
1603
+ bFunctionProtocol 0
1604
+ iFunction 0
1605
+ Interface Descriptor:
1606
+ bLength 9
1607
+ bDescriptorType 4
1608
+ bInterfaceNumber 2
1609
+ bAlternateSetting 0
1610
+ bNumEndpoints 0
1611
+ bInterfaceClass 1 Audio
1612
+ bInterfaceSubClass 1 Control Device
1613
+ bInterfaceProtocol 0
1614
+ iInterface 0
1615
+ AudioControl Interface Descriptor:
1616
+ bLength 9
1617
+ bDescriptorType 36
1618
+ bDescriptorSubtype 1 (HEADER)
1619
+ bcdADC 1.00
1620
+ wTotalLength 38
1621
+ bInCollection 1
1622
+ baInterfaceNr( 0) 3
1623
+ AudioControl Interface Descriptor:
1624
+ bLength 12
1625
+ bDescriptorType 36
1626
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
1627
+ bTerminalID 1
1628
+ wTerminalType 0x0201 Microphone
1629
+ bAssocTerminal 0
1630
+ bNrChannels 1
1631
+ wChannelConfig 0x0003
1632
+ Left Front (L)
1633
+ Right Front (R)
1634
+ iChannelNames 0
1635
+ iTerminal 0
1636
+ AudioControl Interface Descriptor:
1637
+ bLength 9
1638
+ bDescriptorType 36
1639
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
1640
+ bTerminalID 3
1641
+ wTerminalType 0x0101 USB Streaming
1642
+ bAssocTerminal 0
1643
+ bSourceID 5
1644
+ iTerminal 0
1645
+ AudioControl Interface Descriptor:
1646
+ bLength 8
1647
+ bDescriptorType 36
1648
+ bDescriptorSubtype 6 (FEATURE_UNIT)
1649
+ bUnitID 5
1650
+ bSourceID 1
1651
+ bControlSize 1
1652
+ bmaControls( 0) 0x03
1653
+ Mute Control
1654
+ Volume Control
1655
+ iFeature 0
1656
+ Interface Descriptor:
1657
+ bLength 9
1658
+ bDescriptorType 4
1659
+ bInterfaceNumber 3
1660
+ bAlternateSetting 0
1661
+ bNumEndpoints 0
1662
+ bInterfaceClass 1 Audio
1663
+ bInterfaceSubClass 2 Streaming
1664
+ bInterfaceProtocol 0
1665
+ iInterface 0
1666
+ Interface Descriptor:
1667
+ bLength 9
1668
+ bDescriptorType 4
1669
+ bInterfaceNumber 3
1670
+ bAlternateSetting 1
1671
+ bNumEndpoints 1
1672
+ bInterfaceClass 1 Audio
1673
+ bInterfaceSubClass 2 Streaming
1674
+ bInterfaceProtocol 0
1675
+ iInterface 0
1676
+ AudioStreaming Interface Descriptor:
1677
+ bLength 7
1678
+ bDescriptorType 36
1679
+ bDescriptorSubtype 1 (AS_GENERAL)
1680
+ bTerminalLink 3
1681
+ bDelay 255 frames
1682
+ wFormatTag 1 PCM
1683
+ AudioStreaming Interface Descriptor:
1684
+ bLength 11
1685
+ bDescriptorType 36
1686
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1687
+ bFormatType 1 (FORMAT_TYPE_I)
1688
+ bNrChannels 2
1689
+ bSubframeSize 2
1690
+ bBitResolution 16
1691
+ bSamFreqType 1 Discrete
1692
+ tSamFreq[ 0] 16000
1693
+ Endpoint Descriptor:
1694
+ bLength 9
1695
+ bDescriptorType 5
1696
+ bEndpointAddress 0x82 EP 2 IN
1697
+ bmAttributes 5
1698
+ Transfer Type Isochronous
1699
+ Synch Type Asynchronous
1700
+ Usage Type Data
1701
+ wMaxPacketSize 0x0044 1x 68 bytes
1702
+ bInterval 4
1703
+ bRefresh 0
1704
+ bSynchAddress 0
1705
+ AudioControl Endpoint Descriptor:
1706
+ bLength 7
1707
+ bDescriptorType 37
1708
+ bDescriptorSubtype 1 (EP_GENERAL)
1709
+ bmAttributes 0x01
1710
+ Sampling Frequency
1711
+ bLockDelayUnits 0 Undefined
1712
+ wLockDelay 0 Undefined
1713
+ Interface Descriptor:
1714
+ bLength 9
1715
+ bDescriptorType 4
1716
+ bInterfaceNumber 3
1717
+ bAlternateSetting 2
1718
+ bNumEndpoints 1
1719
+ bInterfaceClass 1 Audio
1720
+ bInterfaceSubClass 2 Streaming
1721
+ bInterfaceProtocol 0
1722
+ iInterface 0
1723
+ AudioStreaming Interface Descriptor:
1724
+ bLength 7
1725
+ bDescriptorType 36
1726
+ bDescriptorSubtype 1 (AS_GENERAL)
1727
+ bTerminalLink 3
1728
+ bDelay 255 frames
1729
+ wFormatTag 1 PCM
1730
+ AudioStreaming Interface Descriptor:
1731
+ bLength 11
1732
+ bDescriptorType 36
1733
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1734
+ bFormatType 1 (FORMAT_TYPE_I)
1735
+ bNrChannels 2
1736
+ bSubframeSize 2
1737
+ bBitResolution 16
1738
+ bSamFreqType 1 Discrete
1739
+ tSamFreq[ 0] 24000
1740
+ Endpoint Descriptor:
1741
+ bLength 9
1742
+ bDescriptorType 5
1743
+ bEndpointAddress 0x82 EP 2 IN
1744
+ bmAttributes 5
1745
+ Transfer Type Isochronous
1746
+ Synch Type Asynchronous
1747
+ Usage Type Data
1748
+ wMaxPacketSize 0x0064 1x 100 bytes
1749
+ bInterval 4
1750
+ bRefresh 0
1751
+ bSynchAddress 0
1752
+ AudioControl Endpoint Descriptor:
1753
+ bLength 7
1754
+ bDescriptorType 37
1755
+ bDescriptorSubtype 1 (EP_GENERAL)
1756
+ bmAttributes 0x01
1757
+ Sampling Frequency
1758
+ bLockDelayUnits 0 Undefined
1759
+ wLockDelay 0 Undefined
1760
+ Interface Descriptor:
1761
+ bLength 9
1762
+ bDescriptorType 4
1763
+ bInterfaceNumber 3
1764
+ bAlternateSetting 3
1765
+ bNumEndpoints 1
1766
+ bInterfaceClass 1 Audio
1767
+ bInterfaceSubClass 2 Streaming
1768
+ bInterfaceProtocol 0
1769
+ iInterface 0
1770
+ AudioStreaming Interface Descriptor:
1771
+ bLength 7
1772
+ bDescriptorType 36
1773
+ bDescriptorSubtype 1 (AS_GENERAL)
1774
+ bTerminalLink 3
1775
+ bDelay 255 frames
1776
+ wFormatTag 1 PCM
1777
+ AudioStreaming Interface Descriptor:
1778
+ bLength 11
1779
+ bDescriptorType 36
1780
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1781
+ bFormatType 1 (FORMAT_TYPE_I)
1782
+ bNrChannels 2
1783
+ bSubframeSize 2
1784
+ bBitResolution 16
1785
+ bSamFreqType 1 Discrete
1786
+ tSamFreq[ 0] 32000
1787
+ Endpoint Descriptor:
1788
+ bLength 9
1789
+ bDescriptorType 5
1790
+ bEndpointAddress 0x82 EP 2 IN
1791
+ bmAttributes 5
1792
+ Transfer Type Isochronous
1793
+ Synch Type Asynchronous
1794
+ Usage Type Data
1795
+ wMaxPacketSize 0x0084 1x 132 bytes
1796
+ bInterval 4
1797
+ bRefresh 0
1798
+ bSynchAddress 0
1799
+ AudioControl Endpoint Descriptor:
1800
+ bLength 7
1801
+ bDescriptorType 37
1802
+ bDescriptorSubtype 1 (EP_GENERAL)
1803
+ bmAttributes 0x01
1804
+ Sampling Frequency
1805
+ bLockDelayUnits 0 Undefined
1806
+ wLockDelay 0 Undefined
1807
+ Device Qualifier (for other device speed):
1808
+ bLength 10
1809
+ bDescriptorType 6
1810
+ bcdUSB 2.00
1811
+ bDeviceClass 239 Miscellaneous Device
1812
+ bDeviceSubClass 2 ?
1813
+ bDeviceProtocol 1 Interface Association
1814
+ bMaxPacketSize0 64
1815
+ bNumConfigurations 1
1816
+ Device Status: 0x0000
1817
+ (Bus Powered)
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/ms_lifecam_show.txt ADDED
@@ -0,0 +1,767 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Bus 001 Device 010: ID 045e:0729 Microsoft Corp.
3
+ Device Descriptor:
4
+ bLength 18
5
+ bDescriptorType 1
6
+ bcdUSB 2.00
7
+ bDeviceClass 239 Miscellaneous Device
8
+ bDeviceSubClass 2 ?
9
+ bDeviceProtocol 1 Interface Association
10
+ bMaxPacketSize0 64
11
+ idVendor 0x045e Microsoft Corp.
12
+ idProduct 0x0729
13
+ bcdDevice 1.00
14
+ iManufacturer 1 Microsoft
15
+ iProduct 2 Microsoft� LifeCam Show(TM)
16
+ iSerial 0
17
+ bNumConfigurations 1
18
+ Configuration Descriptor:
19
+ bLength 9
20
+ bDescriptorType 2
21
+ wTotalLength 961
22
+ bNumInterfaces 5
23
+ bConfigurationValue 1
24
+ iConfiguration 0
25
+ bmAttributes 0x80
26
+ (Bus Powered)
27
+ MaxPower 320mA
28
+ Interface Association:
29
+ bLength 8
30
+ bDescriptorType 11
31
+ bFirstInterface 0
32
+ bInterfaceCount 2
33
+ bFunctionClass 14 Video
34
+ bFunctionSubClass 3 Video Interface Collection
35
+ bFunctionProtocol 0
36
+ iFunction 2 Microsoft� LifeCam Show(TM)
37
+ Interface Descriptor:
38
+ bLength 9
39
+ bDescriptorType 4
40
+ bInterfaceNumber 0
41
+ bAlternateSetting 0
42
+ bNumEndpoints 1
43
+ bInterfaceClass 14 Video
44
+ bInterfaceSubClass 1 Video Control
45
+ bInterfaceProtocol 0
46
+ iInterface 2 Microsoft� LifeCam Show(TM)
47
+ VideoControl Interface Descriptor:
48
+ bLength 13
49
+ bDescriptorType 36
50
+ bDescriptorSubtype 1 (HEADER)
51
+ bcdUVC 1.00
52
+ wTotalLength 79
53
+ dwClockFrequency 24.000000MHz
54
+ bInCollection 1
55
+ baInterfaceNr( 0) 1
56
+ VideoControl Interface Descriptor:
57
+ bLength 18
58
+ bDescriptorType 36
59
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
60
+ bTerminalID 1
61
+ wTerminalType 0x0201 Camera Sensor
62
+ bAssocTerminal 0
63
+ iTerminal 0
64
+ wObjectiveFocalLengthMin 0
65
+ wObjectiveFocalLengthMax 0
66
+ wOcularFocalLength 0
67
+ bControlSize 3
68
+ bmControls 0x00000a0a
69
+ Auto-Exposure Mode
70
+ Exposure Time (Absolute)
71
+ Zoom (Absolute)
72
+ PanTilt (Absolute)
73
+ VideoControl Interface Descriptor:
74
+ bLength 11
75
+ bDescriptorType 36
76
+ bDescriptorSubtype 5 (PROCESSING_UNIT)
77
+ Warning: Descriptor too short
78
+ bUnitID 2
79
+ bSourceID 1
80
+ wMaxMultiplier 0
81
+ bControlSize 2
82
+ bmControls 0x0000073b
83
+ Brightness
84
+ Contrast
85
+ Saturation
86
+ Sharpness
87
+ Gamma
88
+ Backlight Compensation
89
+ Gain
90
+ Power Line Frequency
91
+ iProcessing 0
92
+ bmVideoStandards 0x 9
93
+ None
94
+ SECAM - 625/50
95
+ VideoControl Interface Descriptor:
96
+ bLength 9
97
+ bDescriptorType 36
98
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
99
+ bTerminalID 3
100
+ wTerminalType 0x0101 USB Streaming
101
+ bAssocTerminal 0
102
+ bSourceID 2
103
+ iTerminal 0
104
+ VideoControl Interface Descriptor:
105
+ bLength 28
106
+ bDescriptorType 36
107
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
108
+ bUnitID 4
109
+ guidExtensionCode {5dc717a9-1941-da11-ae0e-000d56ac7b4c}
110
+ bNumControl 8
111
+ bNrPins 1
112
+ baSourceID( 0) 1
113
+ bControlSize 3
114
+ bmControls( 0) 0xf9
115
+ bmControls( 1) 0x01
116
+ bmControls( 2) 0xc0
117
+ iExtension 0
118
+ Endpoint Descriptor:
119
+ bLength 7
120
+ bDescriptorType 5
121
+ bEndpointAddress 0x81 EP 1 IN
122
+ bmAttributes 3
123
+ Transfer Type Interrupt
124
+ Synch Type None
125
+ Usage Type Data
126
+ wMaxPacketSize 0x000a 1x 10 bytes
127
+ bInterval 5
128
+ Interface Descriptor:
129
+ bLength 9
130
+ bDescriptorType 4
131
+ bInterfaceNumber 1
132
+ bAlternateSetting 0
133
+ bNumEndpoints 0
134
+ bInterfaceClass 14 Video
135
+ bInterfaceSubClass 2 Video Streaming
136
+ bInterfaceProtocol 0
137
+ iInterface 0
138
+ VideoStreaming Interface Descriptor:
139
+ bLength 15
140
+ bDescriptorType 36
141
+ bDescriptorSubtype 1 (INPUT_HEADER)
142
+ bNumFormats 2
143
+ wTotalLength 587
144
+ bEndPointAddress 130
145
+ bmInfo 0
146
+ bTerminalLink 3
147
+ bStillCaptureMethod 2
148
+ bTriggerSupport 1
149
+ bTriggerUsage 1
150
+ bControlSize 1
151
+ bmaControls( 0) 27
152
+ bmaControls( 1) 27
153
+ VideoStreaming Interface Descriptor:
154
+ bLength 27
155
+ bDescriptorType 36
156
+ bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
157
+ bFormatIndex 1
158
+ bNumFrameDescriptors 6
159
+ guidFormat {59555932-0000-1000-8000-00aa00389b71}
160
+ bBitsPerPixel 16
161
+ bDefaultFrameIndex 1
162
+ bAspectRatioX 0
163
+ bAspectRatioY 0
164
+ bmInterlaceFlags 0x00
165
+ Interlaced stream or variable: No
166
+ Fields per frame: 1 fields
167
+ Field 1 first: No
168
+ Field pattern: Field 1 only
169
+ bCopyProtect 0
170
+ VideoStreaming Interface Descriptor:
171
+ bLength 30
172
+ bDescriptorType 36
173
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
174
+ bFrameIndex 1
175
+ bmCapabilities 0x00
176
+ Still image unsupported
177
+ wWidth 352
178
+ wHeight 288
179
+ dwMinBitRate 196608000
180
+ dwMaxBitRate 196608000
181
+ dwMaxVideoFrameBufferSize 3840000
182
+ dwDefaultFrameInterval 666667
183
+ bFrameIntervalType 1
184
+ dwFrameInterval( 0) 666667
185
+ VideoStreaming Interface Descriptor:
186
+ bLength 30
187
+ bDescriptorType 36
188
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
189
+ bFrameIndex 2
190
+ bmCapabilities 0x00
191
+ Still image unsupported
192
+ wWidth 640
193
+ wHeight 480
194
+ dwMinBitRate 196608000
195
+ dwMaxBitRate 196608000
196
+ dwMaxVideoFrameBufferSize 3840000
197
+ dwDefaultFrameInterval 666667
198
+ bFrameIntervalType 1
199
+ dwFrameInterval( 0) 666667
200
+ VideoStreaming Interface Descriptor:
201
+ bLength 30
202
+ bDescriptorType 36
203
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
204
+ bFrameIndex 3
205
+ bmCapabilities 0x00
206
+ Still image unsupported
207
+ wWidth 320
208
+ wHeight 240
209
+ dwMinBitRate 196608000
210
+ dwMaxBitRate 196608000
211
+ dwMaxVideoFrameBufferSize 3840000
212
+ dwDefaultFrameInterval 666667
213
+ bFrameIntervalType 1
214
+ dwFrameInterval( 0) 666667
215
+ VideoStreaming Interface Descriptor:
216
+ bLength 30
217
+ bDescriptorType 36
218
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
219
+ bFrameIndex 4
220
+ bmCapabilities 0x00
221
+ Still image unsupported
222
+ wWidth 176
223
+ wHeight 144
224
+ dwMinBitRate 196608000
225
+ dwMaxBitRate 196608000
226
+ dwMaxVideoFrameBufferSize 3840000
227
+ dwDefaultFrameInterval 666667
228
+ bFrameIntervalType 1
229
+ dwFrameInterval( 0) 666667
230
+ VideoStreaming Interface Descriptor:
231
+ bLength 30
232
+ bDescriptorType 36
233
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
234
+ bFrameIndex 5
235
+ bmCapabilities 0x00
236
+ Still image unsupported
237
+ wWidth 160
238
+ wHeight 120
239
+ dwMinBitRate 196608000
240
+ dwMaxBitRate 196608000
241
+ dwMaxVideoFrameBufferSize 3840000
242
+ dwDefaultFrameInterval 666667
243
+ bFrameIntervalType 1
244
+ dwFrameInterval( 0) 666667
245
+ VideoStreaming Interface Descriptor:
246
+ bLength 30
247
+ bDescriptorType 36
248
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
249
+ bFrameIndex 6
250
+ bmCapabilities 0x00
251
+ Still image unsupported
252
+ wWidth 800
253
+ wHeight 600
254
+ dwMinBitRate 196608000
255
+ dwMaxBitRate 196608000
256
+ dwMaxVideoFrameBufferSize 3840000
257
+ dwDefaultFrameInterval 666667
258
+ bFrameIntervalType 1
259
+ dwFrameInterval( 0) 666667
260
+ VideoStreaming Interface Descriptor:
261
+ bLength 30
262
+ bDescriptorType 36
263
+ bDescriptorSubtype 3 (STILL_IMAGE_FRAME)
264
+ bEndpointAddress 0
265
+ bNumImageSizePatterns 6
266
+ wWidth( 0) 352
267
+ wHeight( 0) 288
268
+ wWidth( 1) 640
269
+ wHeight( 1) 480
270
+ wWidth( 2) 320
271
+ wHeight( 2) 240
272
+ wWidth( 3) 176
273
+ wHeight( 3) 144
274
+ wWidth( 4) 160
275
+ wHeight( 4) 120
276
+ wWidth( 5) 800
277
+ wHeight( 5) 600
278
+ bNumCompressionPatterns 6
279
+ VideoStreaming Interface Descriptor:
280
+ bLength 6
281
+ bDescriptorType 36
282
+ bDescriptorSubtype 13 (COLORFORMAT)
283
+ bColorPrimaries 0 (Unspecified)
284
+ bTransferCharacteristics 0 (Unspecified)
285
+ bMatrixCoefficients 0 (Unspecified)
286
+ VideoStreaming Interface Descriptor:
287
+ bLength 11
288
+ bDescriptorType 36
289
+ bDescriptorSubtype 6 (FORMAT_MJPEG)
290
+ bFormatIndex 2
291
+ bNumFrameDescriptors 9
292
+ bFlags 1
293
+ Fixed-size samples: Yes
294
+ bDefaultFrameIndex 1
295
+ bAspectRatioX 0
296
+ bAspectRatioY 0
297
+ bmInterlaceFlags 0x00
298
+ Interlaced stream or variable: No
299
+ Fields per frame: 1 fields
300
+ Field 1 first: No
301
+ Field pattern: Field 1 only
302
+ bCopyProtect 0
303
+ VideoStreaming Interface Descriptor:
304
+ bLength 30
305
+ bDescriptorType 36
306
+ bDescriptorSubtype 7 (FRAME_MJPEG)
307
+ bFrameIndex 1
308
+ bmCapabilities 0x00
309
+ Still image unsupported
310
+ wWidth 352
311
+ wHeight 288
312
+ dwMinBitRate 196608000
313
+ dwMaxBitRate 196608000
314
+ dwMaxVideoFrameBufferSize 3840000
315
+ dwDefaultFrameInterval 666667
316
+ bFrameIntervalType 1
317
+ dwFrameInterval( 0) 666667
318
+ VideoStreaming Interface Descriptor:
319
+ bLength 30
320
+ bDescriptorType 36
321
+ bDescriptorSubtype 7 (FRAME_MJPEG)
322
+ bFrameIndex 2
323
+ bmCapabilities 0x00
324
+ Still image unsupported
325
+ wWidth 640
326
+ wHeight 480
327
+ dwMinBitRate 196608000
328
+ dwMaxBitRate 196608000
329
+ dwMaxVideoFrameBufferSize 3840000
330
+ dwDefaultFrameInterval 666667
331
+ bFrameIntervalType 1
332
+ dwFrameInterval( 0) 666667
333
+ VideoStreaming Interface Descriptor:
334
+ bLength 30
335
+ bDescriptorType 36
336
+ bDescriptorSubtype 7 (FRAME_MJPEG)
337
+ bFrameIndex 3
338
+ bmCapabilities 0x00
339
+ Still image unsupported
340
+ wWidth 320
341
+ wHeight 240
342
+ dwMinBitRate 196608000
343
+ dwMaxBitRate 196608000
344
+ dwMaxVideoFrameBufferSize 3840000
345
+ dwDefaultFrameInterval 666667
346
+ bFrameIntervalType 1
347
+ dwFrameInterval( 0) 666667
348
+ VideoStreaming Interface Descriptor:
349
+ bLength 30
350
+ bDescriptorType 36
351
+ bDescriptorSubtype 7 (FRAME_MJPEG)
352
+ bFrameIndex 4
353
+ bmCapabilities 0x00
354
+ Still image unsupported
355
+ wWidth 176
356
+ wHeight 144
357
+ dwMinBitRate 196608000
358
+ dwMaxBitRate 196608000
359
+ dwMaxVideoFrameBufferSize 3840000
360
+ dwDefaultFrameInterval 666667
361
+ bFrameIntervalType 1
362
+ dwFrameInterval( 0) 666667
363
+ VideoStreaming Interface Descriptor:
364
+ bLength 30
365
+ bDescriptorType 36
366
+ bDescriptorSubtype 7 (FRAME_MJPEG)
367
+ bFrameIndex 5
368
+ bmCapabilities 0x00
369
+ Still image unsupported
370
+ wWidth 160
371
+ wHeight 120
372
+ dwMinBitRate 196608000
373
+ dwMaxBitRate 196608000
374
+ dwMaxVideoFrameBufferSize 3840000
375
+ dwDefaultFrameInterval 666667
376
+ bFrameIntervalType 1
377
+ dwFrameInterval( 0) 666667
378
+ VideoStreaming Interface Descriptor:
379
+ bLength 30
380
+ bDescriptorType 36
381
+ bDescriptorSubtype 7 (FRAME_MJPEG)
382
+ bFrameIndex 6
383
+ bmCapabilities 0x00
384
+ Still image unsupported
385
+ wWidth 800
386
+ wHeight 600
387
+ dwMinBitRate 196608000
388
+ dwMaxBitRate 196608000
389
+ dwMaxVideoFrameBufferSize 3840000
390
+ dwDefaultFrameInterval 666667
391
+ bFrameIntervalType 1
392
+ dwFrameInterval( 0) 666667
393
+ VideoStreaming Interface Descriptor:
394
+ bLength 30
395
+ bDescriptorType 36
396
+ bDescriptorSubtype 7 (FRAME_MJPEG)
397
+ bFrameIndex 7
398
+ bmCapabilities 0x00
399
+ Still image unsupported
400
+ wWidth 1024
401
+ wHeight 768
402
+ dwMinBitRate 196608000
403
+ dwMaxBitRate 196608000
404
+ dwMaxVideoFrameBufferSize 3840000
405
+ dwDefaultFrameInterval 1333333
406
+ bFrameIntervalType 1
407
+ dwFrameInterval( 0) 1333333
408
+ VideoStreaming Interface Descriptor:
409
+ bLength 30
410
+ bDescriptorType 36
411
+ bDescriptorSubtype 7 (FRAME_MJPEG)
412
+ bFrameIndex 8
413
+ bmCapabilities 0x00
414
+ Still image unsupported
415
+ wWidth 1280
416
+ wHeight 960
417
+ dwMinBitRate 196608000
418
+ dwMaxBitRate 196608000
419
+ dwMaxVideoFrameBufferSize 3840000
420
+ dwDefaultFrameInterval 1333333
421
+ bFrameIntervalType 1
422
+ dwFrameInterval( 0) 1333333
423
+ VideoStreaming Interface Descriptor:
424
+ bLength 30
425
+ bDescriptorType 36
426
+ bDescriptorSubtype 7 (FRAME_MJPEG)
427
+ bFrameIndex 9
428
+ bmCapabilities 0x00
429
+ Still image unsupported
430
+ wWidth 1600
431
+ wHeight 1200
432
+ dwMinBitRate 196608000
433
+ dwMaxBitRate 196608000
434
+ dwMaxVideoFrameBufferSize 3840000
435
+ dwDefaultFrameInterval 1333333
436
+ bFrameIntervalType 1
437
+ dwFrameInterval( 0) 1333333
438
+ VideoStreaming Interface Descriptor:
439
+ bLength 42
440
+ bDescriptorType 36
441
+ bDescriptorSubtype 3 (STILL_IMAGE_FRAME)
442
+ bEndpointAddress 0
443
+ bNumImageSizePatterns 9
444
+ wWidth( 0) 352
445
+ wHeight( 0) 288
446
+ wWidth( 1) 640
447
+ wHeight( 1) 480
448
+ wWidth( 2) 320
449
+ wHeight( 2) 240
450
+ wWidth( 3) 176
451
+ wHeight( 3) 144
452
+ wWidth( 4) 160
453
+ wHeight( 4) 120
454
+ wWidth( 5) 800
455
+ wHeight( 5) 600
456
+ wWidth( 6) 1024
457
+ wHeight( 6) 768
458
+ wWidth( 7) 1280
459
+ wHeight( 7) 960
460
+ wWidth( 8) 1600
461
+ wHeight( 8) 1200
462
+ bNumCompressionPatterns 9
463
+ VideoStreaming Interface Descriptor:
464
+ bLength 6
465
+ bDescriptorType 36
466
+ bDescriptorSubtype 13 (COLORFORMAT)
467
+ bColorPrimaries 0 (Unspecified)
468
+ bTransferCharacteristics 0 (Unspecified)
469
+ bMatrixCoefficients 0 (Unspecified)
470
+ Interface Descriptor:
471
+ bLength 9
472
+ bDescriptorType 4
473
+ bInterfaceNumber 1
474
+ bAlternateSetting 1
475
+ bNumEndpoints 1
476
+ bInterfaceClass 14 Video
477
+ bInterfaceSubClass 2 Video Streaming
478
+ bInterfaceProtocol 0
479
+ iInterface 0
480
+ Endpoint Descriptor:
481
+ bLength 7
482
+ bDescriptorType 5
483
+ bEndpointAddress 0x82 EP 2 IN
484
+ bmAttributes 5
485
+ Transfer Type Isochronous
486
+ Synch Type Asynchronous
487
+ Usage Type Data
488
+ wMaxPacketSize 0x0080 1x 128 bytes
489
+ bInterval 1
490
+ Interface Descriptor:
491
+ bLength 9
492
+ bDescriptorType 4
493
+ bInterfaceNumber 1
494
+ bAlternateSetting 2
495
+ bNumEndpoints 1
496
+ bInterfaceClass 14 Video
497
+ bInterfaceSubClass 2 Video Streaming
498
+ bInterfaceProtocol 0
499
+ iInterface 0
500
+ Endpoint Descriptor:
501
+ bLength 7
502
+ bDescriptorType 5
503
+ bEndpointAddress 0x82 EP 2 IN
504
+ bmAttributes 5
505
+ Transfer Type Isochronous
506
+ Synch Type Asynchronous
507
+ Usage Type Data
508
+ wMaxPacketSize 0x0200 1x 512 bytes
509
+ bInterval 1
510
+ Interface Descriptor:
511
+ bLength 9
512
+ bDescriptorType 4
513
+ bInterfaceNumber 1
514
+ bAlternateSetting 3
515
+ bNumEndpoints 1
516
+ bInterfaceClass 14 Video
517
+ bInterfaceSubClass 2 Video Streaming
518
+ bInterfaceProtocol 0
519
+ iInterface 0
520
+ Endpoint Descriptor:
521
+ bLength 7
522
+ bDescriptorType 5
523
+ bEndpointAddress 0x82 EP 2 IN
524
+ bmAttributes 5
525
+ Transfer Type Isochronous
526
+ Synch Type Asynchronous
527
+ Usage Type Data
528
+ wMaxPacketSize 0x0400 1x 1024 bytes
529
+ bInterval 1
530
+ Interface Descriptor:
531
+ bLength 9
532
+ bDescriptorType 4
533
+ bInterfaceNumber 1
534
+ bAlternateSetting 4
535
+ bNumEndpoints 1
536
+ bInterfaceClass 14 Video
537
+ bInterfaceSubClass 2 Video Streaming
538
+ bInterfaceProtocol 0
539
+ iInterface 0
540
+ Endpoint Descriptor:
541
+ bLength 7
542
+ bDescriptorType 5
543
+ bEndpointAddress 0x82 EP 2 IN
544
+ bmAttributes 5
545
+ Transfer Type Isochronous
546
+ Synch Type Asynchronous
547
+ Usage Type Data
548
+ wMaxPacketSize 0x0b00 2x 768 bytes
549
+ bInterval 1
550
+ Interface Descriptor:
551
+ bLength 9
552
+ bDescriptorType 4
553
+ bInterfaceNumber 1
554
+ bAlternateSetting 5
555
+ bNumEndpoints 1
556
+ bInterfaceClass 14 Video
557
+ bInterfaceSubClass 2 Video Streaming
558
+ bInterfaceProtocol 0
559
+ iInterface 0
560
+ Endpoint Descriptor:
561
+ bLength 7
562
+ bDescriptorType 5
563
+ bEndpointAddress 0x82 EP 2 IN
564
+ bmAttributes 5
565
+ Transfer Type Isochronous
566
+ Synch Type Asynchronous
567
+ Usage Type Data
568
+ wMaxPacketSize 0x0c00 2x 1024 bytes
569
+ bInterval 1
570
+ Interface Descriptor:
571
+ bLength 9
572
+ bDescriptorType 4
573
+ bInterfaceNumber 1
574
+ bAlternateSetting 6
575
+ bNumEndpoints 1
576
+ bInterfaceClass 14 Video
577
+ bInterfaceSubClass 2 Video Streaming
578
+ bInterfaceProtocol 0
579
+ iInterface 0
580
+ Endpoint Descriptor:
581
+ bLength 7
582
+ bDescriptorType 5
583
+ bEndpointAddress 0x82 EP 2 IN
584
+ bmAttributes 5
585
+ Transfer Type Isochronous
586
+ Synch Type Asynchronous
587
+ Usage Type Data
588
+ wMaxPacketSize 0x1380 3x 896 bytes
589
+ bInterval 1
590
+ Interface Descriptor:
591
+ bLength 9
592
+ bDescriptorType 4
593
+ bInterfaceNumber 1
594
+ bAlternateSetting 7
595
+ bNumEndpoints 1
596
+ bInterfaceClass 14 Video
597
+ bInterfaceSubClass 2 Video Streaming
598
+ bInterfaceProtocol 0
599
+ iInterface 0
600
+ Endpoint Descriptor:
601
+ bLength 7
602
+ bDescriptorType 5
603
+ bEndpointAddress 0x82 EP 2 IN
604
+ bmAttributes 5
605
+ Transfer Type Isochronous
606
+ Synch Type Asynchronous
607
+ Usage Type Data
608
+ wMaxPacketSize 0x1400 3x 1024 bytes
609
+ bInterval 1
610
+ Interface Association:
611
+ bLength 8
612
+ bDescriptorType 11
613
+ bFirstInterface 2
614
+ bInterfaceCount 2
615
+ bFunctionClass 1 Audio
616
+ bFunctionSubClass 2 Streaming
617
+ bFunctionProtocol 0
618
+ iFunction 2 Microsoft� LifeCam Show(TM)
619
+ Interface Descriptor:
620
+ bLength 9
621
+ bDescriptorType 4
622
+ bInterfaceNumber 2
623
+ bAlternateSetting 0
624
+ bNumEndpoints 0
625
+ bInterfaceClass 1 Audio
626
+ bInterfaceSubClass 1 Control Device
627
+ bInterfaceProtocol 0
628
+ iInterface 2 Microsoft� LifeCam Show(TM)
629
+ AudioControl Interface Descriptor:
630
+ bLength 9
631
+ bDescriptorType 36
632
+ bDescriptorSubtype 1 (HEADER)
633
+ bcdADC 1.00
634
+ wTotalLength 39
635
+ bInCollection 1
636
+ baInterfaceNr( 0) 3
637
+ AudioControl Interface Descriptor:
638
+ bLength 12
639
+ bDescriptorType 36
640
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
641
+ bTerminalID 1
642
+ wTerminalType 0x0201 Microphone
643
+ bAssocTerminal 0
644
+ bNrChannels 1
645
+ wChannelConfig 0x0000
646
+ iChannelNames 0
647
+ iTerminal 0
648
+ AudioControl Interface Descriptor:
649
+ bLength 9
650
+ bDescriptorType 36
651
+ bDescriptorSubtype 6 (FEATURE_UNIT)
652
+ bUnitID 2
653
+ bSourceID 1
654
+ bControlSize 1
655
+ bmaControls( 0) 0x00
656
+ bmaControls( 1) 0x03
657
+ Mute
658
+ Volume
659
+ iFeature 0
660
+ AudioControl Interface Descriptor:
661
+ bLength 9
662
+ bDescriptorType 36
663
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
664
+ bTerminalID 3
665
+ wTerminalType 0x0101 USB Streaming
666
+ bAssocTerminal 1
667
+ bSourceID 2
668
+ iTerminal 0
669
+ Interface Descriptor:
670
+ bLength 9
671
+ bDescriptorType 4
672
+ bInterfaceNumber 3
673
+ bAlternateSetting 0
674
+ bNumEndpoints 0
675
+ bInterfaceClass 1 Audio
676
+ bInterfaceSubClass 2 Streaming
677
+ bInterfaceProtocol 0
678
+ iInterface 0
679
+ Interface Descriptor:
680
+ bLength 9
681
+ bDescriptorType 4
682
+ bInterfaceNumber 3
683
+ bAlternateSetting 1
684
+ bNumEndpoints 1
685
+ bInterfaceClass 1 Audio
686
+ bInterfaceSubClass 2 Streaming
687
+ bInterfaceProtocol 0
688
+ iInterface 0
689
+ AudioStreaming Interface Descriptor:
690
+ bLength 7
691
+ bDescriptorType 36
692
+ bDescriptorSubtype 1 (AS_GENERAL)
693
+ bTerminalLink 3
694
+ bDelay 1 frames
695
+ wFormatTag 1 PCM
696
+ AudioStreaming Interface Descriptor:
697
+ bLength 14
698
+ bDescriptorType 36
699
+ bDescriptorSubtype 2 (FORMAT_TYPE)
700
+ bFormatType 1 (FORMAT_TYPE_I)
701
+ bNrChannels 1
702
+ bSubframeSize 2
703
+ bBitResolution 16
704
+ bSamFreqType 2 Discrete
705
+ tSamFreq[ 0] 44100
706
+ tSamFreq[ 1] 48000
707
+ Endpoint Descriptor:
708
+ bLength 9
709
+ bDescriptorType 5
710
+ bEndpointAddress 0x83 EP 3 IN
711
+ bmAttributes 1
712
+ Transfer Type Isochronous
713
+ Synch Type None
714
+ Usage Type Data
715
+ wMaxPacketSize 0x0062 1x 98 bytes
716
+ bInterval 4
717
+ bRefresh 0
718
+ bSynchAddress 0
719
+ AudioControl Endpoint Descriptor:
720
+ bLength 7
721
+ bDescriptorType 37
722
+ bDescriptorSubtype 1 (EP_GENERAL)
723
+ bmAttributes 0x01
724
+ Sampling Frequency
725
+ bLockDelayUnits 0 Undefined
726
+ wLockDelay 0 Undefined
727
+ Interface Descriptor:
728
+ bLength 9
729
+ bDescriptorType 4
730
+ bInterfaceNumber 4
731
+ bAlternateSetting 0
732
+ bNumEndpoints 1
733
+ bInterfaceClass 3 Human Interface Device
734
+ bInterfaceSubClass 1 Boot Interface Subclass
735
+ bInterfaceProtocol 1 Keyboard
736
+ iInterface 0
737
+ HID Device Descriptor:
738
+ bLength 9
739
+ bDescriptorType 33
740
+ bcdHID 1.10
741
+ bCountryCode 0 Not supported
742
+ bNumDescriptors 1
743
+ bDescriptorType 34 Report
744
+ wDescriptorLength 24
745
+ Report Descriptors:
746
+ ** UNAVAILABLE **
747
+ Endpoint Descriptor:
748
+ bLength 7
749
+ bDescriptorType 5
750
+ bEndpointAddress 0x85 EP 5 IN
751
+ bmAttributes 3
752
+ Transfer Type Interrupt
753
+ Synch Type None
754
+ Usage Type Data
755
+ wMaxPacketSize 0x0001 1x 1 bytes
756
+ bInterval 10
757
+ Device Qualifier (for other device speed):
758
+ bLength 10
759
+ bDescriptorType 6
760
+ bcdUSB 2.00
761
+ bDeviceClass 239 Miscellaneous Device
762
+ bDeviceSubClass 2 ?
763
+ bDeviceProtocol 1 Interface Association
764
+ bMaxPacketSize0 64
765
+ bNumConfigurations 1
766
+ Device Status: 0x0000
767
+ (Bus Powered)
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000.txt ADDED
@@ -0,0 +1,1543 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Bus 001 Device 009: ID 046d:0809 Logitech, Inc. Webcam Pro 9000
3
+ Device Descriptor:
4
+ bLength 18
5
+ bDescriptorType 1
6
+ bcdUSB 2.00
7
+ bDeviceClass 239 Miscellaneous Device
8
+ bDeviceSubClass 2 ?
9
+ bDeviceProtocol 1 Interface Association
10
+ bMaxPacketSize0 64
11
+ idVendor 0x046d Logitech, Inc.
12
+ idProduct 0x0809 Webcam Pro 9000
13
+ bcdDevice 0.10
14
+ iManufacturer 0
15
+ iProduct 0
16
+ iSerial 2 XXXXXXXX
17
+ bNumConfigurations 1
18
+ Configuration Descriptor:
19
+ bLength 9
20
+ bDescriptorType 2
21
+ wTotalLength 2589
22
+ bNumInterfaces 4
23
+ bConfigurationValue 1
24
+ iConfiguration 0
25
+ bmAttributes 0x80
26
+ (Bus Powered)
27
+ MaxPower 500mA
28
+ Interface Association:
29
+ bLength 8
30
+ bDescriptorType 11
31
+ bFirstInterface 0
32
+ bInterfaceCount 2
33
+ bFunctionClass 14 Video
34
+ bFunctionSubClass 3 Video Interface Collection
35
+ bFunctionProtocol 0
36
+ iFunction 0
37
+ Interface Descriptor:
38
+ bLength 9
39
+ bDescriptorType 4
40
+ bInterfaceNumber 0
41
+ bAlternateSetting 0
42
+ bNumEndpoints 1
43
+ bInterfaceClass 14 Video
44
+ bInterfaceSubClass 1 Video Control
45
+ bInterfaceProtocol 0
46
+ iInterface 0
47
+ VideoControl Interface Descriptor:
48
+ bLength 13
49
+ bDescriptorType 36
50
+ bDescriptorSubtype 1 (HEADER)
51
+ bcdUVC 1.00
52
+ wTotalLength 245
53
+ dwClockFrequency 48.000000MHz
54
+ bInCollection 1
55
+ baInterfaceNr( 0) 1
56
+ VideoControl Interface Descriptor:
57
+ bLength 18
58
+ bDescriptorType 36
59
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
60
+ bTerminalID 1
61
+ wTerminalType 0x0201 Camera Sensor
62
+ bAssocTerminal 0
63
+ iTerminal 0
64
+ wObjectiveFocalLengthMin 0
65
+ wObjectiveFocalLengthMax 0
66
+ wOcularFocalLength 0
67
+ bControlSize 3
68
+ bmControls 0x0000080e
69
+ Auto-Exposure Mode
70
+ Auto-Exposure Priority
71
+ Exposure Time (Absolute)
72
+ PanTilt (Absolute)
73
+ VideoControl Interface Descriptor:
74
+ bLength 11
75
+ bDescriptorType 36
76
+ bDescriptorSubtype 5 (PROCESSING_UNIT)
77
+ Warning: Descriptor too short
78
+ bUnitID 2
79
+ bSourceID 1
80
+ wMaxMultiplier 16384
81
+ bControlSize 2
82
+ bmControls 0x0000175b
83
+ Brightness
84
+ Contrast
85
+ Saturation
86
+ Sharpness
87
+ White Balance Temperature
88
+ Backlight Compensation
89
+ Gain
90
+ Power Line Frequency
91
+ White Balance Temperature, Auto
92
+ iProcessing 0
93
+ bmVideoStandards 0x1b
94
+ None
95
+ NTSC - 525/60
96
+ SECAM - 625/50
97
+ NTSC - 625/50
98
+ VideoControl Interface Descriptor:
99
+ bLength 27
100
+ bDescriptorType 36
101
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
102
+ bUnitID 4
103
+ guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d221e}
104
+ bNumControl 10
105
+ bNrPins 1
106
+ baSourceID( 0) 2
107
+ bControlSize 2
108
+ bmControls( 0) 0xff
109
+ bmControls( 1) 0x03
110
+ iExtension 0
111
+ VideoControl Interface Descriptor:
112
+ bLength 27
113
+ bDescriptorType 36
114
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
115
+ bUnitID 13
116
+ guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d221f}
117
+ bNumControl 7
118
+ bNrPins 1
119
+ baSourceID( 0) 2
120
+ bControlSize 2
121
+ bmControls( 0) 0x6f
122
+ bmControls( 1) 0x01
123
+ iExtension 0
124
+ VideoControl Interface Descriptor:
125
+ bLength 28
126
+ bDescriptorType 36
127
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
128
+ bUnitID 8
129
+ guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2251}
130
+ bNumControl 3
131
+ bNrPins 1
132
+ baSourceID( 0) 4
133
+ bControlSize 3
134
+ bmControls( 0) 0x19
135
+ bmControls( 1) 0x00
136
+ bmControls( 2) 0x00
137
+ iExtension 0
138
+ VideoControl Interface Descriptor:
139
+ bLength 28
140
+ bDescriptorType 36
141
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
142
+ bUnitID 10
143
+ guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2252}
144
+ bNumControl 24
145
+ bNrPins 1
146
+ baSourceID( 0) 4
147
+ bControlSize 3
148
+ bmControls( 0) 0xff
149
+ bmControls( 1) 0xff
150
+ bmControls( 2) 0xff
151
+ iExtension 0
152
+ VideoControl Interface Descriptor:
153
+ bLength 28
154
+ bDescriptorType 36
155
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
156
+ bUnitID 14
157
+ guidExtensionCode {b7935ba4-15c7-0245-90f4-532a3b311365}
158
+ bNumControl 4
159
+ bNrPins 1
160
+ baSourceID( 0) 1
161
+ bControlSize 3
162
+ bmControls( 0) 0x0f
163
+ bmControls( 1) 0x00
164
+ bmControls( 2) 0x00
165
+ iExtension 0
166
+ VideoControl Interface Descriptor:
167
+ bLength 28
168
+ bDescriptorType 36
169
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
170
+ bUnitID 9
171
+ guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2256}
172
+ bNumControl 5
173
+ bNrPins 1
174
+ baSourceID( 0) 4
175
+ bControlSize 3
176
+ bmControls( 0) 0x0c
177
+ bmControls( 1) 0x00
178
+ bmControls( 2) 0x00
179
+ iExtension 0
180
+ VideoControl Interface Descriptor:
181
+ bLength 28
182
+ bDescriptorType 36
183
+ bDescriptorSubtype 6 (EXTENSION_UNIT)
184
+ bUnitID 12
185
+ guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2250}
186
+ bNumControl 17
187
+ bNrPins 1
188
+ baSourceID( 0) 4
189
+ bControlSize 3
190
+ bmControls( 0) 0xfe
191
+ bmControls( 1) 0x7f
192
+ bmControls( 2) 0x70
193
+ iExtension 0
194
+ VideoControl Interface Descriptor:
195
+ bLength 9
196
+ bDescriptorType 36
197
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
198
+ bTerminalID 5
199
+ wTerminalType 0x0101 USB Streaming
200
+ bAssocTerminal 0
201
+ bSourceID 4
202
+ iTerminal 0
203
+ ** UNRECOGNIZED: 20 41 01 0b 82 06 61 63 70 50 ab 49 b8 cc b3 85 5e 8d 22 55 01 01 04 03 01 00 00 00 00 00 00 00
204
+ Endpoint Descriptor:
205
+ bLength 7
206
+ bDescriptorType 5
207
+ bEndpointAddress 0x87 EP 7 IN
208
+ bmAttributes 3
209
+ Transfer Type Interrupt
210
+ Synch Type None
211
+ Usage Type Data
212
+ wMaxPacketSize 0x0010 1x 16 bytes
213
+ bInterval 8
214
+ Interface Descriptor:
215
+ bLength 9
216
+ bDescriptorType 4
217
+ bInterfaceNumber 1
218
+ bAlternateSetting 0
219
+ bNumEndpoints 0
220
+ bInterfaceClass 14 Video
221
+ bInterfaceSubClass 2 Video Streaming
222
+ bInterfaceProtocol 0
223
+ iInterface 0
224
+ VideoStreaming Interface Descriptor:
225
+ bLength 16
226
+ bDescriptorType 36
227
+ bDescriptorSubtype 1 (INPUT_HEADER)
228
+ bNumFormats 3
229
+ wTotalLength 1852
230
+ bEndPointAddress 129
231
+ bmInfo 0
232
+ bTerminalLink 5
233
+ bStillCaptureMethod 2
234
+ bTriggerSupport 1
235
+ bTriggerUsage 0
236
+ bControlSize 1
237
+ bmaControls( 0) 27
238
+ bmaControls( 1) 27
239
+ bmaControls( 2) 27
240
+ VideoStreaming Interface Descriptor:
241
+ bLength 27
242
+ bDescriptorType 36
243
+ bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
244
+ bFormatIndex 1
245
+ bNumFrameDescriptors 18
246
+ guidFormat {59555932-0000-1000-8000-00aa00389b71}
247
+ bBitsPerPixel 16
248
+ bDefaultFrameIndex 1
249
+ bAspectRatioX 0
250
+ bAspectRatioY 0
251
+ bmInterlaceFlags 0x00
252
+ Interlaced stream or variable: No
253
+ Fields per frame: 1 fields
254
+ Field 1 first: No
255
+ Field pattern: Field 1 only
256
+ bCopyProtect 0
257
+ VideoStreaming Interface Descriptor:
258
+ bLength 50
259
+ bDescriptorType 36
260
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
261
+ bFrameIndex 1
262
+ bmCapabilities 0x00
263
+ Still image unsupported
264
+ wWidth 640
265
+ wHeight 480
266
+ dwMinBitRate 24576000
267
+ dwMaxBitRate 147456000
268
+ dwMaxVideoFrameBufferSize 614400
269
+ dwDefaultFrameInterval 333333
270
+ bFrameIntervalType 6
271
+ dwFrameInterval( 0) 333333
272
+ dwFrameInterval( 1) 400000
273
+ dwFrameInterval( 2) 500000
274
+ dwFrameInterval( 3) 666666
275
+ dwFrameInterval( 4) 1000000
276
+ dwFrameInterval( 5) 2000000
277
+ VideoStreaming Interface Descriptor:
278
+ bLength 50
279
+ bDescriptorType 36
280
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
281
+ bFrameIndex 2
282
+ bmCapabilities 0x00
283
+ Still image unsupported
284
+ wWidth 160
285
+ wHeight 120
286
+ dwMinBitRate 1536000
287
+ dwMaxBitRate 9216000
288
+ dwMaxVideoFrameBufferSize 38400
289
+ dwDefaultFrameInterval 333333
290
+ bFrameIntervalType 6
291
+ dwFrameInterval( 0) 333333
292
+ dwFrameInterval( 1) 400000
293
+ dwFrameInterval( 2) 500000
294
+ dwFrameInterval( 3) 666666
295
+ dwFrameInterval( 4) 1000000
296
+ dwFrameInterval( 5) 2000000
297
+ VideoStreaming Interface Descriptor:
298
+ bLength 50
299
+ bDescriptorType 36
300
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
301
+ bFrameIndex 3
302
+ bmCapabilities 0x00
303
+ Still image unsupported
304
+ wWidth 176
305
+ wHeight 144
306
+ dwMinBitRate 2027520
307
+ dwMaxBitRate 12165120
308
+ dwMaxVideoFrameBufferSize 50688
309
+ dwDefaultFrameInterval 333333
310
+ bFrameIntervalType 6
311
+ dwFrameInterval( 0) 333333
312
+ dwFrameInterval( 1) 400000
313
+ dwFrameInterval( 2) 500000
314
+ dwFrameInterval( 3) 666666
315
+ dwFrameInterval( 4) 1000000
316
+ dwFrameInterval( 5) 2000000
317
+ VideoStreaming Interface Descriptor:
318
+ bLength 50
319
+ bDescriptorType 36
320
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
321
+ bFrameIndex 4
322
+ bmCapabilities 0x00
323
+ Still image unsupported
324
+ wWidth 320
325
+ wHeight 240
326
+ dwMinBitRate 6144000
327
+ dwMaxBitRate 36864000
328
+ dwMaxVideoFrameBufferSize 153600
329
+ dwDefaultFrameInterval 333333
330
+ bFrameIntervalType 6
331
+ dwFrameInterval( 0) 333333
332
+ dwFrameInterval( 1) 400000
333
+ dwFrameInterval( 2) 500000
334
+ dwFrameInterval( 3) 666666
335
+ dwFrameInterval( 4) 1000000
336
+ dwFrameInterval( 5) 2000000
337
+ VideoStreaming Interface Descriptor:
338
+ bLength 50
339
+ bDescriptorType 36
340
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
341
+ bFrameIndex 5
342
+ bmCapabilities 0x00
343
+ Still image unsupported
344
+ wWidth 352
345
+ wHeight 288
346
+ dwMinBitRate 8110080
347
+ dwMaxBitRate 48660480
348
+ dwMaxVideoFrameBufferSize 202752
349
+ dwDefaultFrameInterval 333333
350
+ bFrameIntervalType 6
351
+ dwFrameInterval( 0) 333333
352
+ dwFrameInterval( 1) 400000
353
+ dwFrameInterval( 2) 500000
354
+ dwFrameInterval( 3) 666666
355
+ dwFrameInterval( 4) 1000000
356
+ dwFrameInterval( 5) 2000000
357
+ VideoStreaming Interface Descriptor:
358
+ bLength 50
359
+ bDescriptorType 36
360
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
361
+ bFrameIndex 6
362
+ bmCapabilities 0x00
363
+ Still image unsupported
364
+ wWidth 640
365
+ wHeight 360
366
+ dwMinBitRate 18432000
367
+ dwMaxBitRate 110592000
368
+ dwMaxVideoFrameBufferSize 460800
369
+ dwDefaultFrameInterval 333333
370
+ bFrameIntervalType 6
371
+ dwFrameInterval( 0) 333333
372
+ dwFrameInterval( 1) 400000
373
+ dwFrameInterval( 2) 500000
374
+ dwFrameInterval( 3) 666666
375
+ dwFrameInterval( 4) 1000000
376
+ dwFrameInterval( 5) 2000000
377
+ VideoStreaming Interface Descriptor:
378
+ bLength 50
379
+ bDescriptorType 36
380
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
381
+ bFrameIndex 7
382
+ bmCapabilities 0x00
383
+ Still image unsupported
384
+ wWidth 640
385
+ wHeight 400
386
+ dwMinBitRate 20480000
387
+ dwMaxBitRate 122880000
388
+ dwMaxVideoFrameBufferSize 512000
389
+ dwDefaultFrameInterval 333333
390
+ bFrameIntervalType 6
391
+ dwFrameInterval( 0) 333333
392
+ dwFrameInterval( 1) 400000
393
+ dwFrameInterval( 2) 500000
394
+ dwFrameInterval( 3) 666666
395
+ dwFrameInterval( 4) 1000000
396
+ dwFrameInterval( 5) 2000000
397
+ VideoStreaming Interface Descriptor:
398
+ bLength 46
399
+ bDescriptorType 36
400
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
401
+ bFrameIndex 8
402
+ bmCapabilities 0x00
403
+ Still image unsupported
404
+ wWidth 768
405
+ wHeight 480
406
+ dwMinBitRate 29491200
407
+ dwMaxBitRate 147456000
408
+ dwMaxVideoFrameBufferSize 737280
409
+ dwDefaultFrameInterval 400000
410
+ bFrameIntervalType 5
411
+ dwFrameInterval( 0) 400000
412
+ dwFrameInterval( 1) 500000
413
+ dwFrameInterval( 2) 666666
414
+ dwFrameInterval( 3) 1000000
415
+ dwFrameInterval( 4) 2000000
416
+ VideoStreaming Interface Descriptor:
417
+ bLength 46
418
+ bDescriptorType 36
419
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
420
+ bFrameIndex 9
421
+ bmCapabilities 0x00
422
+ Still image unsupported
423
+ wWidth 800
424
+ wHeight 456
425
+ dwMinBitRate 29184000
426
+ dwMaxBitRate 145920000
427
+ dwMaxVideoFrameBufferSize 729600
428
+ dwDefaultFrameInterval 400000
429
+ bFrameIntervalType 5
430
+ dwFrameInterval( 0) 400000
431
+ dwFrameInterval( 1) 500000
432
+ dwFrameInterval( 2) 666666
433
+ dwFrameInterval( 3) 1000000
434
+ dwFrameInterval( 4) 2000000
435
+ VideoStreaming Interface Descriptor:
436
+ bLength 46
437
+ bDescriptorType 36
438
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
439
+ bFrameIndex 10
440
+ bmCapabilities 0x00
441
+ Still image unsupported
442
+ wWidth 800
443
+ wHeight 504
444
+ dwMinBitRate 32256000
445
+ dwMaxBitRate 161280000
446
+ dwMaxVideoFrameBufferSize 806400
447
+ dwDefaultFrameInterval 400000
448
+ bFrameIntervalType 5
449
+ dwFrameInterval( 0) 400000
450
+ dwFrameInterval( 1) 500000
451
+ dwFrameInterval( 2) 666666
452
+ dwFrameInterval( 3) 1000000
453
+ dwFrameInterval( 4) 2000000
454
+ VideoStreaming Interface Descriptor:
455
+ bLength 46
456
+ bDescriptorType 36
457
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
458
+ bFrameIndex 11
459
+ bmCapabilities 0x00
460
+ Still image unsupported
461
+ wWidth 800
462
+ wHeight 600
463
+ dwMinBitRate 38400000
464
+ dwMaxBitRate 192000000
465
+ dwMaxVideoFrameBufferSize 960000
466
+ dwDefaultFrameInterval 400000
467
+ bFrameIntervalType 5
468
+ dwFrameInterval( 0) 400000
469
+ dwFrameInterval( 1) 500000
470
+ dwFrameInterval( 2) 666666
471
+ dwFrameInterval( 3) 1000000
472
+ dwFrameInterval( 4) 2000000
473
+ VideoStreaming Interface Descriptor:
474
+ bLength 46
475
+ bDescriptorType 36
476
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
477
+ bFrameIndex 12
478
+ bmCapabilities 0x00
479
+ Still image unsupported
480
+ wWidth 864
481
+ wHeight 480
482
+ dwMinBitRate 33177600
483
+ dwMaxBitRate 165888000
484
+ dwMaxVideoFrameBufferSize 829440
485
+ dwDefaultFrameInterval 400000
486
+ bFrameIntervalType 5
487
+ dwFrameInterval( 0) 400000
488
+ dwFrameInterval( 1) 500000
489
+ dwFrameInterval( 2) 666666
490
+ dwFrameInterval( 3) 1000000
491
+ dwFrameInterval( 4) 2000000
492
+ VideoStreaming Interface Descriptor:
493
+ bLength 38
494
+ bDescriptorType 36
495
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
496
+ bFrameIndex 13
497
+ bmCapabilities 0x00
498
+ Still image unsupported
499
+ wWidth 960
500
+ wHeight 720
501
+ dwMinBitRate 55296000
502
+ dwMaxBitRate 165888000
503
+ dwMaxVideoFrameBufferSize 1382400
504
+ dwDefaultFrameInterval 1000000
505
+ bFrameIntervalType 3
506
+ dwFrameInterval( 0) 666666
507
+ dwFrameInterval( 1) 1000000
508
+ dwFrameInterval( 2) 2000000
509
+ VideoStreaming Interface Descriptor:
510
+ bLength 34
511
+ bDescriptorType 36
512
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
513
+ bFrameIndex 14
514
+ bmCapabilities 0x00
515
+ Still image unsupported
516
+ wWidth 1280
517
+ wHeight 720
518
+ dwMinBitRate 73728000
519
+ dwMaxBitRate 147456000
520
+ dwMaxVideoFrameBufferSize 1843200
521
+ dwDefaultFrameInterval 2000000
522
+ bFrameIntervalType 2
523
+ dwFrameInterval( 0) 1333333
524
+ dwFrameInterval( 1) 2000000
525
+ VideoStreaming Interface Descriptor:
526
+ bLength 34
527
+ bDescriptorType 36
528
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
529
+ bFrameIndex 15
530
+ bmCapabilities 0x00
531
+ Still image unsupported
532
+ wWidth 1280
533
+ wHeight 800
534
+ dwMinBitRate 81920000
535
+ dwMaxBitRate 163840000
536
+ dwMaxVideoFrameBufferSize 2048000
537
+ dwDefaultFrameInterval 2000000
538
+ bFrameIntervalType 2
539
+ dwFrameInterval( 0) 1333333
540
+ dwFrameInterval( 1) 2000000
541
+ VideoStreaming Interface Descriptor:
542
+ bLength 30
543
+ bDescriptorType 36
544
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
545
+ bFrameIndex 16
546
+ bmCapabilities 0x00
547
+ Still image unsupported
548
+ wWidth 1600
549
+ wHeight 904
550
+ dwMinBitRate 115712000
551
+ dwMaxBitRate 115712000
552
+ dwMaxVideoFrameBufferSize 2892800
553
+ dwDefaultFrameInterval 2000000
554
+ bFrameIntervalType 1
555
+ dwFrameInterval( 0) 2000000
556
+ VideoStreaming Interface Descriptor:
557
+ bLength 30
558
+ bDescriptorType 36
559
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
560
+ bFrameIndex 17
561
+ bmCapabilities 0x00
562
+ Still image unsupported
563
+ wWidth 1600
564
+ wHeight 1000
565
+ dwMinBitRate 128000000
566
+ dwMaxBitRate 128000000
567
+ dwMaxVideoFrameBufferSize 3200000
568
+ dwDefaultFrameInterval 2000000
569
+ bFrameIntervalType 1
570
+ dwFrameInterval( 0) 2000000
571
+ VideoStreaming Interface Descriptor:
572
+ bLength 30
573
+ bDescriptorType 36
574
+ bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
575
+ bFrameIndex 18
576
+ bmCapabilities 0x00
577
+ Still image unsupported
578
+ wWidth 1600
579
+ wHeight 1200
580
+ dwMinBitRate 153600000
581
+ dwMaxBitRate 153600000
582
+ dwMaxVideoFrameBufferSize 3840000
583
+ dwDefaultFrameInterval 2000000
584
+ bFrameIntervalType 1
585
+ dwFrameInterval( 0) 2000000
586
+ VideoStreaming Interface Descriptor:
587
+ bLength 79
588
+ bDescriptorType 36
589
+ bDescriptorSubtype 3 (STILL_IMAGE_FRAME)
590
+ bEndpointAddress 0
591
+ bNumImageSizePatterns 18
592
+ wWidth( 0) 640
593
+ wHeight( 0) 480
594
+ wWidth( 1) 160
595
+ wHeight( 1) 120
596
+ wWidth( 2) 176
597
+ wHeight( 2) 144
598
+ wWidth( 3) 320
599
+ wHeight( 3) 240
600
+ wWidth( 4) 352
601
+ wHeight( 4) 288
602
+ wWidth( 5) 640
603
+ wHeight( 5) 360
604
+ wWidth( 6) 640
605
+ wHeight( 6) 400
606
+ wWidth( 7) 768
607
+ wHeight( 7) 480
608
+ wWidth( 8) 800
609
+ wHeight( 8) 456
610
+ wWidth( 9) 800
611
+ wHeight( 9) 504
612
+ wWidth(10) 800
613
+ wHeight(10) 600
614
+ wWidth(11) 864
615
+ wHeight(11) 480
616
+ wWidth(12) 960
617
+ wHeight(12) 720
618
+ wWidth(13) 1280
619
+ wHeight(13) 720
620
+ wWidth(14) 1280
621
+ wHeight(14) 800
622
+ wWidth(15) 1600
623
+ wHeight(15) 904
624
+ wWidth(16) 1600
625
+ wHeight(16) 1000
626
+ wWidth(17) 1600
627
+ wHeight(17) 1200
628
+ bNumCompressionPatterns 18
629
+ bCompression( 0) 5
630
+ VideoStreaming Interface Descriptor:
631
+ bLength 6
632
+ bDescriptorType 36
633
+ bDescriptorSubtype 13 (COLORFORMAT)
634
+ bColorPrimaries 1 (BT.709,sRGB)
635
+ bTransferCharacteristics 1 (BT.709)
636
+ bMatrixCoefficients 4 (SMPTE 170M (BT.601))
637
+ VideoStreaming Interface Descriptor:
638
+ bLength 11
639
+ bDescriptorType 36
640
+ bDescriptorSubtype 6 (FORMAT_MJPEG)
641
+ bFormatIndex 2
642
+ bNumFrameDescriptors 18
643
+ bFlags 1
644
+ Fixed-size samples: Yes
645
+ bDefaultFrameIndex 1
646
+ bAspectRatioX 0
647
+ bAspectRatioY 0
648
+ bmInterlaceFlags 0x00
649
+ Interlaced stream or variable: No
650
+ Fields per frame: 1 fields
651
+ Field 1 first: No
652
+ Field pattern: Field 1 only
653
+ bCopyProtect 0
654
+ VideoStreaming Interface Descriptor:
655
+ bLength 50
656
+ bDescriptorType 36
657
+ bDescriptorSubtype 7 (FRAME_MJPEG)
658
+ bFrameIndex 1
659
+ bmCapabilities 0x00
660
+ Still image unsupported
661
+ wWidth 640
662
+ wHeight 480
663
+ dwMinBitRate 24576000
664
+ dwMaxBitRate 147456000
665
+ dwMaxVideoFrameBufferSize 614400
666
+ dwDefaultFrameInterval 333333
667
+ bFrameIntervalType 6
668
+ dwFrameInterval( 0) 333333
669
+ dwFrameInterval( 1) 400000
670
+ dwFrameInterval( 2) 500000
671
+ dwFrameInterval( 3) 666666
672
+ dwFrameInterval( 4) 1000000
673
+ dwFrameInterval( 5) 2000000
674
+ VideoStreaming Interface Descriptor:
675
+ bLength 50
676
+ bDescriptorType 36
677
+ bDescriptorSubtype 7 (FRAME_MJPEG)
678
+ bFrameIndex 2
679
+ bmCapabilities 0x00
680
+ Still image unsupported
681
+ wWidth 160
682
+ wHeight 120
683
+ dwMinBitRate 1536000
684
+ dwMaxBitRate 9216000
685
+ dwMaxVideoFrameBufferSize 38400
686
+ dwDefaultFrameInterval 333333
687
+ bFrameIntervalType 6
688
+ dwFrameInterval( 0) 333333
689
+ dwFrameInterval( 1) 400000
690
+ dwFrameInterval( 2) 500000
691
+ dwFrameInterval( 3) 666666
692
+ dwFrameInterval( 4) 1000000
693
+ dwFrameInterval( 5) 2000000
694
+ VideoStreaming Interface Descriptor:
695
+ bLength 50
696
+ bDescriptorType 36
697
+ bDescriptorSubtype 7 (FRAME_MJPEG)
698
+ bFrameIndex 3
699
+ bmCapabilities 0x00
700
+ Still image unsupported
701
+ wWidth 176
702
+ wHeight 144
703
+ dwMinBitRate 2027520
704
+ dwMaxBitRate 12165120
705
+ dwMaxVideoFrameBufferSize 50688
706
+ dwDefaultFrameInterval 333333
707
+ bFrameIntervalType 6
708
+ dwFrameInterval( 0) 333333
709
+ dwFrameInterval( 1) 400000
710
+ dwFrameInterval( 2) 500000
711
+ dwFrameInterval( 3) 666666
712
+ dwFrameInterval( 4) 1000000
713
+ dwFrameInterval( 5) 2000000
714
+ VideoStreaming Interface Descriptor:
715
+ bLength 50
716
+ bDescriptorType 36
717
+ bDescriptorSubtype 7 (FRAME_MJPEG)
718
+ bFrameIndex 4
719
+ bmCapabilities 0x00
720
+ Still image unsupported
721
+ wWidth 320
722
+ wHeight 240
723
+ dwMinBitRate 6144000
724
+ dwMaxBitRate 36864000
725
+ dwMaxVideoFrameBufferSize 153600
726
+ dwDefaultFrameInterval 333333
727
+ bFrameIntervalType 6
728
+ dwFrameInterval( 0) 333333
729
+ dwFrameInterval( 1) 400000
730
+ dwFrameInterval( 2) 500000
731
+ dwFrameInterval( 3) 666666
732
+ dwFrameInterval( 4) 1000000
733
+ dwFrameInterval( 5) 2000000
734
+ VideoStreaming Interface Descriptor:
735
+ bLength 50
736
+ bDescriptorType 36
737
+ bDescriptorSubtype 7 (FRAME_MJPEG)
738
+ bFrameIndex 5
739
+ bmCapabilities 0x00
740
+ Still image unsupported
741
+ wWidth 352
742
+ wHeight 288
743
+ dwMinBitRate 8110080
744
+ dwMaxBitRate 48660480
745
+ dwMaxVideoFrameBufferSize 202752
746
+ dwDefaultFrameInterval 333333
747
+ bFrameIntervalType 6
748
+ dwFrameInterval( 0) 333333
749
+ dwFrameInterval( 1) 400000
750
+ dwFrameInterval( 2) 500000
751
+ dwFrameInterval( 3) 666666
752
+ dwFrameInterval( 4) 1000000
753
+ dwFrameInterval( 5) 2000000
754
+ VideoStreaming Interface Descriptor:
755
+ bLength 50
756
+ bDescriptorType 36
757
+ bDescriptorSubtype 7 (FRAME_MJPEG)
758
+ bFrameIndex 6
759
+ bmCapabilities 0x00
760
+ Still image unsupported
761
+ wWidth 640
762
+ wHeight 360
763
+ dwMinBitRate 18432000
764
+ dwMaxBitRate 110592000
765
+ dwMaxVideoFrameBufferSize 460800
766
+ dwDefaultFrameInterval 333333
767
+ bFrameIntervalType 6
768
+ dwFrameInterval( 0) 333333
769
+ dwFrameInterval( 1) 400000
770
+ dwFrameInterval( 2) 500000
771
+ dwFrameInterval( 3) 666666
772
+ dwFrameInterval( 4) 1000000
773
+ dwFrameInterval( 5) 2000000
774
+ VideoStreaming Interface Descriptor:
775
+ bLength 50
776
+ bDescriptorType 36
777
+ bDescriptorSubtype 7 (FRAME_MJPEG)
778
+ bFrameIndex 7
779
+ bmCapabilities 0x00
780
+ Still image unsupported
781
+ wWidth 640
782
+ wHeight 400
783
+ dwMinBitRate 20480000
784
+ dwMaxBitRate 122880000
785
+ dwMaxVideoFrameBufferSize 512000
786
+ dwDefaultFrameInterval 333333
787
+ bFrameIntervalType 6
788
+ dwFrameInterval( 0) 333333
789
+ dwFrameInterval( 1) 400000
790
+ dwFrameInterval( 2) 500000
791
+ dwFrameInterval( 3) 666666
792
+ dwFrameInterval( 4) 1000000
793
+ dwFrameInterval( 5) 2000000
794
+ VideoStreaming Interface Descriptor:
795
+ bLength 50
796
+ bDescriptorType 36
797
+ bDescriptorSubtype 7 (FRAME_MJPEG)
798
+ bFrameIndex 8
799
+ bmCapabilities 0x00
800
+ Still image unsupported
801
+ wWidth 768
802
+ wHeight 480
803
+ dwMinBitRate 29491200
804
+ dwMaxBitRate 176947200
805
+ dwMaxVideoFrameBufferSize 737280
806
+ dwDefaultFrameInterval 333333
807
+ bFrameIntervalType 6
808
+ dwFrameInterval( 0) 333333
809
+ dwFrameInterval( 1) 400000
810
+ dwFrameInterval( 2) 500000
811
+ dwFrameInterval( 3) 666666
812
+ dwFrameInterval( 4) 1000000
813
+ dwFrameInterval( 5) 2000000
814
+ VideoStreaming Interface Descriptor:
815
+ bLength 50
816
+ bDescriptorType 36
817
+ bDescriptorSubtype 7 (FRAME_MJPEG)
818
+ bFrameIndex 9
819
+ bmCapabilities 0x00
820
+ Still image unsupported
821
+ wWidth 800
822
+ wHeight 456
823
+ dwMinBitRate 29184000
824
+ dwMaxBitRate 175104000
825
+ dwMaxVideoFrameBufferSize 729600
826
+ dwDefaultFrameInterval 666666
827
+ bFrameIntervalType 6
828
+ dwFrameInterval( 0) 333333
829
+ dwFrameInterval( 1) 400000
830
+ dwFrameInterval( 2) 500000
831
+ dwFrameInterval( 3) 666666
832
+ dwFrameInterval( 4) 1000000
833
+ dwFrameInterval( 5) 2000000
834
+ VideoStreaming Interface Descriptor:
835
+ bLength 50
836
+ bDescriptorType 36
837
+ bDescriptorSubtype 7 (FRAME_MJPEG)
838
+ bFrameIndex 10
839
+ bmCapabilities 0x00
840
+ Still image unsupported
841
+ wWidth 800
842
+ wHeight 504
843
+ dwMinBitRate 32256000
844
+ dwMaxBitRate 193536000
845
+ dwMaxVideoFrameBufferSize 806400
846
+ dwDefaultFrameInterval 666666
847
+ bFrameIntervalType 6
848
+ dwFrameInterval( 0) 333333
849
+ dwFrameInterval( 1) 400000
850
+ dwFrameInterval( 2) 500000
851
+ dwFrameInterval( 3) 666666
852
+ dwFrameInterval( 4) 1000000
853
+ dwFrameInterval( 5) 2000000
854
+ VideoStreaming Interface Descriptor:
855
+ bLength 50
856
+ bDescriptorType 36
857
+ bDescriptorSubtype 7 (FRAME_MJPEG)
858
+ bFrameIndex 11
859
+ bmCapabilities 0x00
860
+ Still image unsupported
861
+ wWidth 800
862
+ wHeight 600
863
+ dwMinBitRate 38400000
864
+ dwMaxBitRate 230400000
865
+ dwMaxVideoFrameBufferSize 960000
866
+ dwDefaultFrameInterval 666666
867
+ bFrameIntervalType 6
868
+ dwFrameInterval( 0) 333333
869
+ dwFrameInterval( 1) 400000
870
+ dwFrameInterval( 2) 500000
871
+ dwFrameInterval( 3) 666666
872
+ dwFrameInterval( 4) 1000000
873
+ dwFrameInterval( 5) 2000000
874
+ VideoStreaming Interface Descriptor:
875
+ bLength 50
876
+ bDescriptorType 36
877
+ bDescriptorSubtype 7 (FRAME_MJPEG)
878
+ bFrameIndex 12
879
+ bmCapabilities 0x00
880
+ Still image unsupported
881
+ wWidth 864
882
+ wHeight 480
883
+ dwMinBitRate 33177600
884
+ dwMaxBitRate 199065600
885
+ dwMaxVideoFrameBufferSize 829440
886
+ dwDefaultFrameInterval 666666
887
+ bFrameIntervalType 6
888
+ dwFrameInterval( 0) 333333
889
+ dwFrameInterval( 1) 400000
890
+ dwFrameInterval( 2) 500000
891
+ dwFrameInterval( 3) 666666
892
+ dwFrameInterval( 4) 1000000
893
+ dwFrameInterval( 5) 2000000
894
+ VideoStreaming Interface Descriptor:
895
+ bLength 50
896
+ bDescriptorType 36
897
+ bDescriptorSubtype 7 (FRAME_MJPEG)
898
+ bFrameIndex 13
899
+ bmCapabilities 0x00
900
+ Still image unsupported
901
+ wWidth 960
902
+ wHeight 720
903
+ dwMinBitRate 55296000
904
+ dwMaxBitRate 331776000
905
+ dwMaxVideoFrameBufferSize 1382400
906
+ dwDefaultFrameInterval 1000000
907
+ bFrameIntervalType 6
908
+ dwFrameInterval( 0) 333333
909
+ dwFrameInterval( 1) 400000
910
+ dwFrameInterval( 2) 500000
911
+ dwFrameInterval( 3) 666666
912
+ dwFrameInterval( 4) 1000000
913
+ dwFrameInterval( 5) 2000000
914
+ VideoStreaming Interface Descriptor:
915
+ bLength 50
916
+ bDescriptorType 36
917
+ bDescriptorSubtype 7 (FRAME_MJPEG)
918
+ bFrameIndex 14
919
+ bmCapabilities 0x00
920
+ Still image unsupported
921
+ wWidth 1280
922
+ wHeight 720
923
+ dwMinBitRate 73728000
924
+ dwMaxBitRate 442368000
925
+ dwMaxVideoFrameBufferSize 1843200
926
+ dwDefaultFrameInterval 1000000
927
+ bFrameIntervalType 6
928
+ dwFrameInterval( 0) 333333
929
+ dwFrameInterval( 1) 400000
930
+ dwFrameInterval( 2) 500000
931
+ dwFrameInterval( 3) 666666
932
+ dwFrameInterval( 4) 1000000
933
+ dwFrameInterval( 5) 2000000
934
+ VideoStreaming Interface Descriptor:
935
+ bLength 46
936
+ bDescriptorType 36
937
+ bDescriptorSubtype 7 (FRAME_MJPEG)
938
+ bFrameIndex 15
939
+ bmCapabilities 0x00
940
+ Still image unsupported
941
+ wWidth 1280
942
+ wHeight 800
943
+ dwMinBitRate 81920000
944
+ dwMaxBitRate 409600000
945
+ dwMaxVideoFrameBufferSize 2048000
946
+ dwDefaultFrameInterval 1000000
947
+ bFrameIntervalType 5
948
+ dwFrameInterval( 0) 400000
949
+ dwFrameInterval( 1) 500000
950
+ dwFrameInterval( 2) 666666
951
+ dwFrameInterval( 3) 1000000
952
+ dwFrameInterval( 4) 2000000
953
+ VideoStreaming Interface Descriptor:
954
+ bLength 34
955
+ bDescriptorType 36
956
+ bDescriptorSubtype 7 (FRAME_MJPEG)
957
+ bFrameIndex 16
958
+ bmCapabilities 0x00
959
+ Still image unsupported
960
+ wWidth 1600
961
+ wHeight 904
962
+ dwMinBitRate 115712000
963
+ dwMaxBitRate 231424000
964
+ dwMaxVideoFrameBufferSize 2892800
965
+ dwDefaultFrameInterval 1000000
966
+ bFrameIntervalType 2
967
+ dwFrameInterval( 0) 1000000
968
+ dwFrameInterval( 1) 2000000
969
+ VideoStreaming Interface Descriptor:
970
+ bLength 34
971
+ bDescriptorType 36
972
+ bDescriptorSubtype 7 (FRAME_MJPEG)
973
+ bFrameIndex 17
974
+ bmCapabilities 0x00
975
+ Still image unsupported
976
+ wWidth 1600
977
+ wHeight 1000
978
+ dwMinBitRate 128000000
979
+ dwMaxBitRate 256000000
980
+ dwMaxVideoFrameBufferSize 3200000
981
+ dwDefaultFrameInterval 1000000
982
+ bFrameIntervalType 2
983
+ dwFrameInterval( 0) 1000000
984
+ dwFrameInterval( 1) 2000000
985
+ VideoStreaming Interface Descriptor:
986
+ bLength 34
987
+ bDescriptorType 36
988
+ bDescriptorSubtype 7 (FRAME_MJPEG)
989
+ bFrameIndex 18
990
+ bmCapabilities 0x00
991
+ Still image unsupported
992
+ wWidth 1600
993
+ wHeight 1200
994
+ dwMinBitRate 153600000
995
+ dwMaxBitRate 307200000
996
+ dwMaxVideoFrameBufferSize 3840000
997
+ dwDefaultFrameInterval 2000000
998
+ bFrameIntervalType 2
999
+ dwFrameInterval( 0) 1000000
1000
+ dwFrameInterval( 1) 2000000
1001
+ VideoStreaming Interface Descriptor:
1002
+ bLength 83
1003
+ bDescriptorType 36
1004
+ bDescriptorSubtype 3 (STILL_IMAGE_FRAME)
1005
+ bEndpointAddress 0
1006
+ bNumImageSizePatterns 18
1007
+ wWidth( 0) 640
1008
+ wHeight( 0) 480
1009
+ wWidth( 1) 160
1010
+ wHeight( 1) 120
1011
+ wWidth( 2) 176
1012
+ wHeight( 2) 144
1013
+ wWidth( 3) 320
1014
+ wHeight( 3) 240
1015
+ wWidth( 4) 352
1016
+ wHeight( 4) 288
1017
+ wWidth( 5) 640
1018
+ wHeight( 5) 360
1019
+ wWidth( 6) 640
1020
+ wHeight( 6) 400
1021
+ wWidth( 7) 768
1022
+ wHeight( 7) 480
1023
+ wWidth( 8) 800
1024
+ wHeight( 8) 456
1025
+ wWidth( 9) 800
1026
+ wHeight( 9) 504
1027
+ wWidth(10) 800
1028
+ wHeight(10) 600
1029
+ wWidth(11) 864
1030
+ wHeight(11) 480
1031
+ wWidth(12) 960
1032
+ wHeight(12) 720
1033
+ wWidth(13) 1280
1034
+ wHeight(13) 720
1035
+ wWidth(14) 1280
1036
+ wHeight(14) 800
1037
+ wWidth(15) 1600
1038
+ wHeight(15) 904
1039
+ wWidth(16) 1600
1040
+ wHeight(16) 1000
1041
+ wWidth(17) 1600
1042
+ wHeight(17) 1200
1043
+ bNumCompressionPatterns 18
1044
+ bCompression( 0) 5
1045
+ bCompression( 1) 10
1046
+ bCompression( 2) 15
1047
+ bCompression( 3) 20
1048
+ bCompression( 4) 25
1049
+ VideoStreaming Interface Descriptor:
1050
+ bLength 6
1051
+ bDescriptorType 36
1052
+ bDescriptorSubtype 13 (COLORFORMAT)
1053
+ bColorPrimaries 1 (BT.709,sRGB)
1054
+ bTransferCharacteristics 1 (BT.709)
1055
+ bMatrixCoefficients 4 (SMPTE 170M (BT.601))
1056
+ Interface Descriptor:
1057
+ bLength 9
1058
+ bDescriptorType 4
1059
+ bInterfaceNumber 1
1060
+ bAlternateSetting 1
1061
+ bNumEndpoints 1
1062
+ bInterfaceClass 14 Video
1063
+ bInterfaceSubClass 2 Video Streaming
1064
+ bInterfaceProtocol 0
1065
+ iInterface 0
1066
+ Endpoint Descriptor:
1067
+ bLength 7
1068
+ bDescriptorType 5
1069
+ bEndpointAddress 0x81 EP 1 IN
1070
+ bmAttributes 5
1071
+ Transfer Type Isochronous
1072
+ Synch Type Asynchronous
1073
+ Usage Type Data
1074
+ wMaxPacketSize 0x00c0 1x 192 bytes
1075
+ bInterval 1
1076
+ Interface Descriptor:
1077
+ bLength 9
1078
+ bDescriptorType 4
1079
+ bInterfaceNumber 1
1080
+ bAlternateSetting 2
1081
+ bNumEndpoints 1
1082
+ bInterfaceClass 14 Video
1083
+ bInterfaceSubClass 2 Video Streaming
1084
+ bInterfaceProtocol 0
1085
+ iInterface 0
1086
+ Endpoint Descriptor:
1087
+ bLength 7
1088
+ bDescriptorType 5
1089
+ bEndpointAddress 0x81 EP 1 IN
1090
+ bmAttributes 5
1091
+ Transfer Type Isochronous
1092
+ Synch Type Asynchronous
1093
+ Usage Type Data
1094
+ wMaxPacketSize 0x0180 1x 384 bytes
1095
+ bInterval 1
1096
+ Interface Descriptor:
1097
+ bLength 9
1098
+ bDescriptorType 4
1099
+ bInterfaceNumber 1
1100
+ bAlternateSetting 3
1101
+ bNumEndpoints 1
1102
+ bInterfaceClass 14 Video
1103
+ bInterfaceSubClass 2 Video Streaming
1104
+ bInterfaceProtocol 0
1105
+ iInterface 0
1106
+ Endpoint Descriptor:
1107
+ bLength 7
1108
+ bDescriptorType 5
1109
+ bEndpointAddress 0x81 EP 1 IN
1110
+ bmAttributes 5
1111
+ Transfer Type Isochronous
1112
+ Synch Type Asynchronous
1113
+ Usage Type Data
1114
+ wMaxPacketSize 0x0200 1x 512 bytes
1115
+ bInterval 1
1116
+ Interface Descriptor:
1117
+ bLength 9
1118
+ bDescriptorType 4
1119
+ bInterfaceNumber 1
1120
+ bAlternateSetting 4
1121
+ bNumEndpoints 1
1122
+ bInterfaceClass 14 Video
1123
+ bInterfaceSubClass 2 Video Streaming
1124
+ bInterfaceProtocol 0
1125
+ iInterface 0
1126
+ Endpoint Descriptor:
1127
+ bLength 7
1128
+ bDescriptorType 5
1129
+ bEndpointAddress 0x81 EP 1 IN
1130
+ bmAttributes 5
1131
+ Transfer Type Isochronous
1132
+ Synch Type Asynchronous
1133
+ Usage Type Data
1134
+ wMaxPacketSize 0x0280 1x 640 bytes
1135
+ bInterval 1
1136
+ Interface Descriptor:
1137
+ bLength 9
1138
+ bDescriptorType 4
1139
+ bInterfaceNumber 1
1140
+ bAlternateSetting 5
1141
+ bNumEndpoints 1
1142
+ bInterfaceClass 14 Video
1143
+ bInterfaceSubClass 2 Video Streaming
1144
+ bInterfaceProtocol 0
1145
+ iInterface 0
1146
+ Endpoint Descriptor:
1147
+ bLength 7
1148
+ bDescriptorType 5
1149
+ bEndpointAddress 0x81 EP 1 IN
1150
+ bmAttributes 5
1151
+ Transfer Type Isochronous
1152
+ Synch Type Asynchronous
1153
+ Usage Type Data
1154
+ wMaxPacketSize 0x0320 1x 800 bytes
1155
+ bInterval 1
1156
+ Interface Descriptor:
1157
+ bLength 9
1158
+ bDescriptorType 4
1159
+ bInterfaceNumber 1
1160
+ bAlternateSetting 6
1161
+ bNumEndpoints 1
1162
+ bInterfaceClass 14 Video
1163
+ bInterfaceSubClass 2 Video Streaming
1164
+ bInterfaceProtocol 0
1165
+ iInterface 0
1166
+ Endpoint Descriptor:
1167
+ bLength 7
1168
+ bDescriptorType 5
1169
+ bEndpointAddress 0x81 EP 1 IN
1170
+ bmAttributes 5
1171
+ Transfer Type Isochronous
1172
+ Synch Type Asynchronous
1173
+ Usage Type Data
1174
+ wMaxPacketSize 0x03b0 1x 944 bytes
1175
+ bInterval 1
1176
+ Interface Descriptor:
1177
+ bLength 9
1178
+ bDescriptorType 4
1179
+ bInterfaceNumber 1
1180
+ bAlternateSetting 7
1181
+ bNumEndpoints 1
1182
+ bInterfaceClass 14 Video
1183
+ bInterfaceSubClass 2 Video Streaming
1184
+ bInterfaceProtocol 0
1185
+ iInterface 0
1186
+ Endpoint Descriptor:
1187
+ bLength 7
1188
+ bDescriptorType 5
1189
+ bEndpointAddress 0x81 EP 1 IN
1190
+ bmAttributes 5
1191
+ Transfer Type Isochronous
1192
+ Synch Type Asynchronous
1193
+ Usage Type Data
1194
+ wMaxPacketSize 0x0a80 2x 640 bytes
1195
+ bInterval 1
1196
+ Interface Descriptor:
1197
+ bLength 9
1198
+ bDescriptorType 4
1199
+ bInterfaceNumber 1
1200
+ bAlternateSetting 8
1201
+ bNumEndpoints 1
1202
+ bInterfaceClass 14 Video
1203
+ bInterfaceSubClass 2 Video Streaming
1204
+ bInterfaceProtocol 0
1205
+ iInterface 0
1206
+ Endpoint Descriptor:
1207
+ bLength 7
1208
+ bDescriptorType 5
1209
+ bEndpointAddress 0x81 EP 1 IN
1210
+ bmAttributes 5
1211
+ Transfer Type Isochronous
1212
+ Synch Type Asynchronous
1213
+ Usage Type Data
1214
+ wMaxPacketSize 0x0b20 2x 800 bytes
1215
+ bInterval 1
1216
+ Interface Descriptor:
1217
+ bLength 9
1218
+ bDescriptorType 4
1219
+ bInterfaceNumber 1
1220
+ bAlternateSetting 9
1221
+ bNumEndpoints 1
1222
+ bInterfaceClass 14 Video
1223
+ bInterfaceSubClass 2 Video Streaming
1224
+ bInterfaceProtocol 0
1225
+ iInterface 0
1226
+ Endpoint Descriptor:
1227
+ bLength 7
1228
+ bDescriptorType 5
1229
+ bEndpointAddress 0x81 EP 1 IN
1230
+ bmAttributes 5
1231
+ Transfer Type Isochronous
1232
+ Synch Type Asynchronous
1233
+ Usage Type Data
1234
+ wMaxPacketSize 0x0be0 2x 992 bytes
1235
+ bInterval 1
1236
+ Interface Descriptor:
1237
+ bLength 9
1238
+ bDescriptorType 4
1239
+ bInterfaceNumber 1
1240
+ bAlternateSetting 10
1241
+ bNumEndpoints 1
1242
+ bInterfaceClass 14 Video
1243
+ bInterfaceSubClass 2 Video Streaming
1244
+ bInterfaceProtocol 0
1245
+ iInterface 0
1246
+ Endpoint Descriptor:
1247
+ bLength 7
1248
+ bDescriptorType 5
1249
+ bEndpointAddress 0x81 EP 1 IN
1250
+ bmAttributes 5
1251
+ Transfer Type Isochronous
1252
+ Synch Type Asynchronous
1253
+ Usage Type Data
1254
+ wMaxPacketSize 0x1380 3x 896 bytes
1255
+ bInterval 1
1256
+ Interface Descriptor:
1257
+ bLength 9
1258
+ bDescriptorType 4
1259
+ bInterfaceNumber 1
1260
+ bAlternateSetting 11
1261
+ bNumEndpoints 1
1262
+ bInterfaceClass 14 Video
1263
+ bInterfaceSubClass 2 Video Streaming
1264
+ bInterfaceProtocol 0
1265
+ iInterface 0
1266
+ Endpoint Descriptor:
1267
+ bLength 7
1268
+ bDescriptorType 5
1269
+ bEndpointAddress 0x81 EP 1 IN
1270
+ bmAttributes 5
1271
+ Transfer Type Isochronous
1272
+ Synch Type Asynchronous
1273
+ Usage Type Data
1274
+ wMaxPacketSize 0x13fc 3x 1020 bytes
1275
+ bInterval 1
1276
+ Interface Association:
1277
+ bLength 8
1278
+ bDescriptorType 11
1279
+ bFirstInterface 2
1280
+ bInterfaceCount 2
1281
+ bFunctionClass 1 Audio
1282
+ bFunctionSubClass 2 Streaming
1283
+ bFunctionProtocol 0
1284
+ iFunction 0
1285
+ Interface Descriptor:
1286
+ bLength 9
1287
+ bDescriptorType 4
1288
+ bInterfaceNumber 2
1289
+ bAlternateSetting 0
1290
+ bNumEndpoints 0
1291
+ bInterfaceClass 1 Audio
1292
+ bInterfaceSubClass 1 Control Device
1293
+ bInterfaceProtocol 0
1294
+ iInterface 0
1295
+ AudioControl Interface Descriptor:
1296
+ bLength 9
1297
+ bDescriptorType 36
1298
+ bDescriptorSubtype 1 (HEADER)
1299
+ bcdADC 1.00
1300
+ wTotalLength 38
1301
+ bInCollection 1
1302
+ baInterfaceNr( 0) 3
1303
+ AudioControl Interface Descriptor:
1304
+ bLength 12
1305
+ bDescriptorType 36
1306
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
1307
+ bTerminalID 1
1308
+ wTerminalType 0x0201 Microphone
1309
+ bAssocTerminal 0
1310
+ bNrChannels 1
1311
+ wChannelConfig 0x0000
1312
+ iChannelNames 0
1313
+ iTerminal 0
1314
+ AudioControl Interface Descriptor:
1315
+ bLength 9
1316
+ bDescriptorType 36
1317
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
1318
+ bTerminalID 3
1319
+ wTerminalType 0x0101 USB Streaming
1320
+ bAssocTerminal 1
1321
+ bSourceID 5
1322
+ iTerminal 0
1323
+ AudioControl Interface Descriptor:
1324
+ bLength 9
1325
+ bDescriptorType 36
1326
+ bDescriptorSubtype 6 (FEATURE_UNIT)
1327
+ bUnitID 5
1328
+ bSourceID 1
1329
+ bControlSize 1
1330
+ bmaControls( 0) 0x03
1331
+ Mute
1332
+ Volume
1333
+ bmaControls( 1) 0x00
1334
+ iFeature 0
1335
+ Interface Descriptor:
1336
+ bLength 9
1337
+ bDescriptorType 4
1338
+ bInterfaceNumber 3
1339
+ bAlternateSetting 0
1340
+ bNumEndpoints 0
1341
+ bInterfaceClass 1 Audio
1342
+ bInterfaceSubClass 2 Streaming
1343
+ bInterfaceProtocol 0
1344
+ iInterface 0
1345
+ Interface Descriptor:
1346
+ bLength 9
1347
+ bDescriptorType 4
1348
+ bInterfaceNumber 3
1349
+ bAlternateSetting 1
1350
+ bNumEndpoints 1
1351
+ bInterfaceClass 1 Audio
1352
+ bInterfaceSubClass 2 Streaming
1353
+ bInterfaceProtocol 0
1354
+ iInterface 0
1355
+ AudioStreaming Interface Descriptor:
1356
+ bLength 7
1357
+ bDescriptorType 36
1358
+ bDescriptorSubtype 1 (AS_GENERAL)
1359
+ bTerminalLink 3
1360
+ bDelay 1 frames
1361
+ wFormatTag 1 PCM
1362
+ AudioStreaming Interface Descriptor:
1363
+ bLength 11
1364
+ bDescriptorType 36
1365
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1366
+ bFormatType 1 (FORMAT_TYPE_I)
1367
+ bNrChannels 1
1368
+ bSubframeSize 2
1369
+ bBitResolution 16
1370
+ bSamFreqType 1 Discrete
1371
+ tSamFreq[ 0] 16000
1372
+ Endpoint Descriptor:
1373
+ bLength 9
1374
+ bDescriptorType 5
1375
+ bEndpointAddress 0x86 EP 6 IN
1376
+ bmAttributes 5
1377
+ Transfer Type Isochronous
1378
+ Synch Type Asynchronous
1379
+ Usage Type Data
1380
+ wMaxPacketSize 0x0044 1x 68 bytes
1381
+ bInterval 4
1382
+ bRefresh 0
1383
+ bSynchAddress 0
1384
+ AudioControl Endpoint Descriptor:
1385
+ bLength 7
1386
+ bDescriptorType 37
1387
+ bDescriptorSubtype 1 (EP_GENERAL)
1388
+ bmAttributes 0x01
1389
+ Sampling Frequency
1390
+ bLockDelayUnits 0 Undefined
1391
+ wLockDelay 0 Undefined
1392
+ Interface Descriptor:
1393
+ bLength 9
1394
+ bDescriptorType 4
1395
+ bInterfaceNumber 3
1396
+ bAlternateSetting 2
1397
+ bNumEndpoints 1
1398
+ bInterfaceClass 1 Audio
1399
+ bInterfaceSubClass 2 Streaming
1400
+ bInterfaceProtocol 0
1401
+ iInterface 0
1402
+ AudioStreaming Interface Descriptor:
1403
+ bLength 7
1404
+ bDescriptorType 36
1405
+ bDescriptorSubtype 1 (AS_GENERAL)
1406
+ bTerminalLink 3
1407
+ bDelay 1 frames
1408
+ wFormatTag 1 PCM
1409
+ AudioStreaming Interface Descriptor:
1410
+ bLength 11
1411
+ bDescriptorType 36
1412
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1413
+ bFormatType 1 (FORMAT_TYPE_I)
1414
+ bNrChannels 1
1415
+ bSubframeSize 2
1416
+ bBitResolution 16
1417
+ bSamFreqType 1 Discrete
1418
+ tSamFreq[ 0] 24000
1419
+ Endpoint Descriptor:
1420
+ bLength 9
1421
+ bDescriptorType 5
1422
+ bEndpointAddress 0x86 EP 6 IN
1423
+ bmAttributes 5
1424
+ Transfer Type Isochronous
1425
+ Synch Type Asynchronous
1426
+ Usage Type Data
1427
+ wMaxPacketSize 0x0064 1x 100 bytes
1428
+ bInterval 4
1429
+ bRefresh 0
1430
+ bSynchAddress 0
1431
+ AudioControl Endpoint Descriptor:
1432
+ bLength 7
1433
+ bDescriptorType 37
1434
+ bDescriptorSubtype 1 (EP_GENERAL)
1435
+ bmAttributes 0x01
1436
+ Sampling Frequency
1437
+ bLockDelayUnits 0 Undefined
1438
+ wLockDelay 0 Undefined
1439
+ Interface Descriptor:
1440
+ bLength 9
1441
+ bDescriptorType 4
1442
+ bInterfaceNumber 3
1443
+ bAlternateSetting 3
1444
+ bNumEndpoints 1
1445
+ bInterfaceClass 1 Audio
1446
+ bInterfaceSubClass 2 Streaming
1447
+ bInterfaceProtocol 0
1448
+ iInterface 0
1449
+ AudioStreaming Interface Descriptor:
1450
+ bLength 7
1451
+ bDescriptorType 36
1452
+ bDescriptorSubtype 1 (AS_GENERAL)
1453
+ bTerminalLink 3
1454
+ bDelay 1 frames
1455
+ wFormatTag 1 PCM
1456
+ AudioStreaming Interface Descriptor:
1457
+ bLength 11
1458
+ bDescriptorType 36
1459
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1460
+ bFormatType 1 (FORMAT_TYPE_I)
1461
+ bNrChannels 1
1462
+ bSubframeSize 2
1463
+ bBitResolution 16
1464
+ bSamFreqType 1 Discrete
1465
+ tSamFreq[ 0] 32000
1466
+ Endpoint Descriptor:
1467
+ bLength 9
1468
+ bDescriptorType 5
1469
+ bEndpointAddress 0x86 EP 6 IN
1470
+ bmAttributes 5
1471
+ Transfer Type Isochronous
1472
+ Synch Type Asynchronous
1473
+ Usage Type Data
1474
+ wMaxPacketSize 0x0084 1x 132 bytes
1475
+ bInterval 4
1476
+ bRefresh 0
1477
+ bSynchAddress 0
1478
+ AudioControl Endpoint Descriptor:
1479
+ bLength 7
1480
+ bDescriptorType 37
1481
+ bDescriptorSubtype 1 (EP_GENERAL)
1482
+ bmAttributes 0x01
1483
+ Sampling Frequency
1484
+ bLockDelayUnits 0 Undefined
1485
+ wLockDelay 0 Undefined
1486
+ Interface Descriptor:
1487
+ bLength 9
1488
+ bDescriptorType 4
1489
+ bInterfaceNumber 3
1490
+ bAlternateSetting 4
1491
+ bNumEndpoints 1
1492
+ bInterfaceClass 1 Audio
1493
+ bInterfaceSubClass 2 Streaming
1494
+ bInterfaceProtocol 0
1495
+ iInterface 0
1496
+ AudioStreaming Interface Descriptor:
1497
+ bLength 7
1498
+ bDescriptorType 36
1499
+ bDescriptorSubtype 1 (AS_GENERAL)
1500
+ bTerminalLink 3
1501
+ bDelay 1 frames
1502
+ wFormatTag 1 PCM
1503
+ AudioStreaming Interface Descriptor:
1504
+ bLength 11
1505
+ bDescriptorType 36
1506
+ bDescriptorSubtype 2 (FORMAT_TYPE)
1507
+ bFormatType 1 (FORMAT_TYPE_I)
1508
+ bNrChannels 1
1509
+ bSubframeSize 2
1510
+ bBitResolution 16
1511
+ bSamFreqType 1 Discrete
1512
+ tSamFreq[ 0] 48000
1513
+ Endpoint Descriptor:
1514
+ bLength 9
1515
+ bDescriptorType 5
1516
+ bEndpointAddress 0x86 EP 6 IN
1517
+ bmAttributes 5
1518
+ Transfer Type Isochronous
1519
+ Synch Type Asynchronous
1520
+ Usage Type Data
1521
+ wMaxPacketSize 0x00c4 1x 196 bytes
1522
+ bInterval 4
1523
+ bRefresh 0
1524
+ bSynchAddress 0
1525
+ AudioControl Endpoint Descriptor:
1526
+ bLength 7
1527
+ bDescriptorType 37
1528
+ bDescriptorSubtype 1 (EP_GENERAL)
1529
+ bmAttributes 0x01
1530
+ Sampling Frequency
1531
+ bLockDelayUnits 0 Undefined
1532
+ wLockDelay 0 Undefined
1533
+ Device Qualifier (for other device speed):
1534
+ bLength 10
1535
+ bDescriptorType 6
1536
+ bcdUSB 2.00
1537
+ bDeviceClass 239 Miscellaneous Device
1538
+ bDeviceSubClass 2 ?
1539
+ bDeviceProtocol 1 Interface Association
1540
+ bMaxPacketSize0 64
1541
+ bNumConfigurations 1
1542
+ Device Status: 0x0000
1543
+ (Bus Powered)
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_builtin_ctrls.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Listing available controls for device video0:
2
+ Exposure, Auto Priority
3
+ Exposure (Absolute)
4
+ Exposure, Auto
5
+ Backlight Compensation
6
+ Sharpness
7
+ White Balance Temperature
8
+ Power Line Frequency
9
+ Gain
10
+ White Balance Temperature, Auto
11
+ Saturation
12
+ Contrast
13
+ Brightness
collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_extra_ctrls.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Listing available controls for device video0:
2
+ Raw bits per pixel
3
+ Disable video processing
4
+ LED1 Frequency
5
+ LED1 Mode
6
+ Focus
7
+ Exposure, Auto Priority
8
+ Exposure (Absolute)
9
+ Exposure, Auto
10
+ Backlight Compensation
11
+ Sharpness
12
+ White Balance Temperature
13
+ Power Line Frequency
14
+ Gain
15
+ White Balance Temperature, Auto
16
+ Saturation
17
+ Contrast
18
+ Brightness
collector/core/gripper/camera_service_src/third_party/libuvc/changelog.txt ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Changes in 0.0.7 (2023-03-31)
2
+ ----------------
3
+
4
+ New features:
5
+ - USB 3 support
6
+ - Several image/stream formats (incl. NV12, H264, BGR, RGB, P010)
7
+ - Format conversion functions
8
+ - Accept pre-opened libusb handles (used on Android)
9
+ - Library filename versioning (libuvc.0.0.7.dylib)
10
+ - Store system time upon receipt of new frame
11
+ - In-stream still-image-capture support
12
+ - Ensure successful stream parameter negotiation
13
+ - Improved build scripts
14
+ - Better logging on Android
15
+
16
+ Bug fixes:
17
+ - Many build issues
18
+ - Log spam in production builds
19
+ - A situation where libuvc could hang during shutdown
20
+ - A deadlock in get_frame()
21
+ - An issue that could cause the first frame to fail
22
+ - Incorrect settings usage in example code
23
+ - Unnecessary device reopening
24
+ - Excessive number of transfer buffers affecting Mac builds
25
+ - Freeing of transfers that may still be in progress
26
+
27
+ Changes in 0.0.6 (2017-09-21)
28
+ ----------------
29
+
30
+ New features:
31
+ - Added support for pkg-config.
32
+ - Silence pkg-config when searching for libjpeg
33
+ - Resolve pkg-config conflict, update CONF_LIBRARY #11
34
+ - Actually use pkg-config to find libjpeg, and set cflags and ldflags for it. #78
35
+ - Add a pkg-config file to allow build systems to identify the flags needed for compiling and linking against this library #77
36
+ - Add support for 16-bit greyscale image format (Y16) #77
37
+ - Add support for 8-bit raw colour formats, specifically: BA81, GRBG, GBRG, RGGB and BGGR #77
38
+ - Improve detection of The Imaging Source Cameras that implement the UVC protocols but don't announce themselves as UVC cameras (and ignore similar cameras that appear to be UVC but are not). #77
39
+ - add routine for listing frame configs #76
40
+ - New Travis configuration
41
+ - Add uvc_find_devices function to support libuvc_ros index selection #36
42
+ - VideoStreaming status processing #30
43
+ - Add conversion from YUYV to Y (GRAY8) and UV (GRAY8) #27
44
+ - Add LICENSE.txt.
45
+ - Add Dw_clock_frequency field and populate acording to UVC1.0 or 1.1 spec. #19
46
+ - Changes to enable compilation with Windows MSVC #13
47
+ - Modify ABS_FMT macro to function correctly with MSVC.
48
+ - Implement gettimeofday for MSVC.
49
+ - Use portable memset instead of bzero for MSVC compatibility.
50
+ - Annotate libusb callback methods with LIBUSB_CALL for MSVC.
51
+
52
+ - Merge of bulk mode transfer support from Tridge, Mauricio and James (#8)
53
+ - Support for BY8 frames
54
+ - (Very basic) support for UVC1.1 camera data structures
55
+ - Support for frame-based video streams
56
+ - Support for TIS astro CCD cameras
57
+ - Squashed a few possible bugs
58
+ - Added section descriptions and control getter/setter documentation
59
+
60
+ Bug fixes:
61
+ - update CMakeLists.txt
62
+ - Add missing include (for ${CMAKE_INSTALL_LIBDIR}), fix static-/shared-only build #15
63
+ - Allow both static and dynamic versions of library to be built to work more neatly when building into runtime and development packages #77
64
+
65
+ - Update device.c, reduce salience of the alert which end user perceives as more important than it actually is. #79
66
+ - Clean up transfer buffers when an error occurs #77
67
+ - Fixed the issue that camera control functions can not work well with some cameras #41
68
+ UVC specification says that low byte of wIndex (for camera control) is interface number for camera control interface but current implementation of libuvc expects it is always zero and sometimes cause trouble.
69
+ Fixed camera control issue when using uvc_get_ctrl_len/uvc_get_ctrl/uvc_set_ctrl with camera that interface number of camera control interface is not zero.
70
+ - In some (as yet unidentified) circumstances it is possible for an interface to be claimed more than once. This can cause an error. #77
71
+ - A race allows queued transfers to arrive and be viable for resubmission even when a stream is no longer running. #77
72
+ - Querying stream controls before claiming the interface can fail, so claim the interface first, then do the query. #77
73
+ - Show error code in error message to help debugging #77
74
+ - Add specific error messages for unsupported frame formats to make failures clearer #77
75
+ - Clean up compiler warnings #77
76
+ - Remove libusb.h from the public header #62
77
+ - Fix the first captured image being dropped #51
78
+ The first frame generated by any camera was always lost in the libuvc layer, and not passed on to the listening application.
79
+ The start value of seq (thus hold_seq) could be arbitrary, but it must be non-zero. Both the callback listener and the polling function's last_seq / last_polled_seq start initialised to zero, which causes any image with hold_seq zero to be ignored.
80
+ - Build fix for Chromium #48, #58
81
+ Some platforms use different version of libusb. For instance, Chromium compiles libusb by itself. So hard coding of libuse version (i.e. <libusb-1.0/libusb.h>) causes compile failure.
82
+ Remove libusb.h from the public header, This should fix the include path problems seen when including libuvc.h into other programs
83
+ - pthread_cond_timedwait nanoseconds shouldn't be greater than 1 billion #47
84
+ While using the library and testing the timed poll with 500000 us wait time, I noticed that it often happened that the timedwait returned EINVAL.
85
+ According to http://stackoverflow.com/questions/11319063/pthread-cond-timedwait-root-causes-of-einval
86
+ this might happen for several reasons, and one of them is when the number of nanoseconds in the timespec is greater than 1 billion (1 billion = 1 second).
87
+ Thus, I added a check that correctly updates the seconds and nanoseconds, bringing the nanosecond values in the range 0-999999999.
88
+ In Issue #16 it is mentioned that code sometimes crashes on uvc_stream_get_frame with some specific timeout values, this might have been the cause.
89
+ Fix for wrong setting of pthread_cond_timedwait nanoseconds
90
+ - Fix control functions for processors and other devices #32
91
+ When using a control function that is pertinent to a particular device (such as a processing device), the id of that device needs to be passed to the camera, or the call will fail
92
+ - Added docs for some more controls and switched to yaml doc file
93
+ - Updated documentation index
94
+ - Enable uvc_mjpeg2rgb function, if JPEG is supported
95
+
96
+ Changes in 0.0.5 (2014-07-19)
97
+ ----------------
98
+
99
+ New features:
100
+ - Added support for all of the camera terminal and processing unit controls, including the controls
101
+ that appeared in UVC 1.1 and 1.5.
102
+ - Added LIBUVC_VERSION_GTE(major, minor, patch) macro.
103
+
104
+ Bug fixes:
105
+ - Switching to explicit kernel driver detachment since auto_detach isn't available in libusb < 1.0.16.
106
+ - The cmake module now looks for libuvc.dylib instead of libuvc.so on OS X.
107
+
108
+
109
+ Changes in 0.0.4 (2014-06-26)
110
+ ----------------
111
+
112
+ New features:
113
+ - Support devices with multiple streaming interfaces and multiple concurrent streams.
114
+ A new uvc_stream* API is added, along with a uvc_stream_handle type to encapsulate the
115
+ state of a single UVC stream. Multiple streams can run alongside each other, provided
116
+ your USB connection has enough bandwidth. Streams can be individually stopped and
117
+ resumed; the old uvc_start/stop_streaming API is still provided as a convenient way
118
+ to interact with the usual one-stream devices.
119
+ - Added support for MJPEG streams.
120
+ - Added functions for checking/setting autofocus mode.
121
+ - Added an interface to set/get arbitrary controls on units and terminals.
122
+ - Made the input, output, processing and extension units public.
123
+ - Implemented uvc_get_device and uvc_get_libusb_handle.
124
+ - Add a library-owned flag to uvc_frame_t so that users may allocate their own frame buffers.
125
+
126
+ Bug fixes:
127
+ - Send frames as soon as they're received, not when the following frame arrives
128
+ - Fixed call to NULL when no status callback is provided.
129
+ - Fixed crash that occurred during shutdown if the USB device was disconnected during streaming.
130
+
131
+ Miscellaneous improvements:
132
+ - Hid the transfer method (isochronous vs bulk) from the user. This was never really
133
+ selectable; the camera's streaming interface supports either bulk or isochronous
134
+ transfers, so now libuvc will figure out which one is appropriate. The `isochronous`
135
+ parameter has been converted to a `flags` parameter, which is currently unused but
136
+ could be used to convey up to 7 bits of stream mode information in the future.
137
+ - Improved the method for claiming the camera's interfaces.
138
+ - Renamed UVC_COLOR_FORMAT_* to UVC_FRAME_FORMAT_*. The old #defines are still available.
139
+ - Simplified format definition and lookup.
140
+ - Improved transfer status (error) handling.
collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindJpegPkg.cmake ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #[==============================================[
2
+ FindJpegPkg
3
+ -----------
4
+
5
+ Searching jpeg library library and creating imported
6
+ target JPEG::JPEG (this is different from shipped one with CMake)
7
+
8
+ #]==============================================]
9
+
10
+ # TODO Append parts for Version compasion and REQUIRED support
11
+ if (MSVC OR MINGW)
12
+ return()
13
+ endif()
14
+
15
+ # Try to find JPEG using a module or pkg-config. If that doesn't work, search for the header.
16
+ if (NOT TARGET JPEG::JPEG)
17
+ find_package(JPEG)
18
+ if (JPEG_FOUND)
19
+ message(STATUS "Found JPEG library using standard module")
20
+ set(IMPORTED_JPEG_INCLUDE_DIRS ${JPEG_INCLUDE_DIR})
21
+ set(IMPORTED_JPEG_LIBRARIES ${JPEG_LIBRARIES})
22
+ else()
23
+ find_package(PkgConfig)
24
+ pkg_check_modules(JPEG libjpeg)
25
+ if(JPEG_FOUND)
26
+ message(STATUS "JPEG found by pkgconfig")
27
+
28
+ if (DEFINED JPEG_INCLUDE_DIRS)
29
+ set(IMPORTED_JPEG_INCLUDE_DIRS ${JPEG_INCLUDE_DIRS})
30
+ endif()
31
+
32
+ if(JPEG_LIBRARIES)
33
+ find_library(JPEG_LIBRARY
34
+ NAMES ${JPEG_LIBRARIES}
35
+ PATHS ${JPEG_LIBDIR} ${JPEG_LIBRARY_DIRS}
36
+ )
37
+ if(JPEG_LIBRARY)
38
+ set(IMPORTED_JPEG_LIBRARIES ${JPEG_LIBRARY})
39
+ else()
40
+ message(WARNING "Could not found libjpeg library file")
41
+ endif()
42
+ endif()
43
+ else()
44
+ message(STATUS "Searching library manually")
45
+ find_path(IMPORTED_JPEG_INCLUDE_DIRS
46
+ NAMES jpeglib.h
47
+ )
48
+
49
+ if (NOT IMPORTED_JPEG_LIBRARIES)
50
+ find_library(IMPORTED_JPEG_LIBRARIES
51
+ NAMES jpeg
52
+ )
53
+ endif()
54
+ endif()
55
+ endif()
56
+
57
+ include(FindPackageHandleStandardArgs)
58
+ find_package_handle_standard_args(JPEG
59
+ REQUIRED_VARS IMPORTED_JPEG_LIBRARIES IMPORTED_JPEG_INCLUDE_DIRS
60
+ )
61
+
62
+ if(JPEG_FOUND)
63
+ set(JpegPkg_FOUND TRUE)
64
+ if (NOT TARGET JPEG::JPEG)
65
+ add_library(JPEG::JPEG
66
+ UNKNOWN IMPORTED
67
+ )
68
+ if(IMPORTED_JPEG_INCLUDE_DIRS)
69
+ set_target_properties(JPEG::JPEG PROPERTIES
70
+ INTERFACE_INCLUDE_DIRECTORIES ${IMPORTED_JPEG_INCLUDE_DIRS}
71
+ )
72
+ endif()
73
+ if(IMPORTED_JPEG_LIBRARIES)
74
+ set_target_properties(JPEG::JPEG PROPERTIES
75
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
76
+ IMPORTED_LOCATION ${IMPORTED_JPEG_LIBRARIES}
77
+ )
78
+ endif()
79
+ endif()
80
+ endif()
81
+
82
+ endif()
collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindLibUSB.cmake ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #[==============================================[
2
+ FindLibUSB
3
+ -----------
4
+
5
+ Searching libusb-1.0 library and creating imported
6
+ target LibUSB::LibUSB
7
+
8
+ #]==============================================]
9
+
10
+ # TODO Append parts for Version compasion and REQUIRED support
11
+
12
+ if (MSVC OR MINGW)
13
+ return()
14
+ endif()
15
+
16
+ if (NOT TARGET LibUSB::LibUSB)
17
+ find_package(PkgConfig)
18
+ pkg_check_modules(LibUSB REQUIRED
19
+ libusb-1.0
20
+ )
21
+
22
+ if(LibUSB_FOUND)
23
+ message(STATUS "libusb-1.0 found using pkgconfig")
24
+
25
+ add_library(LibUSB::LibUSB
26
+ UNKNOWN IMPORTED
27
+ )
28
+ if (DEFINED LibUSB_INCLUDE_DIRS AND NOT LibUSB_INCLUDE_DIRS STREQUAL "")
29
+ set_target_properties(LibUSB::LibUSB PROPERTIES
30
+ INTERFACE_INCLUDE_DIRECTORIES ${LibUSB_INCLUDE_DIRS}
31
+ )
32
+ endif()
33
+
34
+ if(LibUSB_LIBRARIES)
35
+ find_library(LibUSB_LIBRARY
36
+ NAMES ${LibUSB_LIBRARIES}
37
+ PATHS ${LibUSB_LIBDIR} ${LibUSB_LIBRARY_DIRS}
38
+ )
39
+ if(LibUSB_LIBRARY)
40
+ set_target_properties(LibUSB::LibUSB PROPERTIES
41
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
42
+ IMPORTED_LOCATION ${LibUSB_LIBRARY}
43
+ )
44
+ else()
45
+ message(WARNING "Could not found libusb-1.0 library file")
46
+ endif()
47
+ endif()
48
+ endif()
49
+ else()
50
+ message(WARNING "libusb-1.0 could not be found using pkgconfig")
51
+ endif()
collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindOpenCVPkg.cmake ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #[==============================================[
2
+ FindOpenCVPkg
3
+ -----------
4
+
5
+ Searching OpenCV components on systems which does not have fully installed OpenCV.
6
+ Such systems does not include OpenCVConfig.cmake and OpenCVConfigVersion.cmake files.
7
+ Example of such system is Ubuntu 18.04.
8
+ This package try to use OpenCV config file first if it exists.
9
+
10
+ #]==============================================]
11
+
12
+ if (${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS)
13
+ set(comps ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS})
14
+ else()
15
+ set(comps)
16
+ endif()
17
+
18
+ list(LENGTH comps comps_count)
19
+ message(STATUS "Components requested: ${comps}")
20
+
21
+ # Try to find components using standard OpenCV config package
22
+ if(comps_count GREATER 0)
23
+ find_package(OpenCV QUIET
24
+ COMPONENTS ${comps}
25
+ )
26
+ if(OpenCV_FOUND)
27
+ set(OpenCVPkg_FOUND TRUE)
28
+ return()
29
+ endif()
30
+ else()
31
+ find_package(OpenCV QUIET)
32
+ if(OpenCV_FOUND)
33
+ set(OpenCVPkg_FOUND TRUE)
34
+ return()
35
+ endif()
36
+ endif()
37
+
38
+ if(comps_count EQUAL 0)
39
+ set(err_level)
40
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
41
+ set(err_level FATAL_ERROR)
42
+ endif()
43
+ if (${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
44
+ set(err_level STATUS)
45
+ endif()
46
+ message(${err_level} "Without standart OpenCV config file you must list components you want")
47
+ return()
48
+ endif()
49
+
50
+ unset(required_comps_not_found)
51
+ foreach(comp IN LISTS comps)
52
+ string(REPLACE "opencv_" "" comp_name ${comp})
53
+ set(include_rel_path "opencv2/${comp_name}.hpp" "opencv2/${comp_name}/${comp_name}.hpp")
54
+ find_path(OpenCV_${comp}_INCLUDE_DIR
55
+ NAMES ${include_rel_path}
56
+ )
57
+ find_library(OpenCV_${comp}_LIBRARY
58
+ NAMES ${comp}
59
+ )
60
+ if (${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${comp} AND
61
+ (NOT OpenCV_${comp}_INCLUDE_DIR OR NOT OpenCV_${comp}_LIBRARY))
62
+ list(APPEND required_comps_not_found ${comp})
63
+ else()
64
+ message(STATUS "Found component ${comp}: ${OpenCV_${comp}_LIBRARY}")
65
+ endif()
66
+ endforeach()
67
+
68
+ if(required_comps_not_found)
69
+ message(FATAL_ERROR "Following required components not found: ${required_comps_not_found}")
70
+ return()
71
+ endif()
72
+
73
+ foreach(comp IN LISTS comps)
74
+ if(NOT TARGET ${comp})
75
+ message(STATUS "No target ${comp} yet. Creating it")
76
+ add_library(${comp}
77
+ UNKNOWN IMPORTED
78
+ )
79
+ set_target_properties(${comp} PROPERTIES
80
+ INTERFACE_INCLUDE_DIRECTORIES ${OpenCV_${comp}_INCLUDE_DIR}
81
+ IMPORTED_LOCATION ${OpenCV_${comp}_LIBRARY}
82
+ )
83
+ endif()
84
+ endforeach()
85
+
86
+ set(OpenCVPkg_FOUND TRUE)
collector/core/gripper/camera_service_src/third_party/libuvc/doxygen.conf ADDED
The diff for this file is too large to render. See raw diff
 
collector/core/gripper/camera_service_src/third_party/libuvc/include/libuvc/libuvc.h ADDED
@@ -0,0 +1,833 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef LIBUVC_H
2
+ #define LIBUVC_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ #include <stdio.h> // FILE
9
+ #include <stdint.h>
10
+ #include <sys/time.h>
11
+ #include <libuvc/libuvc_config.h>
12
+
13
+ struct libusb_context;
14
+ struct libusb_device_handle;
15
+
16
+ /** UVC error types, based on libusb errors
17
+ * @ingroup diag
18
+ */
19
+ typedef enum uvc_error {
20
+ /** Success (no error) */
21
+ UVC_SUCCESS = 0,
22
+ /** Input/output error */
23
+ UVC_ERROR_IO = -1,
24
+ /** Invalid parameter */
25
+ UVC_ERROR_INVALID_PARAM = -2,
26
+ /** Access denied */
27
+ UVC_ERROR_ACCESS = -3,
28
+ /** No such device */
29
+ UVC_ERROR_NO_DEVICE = -4,
30
+ /** Entity not found */
31
+ UVC_ERROR_NOT_FOUND = -5,
32
+ /** Resource busy */
33
+ UVC_ERROR_BUSY = -6,
34
+ /** Operation timed out */
35
+ UVC_ERROR_TIMEOUT = -7,
36
+ /** Overflow */
37
+ UVC_ERROR_OVERFLOW = -8,
38
+ /** Pipe error */
39
+ UVC_ERROR_PIPE = -9,
40
+ /** System call interrupted */
41
+ UVC_ERROR_INTERRUPTED = -10,
42
+ /** Insufficient memory */
43
+ UVC_ERROR_NO_MEM = -11,
44
+ /** Operation not supported */
45
+ UVC_ERROR_NOT_SUPPORTED = -12,
46
+ /** Device is not UVC-compliant */
47
+ UVC_ERROR_INVALID_DEVICE = -50,
48
+ /** Mode not supported */
49
+ UVC_ERROR_INVALID_MODE = -51,
50
+ /** Resource has a callback (can't use polling and async) */
51
+ UVC_ERROR_CALLBACK_EXISTS = -52,
52
+ /** Undefined error */
53
+ UVC_ERROR_OTHER = -99
54
+ } uvc_error_t;
55
+
56
+ /** Color coding of stream, transport-independent
57
+ * @ingroup streaming
58
+ */
59
+ enum uvc_frame_format {
60
+ UVC_FRAME_FORMAT_UNKNOWN = 0,
61
+ /** Any supported format */
62
+ UVC_FRAME_FORMAT_ANY = 0,
63
+ UVC_FRAME_FORMAT_UNCOMPRESSED,
64
+ UVC_FRAME_FORMAT_COMPRESSED,
65
+ /** YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and
66
+ * one UV (chrominance) pair for every two pixels.
67
+ */
68
+ UVC_FRAME_FORMAT_YUYV,
69
+ UVC_FRAME_FORMAT_UYVY,
70
+ /** 24-bit RGB */
71
+ UVC_FRAME_FORMAT_RGB,
72
+ UVC_FRAME_FORMAT_BGR,
73
+ /** Motion-JPEG (or JPEG) encoded images */
74
+ UVC_FRAME_FORMAT_MJPEG,
75
+ UVC_FRAME_FORMAT_H264,
76
+ /** Greyscale images */
77
+ UVC_FRAME_FORMAT_GRAY8,
78
+ UVC_FRAME_FORMAT_GRAY16,
79
+ /* Raw colour mosaic images */
80
+ UVC_FRAME_FORMAT_BY8,
81
+ UVC_FRAME_FORMAT_BA81,
82
+ UVC_FRAME_FORMAT_SGRBG8,
83
+ UVC_FRAME_FORMAT_SGBRG8,
84
+ UVC_FRAME_FORMAT_SRGGB8,
85
+ UVC_FRAME_FORMAT_SBGGR8,
86
+ /** YUV420: NV12 */
87
+ UVC_FRAME_FORMAT_NV12,
88
+ /** YUV: P010 */
89
+ UVC_FRAME_FORMAT_P010,
90
+ /** Number of formats understood */
91
+ UVC_FRAME_FORMAT_COUNT,
92
+ };
93
+
94
+ /* UVC_COLOR_FORMAT_* have been replaced with UVC_FRAME_FORMAT_*. Please use
95
+ * UVC_FRAME_FORMAT_* instead of using these. */
96
+ #define UVC_COLOR_FORMAT_UNKNOWN UVC_FRAME_FORMAT_UNKNOWN
97
+ #define UVC_COLOR_FORMAT_UNCOMPRESSED UVC_FRAME_FORMAT_UNCOMPRESSED
98
+ #define UVC_COLOR_FORMAT_COMPRESSED UVC_FRAME_FORMAT_COMPRESSED
99
+ #define UVC_COLOR_FORMAT_YUYV UVC_FRAME_FORMAT_YUYV
100
+ #define UVC_COLOR_FORMAT_UYVY UVC_FRAME_FORMAT_UYVY
101
+ #define UVC_COLOR_FORMAT_RGB UVC_FRAME_FORMAT_RGB
102
+ #define UVC_COLOR_FORMAT_BGR UVC_FRAME_FORMAT_BGR
103
+ #define UVC_COLOR_FORMAT_MJPEG UVC_FRAME_FORMAT_MJPEG
104
+ #define UVC_COLOR_FORMAT_GRAY8 UVC_FRAME_FORMAT_GRAY8
105
+ #define UVC_COLOR_FORMAT_GRAY16 UVC_FRAME_FORMAT_GRAY16
106
+ #define UVC_COLOR_FORMAT_NV12 UVC_FRAME_FORMAT_NV12
107
+
108
+ /** VideoStreaming interface descriptor subtype (A.6) */
109
+ enum uvc_vs_desc_subtype {
110
+ UVC_VS_UNDEFINED = 0x00,
111
+ UVC_VS_INPUT_HEADER = 0x01,
112
+ UVC_VS_OUTPUT_HEADER = 0x02,
113
+ UVC_VS_STILL_IMAGE_FRAME = 0x03,
114
+ UVC_VS_FORMAT_UNCOMPRESSED = 0x04,
115
+ UVC_VS_FRAME_UNCOMPRESSED = 0x05,
116
+ UVC_VS_FORMAT_MJPEG = 0x06,
117
+ UVC_VS_FRAME_MJPEG = 0x07,
118
+ UVC_VS_FORMAT_MPEG2TS = 0x0a,
119
+ UVC_VS_FORMAT_DV = 0x0c,
120
+ UVC_VS_COLORFORMAT = 0x0d,
121
+ UVC_VS_FORMAT_FRAME_BASED = 0x10,
122
+ UVC_VS_FRAME_FRAME_BASED = 0x11,
123
+ UVC_VS_FORMAT_STREAM_BASED = 0x12
124
+ };
125
+
126
+ struct uvc_format_desc;
127
+ struct uvc_frame_desc;
128
+
129
+ typedef struct uvc_still_frame_res {
130
+ struct uvc_still_frame_res *prev, *next;
131
+ uint8_t bResolutionIndex;
132
+ /** Image width */
133
+ uint16_t wWidth;
134
+ /** Image height */
135
+ uint16_t wHeight;
136
+ } uvc_still_frame_res_t;
137
+
138
+ typedef struct uvc_still_frame_desc {
139
+ struct uvc_format_desc *parent;
140
+ struct uvc_still_frame_desc *prev, *next;
141
+ /** Type of frame, such as JPEG frame or uncompressed frme */
142
+ enum uvc_vs_desc_subtype bDescriptorSubtype;
143
+ /** Index of the frame within the list of specs available for this format */
144
+ uint8_t bEndPointAddress;
145
+ uvc_still_frame_res_t* imageSizePatterns;
146
+ uint8_t bNumCompressionPattern;
147
+ /* indication of compression level, the higher, the more compression is applied to image */
148
+ uint8_t* bCompression;
149
+ } uvc_still_frame_desc_t;
150
+
151
+ /** Frame descriptor
152
+ *
153
+ * A "frame" is a configuration of a streaming format
154
+ * for a particular image size at one of possibly several
155
+ * available frame rates.
156
+ */
157
+ typedef struct uvc_frame_desc {
158
+ struct uvc_format_desc *parent;
159
+ struct uvc_frame_desc *prev, *next;
160
+ /** Type of frame, such as JPEG frame or uncompressed frme */
161
+ enum uvc_vs_desc_subtype bDescriptorSubtype;
162
+ /** Index of the frame within the list of specs available for this format */
163
+ uint8_t bFrameIndex;
164
+ uint8_t bmCapabilities;
165
+ /** Image width */
166
+ uint16_t wWidth;
167
+ /** Image height */
168
+ uint16_t wHeight;
169
+ /** Bitrate of corresponding stream at minimal frame rate */
170
+ uint32_t dwMinBitRate;
171
+ /** Bitrate of corresponding stream at maximal frame rate */
172
+ uint32_t dwMaxBitRate;
173
+ /** Maximum number of bytes for a video frame */
174
+ uint32_t dwMaxVideoFrameBufferSize;
175
+ /** Default frame interval (in 100ns units) */
176
+ uint32_t dwDefaultFrameInterval;
177
+ /** Minimum frame interval for continuous mode (100ns units) */
178
+ uint32_t dwMinFrameInterval;
179
+ /** Maximum frame interval for continuous mode (100ns units) */
180
+ uint32_t dwMaxFrameInterval;
181
+ /** Granularity of frame interval range for continuous mode (100ns) */
182
+ uint32_t dwFrameIntervalStep;
183
+ /** Frame intervals */
184
+ uint8_t bFrameIntervalType;
185
+ /** number of bytes per line */
186
+ uint32_t dwBytesPerLine;
187
+ /** Available frame rates, zero-terminated (in 100ns units) */
188
+ uint32_t *intervals;
189
+ } uvc_frame_desc_t;
190
+
191
+ /** Format descriptor
192
+ *
193
+ * A "format" determines a stream's image type (e.g., raw YUYV or JPEG)
194
+ * and includes many "frame" configurations.
195
+ */
196
+ typedef struct uvc_format_desc {
197
+ struct uvc_streaming_interface *parent;
198
+ struct uvc_format_desc *prev, *next;
199
+ /** Type of image stream, such as JPEG or uncompressed. */
200
+ enum uvc_vs_desc_subtype bDescriptorSubtype;
201
+ /** Identifier of this format within the VS interface's format list */
202
+ uint8_t bFormatIndex;
203
+ uint8_t bNumFrameDescriptors;
204
+ /** Format specifier */
205
+ union {
206
+ uint8_t guidFormat[16];
207
+ uint8_t fourccFormat[4];
208
+ };
209
+ /** Format-specific data */
210
+ union {
211
+ /** BPP for uncompressed stream */
212
+ uint8_t bBitsPerPixel;
213
+ /** Flags for JPEG stream */
214
+ uint8_t bmFlags;
215
+ };
216
+ /** Default {uvc_frame_desc} to choose given this format */
217
+ uint8_t bDefaultFrameIndex;
218
+ uint8_t bAspectRatioX;
219
+ uint8_t bAspectRatioY;
220
+ uint8_t bmInterlaceFlags;
221
+ uint8_t bCopyProtect;
222
+ uint8_t bVariableSize;
223
+ /** Available frame specifications for this format */
224
+ struct uvc_frame_desc *frame_descs;
225
+ struct uvc_still_frame_desc *still_frame_desc;
226
+ } uvc_format_desc_t;
227
+
228
+ /** UVC request code (A.8) */
229
+ enum uvc_req_code {
230
+ UVC_RC_UNDEFINED = 0x00,
231
+ UVC_SET_CUR = 0x01,
232
+ UVC_GET_CUR = 0x81,
233
+ UVC_GET_MIN = 0x82,
234
+ UVC_GET_MAX = 0x83,
235
+ UVC_GET_RES = 0x84,
236
+ UVC_GET_LEN = 0x85,
237
+ UVC_GET_INFO = 0x86,
238
+ UVC_GET_DEF = 0x87
239
+ };
240
+
241
+ enum uvc_device_power_mode {
242
+ UVC_VC_VIDEO_POWER_MODE_FULL = 0x000b,
243
+ UVC_VC_VIDEO_POWER_MODE_DEVICE_DEPENDENT = 0x001b,
244
+ };
245
+
246
+ /** Camera terminal control selector (A.9.4) */
247
+ enum uvc_ct_ctrl_selector {
248
+ UVC_CT_CONTROL_UNDEFINED = 0x00,
249
+ UVC_CT_SCANNING_MODE_CONTROL = 0x01,
250
+ UVC_CT_AE_MODE_CONTROL = 0x02,
251
+ UVC_CT_AE_PRIORITY_CONTROL = 0x03,
252
+ UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL = 0x04,
253
+ UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL = 0x05,
254
+ UVC_CT_FOCUS_ABSOLUTE_CONTROL = 0x06,
255
+ UVC_CT_FOCUS_RELATIVE_CONTROL = 0x07,
256
+ UVC_CT_FOCUS_AUTO_CONTROL = 0x08,
257
+ UVC_CT_IRIS_ABSOLUTE_CONTROL = 0x09,
258
+ UVC_CT_IRIS_RELATIVE_CONTROL = 0x0a,
259
+ UVC_CT_ZOOM_ABSOLUTE_CONTROL = 0x0b,
260
+ UVC_CT_ZOOM_RELATIVE_CONTROL = 0x0c,
261
+ UVC_CT_PANTILT_ABSOLUTE_CONTROL = 0x0d,
262
+ UVC_CT_PANTILT_RELATIVE_CONTROL = 0x0e,
263
+ UVC_CT_ROLL_ABSOLUTE_CONTROL = 0x0f,
264
+ UVC_CT_ROLL_RELATIVE_CONTROL = 0x10,
265
+ UVC_CT_PRIVACY_CONTROL = 0x11,
266
+ UVC_CT_FOCUS_SIMPLE_CONTROL = 0x12,
267
+ UVC_CT_DIGITAL_WINDOW_CONTROL = 0x13,
268
+ UVC_CT_REGION_OF_INTEREST_CONTROL = 0x14
269
+ };
270
+
271
+ /** Processing unit control selector (A.9.5) */
272
+ enum uvc_pu_ctrl_selector {
273
+ UVC_PU_CONTROL_UNDEFINED = 0x00,
274
+ UVC_PU_BACKLIGHT_COMPENSATION_CONTROL = 0x01,
275
+ UVC_PU_BRIGHTNESS_CONTROL = 0x02,
276
+ UVC_PU_CONTRAST_CONTROL = 0x03,
277
+ UVC_PU_GAIN_CONTROL = 0x04,
278
+ UVC_PU_POWER_LINE_FREQUENCY_CONTROL = 0x05,
279
+ UVC_PU_HUE_CONTROL = 0x06,
280
+ UVC_PU_SATURATION_CONTROL = 0x07,
281
+ UVC_PU_SHARPNESS_CONTROL = 0x08,
282
+ UVC_PU_GAMMA_CONTROL = 0x09,
283
+ UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL = 0x0a,
284
+ UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL = 0x0b,
285
+ UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL = 0x0c,
286
+ UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL = 0x0d,
287
+ UVC_PU_DIGITAL_MULTIPLIER_CONTROL = 0x0e,
288
+ UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL = 0x0f,
289
+ UVC_PU_HUE_AUTO_CONTROL = 0x10,
290
+ UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL = 0x11,
291
+ UVC_PU_ANALOG_LOCK_STATUS_CONTROL = 0x12,
292
+ UVC_PU_CONTRAST_AUTO_CONTROL = 0x13
293
+ };
294
+
295
+ /** USB terminal type (B.1) */
296
+ enum uvc_term_type {
297
+ UVC_TT_VENDOR_SPECIFIC = 0x0100,
298
+ UVC_TT_STREAMING = 0x0101
299
+ };
300
+
301
+ /** Input terminal type (B.2) */
302
+ enum uvc_it_type {
303
+ UVC_ITT_VENDOR_SPECIFIC = 0x0200,
304
+ UVC_ITT_CAMERA = 0x0201,
305
+ UVC_ITT_MEDIA_TRANSPORT_INPUT = 0x0202
306
+ };
307
+
308
+ /** Output terminal type (B.3) */
309
+ enum uvc_ot_type {
310
+ UVC_OTT_VENDOR_SPECIFIC = 0x0300,
311
+ UVC_OTT_DISPLAY = 0x0301,
312
+ UVC_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302
313
+ };
314
+
315
+ /** External terminal type (B.4) */
316
+ enum uvc_et_type {
317
+ UVC_EXTERNAL_VENDOR_SPECIFIC = 0x0400,
318
+ UVC_COMPOSITE_CONNECTOR = 0x0401,
319
+ UVC_SVIDEO_CONNECTOR = 0x0402,
320
+ UVC_COMPONENT_CONNECTOR = 0x0403
321
+ };
322
+
323
+ /** Context, equivalent to libusb's contexts.
324
+ *
325
+ * May either own a libusb context or use one that's already made.
326
+ *
327
+ * Always create these with uvc_get_context.
328
+ */
329
+ struct uvc_context;
330
+ typedef struct uvc_context uvc_context_t;
331
+
332
+ /** UVC device.
333
+ *
334
+ * Get this from uvc_get_device_list() or uvc_find_device().
335
+ */
336
+ struct uvc_device;
337
+ typedef struct uvc_device uvc_device_t;
338
+
339
+ /** Handle on an open UVC device.
340
+ *
341
+ * Get one of these from uvc_open(). Once you uvc_close()
342
+ * it, it's no longer valid.
343
+ */
344
+ struct uvc_device_handle;
345
+ typedef struct uvc_device_handle uvc_device_handle_t;
346
+
347
+ /** Handle on an open UVC stream.
348
+ *
349
+ * Get one of these from uvc_stream_open*().
350
+ * Once you uvc_stream_close() it, it will no longer be valid.
351
+ */
352
+ struct uvc_stream_handle;
353
+ typedef struct uvc_stream_handle uvc_stream_handle_t;
354
+
355
+ /** Representation of the interface that brings data into the UVC device */
356
+ typedef struct uvc_input_terminal {
357
+ struct uvc_input_terminal *prev, *next;
358
+ /** Index of the terminal within the device */
359
+ uint8_t bTerminalID;
360
+ /** Type of terminal (e.g., camera) */
361
+ enum uvc_it_type wTerminalType;
362
+ uint16_t wObjectiveFocalLengthMin;
363
+ uint16_t wObjectiveFocalLengthMax;
364
+ uint16_t wOcularFocalLength;
365
+ /** Camera controls (meaning of bits given in {uvc_ct_ctrl_selector}) */
366
+ uint64_t bmControls;
367
+ } uvc_input_terminal_t;
368
+
369
+ typedef struct uvc_output_terminal {
370
+ struct uvc_output_terminal *prev, *next;
371
+ /** @todo */
372
+ } uvc_output_terminal_t;
373
+
374
+ /** Represents post-capture processing functions */
375
+ typedef struct uvc_processing_unit {
376
+ struct uvc_processing_unit *prev, *next;
377
+ /** Index of the processing unit within the device */
378
+ uint8_t bUnitID;
379
+ /** Index of the terminal from which the device accepts images */
380
+ uint8_t bSourceID;
381
+ /** Processing controls (meaning of bits given in {uvc_pu_ctrl_selector}) */
382
+ uint64_t bmControls;
383
+ } uvc_processing_unit_t;
384
+
385
+ /** Represents selector unit to connect other units */
386
+ typedef struct uvc_selector_unit {
387
+ struct uvc_selector_unit *prev, *next;
388
+ /** Index of the selector unit within the device */
389
+ uint8_t bUnitID;
390
+ } uvc_selector_unit_t;
391
+
392
+ /** Custom processing or camera-control functions */
393
+ typedef struct uvc_extension_unit {
394
+ struct uvc_extension_unit *prev, *next;
395
+ /** Index of the extension unit within the device */
396
+ uint8_t bUnitID;
397
+ /** GUID identifying the extension unit */
398
+ uint8_t guidExtensionCode[16];
399
+ /** Bitmap of available controls (manufacturer-dependent) */
400
+ uint64_t bmControls;
401
+ } uvc_extension_unit_t;
402
+
403
+ enum uvc_status_class {
404
+ UVC_STATUS_CLASS_CONTROL = 0x10,
405
+ UVC_STATUS_CLASS_CONTROL_CAMERA = 0x11,
406
+ UVC_STATUS_CLASS_CONTROL_PROCESSING = 0x12,
407
+ };
408
+
409
+ enum uvc_status_attribute {
410
+ UVC_STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00,
411
+ UVC_STATUS_ATTRIBUTE_INFO_CHANGE = 0x01,
412
+ UVC_STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02,
413
+ UVC_STATUS_ATTRIBUTE_UNKNOWN = 0xff
414
+ };
415
+
416
+ /** A callback function to accept status updates
417
+ * @ingroup device
418
+ */
419
+ typedef void(uvc_status_callback_t)(enum uvc_status_class status_class,
420
+ int event,
421
+ int selector,
422
+ enum uvc_status_attribute status_attribute,
423
+ void *data, size_t data_len,
424
+ void *user_ptr);
425
+
426
+ /** A callback function to accept button events
427
+ * @ingroup device
428
+ */
429
+ typedef void(uvc_button_callback_t)(int button,
430
+ int state,
431
+ void *user_ptr);
432
+
433
+ /** Structure representing a UVC device descriptor.
434
+ *
435
+ * (This isn't a standard structure.)
436
+ */
437
+ typedef struct uvc_device_descriptor {
438
+ /** Vendor ID */
439
+ uint16_t idVendor;
440
+ /** Product ID */
441
+ uint16_t idProduct;
442
+ /** UVC compliance level, e.g. 0x0100 (1.0), 0x0110 */
443
+ uint16_t bcdUVC;
444
+ /** Serial number (null if unavailable) */
445
+ const char *serialNumber;
446
+ /** Device-reported manufacturer name (or null) */
447
+ const char *manufacturer;
448
+ /** Device-reporter product name (or null) */
449
+ const char *product;
450
+ } uvc_device_descriptor_t;
451
+
452
+ /** An image frame received from the UVC device
453
+ * @ingroup streaming
454
+ */
455
+ typedef struct uvc_frame {
456
+ /** Image data for this frame */
457
+ void *data;
458
+ /** Size of image data buffer */
459
+ size_t data_bytes;
460
+ /** Width of image in pixels */
461
+ uint32_t width;
462
+ /** Height of image in pixels */
463
+ uint32_t height;
464
+ /** Pixel data format */
465
+ enum uvc_frame_format frame_format;
466
+ /** Number of bytes per horizontal line (undefined for compressed format) */
467
+ size_t step;
468
+ /** Frame number (may skip, but is strictly monotonically increasing) */
469
+ uint32_t sequence;
470
+ /** Estimate of system time when the device started capturing the image */
471
+ struct timeval capture_time;
472
+ /** Estimate of system time when the device finished receiving the image */
473
+ struct timespec capture_time_finished;
474
+ /** Handle on the device that produced the image.
475
+ * @warning You must not call any uvc_* functions during a callback. */
476
+ uvc_device_handle_t *source;
477
+ /** Is the data buffer owned by the library?
478
+ * If 1, the data buffer can be arbitrarily reallocated by frame conversion
479
+ * functions.
480
+ * If 0, the data buffer will not be reallocated or freed by the library.
481
+ * Set this field to zero if you are supplying the buffer.
482
+ */
483
+ uint8_t library_owns_data;
484
+ /** Metadata for this frame if available */
485
+ void *metadata;
486
+ /** Size of metadata buffer */
487
+ size_t metadata_bytes;
488
+ } uvc_frame_t;
489
+
490
+ /** A callback function to handle incoming assembled UVC frames
491
+ * @ingroup streaming
492
+ */
493
+ typedef void(uvc_frame_callback_t)(struct uvc_frame *frame, void *user_ptr);
494
+
495
+ /** Streaming mode, includes all information needed to select stream
496
+ * @ingroup streaming
497
+ */
498
+ typedef struct uvc_stream_ctrl {
499
+ uint16_t bmHint;
500
+ uint8_t bFormatIndex;
501
+ uint8_t bFrameIndex;
502
+ uint32_t dwFrameInterval;
503
+ uint16_t wKeyFrameRate;
504
+ uint16_t wPFrameRate;
505
+ uint16_t wCompQuality;
506
+ uint16_t wCompWindowSize;
507
+ uint16_t wDelay;
508
+ uint32_t dwMaxVideoFrameSize;
509
+ uint32_t dwMaxPayloadTransferSize;
510
+ uint32_t dwClockFrequency;
511
+ uint8_t bmFramingInfo;
512
+ uint8_t bPreferredVersion;
513
+ uint8_t bMinVersion;
514
+ uint8_t bMaxVersion;
515
+ uint8_t bInterfaceNumber;
516
+ } uvc_stream_ctrl_t;
517
+
518
+ typedef struct uvc_still_ctrl {
519
+ /* Video format index from a format descriptor */
520
+ uint8_t bFormatIndex;
521
+ /* Video frame index from a frame descriptor */
522
+ uint8_t bFrameIndex;
523
+ /* Compression index from a frame descriptor */
524
+ uint8_t bCompressionIndex;
525
+ /* Maximum still image size in bytes. */
526
+ uint32_t dwMaxVideoFrameSize;
527
+ /* Maximum number of byte per payload*/
528
+ uint32_t dwMaxPayloadTransferSize;
529
+ uint8_t bInterfaceNumber;
530
+ } uvc_still_ctrl_t;
531
+
532
+ uvc_error_t uvc_init(uvc_context_t **ctx, struct libusb_context *usb_ctx);
533
+ void uvc_exit(uvc_context_t *ctx);
534
+
535
+ uvc_error_t uvc_get_device_list(
536
+ uvc_context_t *ctx,
537
+ uvc_device_t ***list);
538
+ void uvc_free_device_list(uvc_device_t **list, uint8_t unref_devices);
539
+
540
+ uvc_error_t uvc_get_device_descriptor(
541
+ uvc_device_t *dev,
542
+ uvc_device_descriptor_t **desc);
543
+ void uvc_free_device_descriptor(
544
+ uvc_device_descriptor_t *desc);
545
+
546
+ uint8_t uvc_get_bus_number(uvc_device_t *dev);
547
+ uint8_t uvc_get_device_address(uvc_device_t *dev);
548
+ /** Get the USB port path below the device's root hub. */
549
+ int uvc_get_port_numbers(uvc_device_t *dev, uint8_t *ports,
550
+ uint8_t port_count);
551
+
552
+ uvc_error_t uvc_find_device(
553
+ uvc_context_t *ctx,
554
+ uvc_device_t **dev,
555
+ int vid, int pid, const char *sn);
556
+
557
+ uvc_error_t uvc_find_devices(
558
+ uvc_context_t *ctx,
559
+ uvc_device_t ***devs,
560
+ int vid, int pid, const char *sn);
561
+
562
+ #if LIBUSB_API_VERSION >= 0x01000107
563
+ uvc_error_t uvc_wrap(
564
+ int sys_dev,
565
+ uvc_context_t *context,
566
+ uvc_device_handle_t **devh);
567
+ #endif
568
+
569
+ uvc_error_t uvc_open(
570
+ uvc_device_t *dev,
571
+ uvc_device_handle_t **devh);
572
+ void uvc_close(uvc_device_handle_t *devh);
573
+
574
+ uvc_device_t *uvc_get_device(uvc_device_handle_t *devh);
575
+ struct libusb_device_handle *uvc_get_libusb_handle(uvc_device_handle_t *devh);
576
+
577
+ /** Pin the altsetting (and hence the ISO payload) used for this device.
578
+ *
579
+ * The compile-time quirks table in stream.c is a per-model default. A caller
580
+ * that has measured which setting actually holds for a particular camera and
581
+ * host can override it per open device handle. The override is applied to every
582
+ * stream opened on this handle and wins over the table; pass altsetting <= 0 to
583
+ * clear it and fall back to the table. It takes effect on the next
584
+ * uvc_start_streaming()/uvc_stream_start(); it does not touch a running stream.
585
+ *
586
+ * @param[in] devh Device handle from uvc_open()
587
+ * @param[in] altsetting bAlternateSetting to force, or <= 0 to clear
588
+ * @param[in] payload Payload in bytes to commit and size the ISO transfers for
589
+ * @ingroup stream
590
+ */
591
+ uvc_error_t uvc_set_altsetting_override(
592
+ uvc_device_handle_t *devh,
593
+ int altsetting,
594
+ unsigned int payload);
595
+
596
+ void uvc_ref_device(uvc_device_t *dev);
597
+ void uvc_unref_device(uvc_device_t *dev);
598
+
599
+ void uvc_set_status_callback(uvc_device_handle_t *devh,
600
+ uvc_status_callback_t cb,
601
+ void *user_ptr);
602
+
603
+ void uvc_set_button_callback(uvc_device_handle_t *devh,
604
+ uvc_button_callback_t cb,
605
+ void *user_ptr);
606
+
607
+ const uvc_input_terminal_t *uvc_get_camera_terminal(uvc_device_handle_t *devh);
608
+ const uvc_input_terminal_t *uvc_get_input_terminals(uvc_device_handle_t *devh);
609
+ const uvc_output_terminal_t *uvc_get_output_terminals(uvc_device_handle_t *devh);
610
+ const uvc_selector_unit_t *uvc_get_selector_units(uvc_device_handle_t *devh);
611
+ const uvc_processing_unit_t *uvc_get_processing_units(uvc_device_handle_t *devh);
612
+ const uvc_extension_unit_t *uvc_get_extension_units(uvc_device_handle_t *devh);
613
+
614
+ uvc_error_t uvc_get_stream_ctrl_format_size(
615
+ uvc_device_handle_t *devh,
616
+ uvc_stream_ctrl_t *ctrl,
617
+ enum uvc_frame_format format,
618
+ int width, int height,
619
+ int fps
620
+ );
621
+
622
+ uvc_error_t uvc_get_still_ctrl_format_size(
623
+ uvc_device_handle_t *devh,
624
+ uvc_stream_ctrl_t *ctrl,
625
+ uvc_still_ctrl_t *still_ctrl,
626
+ int width, int height);
627
+
628
+ uvc_error_t uvc_trigger_still(
629
+ uvc_device_handle_t *devh,
630
+ uvc_still_ctrl_t *still_ctrl);
631
+
632
+ const uvc_format_desc_t *uvc_get_format_descs(uvc_device_handle_t* );
633
+
634
+ uvc_error_t uvc_probe_stream_ctrl(
635
+ uvc_device_handle_t *devh,
636
+ uvc_stream_ctrl_t *ctrl);
637
+
638
+ uvc_error_t uvc_probe_still_ctrl(
639
+ uvc_device_handle_t *devh,
640
+ uvc_still_ctrl_t *still_ctrl);
641
+
642
+ uvc_error_t uvc_start_streaming(
643
+ uvc_device_handle_t *devh,
644
+ uvc_stream_ctrl_t *ctrl,
645
+ uvc_frame_callback_t *cb,
646
+ void *user_ptr,
647
+ uint8_t flags);
648
+
649
+ uvc_error_t uvc_start_iso_streaming(
650
+ uvc_device_handle_t *devh,
651
+ uvc_stream_ctrl_t *ctrl,
652
+ uvc_frame_callback_t *cb,
653
+ void *user_ptr);
654
+
655
+ void uvc_stop_streaming(uvc_device_handle_t *devh);
656
+
657
+ uvc_error_t uvc_stream_open_ctrl(uvc_device_handle_t *devh, uvc_stream_handle_t **strmh, uvc_stream_ctrl_t *ctrl);
658
+ uvc_error_t uvc_stream_ctrl(uvc_stream_handle_t *strmh, uvc_stream_ctrl_t *ctrl);
659
+ uvc_error_t uvc_stream_start(uvc_stream_handle_t *strmh,
660
+ uvc_frame_callback_t *cb,
661
+ void *user_ptr,
662
+ uint8_t flags);
663
+ uvc_error_t uvc_stream_start_iso(uvc_stream_handle_t *strmh,
664
+ uvc_frame_callback_t *cb,
665
+ void *user_ptr);
666
+ uvc_error_t uvc_stream_get_frame(
667
+ uvc_stream_handle_t *strmh,
668
+ uvc_frame_t **frame,
669
+ int32_t timeout_us
670
+ );
671
+ uvc_error_t uvc_stream_stop(uvc_stream_handle_t *strmh);
672
+ void uvc_stream_close(uvc_stream_handle_t *strmh);
673
+
674
+ int uvc_get_ctrl_len(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl);
675
+ int uvc_get_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len, enum uvc_req_code req_code);
676
+ int uvc_set_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len);
677
+
678
+ uvc_error_t uvc_get_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode *mode, enum uvc_req_code req_code);
679
+ uvc_error_t uvc_set_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode mode);
680
+
681
+ /* AUTO-GENERATED control accessors! Update them with the output of `ctrl-gen.py decl`. */
682
+ uvc_error_t uvc_get_scanning_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code);
683
+ uvc_error_t uvc_set_scanning_mode(uvc_device_handle_t *devh, uint8_t mode);
684
+
685
+ uvc_error_t uvc_get_ae_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code);
686
+ uvc_error_t uvc_set_ae_mode(uvc_device_handle_t *devh, uint8_t mode);
687
+
688
+ uvc_error_t uvc_get_ae_priority(uvc_device_handle_t *devh, uint8_t* priority, enum uvc_req_code req_code);
689
+ uvc_error_t uvc_set_ae_priority(uvc_device_handle_t *devh, uint8_t priority);
690
+
691
+ uvc_error_t uvc_get_exposure_abs(uvc_device_handle_t *devh, uint32_t* time, enum uvc_req_code req_code);
692
+ uvc_error_t uvc_set_exposure_abs(uvc_device_handle_t *devh, uint32_t time);
693
+
694
+ uvc_error_t uvc_get_exposure_rel(uvc_device_handle_t *devh, int8_t* step, enum uvc_req_code req_code);
695
+ uvc_error_t uvc_set_exposure_rel(uvc_device_handle_t *devh, int8_t step);
696
+
697
+ uvc_error_t uvc_get_focus_abs(uvc_device_handle_t *devh, uint16_t* focus, enum uvc_req_code req_code);
698
+ uvc_error_t uvc_set_focus_abs(uvc_device_handle_t *devh, uint16_t focus);
699
+
700
+ uvc_error_t uvc_get_focus_rel(uvc_device_handle_t *devh, int8_t* focus_rel, uint8_t* speed, enum uvc_req_code req_code);
701
+ uvc_error_t uvc_set_focus_rel(uvc_device_handle_t *devh, int8_t focus_rel, uint8_t speed);
702
+
703
+ uvc_error_t uvc_get_focus_simple_range(uvc_device_handle_t *devh, uint8_t* focus, enum uvc_req_code req_code);
704
+ uvc_error_t uvc_set_focus_simple_range(uvc_device_handle_t *devh, uint8_t focus);
705
+
706
+ uvc_error_t uvc_get_focus_auto(uvc_device_handle_t *devh, uint8_t* state, enum uvc_req_code req_code);
707
+ uvc_error_t uvc_set_focus_auto(uvc_device_handle_t *devh, uint8_t state);
708
+
709
+ uvc_error_t uvc_get_iris_abs(uvc_device_handle_t *devh, uint16_t* iris, enum uvc_req_code req_code);
710
+ uvc_error_t uvc_set_iris_abs(uvc_device_handle_t *devh, uint16_t iris);
711
+
712
+ uvc_error_t uvc_get_iris_rel(uvc_device_handle_t *devh, uint8_t* iris_rel, enum uvc_req_code req_code);
713
+ uvc_error_t uvc_set_iris_rel(uvc_device_handle_t *devh, uint8_t iris_rel);
714
+
715
+ uvc_error_t uvc_get_zoom_abs(uvc_device_handle_t *devh, uint16_t* focal_length, enum uvc_req_code req_code);
716
+ uvc_error_t uvc_set_zoom_abs(uvc_device_handle_t *devh, uint16_t focal_length);
717
+
718
+ uvc_error_t uvc_get_zoom_rel(uvc_device_handle_t *devh, int8_t* zoom_rel, uint8_t* digital_zoom, uint8_t* speed, enum uvc_req_code req_code);
719
+ uvc_error_t uvc_set_zoom_rel(uvc_device_handle_t *devh, int8_t zoom_rel, uint8_t digital_zoom, uint8_t speed);
720
+
721
+ uvc_error_t uvc_get_pantilt_abs(uvc_device_handle_t *devh, int32_t* pan, int32_t* tilt, enum uvc_req_code req_code);
722
+ uvc_error_t uvc_set_pantilt_abs(uvc_device_handle_t *devh, int32_t pan, int32_t tilt);
723
+
724
+ uvc_error_t uvc_get_pantilt_rel(uvc_device_handle_t *devh, int8_t* pan_rel, uint8_t* pan_speed, int8_t* tilt_rel, uint8_t* tilt_speed, enum uvc_req_code req_code);
725
+ uvc_error_t uvc_set_pantilt_rel(uvc_device_handle_t *devh, int8_t pan_rel, uint8_t pan_speed, int8_t tilt_rel, uint8_t tilt_speed);
726
+
727
+ uvc_error_t uvc_get_roll_abs(uvc_device_handle_t *devh, int16_t* roll, enum uvc_req_code req_code);
728
+ uvc_error_t uvc_set_roll_abs(uvc_device_handle_t *devh, int16_t roll);
729
+
730
+ uvc_error_t uvc_get_roll_rel(uvc_device_handle_t *devh, int8_t* roll_rel, uint8_t* speed, enum uvc_req_code req_code);
731
+ uvc_error_t uvc_set_roll_rel(uvc_device_handle_t *devh, int8_t roll_rel, uint8_t speed);
732
+
733
+ uvc_error_t uvc_get_privacy(uvc_device_handle_t *devh, uint8_t* privacy, enum uvc_req_code req_code);
734
+ uvc_error_t uvc_set_privacy(uvc_device_handle_t *devh, uint8_t privacy);
735
+
736
+ uvc_error_t uvc_get_digital_window(uvc_device_handle_t *devh, uint16_t* window_top, uint16_t* window_left, uint16_t* window_bottom, uint16_t* window_right, uint16_t* num_steps, uint16_t* num_steps_units, enum uvc_req_code req_code);
737
+ uvc_error_t uvc_set_digital_window(uvc_device_handle_t *devh, uint16_t window_top, uint16_t window_left, uint16_t window_bottom, uint16_t window_right, uint16_t num_steps, uint16_t num_steps_units);
738
+
739
+ uvc_error_t uvc_get_digital_roi(uvc_device_handle_t *devh, uint16_t* roi_top, uint16_t* roi_left, uint16_t* roi_bottom, uint16_t* roi_right, uint16_t* auto_controls, enum uvc_req_code req_code);
740
+ uvc_error_t uvc_set_digital_roi(uvc_device_handle_t *devh, uint16_t roi_top, uint16_t roi_left, uint16_t roi_bottom, uint16_t roi_right, uint16_t auto_controls);
741
+
742
+ uvc_error_t uvc_get_backlight_compensation(uvc_device_handle_t *devh, uint16_t* backlight_compensation, enum uvc_req_code req_code);
743
+ uvc_error_t uvc_set_backlight_compensation(uvc_device_handle_t *devh, uint16_t backlight_compensation);
744
+
745
+ uvc_error_t uvc_get_brightness(uvc_device_handle_t *devh, int16_t* brightness, enum uvc_req_code req_code);
746
+ uvc_error_t uvc_set_brightness(uvc_device_handle_t *devh, int16_t brightness);
747
+
748
+ uvc_error_t uvc_get_contrast(uvc_device_handle_t *devh, uint16_t* contrast, enum uvc_req_code req_code);
749
+ uvc_error_t uvc_set_contrast(uvc_device_handle_t *devh, uint16_t contrast);
750
+
751
+ uvc_error_t uvc_get_contrast_auto(uvc_device_handle_t *devh, uint8_t* contrast_auto, enum uvc_req_code req_code);
752
+ uvc_error_t uvc_set_contrast_auto(uvc_device_handle_t *devh, uint8_t contrast_auto);
753
+
754
+ uvc_error_t uvc_get_gain(uvc_device_handle_t *devh, uint16_t* gain, enum uvc_req_code req_code);
755
+ uvc_error_t uvc_set_gain(uvc_device_handle_t *devh, uint16_t gain);
756
+
757
+ uvc_error_t uvc_get_power_line_frequency(uvc_device_handle_t *devh, uint8_t* power_line_frequency, enum uvc_req_code req_code);
758
+ uvc_error_t uvc_set_power_line_frequency(uvc_device_handle_t *devh, uint8_t power_line_frequency);
759
+
760
+ uvc_error_t uvc_get_hue(uvc_device_handle_t *devh, int16_t* hue, enum uvc_req_code req_code);
761
+ uvc_error_t uvc_set_hue(uvc_device_handle_t *devh, int16_t hue);
762
+
763
+ uvc_error_t uvc_get_hue_auto(uvc_device_handle_t *devh, uint8_t* hue_auto, enum uvc_req_code req_code);
764
+ uvc_error_t uvc_set_hue_auto(uvc_device_handle_t *devh, uint8_t hue_auto);
765
+
766
+ uvc_error_t uvc_get_saturation(uvc_device_handle_t *devh, uint16_t* saturation, enum uvc_req_code req_code);
767
+ uvc_error_t uvc_set_saturation(uvc_device_handle_t *devh, uint16_t saturation);
768
+
769
+ uvc_error_t uvc_get_sharpness(uvc_device_handle_t *devh, uint16_t* sharpness, enum uvc_req_code req_code);
770
+ uvc_error_t uvc_set_sharpness(uvc_device_handle_t *devh, uint16_t sharpness);
771
+
772
+ uvc_error_t uvc_get_gamma(uvc_device_handle_t *devh, uint16_t* gamma, enum uvc_req_code req_code);
773
+ uvc_error_t uvc_set_gamma(uvc_device_handle_t *devh, uint16_t gamma);
774
+
775
+ uvc_error_t uvc_get_white_balance_temperature(uvc_device_handle_t *devh, uint16_t* temperature, enum uvc_req_code req_code);
776
+ uvc_error_t uvc_set_white_balance_temperature(uvc_device_handle_t *devh, uint16_t temperature);
777
+
778
+ uvc_error_t uvc_get_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t* temperature_auto, enum uvc_req_code req_code);
779
+ uvc_error_t uvc_set_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t temperature_auto);
780
+
781
+ uvc_error_t uvc_get_white_balance_component(uvc_device_handle_t *devh, uint16_t* blue, uint16_t* red, enum uvc_req_code req_code);
782
+ uvc_error_t uvc_set_white_balance_component(uvc_device_handle_t *devh, uint16_t blue, uint16_t red);
783
+
784
+ uvc_error_t uvc_get_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t* white_balance_component_auto, enum uvc_req_code req_code);
785
+ uvc_error_t uvc_set_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t white_balance_component_auto);
786
+
787
+ uvc_error_t uvc_get_digital_multiplier(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code);
788
+ uvc_error_t uvc_set_digital_multiplier(uvc_device_handle_t *devh, uint16_t multiplier_step);
789
+
790
+ uvc_error_t uvc_get_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code);
791
+ uvc_error_t uvc_set_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t multiplier_step);
792
+
793
+ uvc_error_t uvc_get_analog_video_standard(uvc_device_handle_t *devh, uint8_t* video_standard, enum uvc_req_code req_code);
794
+ uvc_error_t uvc_set_analog_video_standard(uvc_device_handle_t *devh, uint8_t video_standard);
795
+
796
+ uvc_error_t uvc_get_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t* status, enum uvc_req_code req_code);
797
+ uvc_error_t uvc_set_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t status);
798
+
799
+ uvc_error_t uvc_get_input_select(uvc_device_handle_t *devh, uint8_t* selector, enum uvc_req_code req_code);
800
+ uvc_error_t uvc_set_input_select(uvc_device_handle_t *devh, uint8_t selector);
801
+ /* end AUTO-GENERATED control accessors */
802
+
803
+ void uvc_perror(uvc_error_t err, const char *msg);
804
+ const char* uvc_strerror(uvc_error_t err);
805
+ void uvc_print_diag(uvc_device_handle_t *devh, FILE *stream);
806
+ void uvc_print_stream_ctrl(uvc_stream_ctrl_t *ctrl, FILE *stream);
807
+
808
+ uvc_frame_t *uvc_allocate_frame(size_t data_bytes);
809
+ void uvc_free_frame(uvc_frame_t *frame);
810
+
811
+ uvc_error_t uvc_duplicate_frame(uvc_frame_t *in, uvc_frame_t *out);
812
+
813
+ uvc_error_t uvc_yuyv2rgb(uvc_frame_t *in, uvc_frame_t *out);
814
+ uvc_error_t uvc_uyvy2rgb(uvc_frame_t *in, uvc_frame_t *out);
815
+ uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out);
816
+
817
+ uvc_error_t uvc_yuyv2bgr(uvc_frame_t *in, uvc_frame_t *out);
818
+ uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out);
819
+ uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out);
820
+
821
+ uvc_error_t uvc_yuyv2y(uvc_frame_t *in, uvc_frame_t *out);
822
+ uvc_error_t uvc_yuyv2uv(uvc_frame_t *in, uvc_frame_t *out);
823
+
824
+ #ifdef LIBUVC_HAS_JPEG
825
+ uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out);
826
+ uvc_error_t uvc_mjpeg2gray(uvc_frame_t *in, uvc_frame_t *out);
827
+ #endif
828
+
829
+ #ifdef __cplusplus
830
+ }
831
+ #endif
832
+
833
+ #endif // !def(LIBUVC_H)
collector/core/gripper/camera_service_src/third_party/libuvc/include/libuvc/libuvc_config.h.in ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef LIBUVC_CONFIG_H
2
+ #define LIBUVC_CONFIG_H
3
+
4
+ #define LIBUVC_VERSION_MAJOR @libuvc_VERSION_MAJOR@
5
+ #define LIBUVC_VERSION_MINOR @libuvc_VERSION_MINOR@
6
+ #define LIBUVC_VERSION_PATCH @libuvc_VERSION_PATCH@
7
+ #define LIBUVC_VERSION_STR "@libuvc_VERSION@"
8
+ #define LIBUVC_VERSION_INT \
9
+ ((@libuvc_VERSION_MAJOR@ << 16) | \
10
+ (@libuvc_VERSION_MINOR@ << 8) | \
11
+ (@libuvc_VERSION_PATCH@))
12
+
13
+ /** @brief Test whether libuvc is new enough
14
+ * This macro evaluates true if and only if the current version is
15
+ * at least as new as the version specified.
16
+ */
17
+ #define LIBUVC_VERSION_GTE(major, minor, patch) \
18
+ (LIBUVC_VERSION_INT >= (((major) << 16) | ((minor) << 8) | (patch)))
19
+
20
+ #cmakedefine LIBUVC_HAS_JPEG 1
21
+
22
+ #endif // !def(LIBUVC_CONFIG_H)
collector/core/gripper/camera_service_src/third_party/libuvc/include/libuvc/libuvc_internal.h ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @file libuvc_internal.h
2
+ * @brief Implementation-specific UVC constants and structures.
3
+ * @cond include_hidden
4
+ */
5
+ #ifndef LIBUVC_INTERNAL_H
6
+ #define LIBUVC_INTERNAL_H
7
+
8
+ #include <assert.h>
9
+ #include <stdlib.h>
10
+ #include <stdio.h>
11
+ #include <string.h>
12
+ #include <pthread.h>
13
+ #include <signal.h>
14
+ #include <libusb.h>
15
+ #include "utlist.h"
16
+
17
+ /** Converts an unaligned four-byte little-endian integer into an int32 */
18
+ #define DW_TO_INT(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24))
19
+ /** Converts an unaligned two-byte little-endian integer into an int16 */
20
+ #define SW_TO_SHORT(p) ((p)[0] | ((p)[1] << 8))
21
+ /** Converts an int16 into an unaligned two-byte little-endian integer */
22
+ #define SHORT_TO_SW(s, p) \
23
+ (p)[0] = (s); \
24
+ (p)[1] = (s) >> 8;
25
+ /** Converts an int32 into an unaligned four-byte little-endian integer */
26
+ #define INT_TO_DW(i, p) \
27
+ (p)[0] = (i); \
28
+ (p)[1] = (i) >> 8; \
29
+ (p)[2] = (i) >> 16; \
30
+ (p)[3] = (i) >> 24;
31
+
32
+ /** Selects the nth item in a doubly linked list. n=-1 selects the last item. */
33
+ #define DL_NTH(head, out, n) \
34
+ do { \
35
+ int dl_nth_i = 0; \
36
+ LDECLTYPE(head) dl_nth_p = (head); \
37
+ if ((n) < 0) { \
38
+ while (dl_nth_p && dl_nth_i > (n)) { \
39
+ dl_nth_p = dl_nth_p->prev; \
40
+ dl_nth_i--; \
41
+ } \
42
+ } else { \
43
+ while (dl_nth_p && dl_nth_i < (n)) { \
44
+ dl_nth_p = dl_nth_p->next; \
45
+ dl_nth_i++; \
46
+ } \
47
+ } \
48
+ (out) = dl_nth_p; \
49
+ } while (0);
50
+
51
+ #ifdef UVC_DEBUGGING
52
+ #include <libgen.h>
53
+ #ifdef __ANDROID__
54
+ #include <android/log.h>
55
+ #define UVC_DEBUG(format, ...) __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
56
+ #define UVC_ENTER() __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
57
+ #define UVC_EXIT(code) __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code)
58
+ #define UVC_EXIT_VOID() __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
59
+ #else
60
+ #define UVC_DEBUG(format, ...) fprintf(stderr, "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
61
+ #define UVC_ENTER() fprintf(stderr, "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
62
+ #define UVC_EXIT(code) fprintf(stderr, "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code)
63
+ #define UVC_EXIT_VOID() fprintf(stderr, "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
64
+ #endif
65
+ #else
66
+ #define UVC_DEBUG(format, ...)
67
+ #define UVC_ENTER()
68
+ #define UVC_EXIT_VOID()
69
+ #define UVC_EXIT(code)
70
+ #endif
71
+
72
+ /* http://stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers */
73
+ #define IS_INDEXABLE(arg) (sizeof(arg[0]))
74
+ #define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
75
+ #define ARRAYSIZE(arr) (sizeof(arr) / (IS_ARRAY(arr) ? sizeof(arr[0]) : 0))
76
+
77
+ /** Video interface subclass code (A.2) */
78
+ enum uvc_int_subclass_code {
79
+ UVC_SC_UNDEFINED = 0x00,
80
+ UVC_SC_VIDEOCONTROL = 0x01,
81
+ UVC_SC_VIDEOSTREAMING = 0x02,
82
+ UVC_SC_VIDEO_INTERFACE_COLLECTION = 0x03
83
+ };
84
+
85
+ /** Video interface protocol code (A.3) */
86
+ enum uvc_int_proto_code {
87
+ UVC_PC_PROTOCOL_UNDEFINED = 0x00
88
+ };
89
+
90
+ /** VideoControl interface descriptor subtype (A.5) */
91
+ enum uvc_vc_desc_subtype {
92
+ UVC_VC_DESCRIPTOR_UNDEFINED = 0x00,
93
+ UVC_VC_HEADER = 0x01,
94
+ UVC_VC_INPUT_TERMINAL = 0x02,
95
+ UVC_VC_OUTPUT_TERMINAL = 0x03,
96
+ UVC_VC_SELECTOR_UNIT = 0x04,
97
+ UVC_VC_PROCESSING_UNIT = 0x05,
98
+ UVC_VC_EXTENSION_UNIT = 0x06
99
+ };
100
+
101
+ /** UVC endpoint descriptor subtype (A.7) */
102
+ enum uvc_ep_desc_subtype {
103
+ UVC_EP_UNDEFINED = 0x00,
104
+ UVC_EP_GENERAL = 0x01,
105
+ UVC_EP_ENDPOINT = 0x02,
106
+ UVC_EP_INTERRUPT = 0x03
107
+ };
108
+
109
+ /** VideoControl interface control selector (A.9.1) */
110
+ enum uvc_vc_ctrl_selector {
111
+ UVC_VC_CONTROL_UNDEFINED = 0x00,
112
+ UVC_VC_VIDEO_POWER_MODE_CONTROL = 0x01,
113
+ UVC_VC_REQUEST_ERROR_CODE_CONTROL = 0x02
114
+ };
115
+
116
+ /** Terminal control selector (A.9.2) */
117
+ enum uvc_term_ctrl_selector {
118
+ UVC_TE_CONTROL_UNDEFINED = 0x00
119
+ };
120
+
121
+ /** Selector unit control selector (A.9.3) */
122
+ enum uvc_su_ctrl_selector {
123
+ UVC_SU_CONTROL_UNDEFINED = 0x00,
124
+ UVC_SU_INPUT_SELECT_CONTROL = 0x01
125
+ };
126
+
127
+ /** Extension unit control selector (A.9.6) */
128
+ enum uvc_xu_ctrl_selector {
129
+ UVC_XU_CONTROL_UNDEFINED = 0x00
130
+ };
131
+
132
+ /** VideoStreaming interface control selector (A.9.7) */
133
+ enum uvc_vs_ctrl_selector {
134
+ UVC_VS_CONTROL_UNDEFINED = 0x00,
135
+ UVC_VS_PROBE_CONTROL = 0x01,
136
+ UVC_VS_COMMIT_CONTROL = 0x02,
137
+ UVC_VS_STILL_PROBE_CONTROL = 0x03,
138
+ UVC_VS_STILL_COMMIT_CONTROL = 0x04,
139
+ UVC_VS_STILL_IMAGE_TRIGGER_CONTROL = 0x05,
140
+ UVC_VS_STREAM_ERROR_CODE_CONTROL = 0x06,
141
+ UVC_VS_GENERATE_KEY_FRAME_CONTROL = 0x07,
142
+ UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL = 0x08,
143
+ UVC_VS_SYNC_DELAY_CONTROL = 0x09
144
+ };
145
+
146
+ /** Status packet type (2.4.2.2) */
147
+ enum uvc_status_type {
148
+ UVC_STATUS_TYPE_CONTROL = 1,
149
+ UVC_STATUS_TYPE_STREAMING = 2
150
+ };
151
+
152
+ /** Payload header flags (2.4.3.3) */
153
+ #define UVC_STREAM_EOH (1 << 7)
154
+ #define UVC_STREAM_ERR (1 << 6)
155
+ #define UVC_STREAM_STI (1 << 5)
156
+ #define UVC_STREAM_RES (1 << 4)
157
+ #define UVC_STREAM_SCR (1 << 3)
158
+ #define UVC_STREAM_PTS (1 << 2)
159
+ #define UVC_STREAM_EOF (1 << 1)
160
+ #define UVC_STREAM_FID (1 << 0)
161
+
162
+ /** Control capabilities (4.1.2) */
163
+ #define UVC_CONTROL_CAP_GET (1 << 0)
164
+ #define UVC_CONTROL_CAP_SET (1 << 1)
165
+ #define UVC_CONTROL_CAP_DISABLED (1 << 2)
166
+ #define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3)
167
+ #define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4)
168
+
169
+ struct uvc_streaming_interface;
170
+ struct uvc_device_info;
171
+
172
+ /** VideoStream interface */
173
+ typedef struct uvc_streaming_interface {
174
+ struct uvc_device_info *parent;
175
+ struct uvc_streaming_interface *prev, *next;
176
+ /** Interface number */
177
+ uint8_t bInterfaceNumber;
178
+ /** Video formats that this interface provides */
179
+ struct uvc_format_desc *format_descs;
180
+ /** USB endpoint to use when communicating with this interface */
181
+ uint8_t bEndpointAddress;
182
+ uint8_t bTerminalLink;
183
+ uint8_t bStillCaptureMethod;
184
+ } uvc_streaming_interface_t;
185
+
186
+ /** VideoControl interface */
187
+ typedef struct uvc_control_interface {
188
+ struct uvc_device_info *parent;
189
+ struct uvc_input_terminal *input_term_descs;
190
+ // struct uvc_output_terminal *output_term_descs;
191
+ struct uvc_selector_unit *selector_unit_descs;
192
+ struct uvc_processing_unit *processing_unit_descs;
193
+ struct uvc_extension_unit *extension_unit_descs;
194
+ uint16_t bcdUVC;
195
+ uint32_t dwClockFrequency;
196
+ uint8_t bEndpointAddress;
197
+ /** Interface number */
198
+ uint8_t bInterfaceNumber;
199
+ } uvc_control_interface_t;
200
+
201
+ struct uvc_stream_ctrl;
202
+
203
+ struct uvc_device {
204
+ struct uvc_context *ctx;
205
+ int ref;
206
+ libusb_device *usb_dev;
207
+ };
208
+
209
+ typedef struct uvc_device_info {
210
+ /** Configuration descriptor for USB device */
211
+ struct libusb_config_descriptor *config;
212
+ /** VideoControl interface provided by device */
213
+ uvc_control_interface_t ctrl_if;
214
+ /** VideoStreaming interfaces on the device */
215
+ uvc_streaming_interface_t *stream_ifs;
216
+ } uvc_device_info_t;
217
+
218
+ /*
219
+ The default Linux value of 100 is too deep for this service: six USB2
220
+ isochronous cameras would submit 600 transfers (up to 32 packets each),
221
+ exhausting the libusb/xHCI in-flight scheduling resources before all
222
+ endpoints receive callbacks. Eight transfers per camera provide 32 ms of
223
+ queued ISO work at the selected endpoint size and keep all six streams
224
+ active. This remains overridable at compile time for other applications.
225
+ */
226
+ #ifndef LIBUVC_NUM_TRANSFER_BUFS
227
+ #if defined(__APPLE__) && defined(__MACH__)
228
+ #define LIBUVC_NUM_TRANSFER_BUFS 20
229
+ #else
230
+ #define LIBUVC_NUM_TRANSFER_BUFS 8
231
+ #endif
232
+ #endif
233
+
234
+ #define LIBUVC_XFER_META_BUF_SIZE ( 4 * 1024 )
235
+
236
+ struct uvc_stream_handle {
237
+ struct uvc_device_handle *devh;
238
+ struct uvc_stream_handle *prev, *next;
239
+ struct uvc_streaming_interface *stream_if;
240
+
241
+ /** if true, stream is running (streaming video to host) */
242
+ uint8_t running;
243
+ /** Current control block */
244
+ struct uvc_stream_ctrl cur_ctrl;
245
+
246
+ /* listeners may only access hold*, and only when holding a
247
+ * lock on cb_mutex (probably signaled with cb_cond) */
248
+ uint8_t fid;
249
+ uint32_t seq, hold_seq;
250
+ uint32_t pts, hold_pts;
251
+ uint32_t last_scr, hold_last_scr;
252
+ size_t got_bytes, hold_bytes;
253
+ uint8_t *outbuf, *holdbuf;
254
+ pthread_mutex_t cb_mutex;
255
+ pthread_cond_t cb_cond;
256
+ pthread_t cb_thread;
257
+ uint32_t last_polled_seq;
258
+ uvc_frame_callback_t *user_cb;
259
+ void *user_ptr;
260
+ struct libusb_transfer *transfers[LIBUVC_NUM_TRANSFER_BUFS];
261
+ uint8_t *transfer_bufs[LIBUVC_NUM_TRANSFER_BUFS];
262
+ struct uvc_frame frame;
263
+ enum uvc_frame_format frame_format;
264
+ struct timespec capture_time_finished;
265
+
266
+ /* raw metadata buffer if available */
267
+ uint8_t *meta_outbuf, *meta_holdbuf;
268
+ size_t meta_got_bytes, meta_hold_bytes;
269
+ };
270
+
271
+ /** Handle on an open UVC device
272
+ *
273
+ * @todo move most of this into a uvc_device struct?
274
+ */
275
+ struct uvc_device_handle {
276
+ struct uvc_device *dev;
277
+ struct uvc_device_handle *prev, *next;
278
+ /** Underlying USB device handle */
279
+ libusb_device_handle *usb_devh;
280
+ struct uvc_device_info *info;
281
+ struct libusb_transfer *status_xfer;
282
+ uint8_t status_buf[32];
283
+ /** Function to call when we receive status updates from the camera */
284
+ uvc_status_callback_t *status_cb;
285
+ void *status_user_ptr;
286
+ /** Function to call when we receive button events from the camera */
287
+ uvc_button_callback_t *button_cb;
288
+ void *button_user_ptr;
289
+
290
+ uvc_stream_handle_t *streams;
291
+ /** Whether the camera is an iSight that sends one header per frame */
292
+ uint8_t is_isight;
293
+ uint32_t claimed;
294
+
295
+ /* Per-machine altsetting override set with uvc_set_altsetting_override().
296
+ * Zero-initialised by the calloc() in uvc_open_internal, so an untouched
297
+ * handle falls through to the compile-time quirks table in stream.c. */
298
+ uint8_t altsetting_override_valid;
299
+ uint8_t altsetting_override_altsetting;
300
+ uint16_t altsetting_override_payload;
301
+ };
302
+
303
+ /** Context within which we communicate with devices */
304
+ struct uvc_context {
305
+ /** Underlying context for USB communication */
306
+ struct libusb_context *usb_ctx;
307
+ /** True iff libuvc initialized the underlying USB context */
308
+ uint8_t own_usb_ctx;
309
+ /** List of open devices in this context */
310
+ uvc_device_handle_t *open_devices;
311
+ pthread_t handler_thread;
312
+ int kill_handler_thread;
313
+ };
314
+
315
+ uvc_error_t uvc_query_stream_ctrl(
316
+ uvc_device_handle_t *devh,
317
+ uvc_stream_ctrl_t *ctrl,
318
+ uint8_t probe,
319
+ enum uvc_req_code req);
320
+
321
+ void uvc_start_handler_thread(uvc_context_t *ctx);
322
+ uvc_error_t uvc_claim_if(uvc_device_handle_t *devh, int idx);
323
+ uvc_error_t uvc_release_if(uvc_device_handle_t *devh, int idx);
324
+
325
+ #endif // !def(LIBUVC_INTERNAL_H)
326
+ /** @endcond */
collector/core/gripper/camera_service_src/third_party/libuvc/include/utlist.h ADDED
@@ -0,0 +1,490 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
+ */
23
+
24
+ #ifndef UTLIST_H
25
+ #define UTLIST_H
26
+
27
+ #define UTLIST_VERSION 1.9.1
28
+
29
+ /*
30
+ * This file contains macros to manipulate singly and doubly-linked lists.
31
+ *
32
+ * 1. LL_ macros: singly-linked lists.
33
+ * 2. DL_ macros: doubly-linked lists.
34
+ * 3. CDL_ macros: circular doubly-linked lists.
35
+ *
36
+ * To use singly-linked lists, your structure must have a "next" pointer.
37
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
38
+ * Either way, the pointer to the head of the list must be initialized to NULL.
39
+ *
40
+ * ----------------.EXAMPLE -------------------------
41
+ * struct item {
42
+ * int id;
43
+ * struct item *prev, *next;
44
+ * }
45
+ *
46
+ * struct item *list = NULL:
47
+ *
48
+ * int main() {
49
+ * struct item *item;
50
+ * ... allocate and populate item ...
51
+ * DL_APPEND(list, item);
52
+ * }
53
+ * --------------------------------------------------
54
+ *
55
+ * For doubly-linked lists, the append and delete macros are O(1)
56
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
57
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
58
+ */
59
+
60
+ /* These macros use decltype or the earlier __typeof GNU extension.
61
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
62
+ when compiling c++ code), this code uses whatever method is needed
63
+ or, for VS2008 where neither is available, uses casting workarounds. */
64
+ #ifdef _MSC_VER /* MS compiler */
65
+ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
66
+ #define LDECLTYPE(x) decltype(x)
67
+ #else /* VS2008 or older (or VS2010 in C mode) */
68
+ #define NO_DECLTYPE
69
+ #define LDECLTYPE(x) char*
70
+ #endif
71
+ #else /* GNU, Sun and other compilers */
72
+ #define LDECLTYPE(x) __typeof(x)
73
+ #endif
74
+
75
+ /* for VS2008 we use some workarounds to get around the lack of decltype,
76
+ * namely, we always reassign our tmp variable to the list head if we need
77
+ * to dereference its prev/next pointers, and save/restore the real head.*/
78
+ #ifdef NO_DECLTYPE
79
+ #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
80
+ #define _NEXT(elt,list) ((char*)((list)->next))
81
+ #define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
82
+ #define _PREV(elt,list) ((char*)((list)->prev))
83
+ #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
84
+ #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
85
+ #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
86
+ #else
87
+ #define _SV(elt,list)
88
+ #define _NEXT(elt,list) ((elt)->next)
89
+ #define _NEXTASGN(elt,list,to) ((elt)->next)=(to)
90
+ #define _PREV(elt,list) ((elt)->prev)
91
+ #define _PREVASGN(elt,list,to) ((elt)->prev)=(to)
92
+ #define _RS(list)
93
+ #define _CASTASGN(a,b) (a)=(b)
94
+ #endif
95
+
96
+ /******************************************************************************
97
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
98
+ * Unwieldy variable names used here to avoid shadowing passed-in variables. *
99
+ *****************************************************************************/
100
+ #define LL_SORT(list, cmp) \
101
+ do { \
102
+ LDECLTYPE(list) _ls_p; \
103
+ LDECLTYPE(list) _ls_q; \
104
+ LDECLTYPE(list) _ls_e; \
105
+ LDECLTYPE(list) _ls_tail; \
106
+ LDECLTYPE(list) _ls_oldhead; \
107
+ LDECLTYPE(list) _tmp; \
108
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
109
+ if (list) { \
110
+ _ls_insize = 1; \
111
+ _ls_looping = 1; \
112
+ while (_ls_looping) { \
113
+ _CASTASGN(_ls_p,list); \
114
+ _CASTASGN(_ls_oldhead,list); \
115
+ list = NULL; \
116
+ _ls_tail = NULL; \
117
+ _ls_nmerges = 0; \
118
+ while (_ls_p) { \
119
+ _ls_nmerges++; \
120
+ _ls_q = _ls_p; \
121
+ _ls_psize = 0; \
122
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
123
+ _ls_psize++; \
124
+ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \
125
+ if (!_ls_q) break; \
126
+ } \
127
+ _ls_qsize = _ls_insize; \
128
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
129
+ if (_ls_psize == 0) { \
130
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
131
+ } else if (_ls_qsize == 0 || !_ls_q) { \
132
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
133
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
134
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
135
+ } else { \
136
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
137
+ } \
138
+ if (_ls_tail) { \
139
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
140
+ } else { \
141
+ _CASTASGN(list,_ls_e); \
142
+ } \
143
+ _ls_tail = _ls_e; \
144
+ } \
145
+ _ls_p = _ls_q; \
146
+ } \
147
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \
148
+ if (_ls_nmerges <= 1) { \
149
+ _ls_looping=0; \
150
+ } \
151
+ _ls_insize *= 2; \
152
+ } \
153
+ } else _tmp=NULL; /* quiet gcc unused variable warning */ \
154
+ } while (0)
155
+
156
+ #define DL_SORT(list, cmp) \
157
+ do { \
158
+ LDECLTYPE(list) _ls_p; \
159
+ LDECLTYPE(list) _ls_q; \
160
+ LDECLTYPE(list) _ls_e; \
161
+ LDECLTYPE(list) _ls_tail; \
162
+ LDECLTYPE(list) _ls_oldhead; \
163
+ LDECLTYPE(list) _tmp; \
164
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
165
+ if (list) { \
166
+ _ls_insize = 1; \
167
+ _ls_looping = 1; \
168
+ while (_ls_looping) { \
169
+ _CASTASGN(_ls_p,list); \
170
+ _CASTASGN(_ls_oldhead,list); \
171
+ list = NULL; \
172
+ _ls_tail = NULL; \
173
+ _ls_nmerges = 0; \
174
+ while (_ls_p) { \
175
+ _ls_nmerges++; \
176
+ _ls_q = _ls_p; \
177
+ _ls_psize = 0; \
178
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
179
+ _ls_psize++; \
180
+ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \
181
+ if (!_ls_q) break; \
182
+ } \
183
+ _ls_qsize = _ls_insize; \
184
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
185
+ if (_ls_psize == 0) { \
186
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
187
+ } else if (_ls_qsize == 0 || !_ls_q) { \
188
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
189
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
190
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
191
+ } else { \
192
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
193
+ } \
194
+ if (_ls_tail) { \
195
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
196
+ } else { \
197
+ _CASTASGN(list,_ls_e); \
198
+ } \
199
+ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \
200
+ _ls_tail = _ls_e; \
201
+ } \
202
+ _ls_p = _ls_q; \
203
+ } \
204
+ _CASTASGN(list->prev, _ls_tail); \
205
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \
206
+ if (_ls_nmerges <= 1) { \
207
+ _ls_looping=0; \
208
+ } \
209
+ _ls_insize *= 2; \
210
+ } \
211
+ } else _tmp=NULL; /* quiet gcc unused variable warning */ \
212
+ } while (0)
213
+
214
+ #define CDL_SORT(list, cmp) \
215
+ do { \
216
+ LDECLTYPE(list) _ls_p; \
217
+ LDECLTYPE(list) _ls_q; \
218
+ LDECLTYPE(list) _ls_e; \
219
+ LDECLTYPE(list) _ls_tail; \
220
+ LDECLTYPE(list) _ls_oldhead; \
221
+ LDECLTYPE(list) _tmp; \
222
+ LDECLTYPE(list) _tmp2; \
223
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
224
+ if (list) { \
225
+ _ls_insize = 1; \
226
+ _ls_looping = 1; \
227
+ while (_ls_looping) { \
228
+ _CASTASGN(_ls_p,list); \
229
+ _CASTASGN(_ls_oldhead,list); \
230
+ list = NULL; \
231
+ _ls_tail = NULL; \
232
+ _ls_nmerges = 0; \
233
+ while (_ls_p) { \
234
+ _ls_nmerges++; \
235
+ _ls_q = _ls_p; \
236
+ _ls_psize = 0; \
237
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
238
+ _ls_psize++; \
239
+ _SV(_ls_q,list); \
240
+ if (_NEXT(_ls_q,list) == _ls_oldhead) { \
241
+ _ls_q = NULL; \
242
+ } else { \
243
+ _ls_q = _NEXT(_ls_q,list); \
244
+ } \
245
+ _RS(list); \
246
+ if (!_ls_q) break; \
247
+ } \
248
+ _ls_qsize = _ls_insize; \
249
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
250
+ if (_ls_psize == 0) { \
251
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
252
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
253
+ } else if (_ls_qsize == 0 || !_ls_q) { \
254
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
255
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
256
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
257
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
258
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
259
+ } else { \
260
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
261
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
262
+ } \
263
+ if (_ls_tail) { \
264
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
265
+ } else { \
266
+ _CASTASGN(list,_ls_e); \
267
+ } \
268
+ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \
269
+ _ls_tail = _ls_e; \
270
+ } \
271
+ _ls_p = _ls_q; \
272
+ } \
273
+ _CASTASGN(list->prev,_ls_tail); \
274
+ _CASTASGN(_tmp2,list); \
275
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \
276
+ if (_ls_nmerges <= 1) { \
277
+ _ls_looping=0; \
278
+ } \
279
+ _ls_insize *= 2; \
280
+ } \
281
+ } else _tmp=NULL; /* quiet gcc unused variable warning */ \
282
+ } while (0)
283
+
284
+ /******************************************************************************
285
+ * singly linked list macros (non-circular) *
286
+ *****************************************************************************/
287
+ #define LL_PREPEND(head,add) \
288
+ do { \
289
+ (add)->next = head; \
290
+ head = add; \
291
+ } while (0)
292
+
293
+ #define LL_APPEND(head,add) \
294
+ do { \
295
+ LDECLTYPE(head) _tmp; \
296
+ (add)->next=NULL; \
297
+ if (head) { \
298
+ _tmp = head; \
299
+ while (_tmp->next) { _tmp = _tmp->next; } \
300
+ _tmp->next=(add); \
301
+ } else { \
302
+ (head)=(add); \
303
+ } \
304
+ } while (0)
305
+
306
+ #define LL_DELETE(head,del) \
307
+ do { \
308
+ LDECLTYPE(head) _tmp; \
309
+ if ((head) == (del)) { \
310
+ (head)=(head)->next; \
311
+ } else { \
312
+ _tmp = head; \
313
+ while (_tmp->next && (_tmp->next != (del))) { \
314
+ _tmp = _tmp->next; \
315
+ } \
316
+ if (_tmp->next) { \
317
+ _tmp->next = ((del)->next); \
318
+ } \
319
+ } \
320
+ } while (0)
321
+
322
+ /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
323
+ #define LL_APPEND_VS2008(head,add) \
324
+ do { \
325
+ if (head) { \
326
+ (add)->next = head; /* use add->next as a temp variable */ \
327
+ while ((add)->next->next) { (add)->next = (add)->next->next; } \
328
+ (add)->next->next=(add); \
329
+ } else { \
330
+ (head)=(add); \
331
+ } \
332
+ (add)->next=NULL; \
333
+ } while (0)
334
+
335
+ #define LL_DELETE_VS2008(head,del) \
336
+ do { \
337
+ if ((head) == (del)) { \
338
+ (head)=(head)->next; \
339
+ } else { \
340
+ char *_tmp = (char*)(head); \
341
+ while (head->next && (head->next != (del))) { \
342
+ head = head->next; \
343
+ } \
344
+ if (head->next) { \
345
+ head->next = ((del)->next); \
346
+ } \
347
+ { \
348
+ char **_head_alias = (char**)&(head); \
349
+ *_head_alias = _tmp; \
350
+ } \
351
+ } \
352
+ } while (0)
353
+ #ifdef NO_DECLTYPE
354
+ #undef LL_APPEND
355
+ #define LL_APPEND LL_APPEND_VS2008
356
+ #undef LL_DELETE
357
+ #define LL_DELETE LL_DELETE_VS2008
358
+ #endif
359
+ /* end VS2008 replacements */
360
+
361
+ #define LL_FOREACH(head,el) \
362
+ for(el=head;el;el=el->next)
363
+
364
+ #define LL_FOREACH_SAFE(head,el,tmp) \
365
+ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
366
+
367
+ #define LL_SEARCH_SCALAR(head,out,field,val) \
368
+ do { \
369
+ LL_FOREACH(head,out) { \
370
+ if ((out)->field == (val)) break; \
371
+ } \
372
+ } while(0)
373
+
374
+ #define LL_SEARCH(head,out,elt,cmp) \
375
+ do { \
376
+ LL_FOREACH(head,out) { \
377
+ if ((cmp(out,elt))==0) break; \
378
+ } \
379
+ } while(0)
380
+
381
+ /******************************************************************************
382
+ * doubly linked list macros (non-circular) *
383
+ *****************************************************************************/
384
+ #define DL_PREPEND(head,add) \
385
+ do { \
386
+ (add)->next = head; \
387
+ if (head) { \
388
+ (add)->prev = (head)->prev; \
389
+ (head)->prev = (add); \
390
+ } else { \
391
+ (add)->prev = (add); \
392
+ } \
393
+ (head) = (add); \
394
+ } while (0)
395
+
396
+ #define DL_APPEND(head,add) \
397
+ do { \
398
+ if (head) { \
399
+ (add)->prev = (head)->prev; \
400
+ (head)->prev->next = (add); \
401
+ (head)->prev = (add); \
402
+ (add)->next = NULL; \
403
+ } else { \
404
+ (head)=(add); \
405
+ (head)->prev = (head); \
406
+ (head)->next = NULL; \
407
+ } \
408
+ } while (0);
409
+
410
+ #define DL_DELETE(head,del) \
411
+ do { \
412
+ if ((del)->prev == (del)) { \
413
+ (head)=NULL; \
414
+ } else if ((del)==(head)) { \
415
+ (del)->next->prev = (del)->prev; \
416
+ (head) = (del)->next; \
417
+ } else { \
418
+ (del)->prev->next = (del)->next; \
419
+ if ((del)->next) { \
420
+ (del)->next->prev = (del)->prev; \
421
+ } else { \
422
+ (head)->prev = (del)->prev; \
423
+ } \
424
+ } \
425
+ } while (0);
426
+
427
+
428
+ #define DL_FOREACH(head,el) \
429
+ for(el=head;el;el=el->next)
430
+
431
+ /* this version is safe for deleting the elements during iteration */
432
+ #define DL_FOREACH_SAFE(head,el,tmp) \
433
+ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
434
+
435
+ /* these are identical to their singly-linked list counterparts */
436
+ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
437
+ #define DL_SEARCH LL_SEARCH
438
+
439
+ /******************************************************************************
440
+ * circular doubly linked list macros *
441
+ *****************************************************************************/
442
+ #define CDL_PREPEND(head,add) \
443
+ do { \
444
+ if (head) { \
445
+ (add)->prev = (head)->prev; \
446
+ (add)->next = (head); \
447
+ (head)->prev = (add); \
448
+ (add)->prev->next = (add); \
449
+ } else { \
450
+ (add)->prev = (add); \
451
+ (add)->next = (add); \
452
+ } \
453
+ (head)=(add); \
454
+ } while (0)
455
+
456
+ #define CDL_DELETE(head,del) \
457
+ do { \
458
+ if ( ((head)==(del)) && ((head)->next == (head))) { \
459
+ (head) = 0L; \
460
+ } else { \
461
+ (del)->next->prev = (del)->prev; \
462
+ (del)->prev->next = (del)->next; \
463
+ if ((del) == (head)) (head)=(del)->next; \
464
+ } \
465
+ } while (0);
466
+
467
+ #define CDL_FOREACH(head,el) \
468
+ for(el=head;el;el=(el->next==head ? 0L : el->next))
469
+
470
+ #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
471
+ for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \
472
+ (el) && ((tmp2)=(el)->next, 1); \
473
+ ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
474
+
475
+ #define CDL_SEARCH_SCALAR(head,out,field,val) \
476
+ do { \
477
+ CDL_FOREACH(head,out) { \
478
+ if ((out)->field == (val)) break; \
479
+ } \
480
+ } while(0)
481
+
482
+ #define CDL_SEARCH(head,out,elt,cmp) \
483
+ do { \
484
+ CDL_FOREACH(head,out) { \
485
+ if ((cmp(out,elt))==0) break; \
486
+ } \
487
+ } while(0)
488
+
489
+ #endif /* UTLIST_H */
490
+
collector/core/gripper/camera_service_src/third_party/libuvc/libuvc.pc.in ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@
2
+ includedir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@
3
+
4
+ Name: libuvc
5
+ Description: @libuvc_DESCRIPTION@
6
+ URL: @libuvc_URL@
7
+ Version: @libuvc_VERSION@
8
+ Libs: -L${libdir} -luvc
9
+ Libs.private: -lusb-1.0 @PKGCONFIG_JPEG_LDFLAG@
10
+ Cflags: -I${includedir}
11
+ Requires: libusb-1.0
collector/core/gripper/camera_service_src/third_party/libuvc/libuvcConfig.cmake ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
2
+
3
+ # If find_package called with REQUIRED or QUIET we need to
4
+ # forward down it
5
+ unset(extraArgs)
6
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
7
+ list(APPEND extraArgs QUIET)
8
+ endif()
9
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
10
+ list(APPEND extraArgs REQUIRED)
11
+ endif()
12
+
13
+ find_package(JpegPkg ${extraArgs})
14
+ find_package(LibUSB ${extraArgs})
15
+ include("${CMAKE_CURRENT_LIST_DIR}/libuvcTargets.cmake")
16
+
17
+ set(libuvc_FOUND TRUE)
collector/core/gripper/camera_service_src/third_party/libuvc/src/ctrl-gen.c ADDED
@@ -0,0 +1,2259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* This is an AUTO-GENERATED file! Update it with the output of `ctrl-gen.py def`. */
2
+ #include "libuvc/libuvc.h"
3
+ #include "libuvc/libuvc_internal.h"
4
+
5
+ static const int REQ_TYPE_SET = 0x21;
6
+ static const int REQ_TYPE_GET = 0xa1;
7
+
8
+ /** @ingroup ctrl
9
+ * @brief Reads the SCANNING_MODE control.
10
+ * @param devh UVC device handle
11
+ * @param[out] mode 0: interlaced, 1: progressive
12
+ * @param req_code UVC_GET_* request to execute
13
+ */
14
+ uvc_error_t uvc_get_scanning_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code) {
15
+ uint8_t data[1];
16
+ uvc_error_t ret;
17
+
18
+ ret = libusb_control_transfer(
19
+ devh->usb_devh,
20
+ REQ_TYPE_GET, req_code,
21
+ UVC_CT_SCANNING_MODE_CONTROL << 8,
22
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
23
+ data,
24
+ sizeof(data),
25
+ 0);
26
+
27
+ if (ret == sizeof(data)) {
28
+ *mode = data[0];
29
+ return UVC_SUCCESS;
30
+ } else {
31
+ return ret;
32
+ }
33
+ }
34
+
35
+
36
+ /** @ingroup ctrl
37
+ * @brief Sets the SCANNING_MODE control.
38
+ * @param devh UVC device handle
39
+ * @param mode 0: interlaced, 1: progressive
40
+ */
41
+ uvc_error_t uvc_set_scanning_mode(uvc_device_handle_t *devh, uint8_t mode) {
42
+ uint8_t data[1];
43
+ uvc_error_t ret;
44
+
45
+ data[0] = mode;
46
+
47
+ ret = libusb_control_transfer(
48
+ devh->usb_devh,
49
+ REQ_TYPE_SET, UVC_SET_CUR,
50
+ UVC_CT_SCANNING_MODE_CONTROL << 8,
51
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
52
+ data,
53
+ sizeof(data),
54
+ 0);
55
+
56
+ if (ret == sizeof(data))
57
+ return UVC_SUCCESS;
58
+ else
59
+ return ret;
60
+ }
61
+
62
+ /** @ingroup ctrl
63
+ * @brief Reads camera's auto-exposure mode.
64
+ *
65
+ * See uvc_set_ae_mode() for a description of the available modes.
66
+ * @param devh UVC device handle
67
+ * @param[out] mode 1: manual mode; 2: auto mode; 4: shutter priority mode; 8: aperture priority mode
68
+ * @param req_code UVC_GET_* request to execute
69
+ */
70
+ uvc_error_t uvc_get_ae_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code) {
71
+ uint8_t data[1];
72
+ uvc_error_t ret;
73
+
74
+ ret = libusb_control_transfer(
75
+ devh->usb_devh,
76
+ REQ_TYPE_GET, req_code,
77
+ UVC_CT_AE_MODE_CONTROL << 8,
78
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
79
+ data,
80
+ sizeof(data),
81
+ 0);
82
+
83
+ if (ret == sizeof(data)) {
84
+ *mode = data[0];
85
+ return UVC_SUCCESS;
86
+ } else {
87
+ return ret;
88
+ }
89
+ }
90
+
91
+
92
+ /** @ingroup ctrl
93
+ * @brief Sets camera's auto-exposure mode.
94
+ *
95
+ * Cameras may support any of the following AE modes:
96
+ * * UVC_AUTO_EXPOSURE_MODE_MANUAL (1) - manual exposure time, manual iris
97
+ * * UVC_AUTO_EXPOSURE_MODE_AUTO (2) - auto exposure time, auto iris
98
+ * * UVC_AUTO_EXPOSURE_MODE_SHUTTER_PRIORITY (4) - manual exposure time, auto iris
99
+ * * UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY (8) - auto exposure time, manual iris
100
+ *
101
+ * Most cameras provide manual mode and aperture priority mode.
102
+ * @param devh UVC device handle
103
+ * @param mode 1: manual mode; 2: auto mode; 4: shutter priority mode; 8: aperture priority mode
104
+ */
105
+ uvc_error_t uvc_set_ae_mode(uvc_device_handle_t *devh, uint8_t mode) {
106
+ uint8_t data[1];
107
+ uvc_error_t ret;
108
+
109
+ data[0] = mode;
110
+
111
+ ret = libusb_control_transfer(
112
+ devh->usb_devh,
113
+ REQ_TYPE_SET, UVC_SET_CUR,
114
+ UVC_CT_AE_MODE_CONTROL << 8,
115
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
116
+ data,
117
+ sizeof(data),
118
+ 0);
119
+
120
+ if (ret == sizeof(data))
121
+ return UVC_SUCCESS;
122
+ else
123
+ return ret;
124
+ }
125
+
126
+ /** @ingroup ctrl
127
+ * @brief Checks whether the camera may vary the frame rate for exposure control reasons.
128
+ * See uvc_set_ae_priority() for a description of the `priority` field.
129
+ * @param devh UVC device handle
130
+ * @param[out] priority 0: frame rate must remain constant; 1: frame rate may be varied for AE purposes
131
+ * @param req_code UVC_GET_* request to execute
132
+ */
133
+ uvc_error_t uvc_get_ae_priority(uvc_device_handle_t *devh, uint8_t* priority, enum uvc_req_code req_code) {
134
+ uint8_t data[1];
135
+ uvc_error_t ret;
136
+
137
+ ret = libusb_control_transfer(
138
+ devh->usb_devh,
139
+ REQ_TYPE_GET, req_code,
140
+ UVC_CT_AE_PRIORITY_CONTROL << 8,
141
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
142
+ data,
143
+ sizeof(data),
144
+ 0);
145
+
146
+ if (ret == sizeof(data)) {
147
+ *priority = data[0];
148
+ return UVC_SUCCESS;
149
+ } else {
150
+ return ret;
151
+ }
152
+ }
153
+
154
+
155
+ /** @ingroup ctrl
156
+ * @brief Chooses whether the camera may vary the frame rate for exposure control reasons.
157
+ * A `priority` value of zero means the camera may not vary its frame rate. A value of 1
158
+ * means the frame rate is variable. This setting has no effect outside of the `auto` and
159
+ * `shutter_priority` auto-exposure modes.
160
+ * @param devh UVC device handle
161
+ * @param priority 0: frame rate must remain constant; 1: frame rate may be varied for AE purposes
162
+ */
163
+ uvc_error_t uvc_set_ae_priority(uvc_device_handle_t *devh, uint8_t priority) {
164
+ uint8_t data[1];
165
+ uvc_error_t ret;
166
+
167
+ data[0] = priority;
168
+
169
+ ret = libusb_control_transfer(
170
+ devh->usb_devh,
171
+ REQ_TYPE_SET, UVC_SET_CUR,
172
+ UVC_CT_AE_PRIORITY_CONTROL << 8,
173
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
174
+ data,
175
+ sizeof(data),
176
+ 0);
177
+
178
+ if (ret == sizeof(data))
179
+ return UVC_SUCCESS;
180
+ else
181
+ return ret;
182
+ }
183
+
184
+ /** @ingroup ctrl
185
+ * @brief Gets the absolute exposure time.
186
+ *
187
+ * See uvc_set_exposure_abs() for a description of the `time` field.
188
+ * @param devh UVC device handle
189
+ * @param[out] time
190
+ * @param req_code UVC_GET_* request to execute
191
+ */
192
+ uvc_error_t uvc_get_exposure_abs(uvc_device_handle_t *devh, uint32_t* time, enum uvc_req_code req_code) {
193
+ uint8_t data[4];
194
+ uvc_error_t ret;
195
+
196
+ ret = libusb_control_transfer(
197
+ devh->usb_devh,
198
+ REQ_TYPE_GET, req_code,
199
+ UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL << 8,
200
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
201
+ data,
202
+ sizeof(data),
203
+ 0);
204
+
205
+ if (ret == sizeof(data)) {
206
+ *time = DW_TO_INT(data + 0);
207
+ return UVC_SUCCESS;
208
+ } else {
209
+ return ret;
210
+ }
211
+ }
212
+
213
+
214
+ /** @ingroup ctrl
215
+ * @brief Sets the absolute exposure time.
216
+ *
217
+ * The `time` parameter should be provided in units of 0.0001 seconds (e.g., use the value 100
218
+ * for a 10ms exposure period). Auto exposure should be set to `manual` or `shutter_priority`
219
+ * before attempting to change this setting.
220
+ * @param devh UVC device handle
221
+ * @param time
222
+ */
223
+ uvc_error_t uvc_set_exposure_abs(uvc_device_handle_t *devh, uint32_t time) {
224
+ uint8_t data[4];
225
+ uvc_error_t ret;
226
+
227
+ INT_TO_DW(time, data + 0);
228
+
229
+ ret = libusb_control_transfer(
230
+ devh->usb_devh,
231
+ REQ_TYPE_SET, UVC_SET_CUR,
232
+ UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL << 8,
233
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
234
+ data,
235
+ sizeof(data),
236
+ 0);
237
+
238
+ if (ret == sizeof(data))
239
+ return UVC_SUCCESS;
240
+ else
241
+ return ret;
242
+ }
243
+
244
+ /** @ingroup ctrl
245
+ * @brief Reads the exposure time relative to the current setting.
246
+ * @param devh UVC device handle
247
+ * @param[out] step number of steps by which to change the exposure time, or zero to set the default exposure time
248
+ * @param req_code UVC_GET_* request to execute
249
+ */
250
+ uvc_error_t uvc_get_exposure_rel(uvc_device_handle_t *devh, int8_t* step, enum uvc_req_code req_code) {
251
+ uint8_t data[1];
252
+ uvc_error_t ret;
253
+
254
+ ret = libusb_control_transfer(
255
+ devh->usb_devh,
256
+ REQ_TYPE_GET, req_code,
257
+ UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL << 8,
258
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
259
+ data,
260
+ sizeof(data),
261
+ 0);
262
+
263
+ if (ret == sizeof(data)) {
264
+ *step = data[0];
265
+ return UVC_SUCCESS;
266
+ } else {
267
+ return ret;
268
+ }
269
+ }
270
+
271
+
272
+ /** @ingroup ctrl
273
+ * @brief Sets the exposure time relative to the current setting.
274
+ * @param devh UVC device handle
275
+ * @param step number of steps by which to change the exposure time, or zero to set the default exposure time
276
+ */
277
+ uvc_error_t uvc_set_exposure_rel(uvc_device_handle_t *devh, int8_t step) {
278
+ uint8_t data[1];
279
+ uvc_error_t ret;
280
+
281
+ data[0] = step;
282
+
283
+ ret = libusb_control_transfer(
284
+ devh->usb_devh,
285
+ REQ_TYPE_SET, UVC_SET_CUR,
286
+ UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL << 8,
287
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
288
+ data,
289
+ sizeof(data),
290
+ 0);
291
+
292
+ if (ret == sizeof(data))
293
+ return UVC_SUCCESS;
294
+ else
295
+ return ret;
296
+ }
297
+
298
+ /** @ingroup ctrl
299
+ * @brief Reads the distance at which an object is optimally focused.
300
+ * @param devh UVC device handle
301
+ * @param[out] focus focal target distance in millimeters
302
+ * @param req_code UVC_GET_* request to execute
303
+ */
304
+ uvc_error_t uvc_get_focus_abs(uvc_device_handle_t *devh, uint16_t* focus, enum uvc_req_code req_code) {
305
+ uint8_t data[2];
306
+ uvc_error_t ret;
307
+
308
+ ret = libusb_control_transfer(
309
+ devh->usb_devh,
310
+ REQ_TYPE_GET, req_code,
311
+ UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
312
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
313
+ data,
314
+ sizeof(data),
315
+ 0);
316
+
317
+ if (ret == sizeof(data)) {
318
+ *focus = SW_TO_SHORT(data + 0);
319
+ return UVC_SUCCESS;
320
+ } else {
321
+ return ret;
322
+ }
323
+ }
324
+
325
+
326
+ /** @ingroup ctrl
327
+ * @brief Sets the distance at which an object is optimally focused.
328
+ * @param devh UVC device handle
329
+ * @param focus focal target distance in millimeters
330
+ */
331
+ uvc_error_t uvc_set_focus_abs(uvc_device_handle_t *devh, uint16_t focus) {
332
+ uint8_t data[2];
333
+ uvc_error_t ret;
334
+
335
+ SHORT_TO_SW(focus, data + 0);
336
+
337
+ ret = libusb_control_transfer(
338
+ devh->usb_devh,
339
+ REQ_TYPE_SET, UVC_SET_CUR,
340
+ UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
341
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
342
+ data,
343
+ sizeof(data),
344
+ 0);
345
+
346
+ if (ret == sizeof(data))
347
+ return UVC_SUCCESS;
348
+ else
349
+ return ret;
350
+ }
351
+
352
+ /** @ingroup ctrl
353
+ * @brief Reads the FOCUS_RELATIVE control.
354
+ * @param devh UVC device handle
355
+ * @param[out] focus_rel TODO
356
+ * @param[out] speed TODO
357
+ * @param req_code UVC_GET_* request to execute
358
+ */
359
+ uvc_error_t uvc_get_focus_rel(uvc_device_handle_t *devh, int8_t* focus_rel, uint8_t* speed, enum uvc_req_code req_code) {
360
+ uint8_t data[2];
361
+ uvc_error_t ret;
362
+
363
+ ret = libusb_control_transfer(
364
+ devh->usb_devh,
365
+ REQ_TYPE_GET, req_code,
366
+ UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
367
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
368
+ data,
369
+ sizeof(data),
370
+ 0);
371
+
372
+ if (ret == sizeof(data)) {
373
+ *focus_rel = data[0];
374
+ *speed = data[1];
375
+ return UVC_SUCCESS;
376
+ } else {
377
+ return ret;
378
+ }
379
+ }
380
+
381
+
382
+ /** @ingroup ctrl
383
+ * @brief Sets the FOCUS_RELATIVE control.
384
+ * @param devh UVC device handle
385
+ * @param focus_rel TODO
386
+ * @param speed TODO
387
+ */
388
+ uvc_error_t uvc_set_focus_rel(uvc_device_handle_t *devh, int8_t focus_rel, uint8_t speed) {
389
+ uint8_t data[2];
390
+ uvc_error_t ret;
391
+
392
+ data[0] = focus_rel;
393
+ data[1] = speed;
394
+
395
+ ret = libusb_control_transfer(
396
+ devh->usb_devh,
397
+ REQ_TYPE_SET, UVC_SET_CUR,
398
+ UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
399
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
400
+ data,
401
+ sizeof(data),
402
+ 0);
403
+
404
+ if (ret == sizeof(data))
405
+ return UVC_SUCCESS;
406
+ else
407
+ return ret;
408
+ }
409
+
410
+ /** @ingroup ctrl
411
+ * @brief Reads the FOCUS_SIMPLE control.
412
+ * @param devh UVC device handle
413
+ * @param[out] focus TODO
414
+ * @param req_code UVC_GET_* request to execute
415
+ */
416
+ uvc_error_t uvc_get_focus_simple_range(uvc_device_handle_t *devh, uint8_t* focus, enum uvc_req_code req_code) {
417
+ uint8_t data[1];
418
+ uvc_error_t ret;
419
+
420
+ ret = libusb_control_transfer(
421
+ devh->usb_devh,
422
+ REQ_TYPE_GET, req_code,
423
+ UVC_CT_FOCUS_SIMPLE_CONTROL << 8,
424
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
425
+ data,
426
+ sizeof(data),
427
+ 0);
428
+
429
+ if (ret == sizeof(data)) {
430
+ *focus = data[0];
431
+ return UVC_SUCCESS;
432
+ } else {
433
+ return ret;
434
+ }
435
+ }
436
+
437
+
438
+ /** @ingroup ctrl
439
+ * @brief Sets the FOCUS_SIMPLE control.
440
+ * @param devh UVC device handle
441
+ * @param focus TODO
442
+ */
443
+ uvc_error_t uvc_set_focus_simple_range(uvc_device_handle_t *devh, uint8_t focus) {
444
+ uint8_t data[1];
445
+ uvc_error_t ret;
446
+
447
+ data[0] = focus;
448
+
449
+ ret = libusb_control_transfer(
450
+ devh->usb_devh,
451
+ REQ_TYPE_SET, UVC_SET_CUR,
452
+ UVC_CT_FOCUS_SIMPLE_CONTROL << 8,
453
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
454
+ data,
455
+ sizeof(data),
456
+ 0);
457
+
458
+ if (ret == sizeof(data))
459
+ return UVC_SUCCESS;
460
+ else
461
+ return ret;
462
+ }
463
+
464
+ /** @ingroup ctrl
465
+ * @brief Reads the FOCUS_AUTO control.
466
+ * @param devh UVC device handle
467
+ * @param[out] state TODO
468
+ * @param req_code UVC_GET_* request to execute
469
+ */
470
+ uvc_error_t uvc_get_focus_auto(uvc_device_handle_t *devh, uint8_t* state, enum uvc_req_code req_code) {
471
+ uint8_t data[1];
472
+ uvc_error_t ret;
473
+
474
+ ret = libusb_control_transfer(
475
+ devh->usb_devh,
476
+ REQ_TYPE_GET, req_code,
477
+ UVC_CT_FOCUS_AUTO_CONTROL << 8,
478
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
479
+ data,
480
+ sizeof(data),
481
+ 0);
482
+
483
+ if (ret == sizeof(data)) {
484
+ *state = data[0];
485
+ return UVC_SUCCESS;
486
+ } else {
487
+ return ret;
488
+ }
489
+ }
490
+
491
+
492
+ /** @ingroup ctrl
493
+ * @brief Sets the FOCUS_AUTO control.
494
+ * @param devh UVC device handle
495
+ * @param state TODO
496
+ */
497
+ uvc_error_t uvc_set_focus_auto(uvc_device_handle_t *devh, uint8_t state) {
498
+ uint8_t data[1];
499
+ uvc_error_t ret;
500
+
501
+ data[0] = state;
502
+
503
+ ret = libusb_control_transfer(
504
+ devh->usb_devh,
505
+ REQ_TYPE_SET, UVC_SET_CUR,
506
+ UVC_CT_FOCUS_AUTO_CONTROL << 8,
507
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
508
+ data,
509
+ sizeof(data),
510
+ 0);
511
+
512
+ if (ret == sizeof(data))
513
+ return UVC_SUCCESS;
514
+ else
515
+ return ret;
516
+ }
517
+
518
+ /** @ingroup ctrl
519
+ * @brief Reads the IRIS_ABSOLUTE control.
520
+ * @param devh UVC device handle
521
+ * @param[out] iris TODO
522
+ * @param req_code UVC_GET_* request to execute
523
+ */
524
+ uvc_error_t uvc_get_iris_abs(uvc_device_handle_t *devh, uint16_t* iris, enum uvc_req_code req_code) {
525
+ uint8_t data[2];
526
+ uvc_error_t ret;
527
+
528
+ ret = libusb_control_transfer(
529
+ devh->usb_devh,
530
+ REQ_TYPE_GET, req_code,
531
+ UVC_CT_IRIS_ABSOLUTE_CONTROL << 8,
532
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
533
+ data,
534
+ sizeof(data),
535
+ 0);
536
+
537
+ if (ret == sizeof(data)) {
538
+ *iris = SW_TO_SHORT(data + 0);
539
+ return UVC_SUCCESS;
540
+ } else {
541
+ return ret;
542
+ }
543
+ }
544
+
545
+
546
+ /** @ingroup ctrl
547
+ * @brief Sets the IRIS_ABSOLUTE control.
548
+ * @param devh UVC device handle
549
+ * @param iris TODO
550
+ */
551
+ uvc_error_t uvc_set_iris_abs(uvc_device_handle_t *devh, uint16_t iris) {
552
+ uint8_t data[2];
553
+ uvc_error_t ret;
554
+
555
+ SHORT_TO_SW(iris, data + 0);
556
+
557
+ ret = libusb_control_transfer(
558
+ devh->usb_devh,
559
+ REQ_TYPE_SET, UVC_SET_CUR,
560
+ UVC_CT_IRIS_ABSOLUTE_CONTROL << 8,
561
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
562
+ data,
563
+ sizeof(data),
564
+ 0);
565
+
566
+ if (ret == sizeof(data))
567
+ return UVC_SUCCESS;
568
+ else
569
+ return ret;
570
+ }
571
+
572
+ /** @ingroup ctrl
573
+ * @brief Reads the IRIS_RELATIVE control.
574
+ * @param devh UVC device handle
575
+ * @param[out] iris_rel TODO
576
+ * @param req_code UVC_GET_* request to execute
577
+ */
578
+ uvc_error_t uvc_get_iris_rel(uvc_device_handle_t *devh, uint8_t* iris_rel, enum uvc_req_code req_code) {
579
+ uint8_t data[1];
580
+ uvc_error_t ret;
581
+
582
+ ret = libusb_control_transfer(
583
+ devh->usb_devh,
584
+ REQ_TYPE_GET, req_code,
585
+ UVC_CT_IRIS_RELATIVE_CONTROL << 8,
586
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
587
+ data,
588
+ sizeof(data),
589
+ 0);
590
+
591
+ if (ret == sizeof(data)) {
592
+ *iris_rel = data[0];
593
+ return UVC_SUCCESS;
594
+ } else {
595
+ return ret;
596
+ }
597
+ }
598
+
599
+
600
+ /** @ingroup ctrl
601
+ * @brief Sets the IRIS_RELATIVE control.
602
+ * @param devh UVC device handle
603
+ * @param iris_rel TODO
604
+ */
605
+ uvc_error_t uvc_set_iris_rel(uvc_device_handle_t *devh, uint8_t iris_rel) {
606
+ uint8_t data[1];
607
+ uvc_error_t ret;
608
+
609
+ data[0] = iris_rel;
610
+
611
+ ret = libusb_control_transfer(
612
+ devh->usb_devh,
613
+ REQ_TYPE_SET, UVC_SET_CUR,
614
+ UVC_CT_IRIS_RELATIVE_CONTROL << 8,
615
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
616
+ data,
617
+ sizeof(data),
618
+ 0);
619
+
620
+ if (ret == sizeof(data))
621
+ return UVC_SUCCESS;
622
+ else
623
+ return ret;
624
+ }
625
+
626
+ /** @ingroup ctrl
627
+ * @brief Reads the ZOOM_ABSOLUTE control.
628
+ * @param devh UVC device handle
629
+ * @param[out] focal_length TODO
630
+ * @param req_code UVC_GET_* request to execute
631
+ */
632
+ uvc_error_t uvc_get_zoom_abs(uvc_device_handle_t *devh, uint16_t* focal_length, enum uvc_req_code req_code) {
633
+ uint8_t data[2];
634
+ uvc_error_t ret;
635
+
636
+ ret = libusb_control_transfer(
637
+ devh->usb_devh,
638
+ REQ_TYPE_GET, req_code,
639
+ UVC_CT_ZOOM_ABSOLUTE_CONTROL << 8,
640
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
641
+ data,
642
+ sizeof(data),
643
+ 0);
644
+
645
+ if (ret == sizeof(data)) {
646
+ *focal_length = SW_TO_SHORT(data + 0);
647
+ return UVC_SUCCESS;
648
+ } else {
649
+ return ret;
650
+ }
651
+ }
652
+
653
+
654
+ /** @ingroup ctrl
655
+ * @brief Sets the ZOOM_ABSOLUTE control.
656
+ * @param devh UVC device handle
657
+ * @param focal_length TODO
658
+ */
659
+ uvc_error_t uvc_set_zoom_abs(uvc_device_handle_t *devh, uint16_t focal_length) {
660
+ uint8_t data[2];
661
+ uvc_error_t ret;
662
+
663
+ SHORT_TO_SW(focal_length, data + 0);
664
+
665
+ ret = libusb_control_transfer(
666
+ devh->usb_devh,
667
+ REQ_TYPE_SET, UVC_SET_CUR,
668
+ UVC_CT_ZOOM_ABSOLUTE_CONTROL << 8,
669
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
670
+ data,
671
+ sizeof(data),
672
+ 0);
673
+
674
+ if (ret == sizeof(data))
675
+ return UVC_SUCCESS;
676
+ else
677
+ return ret;
678
+ }
679
+
680
+ /** @ingroup ctrl
681
+ * @brief Reads the ZOOM_RELATIVE control.
682
+ * @param devh UVC device handle
683
+ * @param[out] zoom_rel TODO
684
+ * @param[out] digital_zoom TODO
685
+ * @param[out] speed TODO
686
+ * @param req_code UVC_GET_* request to execute
687
+ */
688
+ uvc_error_t uvc_get_zoom_rel(uvc_device_handle_t *devh, int8_t* zoom_rel, uint8_t* digital_zoom, uint8_t* speed, enum uvc_req_code req_code) {
689
+ uint8_t data[3];
690
+ uvc_error_t ret;
691
+
692
+ ret = libusb_control_transfer(
693
+ devh->usb_devh,
694
+ REQ_TYPE_GET, req_code,
695
+ UVC_CT_ZOOM_RELATIVE_CONTROL << 8,
696
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
697
+ data,
698
+ sizeof(data),
699
+ 0);
700
+
701
+ if (ret == sizeof(data)) {
702
+ *zoom_rel = data[0];
703
+ *digital_zoom = data[1];
704
+ *speed = data[2];
705
+ return UVC_SUCCESS;
706
+ } else {
707
+ return ret;
708
+ }
709
+ }
710
+
711
+
712
+ /** @ingroup ctrl
713
+ * @brief Sets the ZOOM_RELATIVE control.
714
+ * @param devh UVC device handle
715
+ * @param zoom_rel TODO
716
+ * @param digital_zoom TODO
717
+ * @param speed TODO
718
+ */
719
+ uvc_error_t uvc_set_zoom_rel(uvc_device_handle_t *devh, int8_t zoom_rel, uint8_t digital_zoom, uint8_t speed) {
720
+ uint8_t data[3];
721
+ uvc_error_t ret;
722
+
723
+ data[0] = zoom_rel;
724
+ data[1] = digital_zoom;
725
+ data[2] = speed;
726
+
727
+ ret = libusb_control_transfer(
728
+ devh->usb_devh,
729
+ REQ_TYPE_SET, UVC_SET_CUR,
730
+ UVC_CT_ZOOM_RELATIVE_CONTROL << 8,
731
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
732
+ data,
733
+ sizeof(data),
734
+ 0);
735
+
736
+ if (ret == sizeof(data))
737
+ return UVC_SUCCESS;
738
+ else
739
+ return ret;
740
+ }
741
+
742
+ /** @ingroup ctrl
743
+ * @brief Reads the PANTILT_ABSOLUTE control.
744
+ * @param devh UVC device handle
745
+ * @param[out] pan TODO
746
+ * @param[out] tilt TODO
747
+ * @param req_code UVC_GET_* request to execute
748
+ */
749
+ uvc_error_t uvc_get_pantilt_abs(uvc_device_handle_t *devh, int32_t* pan, int32_t* tilt, enum uvc_req_code req_code) {
750
+ uint8_t data[8];
751
+ uvc_error_t ret;
752
+
753
+ ret = libusb_control_transfer(
754
+ devh->usb_devh,
755
+ REQ_TYPE_GET, req_code,
756
+ UVC_CT_PANTILT_ABSOLUTE_CONTROL << 8,
757
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
758
+ data,
759
+ sizeof(data),
760
+ 0);
761
+
762
+ if (ret == sizeof(data)) {
763
+ *pan = DW_TO_INT(data + 0);
764
+ *tilt = DW_TO_INT(data + 4);
765
+ return UVC_SUCCESS;
766
+ } else {
767
+ return ret;
768
+ }
769
+ }
770
+
771
+
772
+ /** @ingroup ctrl
773
+ * @brief Sets the PANTILT_ABSOLUTE control.
774
+ * @param devh UVC device handle
775
+ * @param pan TODO
776
+ * @param tilt TODO
777
+ */
778
+ uvc_error_t uvc_set_pantilt_abs(uvc_device_handle_t *devh, int32_t pan, int32_t tilt) {
779
+ uint8_t data[8];
780
+ uvc_error_t ret;
781
+
782
+ INT_TO_DW(pan, data + 0);
783
+ INT_TO_DW(tilt, data + 4);
784
+
785
+ ret = libusb_control_transfer(
786
+ devh->usb_devh,
787
+ REQ_TYPE_SET, UVC_SET_CUR,
788
+ UVC_CT_PANTILT_ABSOLUTE_CONTROL << 8,
789
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
790
+ data,
791
+ sizeof(data),
792
+ 0);
793
+
794
+ if (ret == sizeof(data))
795
+ return UVC_SUCCESS;
796
+ else
797
+ return ret;
798
+ }
799
+
800
+ /** @ingroup ctrl
801
+ * @brief Reads the PANTILT_RELATIVE control.
802
+ * @param devh UVC device handle
803
+ * @param[out] pan_rel TODO
804
+ * @param[out] pan_speed TODO
805
+ * @param[out] tilt_rel TODO
806
+ * @param[out] tilt_speed TODO
807
+ * @param req_code UVC_GET_* request to execute
808
+ */
809
+ uvc_error_t uvc_get_pantilt_rel(uvc_device_handle_t *devh, int8_t* pan_rel, uint8_t* pan_speed, int8_t* tilt_rel, uint8_t* tilt_speed, enum uvc_req_code req_code) {
810
+ uint8_t data[4];
811
+ uvc_error_t ret;
812
+
813
+ ret = libusb_control_transfer(
814
+ devh->usb_devh,
815
+ REQ_TYPE_GET, req_code,
816
+ UVC_CT_PANTILT_RELATIVE_CONTROL << 8,
817
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
818
+ data,
819
+ sizeof(data),
820
+ 0);
821
+
822
+ if (ret == sizeof(data)) {
823
+ *pan_rel = data[0];
824
+ *pan_speed = data[1];
825
+ *tilt_rel = data[2];
826
+ *tilt_speed = data[3];
827
+ return UVC_SUCCESS;
828
+ } else {
829
+ return ret;
830
+ }
831
+ }
832
+
833
+
834
+ /** @ingroup ctrl
835
+ * @brief Sets the PANTILT_RELATIVE control.
836
+ * @param devh UVC device handle
837
+ * @param pan_rel TODO
838
+ * @param pan_speed TODO
839
+ * @param tilt_rel TODO
840
+ * @param tilt_speed TODO
841
+ */
842
+ uvc_error_t uvc_set_pantilt_rel(uvc_device_handle_t *devh, int8_t pan_rel, uint8_t pan_speed, int8_t tilt_rel, uint8_t tilt_speed) {
843
+ uint8_t data[4];
844
+ uvc_error_t ret;
845
+
846
+ data[0] = pan_rel;
847
+ data[1] = pan_speed;
848
+ data[2] = tilt_rel;
849
+ data[3] = tilt_speed;
850
+
851
+ ret = libusb_control_transfer(
852
+ devh->usb_devh,
853
+ REQ_TYPE_SET, UVC_SET_CUR,
854
+ UVC_CT_PANTILT_RELATIVE_CONTROL << 8,
855
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
856
+ data,
857
+ sizeof(data),
858
+ 0);
859
+
860
+ if (ret == sizeof(data))
861
+ return UVC_SUCCESS;
862
+ else
863
+ return ret;
864
+ }
865
+
866
+ /** @ingroup ctrl
867
+ * @brief Reads the ROLL_ABSOLUTE control.
868
+ * @param devh UVC device handle
869
+ * @param[out] roll TODO
870
+ * @param req_code UVC_GET_* request to execute
871
+ */
872
+ uvc_error_t uvc_get_roll_abs(uvc_device_handle_t *devh, int16_t* roll, enum uvc_req_code req_code) {
873
+ uint8_t data[2];
874
+ uvc_error_t ret;
875
+
876
+ ret = libusb_control_transfer(
877
+ devh->usb_devh,
878
+ REQ_TYPE_GET, req_code,
879
+ UVC_CT_ROLL_ABSOLUTE_CONTROL << 8,
880
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
881
+ data,
882
+ sizeof(data),
883
+ 0);
884
+
885
+ if (ret == sizeof(data)) {
886
+ *roll = SW_TO_SHORT(data + 0);
887
+ return UVC_SUCCESS;
888
+ } else {
889
+ return ret;
890
+ }
891
+ }
892
+
893
+
894
+ /** @ingroup ctrl
895
+ * @brief Sets the ROLL_ABSOLUTE control.
896
+ * @param devh UVC device handle
897
+ * @param roll TODO
898
+ */
899
+ uvc_error_t uvc_set_roll_abs(uvc_device_handle_t *devh, int16_t roll) {
900
+ uint8_t data[2];
901
+ uvc_error_t ret;
902
+
903
+ SHORT_TO_SW(roll, data + 0);
904
+
905
+ ret = libusb_control_transfer(
906
+ devh->usb_devh,
907
+ REQ_TYPE_SET, UVC_SET_CUR,
908
+ UVC_CT_ROLL_ABSOLUTE_CONTROL << 8,
909
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
910
+ data,
911
+ sizeof(data),
912
+ 0);
913
+
914
+ if (ret == sizeof(data))
915
+ return UVC_SUCCESS;
916
+ else
917
+ return ret;
918
+ }
919
+
920
+ /** @ingroup ctrl
921
+ * @brief Reads the ROLL_RELATIVE control.
922
+ * @param devh UVC device handle
923
+ * @param[out] roll_rel TODO
924
+ * @param[out] speed TODO
925
+ * @param req_code UVC_GET_* request to execute
926
+ */
927
+ uvc_error_t uvc_get_roll_rel(uvc_device_handle_t *devh, int8_t* roll_rel, uint8_t* speed, enum uvc_req_code req_code) {
928
+ uint8_t data[2];
929
+ uvc_error_t ret;
930
+
931
+ ret = libusb_control_transfer(
932
+ devh->usb_devh,
933
+ REQ_TYPE_GET, req_code,
934
+ UVC_CT_ROLL_RELATIVE_CONTROL << 8,
935
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
936
+ data,
937
+ sizeof(data),
938
+ 0);
939
+
940
+ if (ret == sizeof(data)) {
941
+ *roll_rel = data[0];
942
+ *speed = data[1];
943
+ return UVC_SUCCESS;
944
+ } else {
945
+ return ret;
946
+ }
947
+ }
948
+
949
+
950
+ /** @ingroup ctrl
951
+ * @brief Sets the ROLL_RELATIVE control.
952
+ * @param devh UVC device handle
953
+ * @param roll_rel TODO
954
+ * @param speed TODO
955
+ */
956
+ uvc_error_t uvc_set_roll_rel(uvc_device_handle_t *devh, int8_t roll_rel, uint8_t speed) {
957
+ uint8_t data[2];
958
+ uvc_error_t ret;
959
+
960
+ data[0] = roll_rel;
961
+ data[1] = speed;
962
+
963
+ ret = libusb_control_transfer(
964
+ devh->usb_devh,
965
+ REQ_TYPE_SET, UVC_SET_CUR,
966
+ UVC_CT_ROLL_RELATIVE_CONTROL << 8,
967
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
968
+ data,
969
+ sizeof(data),
970
+ 0);
971
+
972
+ if (ret == sizeof(data))
973
+ return UVC_SUCCESS;
974
+ else
975
+ return ret;
976
+ }
977
+
978
+ /** @ingroup ctrl
979
+ * @brief Reads the PRIVACY control.
980
+ * @param devh UVC device handle
981
+ * @param[out] privacy TODO
982
+ * @param req_code UVC_GET_* request to execute
983
+ */
984
+ uvc_error_t uvc_get_privacy(uvc_device_handle_t *devh, uint8_t* privacy, enum uvc_req_code req_code) {
985
+ uint8_t data[1];
986
+ uvc_error_t ret;
987
+
988
+ ret = libusb_control_transfer(
989
+ devh->usb_devh,
990
+ REQ_TYPE_GET, req_code,
991
+ UVC_CT_PRIVACY_CONTROL << 8,
992
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
993
+ data,
994
+ sizeof(data),
995
+ 0);
996
+
997
+ if (ret == sizeof(data)) {
998
+ *privacy = data[0];
999
+ return UVC_SUCCESS;
1000
+ } else {
1001
+ return ret;
1002
+ }
1003
+ }
1004
+
1005
+
1006
+ /** @ingroup ctrl
1007
+ * @brief Sets the PRIVACY control.
1008
+ * @param devh UVC device handle
1009
+ * @param privacy TODO
1010
+ */
1011
+ uvc_error_t uvc_set_privacy(uvc_device_handle_t *devh, uint8_t privacy) {
1012
+ uint8_t data[1];
1013
+ uvc_error_t ret;
1014
+
1015
+ data[0] = privacy;
1016
+
1017
+ ret = libusb_control_transfer(
1018
+ devh->usb_devh,
1019
+ REQ_TYPE_SET, UVC_SET_CUR,
1020
+ UVC_CT_PRIVACY_CONTROL << 8,
1021
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1022
+ data,
1023
+ sizeof(data),
1024
+ 0);
1025
+
1026
+ if (ret == sizeof(data))
1027
+ return UVC_SUCCESS;
1028
+ else
1029
+ return ret;
1030
+ }
1031
+
1032
+ /** @ingroup ctrl
1033
+ * @brief Reads the DIGITAL_WINDOW control.
1034
+ * @param devh UVC device handle
1035
+ * @param[out] window_top TODO
1036
+ * @param[out] window_left TODO
1037
+ * @param[out] window_bottom TODO
1038
+ * @param[out] window_right TODO
1039
+ * @param[out] num_steps TODO
1040
+ * @param[out] num_steps_units TODO
1041
+ * @param req_code UVC_GET_* request to execute
1042
+ */
1043
+ uvc_error_t uvc_get_digital_window(uvc_device_handle_t *devh, uint16_t* window_top, uint16_t* window_left, uint16_t* window_bottom, uint16_t* window_right, uint16_t* num_steps, uint16_t* num_steps_units, enum uvc_req_code req_code) {
1044
+ uint8_t data[12];
1045
+ uvc_error_t ret;
1046
+
1047
+ ret = libusb_control_transfer(
1048
+ devh->usb_devh,
1049
+ REQ_TYPE_GET, req_code,
1050
+ UVC_CT_DIGITAL_WINDOW_CONTROL << 8,
1051
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1052
+ data,
1053
+ sizeof(data),
1054
+ 0);
1055
+
1056
+ if (ret == sizeof(data)) {
1057
+ *window_top = SW_TO_SHORT(data + 0);
1058
+ *window_left = SW_TO_SHORT(data + 2);
1059
+ *window_bottom = SW_TO_SHORT(data + 4);
1060
+ *window_right = SW_TO_SHORT(data + 6);
1061
+ *num_steps = SW_TO_SHORT(data + 8);
1062
+ *num_steps_units = SW_TO_SHORT(data + 10);
1063
+ return UVC_SUCCESS;
1064
+ } else {
1065
+ return ret;
1066
+ }
1067
+ }
1068
+
1069
+
1070
+ /** @ingroup ctrl
1071
+ * @brief Sets the DIGITAL_WINDOW control.
1072
+ * @param devh UVC device handle
1073
+ * @param window_top TODO
1074
+ * @param window_left TODO
1075
+ * @param window_bottom TODO
1076
+ * @param window_right TODO
1077
+ * @param num_steps TODO
1078
+ * @param num_steps_units TODO
1079
+ */
1080
+ uvc_error_t uvc_set_digital_window(uvc_device_handle_t *devh, uint16_t window_top, uint16_t window_left, uint16_t window_bottom, uint16_t window_right, uint16_t num_steps, uint16_t num_steps_units) {
1081
+ uint8_t data[12];
1082
+ uvc_error_t ret;
1083
+
1084
+ SHORT_TO_SW(window_top, data + 0);
1085
+ SHORT_TO_SW(window_left, data + 2);
1086
+ SHORT_TO_SW(window_bottom, data + 4);
1087
+ SHORT_TO_SW(window_right, data + 6);
1088
+ SHORT_TO_SW(num_steps, data + 8);
1089
+ SHORT_TO_SW(num_steps_units, data + 10);
1090
+
1091
+ ret = libusb_control_transfer(
1092
+ devh->usb_devh,
1093
+ REQ_TYPE_SET, UVC_SET_CUR,
1094
+ UVC_CT_DIGITAL_WINDOW_CONTROL << 8,
1095
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1096
+ data,
1097
+ sizeof(data),
1098
+ 0);
1099
+
1100
+ if (ret == sizeof(data))
1101
+ return UVC_SUCCESS;
1102
+ else
1103
+ return ret;
1104
+ }
1105
+
1106
+ /** @ingroup ctrl
1107
+ * @brief Reads the REGION_OF_INTEREST control.
1108
+ * @param devh UVC device handle
1109
+ * @param[out] roi_top TODO
1110
+ * @param[out] roi_left TODO
1111
+ * @param[out] roi_bottom TODO
1112
+ * @param[out] roi_right TODO
1113
+ * @param[out] auto_controls TODO
1114
+ * @param req_code UVC_GET_* request to execute
1115
+ */
1116
+ uvc_error_t uvc_get_digital_roi(uvc_device_handle_t *devh, uint16_t* roi_top, uint16_t* roi_left, uint16_t* roi_bottom, uint16_t* roi_right, uint16_t* auto_controls, enum uvc_req_code req_code) {
1117
+ uint8_t data[10];
1118
+ uvc_error_t ret;
1119
+
1120
+ ret = libusb_control_transfer(
1121
+ devh->usb_devh,
1122
+ REQ_TYPE_GET, req_code,
1123
+ UVC_CT_REGION_OF_INTEREST_CONTROL << 8,
1124
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1125
+ data,
1126
+ sizeof(data),
1127
+ 0);
1128
+
1129
+ if (ret == sizeof(data)) {
1130
+ *roi_top = SW_TO_SHORT(data + 0);
1131
+ *roi_left = SW_TO_SHORT(data + 2);
1132
+ *roi_bottom = SW_TO_SHORT(data + 4);
1133
+ *roi_right = SW_TO_SHORT(data + 6);
1134
+ *auto_controls = SW_TO_SHORT(data + 8);
1135
+ return UVC_SUCCESS;
1136
+ } else {
1137
+ return ret;
1138
+ }
1139
+ }
1140
+
1141
+
1142
+ /** @ingroup ctrl
1143
+ * @brief Sets the REGION_OF_INTEREST control.
1144
+ * @param devh UVC device handle
1145
+ * @param roi_top TODO
1146
+ * @param roi_left TODO
1147
+ * @param roi_bottom TODO
1148
+ * @param roi_right TODO
1149
+ * @param auto_controls TODO
1150
+ */
1151
+ uvc_error_t uvc_set_digital_roi(uvc_device_handle_t *devh, uint16_t roi_top, uint16_t roi_left, uint16_t roi_bottom, uint16_t roi_right, uint16_t auto_controls) {
1152
+ uint8_t data[10];
1153
+ uvc_error_t ret;
1154
+
1155
+ SHORT_TO_SW(roi_top, data + 0);
1156
+ SHORT_TO_SW(roi_left, data + 2);
1157
+ SHORT_TO_SW(roi_bottom, data + 4);
1158
+ SHORT_TO_SW(roi_right, data + 6);
1159
+ SHORT_TO_SW(auto_controls, data + 8);
1160
+
1161
+ ret = libusb_control_transfer(
1162
+ devh->usb_devh,
1163
+ REQ_TYPE_SET, UVC_SET_CUR,
1164
+ UVC_CT_REGION_OF_INTEREST_CONTROL << 8,
1165
+ uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1166
+ data,
1167
+ sizeof(data),
1168
+ 0);
1169
+
1170
+ if (ret == sizeof(data))
1171
+ return UVC_SUCCESS;
1172
+ else
1173
+ return ret;
1174
+ }
1175
+
1176
+ /** @ingroup ctrl
1177
+ * @brief Reads the BACKLIGHT_COMPENSATION control.
1178
+ * @param devh UVC device handle
1179
+ * @param[out] backlight_compensation device-dependent backlight compensation mode; zero means backlight compensation is disabled
1180
+ * @param req_code UVC_GET_* request to execute
1181
+ */
1182
+ uvc_error_t uvc_get_backlight_compensation(uvc_device_handle_t *devh, uint16_t* backlight_compensation, enum uvc_req_code req_code) {
1183
+ uint8_t data[2];
1184
+ uvc_error_t ret;
1185
+
1186
+ ret = libusb_control_transfer(
1187
+ devh->usb_devh,
1188
+ REQ_TYPE_GET, req_code,
1189
+ UVC_PU_BACKLIGHT_COMPENSATION_CONTROL << 8,
1190
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1191
+ data,
1192
+ sizeof(data),
1193
+ 0);
1194
+
1195
+ if (ret == sizeof(data)) {
1196
+ *backlight_compensation = SW_TO_SHORT(data + 0);
1197
+ return UVC_SUCCESS;
1198
+ } else {
1199
+ return ret;
1200
+ }
1201
+ }
1202
+
1203
+
1204
+ /** @ingroup ctrl
1205
+ * @brief Sets the BACKLIGHT_COMPENSATION control.
1206
+ * @param devh UVC device handle
1207
+ * @param backlight_compensation device-dependent backlight compensation mode; zero means backlight compensation is disabled
1208
+ */
1209
+ uvc_error_t uvc_set_backlight_compensation(uvc_device_handle_t *devh, uint16_t backlight_compensation) {
1210
+ uint8_t data[2];
1211
+ uvc_error_t ret;
1212
+
1213
+ SHORT_TO_SW(backlight_compensation, data + 0);
1214
+
1215
+ ret = libusb_control_transfer(
1216
+ devh->usb_devh,
1217
+ REQ_TYPE_SET, UVC_SET_CUR,
1218
+ UVC_PU_BACKLIGHT_COMPENSATION_CONTROL << 8,
1219
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1220
+ data,
1221
+ sizeof(data),
1222
+ 0);
1223
+
1224
+ if (ret == sizeof(data))
1225
+ return UVC_SUCCESS;
1226
+ else
1227
+ return ret;
1228
+ }
1229
+
1230
+ /** @ingroup ctrl
1231
+ * @brief Reads the BRIGHTNESS control.
1232
+ * @param devh UVC device handle
1233
+ * @param[out] brightness TODO
1234
+ * @param req_code UVC_GET_* request to execute
1235
+ */
1236
+ uvc_error_t uvc_get_brightness(uvc_device_handle_t *devh, int16_t* brightness, enum uvc_req_code req_code) {
1237
+ uint8_t data[2];
1238
+ uvc_error_t ret;
1239
+
1240
+ ret = libusb_control_transfer(
1241
+ devh->usb_devh,
1242
+ REQ_TYPE_GET, req_code,
1243
+ UVC_PU_BRIGHTNESS_CONTROL << 8,
1244
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1245
+ data,
1246
+ sizeof(data),
1247
+ 0);
1248
+
1249
+ if (ret == sizeof(data)) {
1250
+ *brightness = SW_TO_SHORT(data + 0);
1251
+ return UVC_SUCCESS;
1252
+ } else {
1253
+ return ret;
1254
+ }
1255
+ }
1256
+
1257
+
1258
+ /** @ingroup ctrl
1259
+ * @brief Sets the BRIGHTNESS control.
1260
+ * @param devh UVC device handle
1261
+ * @param brightness TODO
1262
+ */
1263
+ uvc_error_t uvc_set_brightness(uvc_device_handle_t *devh, int16_t brightness) {
1264
+ uint8_t data[2];
1265
+ uvc_error_t ret;
1266
+
1267
+ SHORT_TO_SW(brightness, data + 0);
1268
+
1269
+ ret = libusb_control_transfer(
1270
+ devh->usb_devh,
1271
+ REQ_TYPE_SET, UVC_SET_CUR,
1272
+ UVC_PU_BRIGHTNESS_CONTROL << 8,
1273
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1274
+ data,
1275
+ sizeof(data),
1276
+ 0);
1277
+
1278
+ if (ret == sizeof(data))
1279
+ return UVC_SUCCESS;
1280
+ else
1281
+ return ret;
1282
+ }
1283
+
1284
+ /** @ingroup ctrl
1285
+ * @brief Reads the CONTRAST control.
1286
+ * @param devh UVC device handle
1287
+ * @param[out] contrast TODO
1288
+ * @param req_code UVC_GET_* request to execute
1289
+ */
1290
+ uvc_error_t uvc_get_contrast(uvc_device_handle_t *devh, uint16_t* contrast, enum uvc_req_code req_code) {
1291
+ uint8_t data[2];
1292
+ uvc_error_t ret;
1293
+
1294
+ ret = libusb_control_transfer(
1295
+ devh->usb_devh,
1296
+ REQ_TYPE_GET, req_code,
1297
+ UVC_PU_CONTRAST_CONTROL << 8,
1298
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1299
+ data,
1300
+ sizeof(data),
1301
+ 0);
1302
+
1303
+ if (ret == sizeof(data)) {
1304
+ *contrast = SW_TO_SHORT(data + 0);
1305
+ return UVC_SUCCESS;
1306
+ } else {
1307
+ return ret;
1308
+ }
1309
+ }
1310
+
1311
+
1312
+ /** @ingroup ctrl
1313
+ * @brief Sets the CONTRAST control.
1314
+ * @param devh UVC device handle
1315
+ * @param contrast TODO
1316
+ */
1317
+ uvc_error_t uvc_set_contrast(uvc_device_handle_t *devh, uint16_t contrast) {
1318
+ uint8_t data[2];
1319
+ uvc_error_t ret;
1320
+
1321
+ SHORT_TO_SW(contrast, data + 0);
1322
+
1323
+ ret = libusb_control_transfer(
1324
+ devh->usb_devh,
1325
+ REQ_TYPE_SET, UVC_SET_CUR,
1326
+ UVC_PU_CONTRAST_CONTROL << 8,
1327
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1328
+ data,
1329
+ sizeof(data),
1330
+ 0);
1331
+
1332
+ if (ret == sizeof(data))
1333
+ return UVC_SUCCESS;
1334
+ else
1335
+ return ret;
1336
+ }
1337
+
1338
+ /** @ingroup ctrl
1339
+ * @brief Reads the CONTRAST_AUTO control.
1340
+ * @param devh UVC device handle
1341
+ * @param[out] contrast_auto TODO
1342
+ * @param req_code UVC_GET_* request to execute
1343
+ */
1344
+ uvc_error_t uvc_get_contrast_auto(uvc_device_handle_t *devh, uint8_t* contrast_auto, enum uvc_req_code req_code) {
1345
+ uint8_t data[1];
1346
+ uvc_error_t ret;
1347
+
1348
+ ret = libusb_control_transfer(
1349
+ devh->usb_devh,
1350
+ REQ_TYPE_GET, req_code,
1351
+ UVC_PU_CONTRAST_AUTO_CONTROL << 8,
1352
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1353
+ data,
1354
+ sizeof(data),
1355
+ 0);
1356
+
1357
+ if (ret == sizeof(data)) {
1358
+ *contrast_auto = data[0];
1359
+ return UVC_SUCCESS;
1360
+ } else {
1361
+ return ret;
1362
+ }
1363
+ }
1364
+
1365
+
1366
+ /** @ingroup ctrl
1367
+ * @brief Sets the CONTRAST_AUTO control.
1368
+ * @param devh UVC device handle
1369
+ * @param contrast_auto TODO
1370
+ */
1371
+ uvc_error_t uvc_set_contrast_auto(uvc_device_handle_t *devh, uint8_t contrast_auto) {
1372
+ uint8_t data[1];
1373
+ uvc_error_t ret;
1374
+
1375
+ data[0] = contrast_auto;
1376
+
1377
+ ret = libusb_control_transfer(
1378
+ devh->usb_devh,
1379
+ REQ_TYPE_SET, UVC_SET_CUR,
1380
+ UVC_PU_CONTRAST_AUTO_CONTROL << 8,
1381
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1382
+ data,
1383
+ sizeof(data),
1384
+ 0);
1385
+
1386
+ if (ret == sizeof(data))
1387
+ return UVC_SUCCESS;
1388
+ else
1389
+ return ret;
1390
+ }
1391
+
1392
+ /** @ingroup ctrl
1393
+ * @brief Reads the GAIN control.
1394
+ * @param devh UVC device handle
1395
+ * @param[out] gain TODO
1396
+ * @param req_code UVC_GET_* request to execute
1397
+ */
1398
+ uvc_error_t uvc_get_gain(uvc_device_handle_t *devh, uint16_t* gain, enum uvc_req_code req_code) {
1399
+ uint8_t data[2];
1400
+ uvc_error_t ret;
1401
+
1402
+ ret = libusb_control_transfer(
1403
+ devh->usb_devh,
1404
+ REQ_TYPE_GET, req_code,
1405
+ UVC_PU_GAIN_CONTROL << 8,
1406
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1407
+ data,
1408
+ sizeof(data),
1409
+ 0);
1410
+
1411
+ if (ret == sizeof(data)) {
1412
+ *gain = SW_TO_SHORT(data + 0);
1413
+ return UVC_SUCCESS;
1414
+ } else {
1415
+ return ret;
1416
+ }
1417
+ }
1418
+
1419
+
1420
+ /** @ingroup ctrl
1421
+ * @brief Sets the GAIN control.
1422
+ * @param devh UVC device handle
1423
+ * @param gain TODO
1424
+ */
1425
+ uvc_error_t uvc_set_gain(uvc_device_handle_t *devh, uint16_t gain) {
1426
+ uint8_t data[2];
1427
+ uvc_error_t ret;
1428
+
1429
+ SHORT_TO_SW(gain, data + 0);
1430
+
1431
+ ret = libusb_control_transfer(
1432
+ devh->usb_devh,
1433
+ REQ_TYPE_SET, UVC_SET_CUR,
1434
+ UVC_PU_GAIN_CONTROL << 8,
1435
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1436
+ data,
1437
+ sizeof(data),
1438
+ 0);
1439
+
1440
+ if (ret == sizeof(data))
1441
+ return UVC_SUCCESS;
1442
+ else
1443
+ return ret;
1444
+ }
1445
+
1446
+ /** @ingroup ctrl
1447
+ * @brief Reads the POWER_LINE_FREQUENCY control.
1448
+ * @param devh UVC device handle
1449
+ * @param[out] power_line_frequency TODO
1450
+ * @param req_code UVC_GET_* request to execute
1451
+ */
1452
+ uvc_error_t uvc_get_power_line_frequency(uvc_device_handle_t *devh, uint8_t* power_line_frequency, enum uvc_req_code req_code) {
1453
+ uint8_t data[1];
1454
+ uvc_error_t ret;
1455
+
1456
+ ret = libusb_control_transfer(
1457
+ devh->usb_devh,
1458
+ REQ_TYPE_GET, req_code,
1459
+ UVC_PU_POWER_LINE_FREQUENCY_CONTROL << 8,
1460
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1461
+ data,
1462
+ sizeof(data),
1463
+ 0);
1464
+
1465
+ if (ret == sizeof(data)) {
1466
+ *power_line_frequency = data[0];
1467
+ return UVC_SUCCESS;
1468
+ } else {
1469
+ return ret;
1470
+ }
1471
+ }
1472
+
1473
+
1474
+ /** @ingroup ctrl
1475
+ * @brief Sets the POWER_LINE_FREQUENCY control.
1476
+ * @param devh UVC device handle
1477
+ * @param power_line_frequency TODO
1478
+ */
1479
+ uvc_error_t uvc_set_power_line_frequency(uvc_device_handle_t *devh, uint8_t power_line_frequency) {
1480
+ uint8_t data[1];
1481
+ uvc_error_t ret;
1482
+
1483
+ data[0] = power_line_frequency;
1484
+
1485
+ ret = libusb_control_transfer(
1486
+ devh->usb_devh,
1487
+ REQ_TYPE_SET, UVC_SET_CUR,
1488
+ UVC_PU_POWER_LINE_FREQUENCY_CONTROL << 8,
1489
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1490
+ data,
1491
+ sizeof(data),
1492
+ 0);
1493
+
1494
+ if (ret == sizeof(data))
1495
+ return UVC_SUCCESS;
1496
+ else
1497
+ return ret;
1498
+ }
1499
+
1500
+ /** @ingroup ctrl
1501
+ * @brief Reads the HUE control.
1502
+ * @param devh UVC device handle
1503
+ * @param[out] hue TODO
1504
+ * @param req_code UVC_GET_* request to execute
1505
+ */
1506
+ uvc_error_t uvc_get_hue(uvc_device_handle_t *devh, int16_t* hue, enum uvc_req_code req_code) {
1507
+ uint8_t data[2];
1508
+ uvc_error_t ret;
1509
+
1510
+ ret = libusb_control_transfer(
1511
+ devh->usb_devh,
1512
+ REQ_TYPE_GET, req_code,
1513
+ UVC_PU_HUE_CONTROL << 8,
1514
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1515
+ data,
1516
+ sizeof(data),
1517
+ 0);
1518
+
1519
+ if (ret == sizeof(data)) {
1520
+ *hue = SW_TO_SHORT(data + 0);
1521
+ return UVC_SUCCESS;
1522
+ } else {
1523
+ return ret;
1524
+ }
1525
+ }
1526
+
1527
+
1528
+ /** @ingroup ctrl
1529
+ * @brief Sets the HUE control.
1530
+ * @param devh UVC device handle
1531
+ * @param hue TODO
1532
+ */
1533
+ uvc_error_t uvc_set_hue(uvc_device_handle_t *devh, int16_t hue) {
1534
+ uint8_t data[2];
1535
+ uvc_error_t ret;
1536
+
1537
+ SHORT_TO_SW(hue, data + 0);
1538
+
1539
+ ret = libusb_control_transfer(
1540
+ devh->usb_devh,
1541
+ REQ_TYPE_SET, UVC_SET_CUR,
1542
+ UVC_PU_HUE_CONTROL << 8,
1543
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1544
+ data,
1545
+ sizeof(data),
1546
+ 0);
1547
+
1548
+ if (ret == sizeof(data))
1549
+ return UVC_SUCCESS;
1550
+ else
1551
+ return ret;
1552
+ }
1553
+
1554
+ /** @ingroup ctrl
1555
+ * @brief Reads the HUE_AUTO control.
1556
+ * @param devh UVC device handle
1557
+ * @param[out] hue_auto TODO
1558
+ * @param req_code UVC_GET_* request to execute
1559
+ */
1560
+ uvc_error_t uvc_get_hue_auto(uvc_device_handle_t *devh, uint8_t* hue_auto, enum uvc_req_code req_code) {
1561
+ uint8_t data[1];
1562
+ uvc_error_t ret;
1563
+
1564
+ ret = libusb_control_transfer(
1565
+ devh->usb_devh,
1566
+ REQ_TYPE_GET, req_code,
1567
+ UVC_PU_HUE_AUTO_CONTROL << 8,
1568
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1569
+ data,
1570
+ sizeof(data),
1571
+ 0);
1572
+
1573
+ if (ret == sizeof(data)) {
1574
+ *hue_auto = data[0];
1575
+ return UVC_SUCCESS;
1576
+ } else {
1577
+ return ret;
1578
+ }
1579
+ }
1580
+
1581
+
1582
+ /** @ingroup ctrl
1583
+ * @brief Sets the HUE_AUTO control.
1584
+ * @param devh UVC device handle
1585
+ * @param hue_auto TODO
1586
+ */
1587
+ uvc_error_t uvc_set_hue_auto(uvc_device_handle_t *devh, uint8_t hue_auto) {
1588
+ uint8_t data[1];
1589
+ uvc_error_t ret;
1590
+
1591
+ data[0] = hue_auto;
1592
+
1593
+ ret = libusb_control_transfer(
1594
+ devh->usb_devh,
1595
+ REQ_TYPE_SET, UVC_SET_CUR,
1596
+ UVC_PU_HUE_AUTO_CONTROL << 8,
1597
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1598
+ data,
1599
+ sizeof(data),
1600
+ 0);
1601
+
1602
+ if (ret == sizeof(data))
1603
+ return UVC_SUCCESS;
1604
+ else
1605
+ return ret;
1606
+ }
1607
+
1608
+ /** @ingroup ctrl
1609
+ * @brief Reads the SATURATION control.
1610
+ * @param devh UVC device handle
1611
+ * @param[out] saturation TODO
1612
+ * @param req_code UVC_GET_* request to execute
1613
+ */
1614
+ uvc_error_t uvc_get_saturation(uvc_device_handle_t *devh, uint16_t* saturation, enum uvc_req_code req_code) {
1615
+ uint8_t data[2];
1616
+ uvc_error_t ret;
1617
+
1618
+ ret = libusb_control_transfer(
1619
+ devh->usb_devh,
1620
+ REQ_TYPE_GET, req_code,
1621
+ UVC_PU_SATURATION_CONTROL << 8,
1622
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1623
+ data,
1624
+ sizeof(data),
1625
+ 0);
1626
+
1627
+ if (ret == sizeof(data)) {
1628
+ *saturation = SW_TO_SHORT(data + 0);
1629
+ return UVC_SUCCESS;
1630
+ } else {
1631
+ return ret;
1632
+ }
1633
+ }
1634
+
1635
+
1636
+ /** @ingroup ctrl
1637
+ * @brief Sets the SATURATION control.
1638
+ * @param devh UVC device handle
1639
+ * @param saturation TODO
1640
+ */
1641
+ uvc_error_t uvc_set_saturation(uvc_device_handle_t *devh, uint16_t saturation) {
1642
+ uint8_t data[2];
1643
+ uvc_error_t ret;
1644
+
1645
+ SHORT_TO_SW(saturation, data + 0);
1646
+
1647
+ ret = libusb_control_transfer(
1648
+ devh->usb_devh,
1649
+ REQ_TYPE_SET, UVC_SET_CUR,
1650
+ UVC_PU_SATURATION_CONTROL << 8,
1651
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1652
+ data,
1653
+ sizeof(data),
1654
+ 0);
1655
+
1656
+ if (ret == sizeof(data))
1657
+ return UVC_SUCCESS;
1658
+ else
1659
+ return ret;
1660
+ }
1661
+
1662
+ /** @ingroup ctrl
1663
+ * @brief Reads the SHARPNESS control.
1664
+ * @param devh UVC device handle
1665
+ * @param[out] sharpness TODO
1666
+ * @param req_code UVC_GET_* request to execute
1667
+ */
1668
+ uvc_error_t uvc_get_sharpness(uvc_device_handle_t *devh, uint16_t* sharpness, enum uvc_req_code req_code) {
1669
+ uint8_t data[2];
1670
+ uvc_error_t ret;
1671
+
1672
+ ret = libusb_control_transfer(
1673
+ devh->usb_devh,
1674
+ REQ_TYPE_GET, req_code,
1675
+ UVC_PU_SHARPNESS_CONTROL << 8,
1676
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1677
+ data,
1678
+ sizeof(data),
1679
+ 0);
1680
+
1681
+ if (ret == sizeof(data)) {
1682
+ *sharpness = SW_TO_SHORT(data + 0);
1683
+ return UVC_SUCCESS;
1684
+ } else {
1685
+ return ret;
1686
+ }
1687
+ }
1688
+
1689
+
1690
+ /** @ingroup ctrl
1691
+ * @brief Sets the SHARPNESS control.
1692
+ * @param devh UVC device handle
1693
+ * @param sharpness TODO
1694
+ */
1695
+ uvc_error_t uvc_set_sharpness(uvc_device_handle_t *devh, uint16_t sharpness) {
1696
+ uint8_t data[2];
1697
+ uvc_error_t ret;
1698
+
1699
+ SHORT_TO_SW(sharpness, data + 0);
1700
+
1701
+ ret = libusb_control_transfer(
1702
+ devh->usb_devh,
1703
+ REQ_TYPE_SET, UVC_SET_CUR,
1704
+ UVC_PU_SHARPNESS_CONTROL << 8,
1705
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1706
+ data,
1707
+ sizeof(data),
1708
+ 0);
1709
+
1710
+ if (ret == sizeof(data))
1711
+ return UVC_SUCCESS;
1712
+ else
1713
+ return ret;
1714
+ }
1715
+
1716
+ /** @ingroup ctrl
1717
+ * @brief Reads the GAMMA control.
1718
+ * @param devh UVC device handle
1719
+ * @param[out] gamma TODO
1720
+ * @param req_code UVC_GET_* request to execute
1721
+ */
1722
+ uvc_error_t uvc_get_gamma(uvc_device_handle_t *devh, uint16_t* gamma, enum uvc_req_code req_code) {
1723
+ uint8_t data[2];
1724
+ uvc_error_t ret;
1725
+
1726
+ ret = libusb_control_transfer(
1727
+ devh->usb_devh,
1728
+ REQ_TYPE_GET, req_code,
1729
+ UVC_PU_GAMMA_CONTROL << 8,
1730
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1731
+ data,
1732
+ sizeof(data),
1733
+ 0);
1734
+
1735
+ if (ret == sizeof(data)) {
1736
+ *gamma = SW_TO_SHORT(data + 0);
1737
+ return UVC_SUCCESS;
1738
+ } else {
1739
+ return ret;
1740
+ }
1741
+ }
1742
+
1743
+
1744
+ /** @ingroup ctrl
1745
+ * @brief Sets the GAMMA control.
1746
+ * @param devh UVC device handle
1747
+ * @param gamma TODO
1748
+ */
1749
+ uvc_error_t uvc_set_gamma(uvc_device_handle_t *devh, uint16_t gamma) {
1750
+ uint8_t data[2];
1751
+ uvc_error_t ret;
1752
+
1753
+ SHORT_TO_SW(gamma, data + 0);
1754
+
1755
+ ret = libusb_control_transfer(
1756
+ devh->usb_devh,
1757
+ REQ_TYPE_SET, UVC_SET_CUR,
1758
+ UVC_PU_GAMMA_CONTROL << 8,
1759
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1760
+ data,
1761
+ sizeof(data),
1762
+ 0);
1763
+
1764
+ if (ret == sizeof(data))
1765
+ return UVC_SUCCESS;
1766
+ else
1767
+ return ret;
1768
+ }
1769
+
1770
+ /** @ingroup ctrl
1771
+ * @brief Reads the WHITE_BALANCE_TEMPERATURE control.
1772
+ * @param devh UVC device handle
1773
+ * @param[out] temperature TODO
1774
+ * @param req_code UVC_GET_* request to execute
1775
+ */
1776
+ uvc_error_t uvc_get_white_balance_temperature(uvc_device_handle_t *devh, uint16_t* temperature, enum uvc_req_code req_code) {
1777
+ uint8_t data[2];
1778
+ uvc_error_t ret;
1779
+
1780
+ ret = libusb_control_transfer(
1781
+ devh->usb_devh,
1782
+ REQ_TYPE_GET, req_code,
1783
+ UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8,
1784
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1785
+ data,
1786
+ sizeof(data),
1787
+ 0);
1788
+
1789
+ if (ret == sizeof(data)) {
1790
+ *temperature = SW_TO_SHORT(data + 0);
1791
+ return UVC_SUCCESS;
1792
+ } else {
1793
+ return ret;
1794
+ }
1795
+ }
1796
+
1797
+
1798
+ /** @ingroup ctrl
1799
+ * @brief Sets the WHITE_BALANCE_TEMPERATURE control.
1800
+ * @param devh UVC device handle
1801
+ * @param temperature TODO
1802
+ */
1803
+ uvc_error_t uvc_set_white_balance_temperature(uvc_device_handle_t *devh, uint16_t temperature) {
1804
+ uint8_t data[2];
1805
+ uvc_error_t ret;
1806
+
1807
+ SHORT_TO_SW(temperature, data + 0);
1808
+
1809
+ ret = libusb_control_transfer(
1810
+ devh->usb_devh,
1811
+ REQ_TYPE_SET, UVC_SET_CUR,
1812
+ UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8,
1813
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1814
+ data,
1815
+ sizeof(data),
1816
+ 0);
1817
+
1818
+ if (ret == sizeof(data))
1819
+ return UVC_SUCCESS;
1820
+ else
1821
+ return ret;
1822
+ }
1823
+
1824
+ /** @ingroup ctrl
1825
+ * @brief Reads the WHITE_BALANCE_TEMPERATURE_AUTO control.
1826
+ * @param devh UVC device handle
1827
+ * @param[out] temperature_auto TODO
1828
+ * @param req_code UVC_GET_* request to execute
1829
+ */
1830
+ uvc_error_t uvc_get_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t* temperature_auto, enum uvc_req_code req_code) {
1831
+ uint8_t data[1];
1832
+ uvc_error_t ret;
1833
+
1834
+ ret = libusb_control_transfer(
1835
+ devh->usb_devh,
1836
+ REQ_TYPE_GET, req_code,
1837
+ UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL << 8,
1838
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1839
+ data,
1840
+ sizeof(data),
1841
+ 0);
1842
+
1843
+ if (ret == sizeof(data)) {
1844
+ *temperature_auto = data[0];
1845
+ return UVC_SUCCESS;
1846
+ } else {
1847
+ return ret;
1848
+ }
1849
+ }
1850
+
1851
+
1852
+ /** @ingroup ctrl
1853
+ * @brief Sets the WHITE_BALANCE_TEMPERATURE_AUTO control.
1854
+ * @param devh UVC device handle
1855
+ * @param temperature_auto TODO
1856
+ */
1857
+ uvc_error_t uvc_set_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t temperature_auto) {
1858
+ uint8_t data[1];
1859
+ uvc_error_t ret;
1860
+
1861
+ data[0] = temperature_auto;
1862
+
1863
+ ret = libusb_control_transfer(
1864
+ devh->usb_devh,
1865
+ REQ_TYPE_SET, UVC_SET_CUR,
1866
+ UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL << 8,
1867
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1868
+ data,
1869
+ sizeof(data),
1870
+ 0);
1871
+
1872
+ if (ret == sizeof(data))
1873
+ return UVC_SUCCESS;
1874
+ else
1875
+ return ret;
1876
+ }
1877
+
1878
+ /** @ingroup ctrl
1879
+ * @brief Reads the WHITE_BALANCE_COMPONENT control.
1880
+ * @param devh UVC device handle
1881
+ * @param[out] blue TODO
1882
+ * @param[out] red TODO
1883
+ * @param req_code UVC_GET_* request to execute
1884
+ */
1885
+ uvc_error_t uvc_get_white_balance_component(uvc_device_handle_t *devh, uint16_t* blue, uint16_t* red, enum uvc_req_code req_code) {
1886
+ uint8_t data[4];
1887
+ uvc_error_t ret;
1888
+
1889
+ ret = libusb_control_transfer(
1890
+ devh->usb_devh,
1891
+ REQ_TYPE_GET, req_code,
1892
+ UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL << 8,
1893
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1894
+ data,
1895
+ sizeof(data),
1896
+ 0);
1897
+
1898
+ if (ret == sizeof(data)) {
1899
+ *blue = SW_TO_SHORT(data + 0);
1900
+ *red = SW_TO_SHORT(data + 2);
1901
+ return UVC_SUCCESS;
1902
+ } else {
1903
+ return ret;
1904
+ }
1905
+ }
1906
+
1907
+
1908
+ /** @ingroup ctrl
1909
+ * @brief Sets the WHITE_BALANCE_COMPONENT control.
1910
+ * @param devh UVC device handle
1911
+ * @param blue TODO
1912
+ * @param red TODO
1913
+ */
1914
+ uvc_error_t uvc_set_white_balance_component(uvc_device_handle_t *devh, uint16_t blue, uint16_t red) {
1915
+ uint8_t data[4];
1916
+ uvc_error_t ret;
1917
+
1918
+ SHORT_TO_SW(blue, data + 0);
1919
+ SHORT_TO_SW(red, data + 2);
1920
+
1921
+ ret = libusb_control_transfer(
1922
+ devh->usb_devh,
1923
+ REQ_TYPE_SET, UVC_SET_CUR,
1924
+ UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL << 8,
1925
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1926
+ data,
1927
+ sizeof(data),
1928
+ 0);
1929
+
1930
+ if (ret == sizeof(data))
1931
+ return UVC_SUCCESS;
1932
+ else
1933
+ return ret;
1934
+ }
1935
+
1936
+ /** @ingroup ctrl
1937
+ * @brief Reads the WHITE_BALANCE_COMPONENT_AUTO control.
1938
+ * @param devh UVC device handle
1939
+ * @param[out] white_balance_component_auto TODO
1940
+ * @param req_code UVC_GET_* request to execute
1941
+ */
1942
+ uvc_error_t uvc_get_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t* white_balance_component_auto, enum uvc_req_code req_code) {
1943
+ uint8_t data[1];
1944
+ uvc_error_t ret;
1945
+
1946
+ ret = libusb_control_transfer(
1947
+ devh->usb_devh,
1948
+ REQ_TYPE_GET, req_code,
1949
+ UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL << 8,
1950
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1951
+ data,
1952
+ sizeof(data),
1953
+ 0);
1954
+
1955
+ if (ret == sizeof(data)) {
1956
+ *white_balance_component_auto = data[0];
1957
+ return UVC_SUCCESS;
1958
+ } else {
1959
+ return ret;
1960
+ }
1961
+ }
1962
+
1963
+
1964
+ /** @ingroup ctrl
1965
+ * @brief Sets the WHITE_BALANCE_COMPONENT_AUTO control.
1966
+ * @param devh UVC device handle
1967
+ * @param white_balance_component_auto TODO
1968
+ */
1969
+ uvc_error_t uvc_set_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t white_balance_component_auto) {
1970
+ uint8_t data[1];
1971
+ uvc_error_t ret;
1972
+
1973
+ data[0] = white_balance_component_auto;
1974
+
1975
+ ret = libusb_control_transfer(
1976
+ devh->usb_devh,
1977
+ REQ_TYPE_SET, UVC_SET_CUR,
1978
+ UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL << 8,
1979
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
1980
+ data,
1981
+ sizeof(data),
1982
+ 0);
1983
+
1984
+ if (ret == sizeof(data))
1985
+ return UVC_SUCCESS;
1986
+ else
1987
+ return ret;
1988
+ }
1989
+
1990
+ /** @ingroup ctrl
1991
+ * @brief Reads the DIGITAL_MULTIPLIER control.
1992
+ * @param devh UVC device handle
1993
+ * @param[out] multiplier_step TODO
1994
+ * @param req_code UVC_GET_* request to execute
1995
+ */
1996
+ uvc_error_t uvc_get_digital_multiplier(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code) {
1997
+ uint8_t data[2];
1998
+ uvc_error_t ret;
1999
+
2000
+ ret = libusb_control_transfer(
2001
+ devh->usb_devh,
2002
+ REQ_TYPE_GET, req_code,
2003
+ UVC_PU_DIGITAL_MULTIPLIER_CONTROL << 8,
2004
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2005
+ data,
2006
+ sizeof(data),
2007
+ 0);
2008
+
2009
+ if (ret == sizeof(data)) {
2010
+ *multiplier_step = SW_TO_SHORT(data + 0);
2011
+ return UVC_SUCCESS;
2012
+ } else {
2013
+ return ret;
2014
+ }
2015
+ }
2016
+
2017
+
2018
+ /** @ingroup ctrl
2019
+ * @brief Sets the DIGITAL_MULTIPLIER control.
2020
+ * @param devh UVC device handle
2021
+ * @param multiplier_step TODO
2022
+ */
2023
+ uvc_error_t uvc_set_digital_multiplier(uvc_device_handle_t *devh, uint16_t multiplier_step) {
2024
+ uint8_t data[2];
2025
+ uvc_error_t ret;
2026
+
2027
+ SHORT_TO_SW(multiplier_step, data + 0);
2028
+
2029
+ ret = libusb_control_transfer(
2030
+ devh->usb_devh,
2031
+ REQ_TYPE_SET, UVC_SET_CUR,
2032
+ UVC_PU_DIGITAL_MULTIPLIER_CONTROL << 8,
2033
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2034
+ data,
2035
+ sizeof(data),
2036
+ 0);
2037
+
2038
+ if (ret == sizeof(data))
2039
+ return UVC_SUCCESS;
2040
+ else
2041
+ return ret;
2042
+ }
2043
+
2044
+ /** @ingroup ctrl
2045
+ * @brief Reads the DIGITAL_MULTIPLIER_LIMIT control.
2046
+ * @param devh UVC device handle
2047
+ * @param[out] multiplier_step TODO
2048
+ * @param req_code UVC_GET_* request to execute
2049
+ */
2050
+ uvc_error_t uvc_get_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code) {
2051
+ uint8_t data[2];
2052
+ uvc_error_t ret;
2053
+
2054
+ ret = libusb_control_transfer(
2055
+ devh->usb_devh,
2056
+ REQ_TYPE_GET, req_code,
2057
+ UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL << 8,
2058
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2059
+ data,
2060
+ sizeof(data),
2061
+ 0);
2062
+
2063
+ if (ret == sizeof(data)) {
2064
+ *multiplier_step = SW_TO_SHORT(data + 0);
2065
+ return UVC_SUCCESS;
2066
+ } else {
2067
+ return ret;
2068
+ }
2069
+ }
2070
+
2071
+
2072
+ /** @ingroup ctrl
2073
+ * @brief Sets the DIGITAL_MULTIPLIER_LIMIT control.
2074
+ * @param devh UVC device handle
2075
+ * @param multiplier_step TODO
2076
+ */
2077
+ uvc_error_t uvc_set_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t multiplier_step) {
2078
+ uint8_t data[2];
2079
+ uvc_error_t ret;
2080
+
2081
+ SHORT_TO_SW(multiplier_step, data + 0);
2082
+
2083
+ ret = libusb_control_transfer(
2084
+ devh->usb_devh,
2085
+ REQ_TYPE_SET, UVC_SET_CUR,
2086
+ UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL << 8,
2087
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2088
+ data,
2089
+ sizeof(data),
2090
+ 0);
2091
+
2092
+ if (ret == sizeof(data))
2093
+ return UVC_SUCCESS;
2094
+ else
2095
+ return ret;
2096
+ }
2097
+
2098
+ /** @ingroup ctrl
2099
+ * @brief Reads the ANALOG_VIDEO_STANDARD control.
2100
+ * @param devh UVC device handle
2101
+ * @param[out] video_standard TODO
2102
+ * @param req_code UVC_GET_* request to execute
2103
+ */
2104
+ uvc_error_t uvc_get_analog_video_standard(uvc_device_handle_t *devh, uint8_t* video_standard, enum uvc_req_code req_code) {
2105
+ uint8_t data[1];
2106
+ uvc_error_t ret;
2107
+
2108
+ ret = libusb_control_transfer(
2109
+ devh->usb_devh,
2110
+ REQ_TYPE_GET, req_code,
2111
+ UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL << 8,
2112
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2113
+ data,
2114
+ sizeof(data),
2115
+ 0);
2116
+
2117
+ if (ret == sizeof(data)) {
2118
+ *video_standard = data[0];
2119
+ return UVC_SUCCESS;
2120
+ } else {
2121
+ return ret;
2122
+ }
2123
+ }
2124
+
2125
+
2126
+ /** @ingroup ctrl
2127
+ * @brief Sets the ANALOG_VIDEO_STANDARD control.
2128
+ * @param devh UVC device handle
2129
+ * @param video_standard TODO
2130
+ */
2131
+ uvc_error_t uvc_set_analog_video_standard(uvc_device_handle_t *devh, uint8_t video_standard) {
2132
+ uint8_t data[1];
2133
+ uvc_error_t ret;
2134
+
2135
+ data[0] = video_standard;
2136
+
2137
+ ret = libusb_control_transfer(
2138
+ devh->usb_devh,
2139
+ REQ_TYPE_SET, UVC_SET_CUR,
2140
+ UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL << 8,
2141
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2142
+ data,
2143
+ sizeof(data),
2144
+ 0);
2145
+
2146
+ if (ret == sizeof(data))
2147
+ return UVC_SUCCESS;
2148
+ else
2149
+ return ret;
2150
+ }
2151
+
2152
+ /** @ingroup ctrl
2153
+ * @brief Reads the ANALOG_LOCK_STATUS control.
2154
+ * @param devh UVC device handle
2155
+ * @param[out] status TODO
2156
+ * @param req_code UVC_GET_* request to execute
2157
+ */
2158
+ uvc_error_t uvc_get_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t* status, enum uvc_req_code req_code) {
2159
+ uint8_t data[1];
2160
+ uvc_error_t ret;
2161
+
2162
+ ret = libusb_control_transfer(
2163
+ devh->usb_devh,
2164
+ REQ_TYPE_GET, req_code,
2165
+ UVC_PU_ANALOG_LOCK_STATUS_CONTROL << 8,
2166
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2167
+ data,
2168
+ sizeof(data),
2169
+ 0);
2170
+
2171
+ if (ret == sizeof(data)) {
2172
+ *status = data[0];
2173
+ return UVC_SUCCESS;
2174
+ } else {
2175
+ return ret;
2176
+ }
2177
+ }
2178
+
2179
+
2180
+ /** @ingroup ctrl
2181
+ * @brief Sets the ANALOG_LOCK_STATUS control.
2182
+ * @param devh UVC device handle
2183
+ * @param status TODO
2184
+ */
2185
+ uvc_error_t uvc_set_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t status) {
2186
+ uint8_t data[1];
2187
+ uvc_error_t ret;
2188
+
2189
+ data[0] = status;
2190
+
2191
+ ret = libusb_control_transfer(
2192
+ devh->usb_devh,
2193
+ REQ_TYPE_SET, UVC_SET_CUR,
2194
+ UVC_PU_ANALOG_LOCK_STATUS_CONTROL << 8,
2195
+ uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2196
+ data,
2197
+ sizeof(data),
2198
+ 0);
2199
+
2200
+ if (ret == sizeof(data))
2201
+ return UVC_SUCCESS;
2202
+ else
2203
+ return ret;
2204
+ }
2205
+
2206
+ /** @ingroup ctrl
2207
+ * @brief Reads the INPUT_SELECT control.
2208
+ * @param devh UVC device handle
2209
+ * @param[out] selector TODO
2210
+ * @param req_code UVC_GET_* request to execute
2211
+ */
2212
+ uvc_error_t uvc_get_input_select(uvc_device_handle_t *devh, uint8_t* selector, enum uvc_req_code req_code) {
2213
+ uint8_t data[1];
2214
+ uvc_error_t ret;
2215
+
2216
+ ret = libusb_control_transfer(
2217
+ devh->usb_devh,
2218
+ REQ_TYPE_GET, req_code,
2219
+ UVC_SU_INPUT_SELECT_CONTROL << 8,
2220
+ uvc_get_selector_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2221
+ data,
2222
+ sizeof(data),
2223
+ 0);
2224
+
2225
+ if (ret == sizeof(data)) {
2226
+ *selector = data[0];
2227
+ return UVC_SUCCESS;
2228
+ } else {
2229
+ return ret;
2230
+ }
2231
+ }
2232
+
2233
+
2234
+ /** @ingroup ctrl
2235
+ * @brief Sets the INPUT_SELECT control.
2236
+ * @param devh UVC device handle
2237
+ * @param selector TODO
2238
+ */
2239
+ uvc_error_t uvc_set_input_select(uvc_device_handle_t *devh, uint8_t selector) {
2240
+ uint8_t data[1];
2241
+ uvc_error_t ret;
2242
+
2243
+ data[0] = selector;
2244
+
2245
+ ret = libusb_control_transfer(
2246
+ devh->usb_devh,
2247
+ REQ_TYPE_SET, UVC_SET_CUR,
2248
+ UVC_SU_INPUT_SELECT_CONTROL << 8,
2249
+ uvc_get_selector_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
2250
+ data,
2251
+ sizeof(data),
2252
+ 0);
2253
+
2254
+ if (ret == sizeof(data))
2255
+ return UVC_SUCCESS;
2256
+ else
2257
+ return ret;
2258
+ }
2259
+
collector/core/gripper/camera_service_src/third_party/libuvc/src/ctrl-gen.py ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ from __future__ import print_function
3
+ from collections import OrderedDict
4
+ import getopt
5
+ import sys
6
+ import yaml
7
+
8
+ class quoted(str): pass
9
+
10
+ def quoted_presenter(dumper, data):
11
+ return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
12
+ yaml.add_representer(quoted, quoted_presenter)
13
+
14
+ class literal(str): pass
15
+
16
+ def literal_presenter(dumper, data):
17
+ return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
18
+ yaml.add_representer(literal, literal_presenter)
19
+
20
+ def ordered_dict_presenter(dumper, data):
21
+ return dumper.represent_dict(data.items())
22
+ yaml.add_representer(OrderedDict, ordered_dict_presenter)
23
+
24
+ def dict_constructor(loader, node):
25
+ return OrderedDict(loader.construct_pairs(node))
26
+ _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
27
+ yaml.add_constructor(_mapping_tag, dict_constructor)
28
+
29
+ class IntField(object):
30
+ def __init__(self, name, position, length, signed):
31
+ self.name = name
32
+ self.position = position
33
+ self.length = length
34
+ self.signed = signed
35
+
36
+ if not self.length in [1, 2, 4]:
37
+ raise Exception("bad length " + str(self.length))
38
+
39
+ self.user_type = ('u' if not signed else '') + 'int' + str(length * 8) + '_t'
40
+
41
+ def getter_sig(self):
42
+ return "{0}* {1}".format(self.user_type, self.name)
43
+
44
+ def unpack(self):
45
+ if self.length == 1:
46
+ return "*{0} = data[{1}];".format(self.name, self.position)
47
+ elif self.length == 2:
48
+ return "*{0} = SW_TO_SHORT(data + {1});".format(self.name, self.position)
49
+ elif self.length == 4:
50
+ return "*{0} = DW_TO_INT(data + {1});".format(self.name, self.position)
51
+
52
+ def setter_sig(self):
53
+ return "{0} {1}".format(self.user_type, self.name)
54
+
55
+ def pack(self):
56
+ if self.length == 1:
57
+ return "data[{0}] = {1};".format(self.position, self.name)
58
+ elif self.length == 2:
59
+ return "SHORT_TO_SW({0}, data + {1});".format(self.name, self.position)
60
+ elif self.length == 4:
61
+ return "INT_TO_DW({0}, data + {1});".format(self.name, self.position)
62
+
63
+ def spec(self):
64
+ rep = [('position', self.position), ('length', self.length)]
65
+ if self.signed:
66
+ rep.append(('signed', True))
67
+ return rep
68
+
69
+ @staticmethod
70
+ def load(spec):
71
+ return IntField(spec['name'], spec['position'], spec['length'], spec['signed'] if signed in spec else False)
72
+
73
+ def load_field(name, spec):
74
+ if spec['type'] == 'int':
75
+ return IntField(name, spec['position'], spec['length'], spec.get('signed', False))
76
+ else:
77
+ raise Exception("unknown field type '{0}'".format(spec['type']))
78
+
79
+ GETTER_TEMPLATE = """/** @ingroup ctrl
80
+ * {gen_doc}
81
+ * @param devh UVC device handle
82
+ * {args_doc}
83
+ * @param req_code UVC_GET_* request to execute
84
+ */
85
+ uvc_error_t uvc_get_{control_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code) {{
86
+ uint8_t data[{control_length}];
87
+ uvc_error_t ret;
88
+
89
+ ret = libusb_control_transfer(
90
+ devh->usb_devh,
91
+ REQ_TYPE_GET, req_code,
92
+ {control_code} << 8,
93
+ {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber,
94
+ data,
95
+ sizeof(data),
96
+ 0);
97
+
98
+ if (ret == sizeof(data)) {{
99
+ {unpack}
100
+ return UVC_SUCCESS;
101
+ }} else {{
102
+ return ret;
103
+ }}
104
+ }}
105
+ """
106
+
107
+ SETTER_TEMPLATE = """/** @ingroup ctrl
108
+ * {gen_doc}
109
+ * @param devh UVC device handle
110
+ * {args_doc}
111
+ */
112
+ uvc_error_t uvc_set_{control_name}(uvc_device_handle_t *devh, {args_signature}) {{
113
+ uint8_t data[{control_length}];
114
+ uvc_error_t ret;
115
+
116
+ {pack}
117
+
118
+ ret = libusb_control_transfer(
119
+ devh->usb_devh,
120
+ REQ_TYPE_SET, UVC_SET_CUR,
121
+ {control_code} << 8,
122
+ {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber,
123
+ data,
124
+ sizeof(data),
125
+ 0);
126
+
127
+ if (ret == sizeof(data))
128
+ return UVC_SUCCESS;
129
+ else
130
+ return ret;
131
+ }}
132
+ """
133
+
134
+ def gen_decl(unit_name, unit, control_name, control):
135
+ fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else []
136
+
137
+ get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields])
138
+ set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields])
139
+
140
+ return "uvc_error_t uvc_get_{function_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code);\n".format(**{
141
+ "function_name": control_name,
142
+ "args_signature": get_args_signature
143
+ }) + "uvc_error_t uvc_set_{function_name}(uvc_device_handle_t *devh, {args_signature});\n".format(**{
144
+ "function_name": control_name,
145
+ "args_signature": set_args_signature
146
+ })
147
+
148
+ def gen_ctrl(unit_name, unit, control_name, control):
149
+ fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else []
150
+
151
+ get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields])
152
+ set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields])
153
+ unpack = "\n ".join([field.unpack() for (field, desc) in fields])
154
+ pack = "\n ".join([field.pack() for (field, desc) in fields])
155
+
156
+ get_gen_doc_raw = None
157
+ set_gen_doc_raw = None
158
+
159
+ if 'doc' in control:
160
+ doc = control['doc']
161
+
162
+ if isinstance(doc, str):
163
+ get_gen_doc_raw = "\n * ".join(doc.splitlines())
164
+ set_gen_doc_raw = get_gen_doc_raw
165
+ else:
166
+ if 'get' in doc:
167
+ get_gen_doc_raw = "\n * ".join(doc['get'].splitlines())
168
+ if 'set' in doc:
169
+ set_gen_doc_raw = "\n * ".join(doc['set'].splitlines())
170
+
171
+ if get_gen_doc_raw is not None:
172
+ get_gen_doc = get_gen_doc_raw.format(gets_sets='Reads')
173
+ else:
174
+ get_gen_doc = '@brief Reads the ' + control['control'] + ' control.'
175
+
176
+ if set_gen_doc_raw is not None:
177
+ set_gen_doc = set_gen_doc_raw.format(gets_sets='Sets')
178
+ else:
179
+ set_gen_doc = '@brief Sets the ' + control['control'] + ' control.'
180
+
181
+ get_args_doc = "\n * ".join(["@param[out] {0} {1}".format(field.name, desc) for (field, desc) in fields])
182
+ set_args_doc = "\n * ".join(["@param {0} {1}".format(field.name, desc) for (field, desc) in fields])
183
+
184
+ control_code = 'UVC_' + unit['control_prefix'] + '_' + control['control'] + '_CONTROL'
185
+
186
+ unit_fn = "uvc_get_camera_terminal(devh)->bTerminalID" if (unit_name == "camera_terminal") else ("uvc_get_" + unit_name + "s(devh)->bUnitID")
187
+
188
+ return GETTER_TEMPLATE.format(
189
+ unit=unit,
190
+ unit_fn=unit_fn,
191
+ control_name=control_name,
192
+ control_code=control_code,
193
+ control_length=control['length'],
194
+ args_signature=get_args_signature,
195
+ args_doc=get_args_doc,
196
+ gen_doc=get_gen_doc,
197
+ unpack=unpack) + "\n\n" + SETTER_TEMPLATE.format(
198
+ unit=unit,
199
+ unit_fn=unit_fn,
200
+ control_name=control_name,
201
+ control_code=control_code,
202
+ control_length=control['length'],
203
+ args_signature=set_args_signature,
204
+ args_doc=set_args_doc,
205
+ gen_doc=set_gen_doc,
206
+ pack=pack
207
+ )
208
+
209
+ def export_unit(unit):
210
+ def fmt_doc(doc):
211
+ def wrap_doc_entry(entry):
212
+ if "\n" in entry:
213
+ return literal(entry)
214
+ else:
215
+ return entry
216
+
217
+ if isinstance(doc, str):
218
+ return wrap_doc_entry(doc)
219
+ else:
220
+ return OrderedDict([(mode, wrap_doc_entry(text)) for mode, text in doc.items()])
221
+
222
+ def fmt_ctrl(control_name, control_details):
223
+ contents = OrderedDict()
224
+ contents['control'] = control_details['control']
225
+ contents['length'] = control_details['length']
226
+ contents['fields'] = control_details['fields']
227
+
228
+ if 'doc' in control_details:
229
+ contents['doc'] = fmt_doc(control_details['doc'])
230
+
231
+ return (control_name, contents)
232
+
233
+ unit_out = OrderedDict()
234
+ unit_out['type'] = unit['type']
235
+ if 'guid' in unit:
236
+ unit_out['guid'] = unit['guid']
237
+ if 'description' in unit:
238
+ unit_out['description'] = unit['description']
239
+ if 'control_prefix' in unit:
240
+ unit_out['control_prefix'] = unit['control_prefix']
241
+ unit_out['controls'] = OrderedDict([fmt_ctrl(ctrl_name, ctrl_details) for ctrl_name, ctrl_details in unit['controls'].items()])
242
+ return unit_out
243
+
244
+ if __name__ == '__main__':
245
+ try:
246
+ opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "input="])
247
+ except getopt.GetoptError as err:
248
+ print(str(err))
249
+ usage()
250
+ sys.exit(-1)
251
+
252
+ inputs = []
253
+
254
+ for opt, val in opts:
255
+ if opt in ('-h', '--help'):
256
+ usage()
257
+ sys.exit(0)
258
+ elif opt in ('-i', '--input'):
259
+ inputs.append(val)
260
+
261
+ mode = None
262
+ for arg in args:
263
+ if arg in ('def', 'decl', 'yaml'):
264
+ if mode is None:
265
+ mode = arg
266
+ else:
267
+ print("Can't specify more than one mode")
268
+ sys.exit(-1)
269
+ else:
270
+ print("Invalid mode '{0}'".format(arg))
271
+ sys.exit(-1)
272
+
273
+ def iterunits():
274
+ for input_file in inputs:
275
+ with open(input_file, "r") as fp:
276
+ units = yaml.load(fp)['units']
277
+ for unit_name, unit_details in units.iteritems():
278
+ yield unit_name, unit_details
279
+
280
+ if mode == 'def':
281
+ print("""/* This is an AUTO-GENERATED file! Update it with the output of `ctrl-gen.py def`. */
282
+ #include "libuvc/libuvc.h"
283
+ #include "libuvc/libuvc_internal.h"
284
+
285
+ static const int REQ_TYPE_SET = 0x21;
286
+ static const int REQ_TYPE_GET = 0xa1;
287
+ """)
288
+ fun = gen_ctrl
289
+ elif mode == 'decl':
290
+ fun = gen_decl
291
+ elif mode == 'yaml':
292
+ exported_units = OrderedDict()
293
+ for unit_name, unit_details in iterunits():
294
+ exported_units[unit_name] = export_unit(unit_details)
295
+
296
+ yaml.dump({'units': exported_units}, sys.stdout, default_flow_style=False)
297
+ sys.exit(0)
298
+
299
+ for unit_name, unit_details in iterunits():
300
+ for control_name, control_details in unit_details['controls'].iteritems():
301
+ code = fun(unit_name, unit_details, control_name, control_details)
302
+ print(code)
collector/core/gripper/camera_service_src/third_party/libuvc/src/ctrl.c ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ /**
35
+ * @defgroup ctrl Video capture and processing controls
36
+ * @brief Functions for manipulating device settings and stream parameters
37
+ *
38
+ * The `uvc_get_*` and `uvc_set_*` functions are used to read and write the settings associated
39
+ * with the device's input, processing and output units.
40
+ */
41
+
42
+ #include "libuvc/libuvc.h"
43
+ #include "libuvc/libuvc_internal.h"
44
+
45
+ static const int REQ_TYPE_SET = 0x21;
46
+ static const int REQ_TYPE_GET = 0xa1;
47
+
48
+ /***** GENERIC CONTROLS *****/
49
+ /**
50
+ * @brief Get the length of a control on a terminal or unit.
51
+ *
52
+ * @param devh UVC device handle
53
+ * @param unit Unit or Terminal ID; obtain this from the uvc_extension_unit_t describing the extension unit
54
+ * @param ctrl Vendor-specific control number to query
55
+ * @return On success, the length of the control as reported by the device. Otherwise,
56
+ * a uvc_error_t error describing the error encountered.
57
+ * @ingroup ctrl
58
+ */
59
+ int uvc_get_ctrl_len(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl) {
60
+ unsigned char buf[2];
61
+
62
+ int ret = libusb_control_transfer(
63
+ devh->usb_devh,
64
+ REQ_TYPE_GET, UVC_GET_LEN,
65
+ ctrl << 8,
66
+ unit << 8 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki
67
+ buf,
68
+ 2,
69
+ 0 /* timeout */);
70
+
71
+ if (ret < 0)
72
+ return ret;
73
+ else
74
+ return (unsigned short)SW_TO_SHORT(buf);
75
+ }
76
+
77
+ /**
78
+ * @brief Perform a GET_* request from an extension unit.
79
+ *
80
+ * @param devh UVC device handle
81
+ * @param unit Unit ID; obtain this from the uvc_extension_unit_t describing the extension unit
82
+ * @param ctrl Control number to query
83
+ * @param data Data buffer to be filled by the device
84
+ * @param len Size of data buffer
85
+ * @param req_code GET_* request to execute
86
+ * @return On success, the number of bytes actually transferred. Otherwise,
87
+ * a uvc_error_t error describing the error encountered.
88
+ * @ingroup ctrl
89
+ */
90
+ int uvc_get_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len, enum uvc_req_code req_code) {
91
+ return libusb_control_transfer(
92
+ devh->usb_devh,
93
+ REQ_TYPE_GET, req_code,
94
+ ctrl << 8,
95
+ unit << 8 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki
96
+ data,
97
+ len,
98
+ 0 /* timeout */);
99
+ }
100
+
101
+ /**
102
+ * @brief Perform a SET_CUR request to a terminal or unit.
103
+ *
104
+ * @param devh UVC device handle
105
+ * @param unit Unit or Terminal ID
106
+ * @param ctrl Control number to set
107
+ * @param data Data buffer to be sent to the device
108
+ * @param len Size of data buffer
109
+ * @return On success, the number of bytes actually transferred. Otherwise,
110
+ * a uvc_error_t error describing the error encountered.
111
+ * @ingroup ctrl
112
+ */
113
+ int uvc_set_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len) {
114
+ return libusb_control_transfer(
115
+ devh->usb_devh,
116
+ REQ_TYPE_SET, UVC_SET_CUR,
117
+ ctrl << 8,
118
+ unit << 8 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki
119
+ data,
120
+ len,
121
+ 0 /* timeout */);
122
+ }
123
+
124
+ /***** INTERFACE CONTROLS *****/
125
+ uvc_error_t uvc_get_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode *mode, enum uvc_req_code req_code) {
126
+ uint8_t mode_char;
127
+ uvc_error_t ret;
128
+
129
+ ret = libusb_control_transfer(
130
+ devh->usb_devh,
131
+ REQ_TYPE_GET, req_code,
132
+ UVC_VC_VIDEO_POWER_MODE_CONTROL << 8,
133
+ devh->info->ctrl_if.bInterfaceNumber, // XXX saki
134
+ &mode_char,
135
+ sizeof(mode_char),
136
+ 0);
137
+
138
+ if (ret == 1) {
139
+ *mode = mode_char;
140
+ return UVC_SUCCESS;
141
+ } else {
142
+ return ret;
143
+ }
144
+ }
145
+
146
+ uvc_error_t uvc_set_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode mode) {
147
+ uint8_t mode_char = mode;
148
+ uvc_error_t ret;
149
+
150
+ ret = libusb_control_transfer(
151
+ devh->usb_devh,
152
+ REQ_TYPE_SET, UVC_SET_CUR,
153
+ UVC_VC_VIDEO_POWER_MODE_CONTROL << 8,
154
+ devh->info->ctrl_if.bInterfaceNumber, // XXX saki
155
+ &mode_char,
156
+ sizeof(mode_char),
157
+ 0);
158
+
159
+ if (ret == 1)
160
+ return UVC_SUCCESS;
161
+ else
162
+ return ret;
163
+ }
164
+
165
+ /** @todo Request Error Code Control (UVC 1.5, 4.2.1.2) */
collector/core/gripper/camera_service_src/third_party/libuvc/src/device.c ADDED
@@ -0,0 +1,2005 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ /**
35
+ * @defgroup device Device handling and enumeration
36
+ * @brief Support for finding, inspecting and opening UVC devices
37
+ */
38
+
39
+ #include "libuvc/libuvc.h"
40
+ #include "libuvc/libuvc_internal.h"
41
+
42
+ int uvc_already_open(uvc_context_t *ctx, struct libusb_device *usb_dev);
43
+ void uvc_free_devh(uvc_device_handle_t *devh);
44
+
45
+ uvc_error_t uvc_get_device_info(uvc_device_handle_t *devh, uvc_device_info_t **info);
46
+ void uvc_free_device_info(uvc_device_info_t *info);
47
+
48
+ uvc_error_t uvc_scan_control(uvc_device_handle_t *devh, uvc_device_info_t *info);
49
+ uvc_error_t uvc_parse_vc(uvc_device_t *dev,
50
+ uvc_device_info_t *info,
51
+ const unsigned char *block, size_t block_size);
52
+ uvc_error_t uvc_parse_vc_selector_unit(uvc_device_t *dev,
53
+ uvc_device_info_t *info,
54
+ const unsigned char *block, size_t block_size);
55
+ uvc_error_t uvc_parse_vc_extension_unit(uvc_device_t *dev,
56
+ uvc_device_info_t *info,
57
+ const unsigned char *block,
58
+ size_t block_size);
59
+ uvc_error_t uvc_parse_vc_header(uvc_device_t *dev,
60
+ uvc_device_info_t *info,
61
+ const unsigned char *block, size_t block_size);
62
+ uvc_error_t uvc_parse_vc_input_terminal(uvc_device_t *dev,
63
+ uvc_device_info_t *info,
64
+ const unsigned char *block,
65
+ size_t block_size);
66
+ uvc_error_t uvc_parse_vc_processing_unit(uvc_device_t *dev,
67
+ uvc_device_info_t *info,
68
+ const unsigned char *block,
69
+ size_t block_size);
70
+
71
+ uvc_error_t uvc_scan_streaming(uvc_device_t *dev,
72
+ uvc_device_info_t *info,
73
+ int interface_idx);
74
+ uvc_error_t uvc_parse_vs(uvc_device_t *dev,
75
+ uvc_device_info_t *info,
76
+ uvc_streaming_interface_t *stream_if,
77
+ const unsigned char *block, size_t block_size);
78
+ uvc_error_t uvc_parse_vs_format_uncompressed(uvc_streaming_interface_t *stream_if,
79
+ const unsigned char *block,
80
+ size_t block_size);
81
+ uvc_error_t uvc_parse_vs_format_mjpeg(uvc_streaming_interface_t *stream_if,
82
+ const unsigned char *block,
83
+ size_t block_size);
84
+ uvc_error_t uvc_parse_vs_frame_uncompressed(uvc_streaming_interface_t *stream_if,
85
+ const unsigned char *block,
86
+ size_t block_size);
87
+ uvc_error_t uvc_parse_vs_frame_format(uvc_streaming_interface_t *stream_if,
88
+ const unsigned char *block,
89
+ size_t block_size);
90
+ uvc_error_t uvc_parse_vs_frame_frame(uvc_streaming_interface_t *stream_if,
91
+ const unsigned char *block,
92
+ size_t block_size);
93
+ uvc_error_t uvc_parse_vs_input_header(uvc_streaming_interface_t *stream_if,
94
+ const unsigned char *block,
95
+ size_t block_size);
96
+
97
+ void LIBUSB_CALL _uvc_status_callback(struct libusb_transfer *transfer);
98
+
99
+ /** @internal
100
+ * @brief Test whether the specified USB device has been opened as a UVC device
101
+ * @ingroup device
102
+ *
103
+ * @param ctx Context in which to search for the UVC device
104
+ * @param usb_dev USB device to find
105
+ * @return true if the device is open in this context
106
+ */
107
+ int uvc_already_open(uvc_context_t *ctx, struct libusb_device *usb_dev) {
108
+ uvc_device_handle_t *devh;
109
+
110
+ DL_FOREACH(ctx->open_devices, devh) {
111
+ if (usb_dev == devh->dev->usb_dev)
112
+ return 1;
113
+ }
114
+
115
+ return 0;
116
+ }
117
+
118
+ /** @brief Finds a camera identified by vendor, product and/or serial number
119
+ * @ingroup device
120
+ *
121
+ * @param[in] ctx UVC context in which to search for the camera
122
+ * @param[out] dev Reference to the camera, or NULL if not found
123
+ * @param[in] vid Vendor ID number, optional
124
+ * @param[in] pid Product ID number, optional
125
+ * @param[in] sn Serial number or NULL
126
+ * @return Error finding device or UVC_SUCCESS
127
+ */
128
+ uvc_error_t uvc_find_device(
129
+ uvc_context_t *ctx, uvc_device_t **dev,
130
+ int vid, int pid, const char *sn) {
131
+ uvc_error_t ret = UVC_SUCCESS;
132
+
133
+ uvc_device_t **list;
134
+ uvc_device_t *test_dev;
135
+ int dev_idx;
136
+ int found_dev;
137
+
138
+ UVC_ENTER();
139
+
140
+ ret = uvc_get_device_list(ctx, &list);
141
+
142
+ if (ret != UVC_SUCCESS) {
143
+ UVC_EXIT(ret);
144
+ return ret;
145
+ }
146
+
147
+ dev_idx = 0;
148
+ found_dev = 0;
149
+
150
+ while (!found_dev && (test_dev = list[dev_idx++]) != NULL) {
151
+ uvc_device_descriptor_t *desc;
152
+
153
+ if (uvc_get_device_descriptor(test_dev, &desc) != UVC_SUCCESS)
154
+ continue;
155
+
156
+ if ((!vid || desc->idVendor == vid)
157
+ && (!pid || desc->idProduct == pid)
158
+ && (!sn || (desc->serialNumber && !strcmp(desc->serialNumber, sn))))
159
+ found_dev = 1;
160
+
161
+ uvc_free_device_descriptor(desc);
162
+ }
163
+
164
+ if (found_dev)
165
+ uvc_ref_device(test_dev);
166
+
167
+ uvc_free_device_list(list, 1);
168
+
169
+ if (found_dev) {
170
+ *dev = test_dev;
171
+ UVC_EXIT(UVC_SUCCESS);
172
+ return UVC_SUCCESS;
173
+ } else {
174
+ UVC_EXIT(UVC_ERROR_NO_DEVICE);
175
+ return UVC_ERROR_NO_DEVICE;
176
+ }
177
+ }
178
+
179
+ /** @brief Finds all cameras identified by vendor, product and/or serial number
180
+ * @ingroup device
181
+ *
182
+ * @param[in] ctx UVC context in which to search for the camera
183
+ * @param[out] devs List of matching cameras
184
+ * @param[in] vid Vendor ID number, optional
185
+ * @param[in] pid Product ID number, optional
186
+ * @param[in] sn Serial number or NULL
187
+ * @return Error finding device or UVC_SUCCESS
188
+ */
189
+ uvc_error_t uvc_find_devices(
190
+ uvc_context_t *ctx, uvc_device_t ***devs,
191
+ int vid, int pid, const char *sn) {
192
+ uvc_error_t ret = UVC_SUCCESS;
193
+
194
+ uvc_device_t **list;
195
+ uvc_device_t *test_dev;
196
+ int dev_idx;
197
+ int found_dev;
198
+
199
+ uvc_device_t **list_internal;
200
+ int num_uvc_devices;
201
+
202
+ UVC_ENTER();
203
+
204
+ ret = uvc_get_device_list(ctx, &list);
205
+
206
+ if (ret != UVC_SUCCESS) {
207
+ UVC_EXIT(ret);
208
+ return ret;
209
+ }
210
+
211
+ num_uvc_devices = 0;
212
+ dev_idx = 0;
213
+ found_dev = 0;
214
+
215
+ list_internal = malloc(sizeof(*list_internal));
216
+ *list_internal = NULL;
217
+
218
+ while ((test_dev = list[dev_idx++]) != NULL) {
219
+ uvc_device_descriptor_t *desc;
220
+
221
+ if (uvc_get_device_descriptor(test_dev, &desc) != UVC_SUCCESS)
222
+ continue;
223
+
224
+ if ((!vid || desc->idVendor == vid)
225
+ && (!pid || desc->idProduct == pid)
226
+ && (!sn || (desc->serialNumber && !strcmp(desc->serialNumber, sn)))) {
227
+ found_dev = 1;
228
+ uvc_ref_device(test_dev);
229
+
230
+ num_uvc_devices++;
231
+ list_internal = realloc(list_internal, (num_uvc_devices + 1) * sizeof(*list_internal));
232
+
233
+ list_internal[num_uvc_devices - 1] = test_dev;
234
+ list_internal[num_uvc_devices] = NULL;
235
+ }
236
+
237
+ uvc_free_device_descriptor(desc);
238
+ }
239
+
240
+ uvc_free_device_list(list, 1);
241
+
242
+ if (found_dev) {
243
+ *devs = list_internal;
244
+ UVC_EXIT(UVC_SUCCESS);
245
+ return UVC_SUCCESS;
246
+ } else {
247
+ UVC_EXIT(UVC_ERROR_NO_DEVICE);
248
+ return UVC_ERROR_NO_DEVICE;
249
+ }
250
+ }
251
+
252
+ /** @brief Get the number of the bus to which the device is attached
253
+ * @ingroup device
254
+ */
255
+ uint8_t uvc_get_bus_number(uvc_device_t *dev) {
256
+ return libusb_get_bus_number(dev->usb_dev);
257
+ }
258
+
259
+ /** @brief Get the number assigned to the device within its bus
260
+ * @ingroup device
261
+ */
262
+ uint8_t uvc_get_device_address(uvc_device_t *dev) {
263
+ return libusb_get_device_address(dev->usb_dev);
264
+ }
265
+
266
+ int uvc_get_port_numbers(uvc_device_t *dev, uint8_t *ports,
267
+ uint8_t port_count) {
268
+ if (dev == NULL || ports == NULL || port_count == 0)
269
+ return LIBUSB_ERROR_INVALID_PARAM;
270
+ return libusb_get_port_numbers(dev->usb_dev, ports, port_count);
271
+ }
272
+
273
+ static uvc_error_t uvc_open_internal(uvc_device_t *dev, struct libusb_device_handle *usb_devh, uvc_device_handle_t **devh);
274
+
275
+ #if LIBUSB_API_VERSION >= 0x01000107
276
+ /** @brief Wrap a platform-specific system device handle and obtain a UVC device handle.
277
+ * The handle allows you to use libusb to perform I/O on the device in question.
278
+ *
279
+ * On Linux, the system device handle must be a valid file descriptor opened on the device node.
280
+ *
281
+ * The system device handle must remain open until uvc_close() is called. The system device handle will not be closed by uvc_close().
282
+ * @ingroup device
283
+ *
284
+ * @param sys_dev the platform-specific system device handle
285
+ * @param context UVC context to prepare the device
286
+ * @param[out] devh Handle on opened device
287
+ * @return Error opening device or SUCCESS
288
+ */
289
+ uvc_error_t uvc_wrap(
290
+ int sys_dev,
291
+ uvc_context_t *context,
292
+ uvc_device_handle_t **devh) {
293
+ uvc_error_t ret;
294
+ struct libusb_device_handle *usb_devh;
295
+
296
+ UVC_ENTER();
297
+
298
+ uvc_device_t *dev = NULL;
299
+ int err = libusb_wrap_sys_device(context->usb_ctx, sys_dev, &usb_devh);
300
+ UVC_DEBUG("libusb_wrap_sys_device() = %d", err);
301
+ if (err != LIBUSB_SUCCESS) {
302
+ UVC_EXIT(err);
303
+ return err;
304
+ }
305
+
306
+ dev = calloc(1, sizeof(uvc_device_t));
307
+ dev->ctx = context;
308
+ dev->usb_dev = libusb_get_device(usb_devh);
309
+
310
+ ret = uvc_open_internal(dev, usb_devh, devh);
311
+ UVC_EXIT(ret);
312
+ return ret;
313
+ }
314
+ #endif
315
+
316
+ /** @brief Open a UVC device
317
+ * @ingroup device
318
+ *
319
+ * @param dev Device to open
320
+ * @param[out] devh Handle on opened device
321
+ * @return Error opening device or SUCCESS
322
+ */
323
+ uvc_error_t uvc_open(
324
+ uvc_device_t *dev,
325
+ uvc_device_handle_t **devh) {
326
+ uvc_error_t ret;
327
+ struct libusb_device_handle *usb_devh;
328
+
329
+ UVC_ENTER();
330
+
331
+ ret = libusb_open(dev->usb_dev, &usb_devh);
332
+ UVC_DEBUG("libusb_open() = %d", ret);
333
+
334
+ if (ret != UVC_SUCCESS) {
335
+ UVC_EXIT(ret);
336
+ return ret;
337
+ }
338
+
339
+ ret = uvc_open_internal(dev, usb_devh, devh);
340
+ UVC_EXIT(ret);
341
+ return ret;
342
+ }
343
+
344
+ static uvc_error_t uvc_open_internal(
345
+ uvc_device_t *dev,
346
+ struct libusb_device_handle *usb_devh,
347
+ uvc_device_handle_t **devh) {
348
+ uvc_error_t ret;
349
+ uvc_device_handle_t *internal_devh;
350
+ struct libusb_device_descriptor desc;
351
+
352
+ UVC_ENTER();
353
+
354
+ uvc_ref_device(dev);
355
+
356
+ internal_devh = calloc(1, sizeof(*internal_devh));
357
+ internal_devh->dev = dev;
358
+ internal_devh->usb_devh = usb_devh;
359
+
360
+ ret = uvc_get_device_info(internal_devh, &(internal_devh->info));
361
+
362
+ if (ret != UVC_SUCCESS)
363
+ goto fail;
364
+
365
+ UVC_DEBUG("claiming control interface %d", internal_devh->info->ctrl_if.bInterfaceNumber);
366
+ ret = uvc_claim_if(internal_devh, internal_devh->info->ctrl_if.bInterfaceNumber);
367
+ if (ret != UVC_SUCCESS)
368
+ goto fail;
369
+
370
+ libusb_get_device_descriptor(dev->usb_dev, &desc);
371
+ internal_devh->is_isight = (desc.idVendor == 0x05ac && desc.idProduct == 0x8501);
372
+
373
+ if (internal_devh->info->ctrl_if.bEndpointAddress) {
374
+ internal_devh->status_xfer = libusb_alloc_transfer(0);
375
+ if (!internal_devh->status_xfer) {
376
+ ret = UVC_ERROR_NO_MEM;
377
+ goto fail;
378
+ }
379
+
380
+ libusb_fill_interrupt_transfer(internal_devh->status_xfer,
381
+ usb_devh,
382
+ internal_devh->info->ctrl_if.bEndpointAddress,
383
+ internal_devh->status_buf,
384
+ sizeof(internal_devh->status_buf),
385
+ _uvc_status_callback,
386
+ internal_devh,
387
+ 0);
388
+ ret = libusb_submit_transfer(internal_devh->status_xfer);
389
+ UVC_DEBUG("libusb_submit_transfer() = %d", ret);
390
+
391
+ if (ret) {
392
+ fprintf(stderr,
393
+ "uvc: device has a status interrupt endpoint, but unable to read from it\n");
394
+ goto fail;
395
+ }
396
+ }
397
+
398
+ if (dev->ctx->own_usb_ctx && dev->ctx->open_devices == NULL) {
399
+ /* Since this is our first device, we need to spawn the event handler thread */
400
+ uvc_start_handler_thread(dev->ctx);
401
+ }
402
+
403
+ DL_APPEND(dev->ctx->open_devices, internal_devh);
404
+ *devh = internal_devh;
405
+
406
+ UVC_EXIT(ret);
407
+
408
+ return ret;
409
+
410
+ fail:
411
+ if ( internal_devh->info ) {
412
+ uvc_release_if(internal_devh, internal_devh->info->ctrl_if.bInterfaceNumber);
413
+ }
414
+ libusb_close(usb_devh);
415
+ uvc_unref_device(dev);
416
+ uvc_free_devh(internal_devh);
417
+
418
+ UVC_EXIT(ret);
419
+
420
+ return ret;
421
+ }
422
+
423
+ /**
424
+ * @internal
425
+ * @brief Parses the complete device descriptor for a device
426
+ * @ingroup device
427
+ * @note Free *info with uvc_free_device_info when you're done
428
+ *
429
+ * @param dev Device to parse descriptor for
430
+ * @param info Where to store a pointer to the new info struct
431
+ */
432
+ uvc_error_t uvc_get_device_info(uvc_device_handle_t *devh,
433
+ uvc_device_info_t **info) {
434
+ uvc_error_t ret;
435
+ uvc_device_info_t *internal_info;
436
+
437
+ UVC_ENTER();
438
+
439
+ internal_info = calloc(1, sizeof(*internal_info));
440
+ if (!internal_info) {
441
+ UVC_EXIT(UVC_ERROR_NO_MEM);
442
+ return UVC_ERROR_NO_MEM;
443
+ }
444
+
445
+ if (libusb_get_config_descriptor(devh->dev->usb_dev,
446
+ 0,
447
+ &(internal_info->config)) != 0) {
448
+ free(internal_info);
449
+ UVC_EXIT(UVC_ERROR_IO);
450
+ return UVC_ERROR_IO;
451
+ }
452
+
453
+ ret = uvc_scan_control(devh, internal_info);
454
+ if (ret != UVC_SUCCESS) {
455
+ uvc_free_device_info(internal_info);
456
+ UVC_EXIT(ret);
457
+ return ret;
458
+ }
459
+
460
+ *info = internal_info;
461
+
462
+ UVC_EXIT(ret);
463
+ return ret;
464
+ }
465
+
466
+ /**
467
+ * @internal
468
+ * @brief Frees the device descriptor for a device
469
+ * @ingroup device
470
+ *
471
+ * @param info Which device info block to free
472
+ */
473
+ void uvc_free_device_info(uvc_device_info_t *info) {
474
+ uvc_input_terminal_t *input_term, *input_term_tmp;
475
+ uvc_processing_unit_t *proc_unit, *proc_unit_tmp;
476
+ uvc_extension_unit_t *ext_unit, *ext_unit_tmp;
477
+
478
+ uvc_streaming_interface_t *stream_if, *stream_if_tmp;
479
+ uvc_format_desc_t *format, *format_tmp;
480
+ uvc_frame_desc_t *frame, *frame_tmp;
481
+ uvc_still_frame_desc_t *still_frame, *still_frame_tmp;
482
+ uvc_still_frame_res_t *still_res, *still_res_tmp;
483
+
484
+ UVC_ENTER();
485
+
486
+ DL_FOREACH_SAFE(info->ctrl_if.input_term_descs, input_term, input_term_tmp) {
487
+ DL_DELETE(info->ctrl_if.input_term_descs, input_term);
488
+ free(input_term);
489
+ }
490
+
491
+ DL_FOREACH_SAFE(info->ctrl_if.processing_unit_descs, proc_unit, proc_unit_tmp) {
492
+ DL_DELETE(info->ctrl_if.processing_unit_descs, proc_unit);
493
+ free(proc_unit);
494
+ }
495
+
496
+ DL_FOREACH_SAFE(info->ctrl_if.extension_unit_descs, ext_unit, ext_unit_tmp) {
497
+ DL_DELETE(info->ctrl_if.extension_unit_descs, ext_unit);
498
+ free(ext_unit);
499
+ }
500
+
501
+ DL_FOREACH_SAFE(info->stream_ifs, stream_if, stream_if_tmp) {
502
+ DL_FOREACH_SAFE(stream_if->format_descs, format, format_tmp) {
503
+ DL_FOREACH_SAFE(format->frame_descs, frame, frame_tmp) {
504
+ if (frame->intervals)
505
+ free(frame->intervals);
506
+
507
+ DL_DELETE(format->frame_descs, frame);
508
+ free(frame);
509
+ }
510
+
511
+ if(format->still_frame_desc) {
512
+ DL_FOREACH_SAFE(format->still_frame_desc, still_frame, still_frame_tmp) {
513
+ DL_FOREACH_SAFE(still_frame->imageSizePatterns, still_res, still_res_tmp) {
514
+ free(still_res);
515
+ }
516
+
517
+ if(still_frame->bCompression) {
518
+ free(still_frame->bCompression);
519
+ }
520
+ free(still_frame);
521
+ }
522
+ }
523
+
524
+ DL_DELETE(stream_if->format_descs, format);
525
+ free(format);
526
+ }
527
+
528
+ DL_DELETE(info->stream_ifs, stream_if);
529
+ free(stream_if);
530
+ }
531
+
532
+ if (info->config)
533
+ libusb_free_config_descriptor(info->config);
534
+
535
+ free(info);
536
+
537
+ UVC_EXIT_VOID();
538
+ }
539
+
540
+ static uvc_error_t get_device_descriptor(
541
+ uvc_device_handle_t *devh,
542
+ uvc_device_descriptor_t **desc) {
543
+ uvc_device_descriptor_t *desc_internal;
544
+ struct libusb_device_descriptor usb_desc;
545
+ struct libusb_device_handle *usb_devh = devh->usb_devh;
546
+ uvc_error_t ret;
547
+
548
+ UVC_ENTER();
549
+
550
+ ret = libusb_get_device_descriptor(devh->dev->usb_dev, &usb_desc);
551
+
552
+ if (ret != UVC_SUCCESS) {
553
+ UVC_EXIT(ret);
554
+ return ret;
555
+ }
556
+
557
+ desc_internal = calloc(1, sizeof(*desc_internal));
558
+ desc_internal->idVendor = usb_desc.idVendor;
559
+ desc_internal->idProduct = usb_desc.idProduct;
560
+
561
+ unsigned char buf[64];
562
+
563
+ int bytes = libusb_get_string_descriptor_ascii(
564
+ usb_devh, usb_desc.iSerialNumber, buf, sizeof(buf));
565
+
566
+ if (bytes > 0)
567
+ desc_internal->serialNumber = strdup((const char*) buf);
568
+
569
+ bytes = libusb_get_string_descriptor_ascii(
570
+ usb_devh, usb_desc.iManufacturer, buf, sizeof(buf));
571
+
572
+ if (bytes > 0)
573
+ desc_internal->manufacturer = strdup((const char*) buf);
574
+
575
+ bytes = libusb_get_string_descriptor_ascii(
576
+ usb_devh, usb_desc.iProduct, buf, sizeof(buf));
577
+
578
+ if (bytes > 0)
579
+ desc_internal->product = strdup((const char*) buf);
580
+
581
+ *desc = desc_internal;
582
+
583
+ UVC_EXIT(ret);
584
+ return ret;
585
+ }
586
+
587
+ /**
588
+ * @brief Get a descriptor that contains the general information about
589
+ * a device
590
+ * @ingroup device
591
+ *
592
+ * Free *desc with uvc_free_device_descriptor when you're done.
593
+ *
594
+ * @param dev Device to fetch information about
595
+ * @param[out] desc Descriptor structure
596
+ * @return Error if unable to fetch information, else SUCCESS
597
+ */
598
+ uvc_error_t uvc_get_device_descriptor(
599
+ uvc_device_t *dev,
600
+ uvc_device_descriptor_t **desc) {
601
+ uvc_device_descriptor_t *desc_internal;
602
+ struct libusb_device_descriptor usb_desc;
603
+ struct libusb_device_handle *usb_devh;
604
+ uvc_error_t ret;
605
+
606
+ UVC_ENTER();
607
+
608
+ ret = libusb_get_device_descriptor(dev->usb_dev, &usb_desc);
609
+
610
+ if (ret != UVC_SUCCESS) {
611
+ UVC_EXIT(ret);
612
+ return ret;
613
+ }
614
+
615
+ desc_internal = calloc(1, sizeof(*desc_internal));
616
+ desc_internal->idVendor = usb_desc.idVendor;
617
+ desc_internal->idProduct = usb_desc.idProduct;
618
+
619
+ if (libusb_open(dev->usb_dev, &usb_devh) == 0) {
620
+ unsigned char buf[64];
621
+
622
+ int bytes = libusb_get_string_descriptor_ascii(
623
+ usb_devh, usb_desc.iSerialNumber, buf, sizeof(buf));
624
+
625
+ if (bytes > 0)
626
+ desc_internal->serialNumber = strdup((const char*) buf);
627
+
628
+ bytes = libusb_get_string_descriptor_ascii(
629
+ usb_devh, usb_desc.iManufacturer, buf, sizeof(buf));
630
+
631
+ if (bytes > 0)
632
+ desc_internal->manufacturer = strdup((const char*) buf);
633
+
634
+ bytes = libusb_get_string_descriptor_ascii(
635
+ usb_devh, usb_desc.iProduct, buf, sizeof(buf));
636
+
637
+ if (bytes > 0)
638
+ desc_internal->product = strdup((const char*) buf);
639
+
640
+ libusb_close(usb_devh);
641
+ } else {
642
+ UVC_DEBUG("can't open device %04x:%04x, not fetching serial etc.",
643
+ usb_desc.idVendor, usb_desc.idProduct);
644
+ }
645
+
646
+ *desc = desc_internal;
647
+
648
+ UVC_EXIT(ret);
649
+ return ret;
650
+ }
651
+
652
+ /**
653
+ * @brief Frees a device descriptor created with uvc_get_device_descriptor
654
+ * @ingroup device
655
+ *
656
+ * @param desc Descriptor to free
657
+ */
658
+ void uvc_free_device_descriptor(
659
+ uvc_device_descriptor_t *desc) {
660
+ UVC_ENTER();
661
+
662
+ if (desc->serialNumber)
663
+ free((void*) desc->serialNumber);
664
+
665
+ if (desc->manufacturer)
666
+ free((void*) desc->manufacturer);
667
+
668
+ if (desc->product)
669
+ free((void*) desc->product);
670
+
671
+ free(desc);
672
+
673
+ UVC_EXIT_VOID();
674
+ }
675
+
676
+ /**
677
+ * @brief Get a list of the UVC devices attached to the system
678
+ * @ingroup device
679
+ *
680
+ * @note Free the list with uvc_free_device_list when you're done.
681
+ *
682
+ * @param ctx UVC context in which to list devices
683
+ * @param list List of uvc_device structures
684
+ * @return Error if unable to list devices, else SUCCESS
685
+ */
686
+ uvc_error_t uvc_get_device_list(
687
+ uvc_context_t *ctx,
688
+ uvc_device_t ***list) {
689
+ struct libusb_device **usb_dev_list;
690
+ struct libusb_device *usb_dev;
691
+ int num_usb_devices;
692
+
693
+ uvc_device_t **list_internal;
694
+ int num_uvc_devices;
695
+
696
+ /* per device */
697
+ int dev_idx;
698
+ struct libusb_config_descriptor *config;
699
+ struct libusb_device_descriptor desc;
700
+ uint8_t got_interface;
701
+
702
+ /* per interface */
703
+ int interface_idx;
704
+ const struct libusb_interface *interface;
705
+
706
+ /* per altsetting */
707
+ int altsetting_idx;
708
+ const struct libusb_interface_descriptor *if_desc;
709
+
710
+ UVC_ENTER();
711
+
712
+ num_usb_devices = libusb_get_device_list(ctx->usb_ctx, &usb_dev_list);
713
+
714
+ if (num_usb_devices < 0) {
715
+ UVC_EXIT(UVC_ERROR_IO);
716
+ return UVC_ERROR_IO;
717
+ }
718
+
719
+ list_internal = malloc(sizeof(*list_internal));
720
+ *list_internal = NULL;
721
+
722
+ num_uvc_devices = 0;
723
+ dev_idx = -1;
724
+
725
+ while ((usb_dev = usb_dev_list[++dev_idx]) != NULL) {
726
+ got_interface = 0;
727
+
728
+ if (libusb_get_config_descriptor(usb_dev, 0, &config) != 0)
729
+ continue;
730
+
731
+ if ( libusb_get_device_descriptor ( usb_dev, &desc ) != LIBUSB_SUCCESS )
732
+ continue;
733
+
734
+ for (interface_idx = 0;
735
+ !got_interface && interface_idx < config->bNumInterfaces;
736
+ ++interface_idx) {
737
+ interface = &config->interface[interface_idx];
738
+
739
+ for (altsetting_idx = 0;
740
+ !got_interface && altsetting_idx < interface->num_altsetting;
741
+ ++altsetting_idx) {
742
+ if_desc = &interface->altsetting[altsetting_idx];
743
+
744
+ // Skip TIS cameras that definitely aren't UVC even though they might
745
+ // look that way
746
+
747
+ if ( 0x199e == desc.idVendor && desc.idProduct >= 0x8201 &&
748
+ desc.idProduct <= 0x8208 ) {
749
+ continue;
750
+ }
751
+
752
+ // Special case for Imaging Source cameras
753
+ /* Video, Streaming */
754
+ if ( 0x199e == desc.idVendor && ( 0x8101 == desc.idProduct ||
755
+ 0x8102 == desc.idProduct ) &&
756
+ if_desc->bInterfaceClass == 255 &&
757
+ if_desc->bInterfaceSubClass == 2 ) {
758
+ got_interface = 1;
759
+ }
760
+
761
+ /* Video, Streaming */
762
+ if (if_desc->bInterfaceClass == 14 && if_desc->bInterfaceSubClass == 2) {
763
+ got_interface = 1;
764
+ }
765
+ }
766
+ }
767
+
768
+ libusb_free_config_descriptor(config);
769
+
770
+ if (got_interface) {
771
+ uvc_device_t *uvc_dev = malloc(sizeof(*uvc_dev));
772
+ uvc_dev->ctx = ctx;
773
+ uvc_dev->ref = 0;
774
+ uvc_dev->usb_dev = usb_dev;
775
+ uvc_ref_device(uvc_dev);
776
+
777
+ num_uvc_devices++;
778
+ list_internal = realloc(list_internal, (num_uvc_devices + 1) * sizeof(*list_internal));
779
+
780
+ list_internal[num_uvc_devices - 1] = uvc_dev;
781
+ list_internal[num_uvc_devices] = NULL;
782
+
783
+ UVC_DEBUG(" UVC: %d", dev_idx);
784
+ } else {
785
+ UVC_DEBUG("non-UVC: %d", dev_idx);
786
+ }
787
+ }
788
+
789
+ libusb_free_device_list(usb_dev_list, 1);
790
+
791
+ *list = list_internal;
792
+
793
+ UVC_EXIT(UVC_SUCCESS);
794
+ return UVC_SUCCESS;
795
+ }
796
+
797
+ /**
798
+ * @brief Frees a list of device structures created with uvc_get_device_list.
799
+ * @ingroup device
800
+ *
801
+ * @param list Device list to free
802
+ * @param unref_devices Decrement the reference counter for each device
803
+ * in the list, and destroy any entries that end up with zero references
804
+ */
805
+ void uvc_free_device_list(uvc_device_t **list, uint8_t unref_devices) {
806
+ uvc_device_t *dev;
807
+ int dev_idx = 0;
808
+
809
+ UVC_ENTER();
810
+
811
+ if (unref_devices) {
812
+ while ((dev = list[dev_idx++]) != NULL) {
813
+ uvc_unref_device(dev);
814
+ }
815
+ }
816
+
817
+ free(list);
818
+
819
+ UVC_EXIT_VOID();
820
+ }
821
+
822
+ /**
823
+ * @brief Get the uvc_device_t corresponding to an open device
824
+ * @ingroup device
825
+ *
826
+ * @note Unref the uvc_device_t when you're done with it
827
+ *
828
+ * @param devh Device handle to an open UVC device
829
+ */
830
+ uvc_device_t *uvc_get_device(uvc_device_handle_t *devh) {
831
+ uvc_ref_device(devh->dev);
832
+ return devh->dev;
833
+ }
834
+
835
+ uvc_error_t uvc_set_altsetting_override(
836
+ uvc_device_handle_t *devh,
837
+ int altsetting,
838
+ unsigned int payload) {
839
+ if (devh == NULL) {
840
+ return UVC_ERROR_INVALID_PARAM;
841
+ }
842
+ if (altsetting <= 0) {
843
+ devh->altsetting_override_valid = 0;
844
+ devh->altsetting_override_altsetting = 0;
845
+ devh->altsetting_override_payload = 0;
846
+ return UVC_SUCCESS;
847
+ }
848
+ if (altsetting > 0xff || payload == 0 || payload > 0xffff) {
849
+ return UVC_ERROR_INVALID_PARAM;
850
+ }
851
+ devh->altsetting_override_altsetting = (uint8_t)altsetting;
852
+ devh->altsetting_override_payload = (uint16_t)payload;
853
+ devh->altsetting_override_valid = 1;
854
+ UVC_DEBUG("altsetting override: alt=%d payload=%u", altsetting, payload);
855
+ return UVC_SUCCESS;
856
+ }
857
+
858
+ /**
859
+ * @brief Get the underlying libusb device handle for an open device
860
+ * @ingroup device
861
+ *
862
+ * This can be used to access other interfaces on the same device, e.g.
863
+ * a webcam microphone.
864
+ *
865
+ * @note The libusb device handle is only valid while the UVC device is open;
866
+ * it will be invalidated upon calling uvc_close.
867
+ *
868
+ * @param devh UVC device handle to an open device
869
+ */
870
+ libusb_device_handle *uvc_get_libusb_handle(uvc_device_handle_t *devh) {
871
+ return devh->usb_devh;
872
+ }
873
+
874
+ /**
875
+ * @brief Get camera terminal descriptor for the open device.
876
+ *
877
+ * @note Do not modify the returned structure.
878
+ * @note The returned structure is part of a linked list, but iterating through
879
+ * it will make it no longer the camera terminal
880
+ *
881
+ * @param devh Device handle to an open UVC device
882
+ */
883
+ const uvc_input_terminal_t *uvc_get_camera_terminal(uvc_device_handle_t *devh) {
884
+ const uvc_input_terminal_t *term = uvc_get_input_terminals(devh);
885
+ while(term != NULL) {
886
+ if (term->wTerminalType == UVC_ITT_CAMERA) {
887
+ break;
888
+ }
889
+ else {
890
+ term = term->next;
891
+ }
892
+ }
893
+ return term;
894
+ }
895
+
896
+
897
+ /**
898
+ * @brief Get input terminal descriptors for the open device.
899
+ *
900
+ * @note Do not modify the returned structure.
901
+ * @note The returned structure is part of a linked list. Iterate through
902
+ * it by using the 'next' pointers.
903
+ *
904
+ * @param devh Device handle to an open UVC device
905
+ */
906
+ const uvc_input_terminal_t *uvc_get_input_terminals(uvc_device_handle_t *devh) {
907
+ return devh->info->ctrl_if.input_term_descs;
908
+ }
909
+
910
+ /**
911
+ * @brief Get output terminal descriptors for the open device.
912
+ *
913
+ * @note Do not modify the returned structure.
914
+ * @note The returned structure is part of a linked list. Iterate through
915
+ * it by using the 'next' pointers.
916
+ *
917
+ * @param devh Device handle to an open UVC device
918
+ */
919
+ const uvc_output_terminal_t *uvc_get_output_terminals(uvc_device_handle_t *devh) {
920
+ return NULL; /* @todo */
921
+ }
922
+
923
+ /**
924
+ * @brief Get selector unit descriptors for the open device.
925
+ *
926
+ * @note Do not modify the returned structure.
927
+ * @note The returned structure is part of a linked list. Iterate through
928
+ * it by using the 'next' pointers.
929
+ *
930
+ * @param devh Device handle to an open UVC device
931
+ */
932
+ const uvc_selector_unit_t *uvc_get_selector_units(uvc_device_handle_t *devh) {
933
+ return devh->info->ctrl_if.selector_unit_descs;
934
+ }
935
+
936
+ /**
937
+ * @brief Get processing unit descriptors for the open device.
938
+ *
939
+ * @note Do not modify the returned structure.
940
+ * @note The returned structure is part of a linked list. Iterate through
941
+ * it by using the 'next' pointers.
942
+ *
943
+ * @param devh Device handle to an open UVC device
944
+ */
945
+ const uvc_processing_unit_t *uvc_get_processing_units(uvc_device_handle_t *devh) {
946
+ return devh->info->ctrl_if.processing_unit_descs;
947
+ }
948
+
949
+ /**
950
+ * @brief Get extension unit descriptors for the open device.
951
+ *
952
+ * @note Do not modify the returned structure.
953
+ * @note The returned structure is part of a linked list. Iterate through
954
+ * it by using the 'next' pointers.
955
+ *
956
+ * @param devh Device handle to an open UVC device
957
+ */
958
+ const uvc_extension_unit_t *uvc_get_extension_units(uvc_device_handle_t *devh) {
959
+ return devh->info->ctrl_if.extension_unit_descs;
960
+ }
961
+
962
+ /**
963
+ * @brief Increment the reference count for a device
964
+ * @ingroup device
965
+ *
966
+ * @param dev Device to reference
967
+ */
968
+ void uvc_ref_device(uvc_device_t *dev) {
969
+ UVC_ENTER();
970
+
971
+ dev->ref++;
972
+ libusb_ref_device(dev->usb_dev);
973
+
974
+ UVC_EXIT_VOID();
975
+ }
976
+
977
+ /**
978
+ * @brief Decrement the reference count for a device
979
+ * @ingropu device
980
+ * @note If the count reaches zero, the device will be discarded
981
+ *
982
+ * @param dev Device to unreference
983
+ */
984
+ void uvc_unref_device(uvc_device_t *dev) {
985
+ UVC_ENTER();
986
+
987
+ libusb_unref_device(dev->usb_dev);
988
+ dev->ref--;
989
+
990
+ if (dev->ref == 0)
991
+ free(dev);
992
+
993
+ UVC_EXIT_VOID();
994
+ }
995
+
996
+ /** @internal
997
+ * Claim a UVC interface, detaching the kernel driver if necessary.
998
+ * @ingroup device
999
+ *
1000
+ * @param devh UVC device handle
1001
+ * @param idx UVC interface index
1002
+ */
1003
+ uvc_error_t uvc_claim_if(uvc_device_handle_t *devh, int idx) {
1004
+ int ret = UVC_SUCCESS;
1005
+
1006
+ UVC_ENTER();
1007
+
1008
+ if ( devh->claimed & ( 1 << idx )) {
1009
+ UVC_DEBUG("attempt to claim already-claimed interface %d\n", idx );
1010
+ UVC_EXIT(ret);
1011
+ return ret;
1012
+ }
1013
+
1014
+ /* Tell libusb to detach any active kernel drivers. libusb will keep track of whether
1015
+ * it found a kernel driver for this interface. */
1016
+ ret = libusb_detach_kernel_driver(devh->usb_devh, idx);
1017
+
1018
+ if (ret == UVC_SUCCESS || ret == LIBUSB_ERROR_NOT_FOUND || ret == LIBUSB_ERROR_NOT_SUPPORTED) {
1019
+ UVC_DEBUG("claiming interface %d", idx);
1020
+ if (!( ret = libusb_claim_interface(devh->usb_devh, idx))) {
1021
+ devh->claimed |= ( 1 << idx );
1022
+ }
1023
+ } else {
1024
+ UVC_DEBUG("not claiming interface %d: unable to detach kernel driver (%s)",
1025
+ idx, uvc_strerror(ret));
1026
+ }
1027
+
1028
+ UVC_EXIT(ret);
1029
+ return ret;
1030
+ }
1031
+
1032
+ /** @internal
1033
+ * Release a UVC interface.
1034
+ * @ingroup device
1035
+ *
1036
+ * @param devh UVC device handle
1037
+ * @param idx UVC interface index
1038
+ */
1039
+ uvc_error_t uvc_release_if(uvc_device_handle_t *devh, int idx) {
1040
+ int ret = UVC_SUCCESS;
1041
+
1042
+ UVC_ENTER();
1043
+ UVC_DEBUG("releasing interface %d", idx);
1044
+ if (!( devh->claimed & ( 1 << idx ))) {
1045
+ UVC_DEBUG("attempt to release unclaimed interface %d\n", idx );
1046
+ UVC_EXIT(ret);
1047
+ return ret;
1048
+ }
1049
+
1050
+ /* libusb_release_interface *should* reset the alternate setting to the first available,
1051
+ but sometimes (e.g. on Darwin) it doesn't. Thus, we do it explicitly here.
1052
+ This is needed to de-initialize certain cameras. */
1053
+ libusb_set_interface_alt_setting(devh->usb_devh, idx, 0);
1054
+ ret = libusb_release_interface(devh->usb_devh, idx);
1055
+
1056
+ if (UVC_SUCCESS == ret) {
1057
+ devh->claimed &= ~( 1 << idx );
1058
+ /* Reattach any kernel drivers that were disabled when we claimed this interface */
1059
+ ret = libusb_attach_kernel_driver(devh->usb_devh, idx);
1060
+
1061
+ if (ret == UVC_SUCCESS) {
1062
+ UVC_DEBUG("reattached kernel driver to interface %d", idx);
1063
+ } else if (ret == LIBUSB_ERROR_NOT_FOUND || ret == LIBUSB_ERROR_NOT_SUPPORTED) {
1064
+ ret = UVC_SUCCESS; /* NOT_FOUND and NOT_SUPPORTED are OK: nothing to do */
1065
+ } else {
1066
+ UVC_DEBUG("error reattaching kernel driver to interface %d: %s",
1067
+ idx, uvc_strerror(ret));
1068
+ }
1069
+ }
1070
+
1071
+ UVC_EXIT(ret);
1072
+ return ret;
1073
+ }
1074
+
1075
+ /** @internal
1076
+ * Find a device's VideoControl interface and process its descriptor
1077
+ * @ingroup device
1078
+ */
1079
+ uvc_error_t uvc_scan_control(uvc_device_handle_t *devh, uvc_device_info_t *info) {
1080
+ const struct libusb_interface_descriptor *if_desc;
1081
+ uvc_error_t parse_ret, ret;
1082
+ int interface_idx;
1083
+ const unsigned char *buffer;
1084
+ size_t buffer_left, block_size;
1085
+
1086
+ UVC_ENTER();
1087
+
1088
+ ret = UVC_SUCCESS;
1089
+ if_desc = NULL;
1090
+
1091
+ uvc_device_descriptor_t* dev_desc;
1092
+ int haveTISCamera = 0;
1093
+ if ( get_device_descriptor ( devh, &dev_desc ) == UVC_SUCCESS ) {
1094
+ if ( 0x199e == dev_desc->idVendor && ( 0x8101 == dev_desc->idProduct ||
1095
+ 0x8102 == dev_desc->idProduct )) {
1096
+ haveTISCamera = 1;
1097
+ }
1098
+ uvc_free_device_descriptor ( dev_desc );
1099
+ }
1100
+
1101
+ for (interface_idx = 0; interface_idx < info->config->bNumInterfaces; ++interface_idx) {
1102
+ if_desc = &info->config->interface[interface_idx].altsetting[0];
1103
+
1104
+ if ( haveTISCamera && if_desc->bInterfaceClass == 255 && if_desc->bInterfaceSubClass == 1) // Video, Control
1105
+ break;
1106
+
1107
+ if (if_desc->bInterfaceClass == 14 && if_desc->bInterfaceSubClass == 1) // Video, Control
1108
+ break;
1109
+
1110
+ if_desc = NULL;
1111
+ }
1112
+
1113
+ if (if_desc == NULL) {
1114
+ UVC_EXIT(UVC_ERROR_INVALID_DEVICE);
1115
+ return UVC_ERROR_INVALID_DEVICE;
1116
+ }
1117
+
1118
+ info->ctrl_if.bInterfaceNumber = interface_idx;
1119
+ if (if_desc->bNumEndpoints != 0) {
1120
+ info->ctrl_if.bEndpointAddress = if_desc->endpoint[0].bEndpointAddress;
1121
+ }
1122
+
1123
+ buffer = if_desc->extra;
1124
+ buffer_left = if_desc->extra_length;
1125
+
1126
+ while (buffer_left >= 3) { // parseX needs to see buf[0,2] = length,type
1127
+ block_size = buffer[0];
1128
+ parse_ret = uvc_parse_vc(devh->dev, info, buffer, block_size);
1129
+
1130
+ if (parse_ret != UVC_SUCCESS) {
1131
+ ret = parse_ret;
1132
+ break;
1133
+ }
1134
+
1135
+ buffer_left -= block_size;
1136
+ buffer += block_size;
1137
+ }
1138
+
1139
+ UVC_EXIT(ret);
1140
+ return ret;
1141
+ }
1142
+
1143
+ /** @internal
1144
+ * @brief Parse a VideoControl header.
1145
+ * @ingroup device
1146
+ */
1147
+ uvc_error_t uvc_parse_vc_header(uvc_device_t *dev,
1148
+ uvc_device_info_t *info,
1149
+ const unsigned char *block, size_t block_size) {
1150
+ size_t i;
1151
+ uvc_error_t scan_ret, ret = UVC_SUCCESS;
1152
+
1153
+ UVC_ENTER();
1154
+
1155
+ /*
1156
+ int uvc_version;
1157
+ uvc_version = (block[4] >> 4) * 1000 + (block[4] & 0x0f) * 100
1158
+ + (block[3] >> 4) * 10 + (block[3] & 0x0f);
1159
+ */
1160
+
1161
+ info->ctrl_if.bcdUVC = SW_TO_SHORT(&block[3]);
1162
+
1163
+ switch (info->ctrl_if.bcdUVC) {
1164
+ case 0x0100:
1165
+ info->ctrl_if.dwClockFrequency = DW_TO_INT(block + 7);
1166
+ break;
1167
+ case 0x010a:
1168
+ info->ctrl_if.dwClockFrequency = DW_TO_INT(block + 7);
1169
+ break;
1170
+ case 0x0110:
1171
+ break;
1172
+ default:
1173
+ UVC_EXIT(UVC_ERROR_NOT_SUPPORTED);
1174
+ return UVC_ERROR_NOT_SUPPORTED;
1175
+ }
1176
+
1177
+ for (i = 12; i < block_size; ++i) {
1178
+ scan_ret = uvc_scan_streaming(dev, info, block[i]);
1179
+ if (scan_ret != UVC_SUCCESS) {
1180
+ ret = scan_ret;
1181
+ break;
1182
+ }
1183
+ }
1184
+
1185
+ UVC_EXIT(ret);
1186
+ return ret;
1187
+ }
1188
+
1189
+ /** @internal
1190
+ * @brief Parse a VideoControl input terminal.
1191
+ * @ingroup device
1192
+ */
1193
+ uvc_error_t uvc_parse_vc_input_terminal(uvc_device_t *dev,
1194
+ uvc_device_info_t *info,
1195
+ const unsigned char *block, size_t block_size) {
1196
+ uvc_input_terminal_t *term;
1197
+ size_t i;
1198
+
1199
+ UVC_ENTER();
1200
+
1201
+ /* only supporting camera-type input terminals */
1202
+ if (SW_TO_SHORT(&block[4]) != UVC_ITT_CAMERA) {
1203
+ UVC_EXIT(UVC_SUCCESS);
1204
+ return UVC_SUCCESS;
1205
+ }
1206
+
1207
+ term = calloc(1, sizeof(*term));
1208
+
1209
+ term->bTerminalID = block[3];
1210
+ term->wTerminalType = SW_TO_SHORT(&block[4]);
1211
+ term->wObjectiveFocalLengthMin = SW_TO_SHORT(&block[8]);
1212
+ term->wObjectiveFocalLengthMax = SW_TO_SHORT(&block[10]);
1213
+ term->wOcularFocalLength = SW_TO_SHORT(&block[12]);
1214
+
1215
+ for (i = 14 + block[14]; i >= 15; --i)
1216
+ term->bmControls = block[i] + (term->bmControls << 8);
1217
+
1218
+ DL_APPEND(info->ctrl_if.input_term_descs, term);
1219
+
1220
+ UVC_EXIT(UVC_SUCCESS);
1221
+ return UVC_SUCCESS;
1222
+ }
1223
+
1224
+ /** @internal
1225
+ * @brief Parse a VideoControl processing unit.
1226
+ * @ingroup device
1227
+ */
1228
+ uvc_error_t uvc_parse_vc_processing_unit(uvc_device_t *dev,
1229
+ uvc_device_info_t *info,
1230
+ const unsigned char *block, size_t block_size) {
1231
+ uvc_processing_unit_t *unit;
1232
+ size_t i;
1233
+
1234
+ UVC_ENTER();
1235
+
1236
+ unit = calloc(1, sizeof(*unit));
1237
+ unit->bUnitID = block[3];
1238
+ unit->bSourceID = block[4];
1239
+
1240
+ for (i = 7 + block[7]; i >= 8; --i)
1241
+ unit->bmControls = block[i] + (unit->bmControls << 8);
1242
+
1243
+ DL_APPEND(info->ctrl_if.processing_unit_descs, unit);
1244
+
1245
+ UVC_EXIT(UVC_SUCCESS);
1246
+ return UVC_SUCCESS;
1247
+ }
1248
+
1249
+ /** @internal
1250
+ * @brief Parse a VideoControl selector unit.
1251
+ * @ingroup device
1252
+ */
1253
+ uvc_error_t uvc_parse_vc_selector_unit(uvc_device_t *dev,
1254
+ uvc_device_info_t *info,
1255
+ const unsigned char *block, size_t block_size) {
1256
+ uvc_selector_unit_t *unit;
1257
+
1258
+ UVC_ENTER();
1259
+
1260
+ unit = calloc(1, sizeof(*unit));
1261
+ unit->bUnitID = block[3];
1262
+
1263
+ DL_APPEND(info->ctrl_if.selector_unit_descs, unit);
1264
+
1265
+ UVC_EXIT(UVC_SUCCESS);
1266
+ return UVC_SUCCESS;
1267
+ }
1268
+
1269
+ /** @internal
1270
+ * @brief Parse a VideoControl extension unit.
1271
+ * @ingroup device
1272
+ */
1273
+ uvc_error_t uvc_parse_vc_extension_unit(uvc_device_t *dev,
1274
+ uvc_device_info_t *info,
1275
+ const unsigned char *block, size_t block_size) {
1276
+ uvc_extension_unit_t *unit = calloc(1, sizeof(*unit));
1277
+ const uint8_t *start_of_controls;
1278
+ int size_of_controls, num_in_pins;
1279
+ int i;
1280
+
1281
+ UVC_ENTER();
1282
+
1283
+ unit->bUnitID = block[3];
1284
+ memcpy(unit->guidExtensionCode, &block[4], 16);
1285
+
1286
+ num_in_pins = block[21];
1287
+ size_of_controls = block[22 + num_in_pins];
1288
+ start_of_controls = &block[23 + num_in_pins];
1289
+
1290
+ for (i = size_of_controls - 1; i >= 0; --i)
1291
+ unit->bmControls = start_of_controls[i] + (unit->bmControls << 8);
1292
+
1293
+ DL_APPEND(info->ctrl_if.extension_unit_descs, unit);
1294
+
1295
+ UVC_EXIT(UVC_SUCCESS);
1296
+ return UVC_SUCCESS;
1297
+ }
1298
+
1299
+ /** @internal
1300
+ * Process a single VideoControl descriptor block
1301
+ * @ingroup device
1302
+ */
1303
+ uvc_error_t uvc_parse_vc(
1304
+ uvc_device_t *dev,
1305
+ uvc_device_info_t *info,
1306
+ const unsigned char *block, size_t block_size) {
1307
+ int descriptor_subtype;
1308
+ uvc_error_t ret = UVC_SUCCESS;
1309
+
1310
+ UVC_ENTER();
1311
+
1312
+ if (block[1] != 36) { // not a CS_INTERFACE descriptor??
1313
+ UVC_EXIT(UVC_SUCCESS);
1314
+ return UVC_SUCCESS; // UVC_ERROR_INVALID_DEVICE;
1315
+ }
1316
+
1317
+ descriptor_subtype = block[2];
1318
+
1319
+ switch (descriptor_subtype) {
1320
+ case UVC_VC_HEADER:
1321
+ ret = uvc_parse_vc_header(dev, info, block, block_size);
1322
+ break;
1323
+ case UVC_VC_INPUT_TERMINAL:
1324
+ ret = uvc_parse_vc_input_terminal(dev, info, block, block_size);
1325
+ break;
1326
+ case UVC_VC_OUTPUT_TERMINAL:
1327
+ break;
1328
+ case UVC_VC_SELECTOR_UNIT:
1329
+ ret = uvc_parse_vc_selector_unit(dev, info, block, block_size);
1330
+ break;
1331
+ case UVC_VC_PROCESSING_UNIT:
1332
+ ret = uvc_parse_vc_processing_unit(dev, info, block, block_size);
1333
+ break;
1334
+ case UVC_VC_EXTENSION_UNIT:
1335
+ ret = uvc_parse_vc_extension_unit(dev, info, block, block_size);
1336
+ break;
1337
+ default:
1338
+ ret = UVC_ERROR_INVALID_DEVICE;
1339
+ }
1340
+
1341
+ UVC_EXIT(ret);
1342
+ return ret;
1343
+ }
1344
+
1345
+ /** @internal
1346
+ * Process a VideoStreaming interface
1347
+ * @ingroup device
1348
+ */
1349
+ uvc_error_t uvc_scan_streaming(uvc_device_t *dev,
1350
+ uvc_device_info_t *info,
1351
+ int interface_idx) {
1352
+ const struct libusb_interface_descriptor *if_desc;
1353
+ const unsigned char *buffer;
1354
+ size_t buffer_left, block_size;
1355
+ uvc_error_t ret, parse_ret;
1356
+ uvc_streaming_interface_t *stream_if;
1357
+
1358
+ UVC_ENTER();
1359
+
1360
+ ret = UVC_SUCCESS;
1361
+
1362
+ if_desc = &(info->config->interface[interface_idx].altsetting[0]);
1363
+ buffer = if_desc->extra;
1364
+ buffer_left = if_desc->extra_length;
1365
+
1366
+ stream_if = calloc(1, sizeof(*stream_if));
1367
+ stream_if->parent = info;
1368
+ stream_if->bInterfaceNumber = if_desc->bInterfaceNumber;
1369
+ DL_APPEND(info->stream_ifs, stream_if);
1370
+
1371
+ while (buffer_left >= 3) {
1372
+ block_size = buffer[0];
1373
+ parse_ret = uvc_parse_vs(dev, info, stream_if, buffer, block_size);
1374
+
1375
+ if (parse_ret != UVC_SUCCESS) {
1376
+ ret = parse_ret;
1377
+ break;
1378
+ }
1379
+
1380
+ buffer_left -= block_size;
1381
+ buffer += block_size;
1382
+ }
1383
+
1384
+ UVC_EXIT(ret);
1385
+ return ret;
1386
+ }
1387
+
1388
+ /** @internal
1389
+ * @brief Parse a VideoStreaming header block.
1390
+ * @ingroup device
1391
+ */
1392
+ uvc_error_t uvc_parse_vs_input_header(uvc_streaming_interface_t *stream_if,
1393
+ const unsigned char *block,
1394
+ size_t block_size) {
1395
+ UVC_ENTER();
1396
+
1397
+ stream_if->bEndpointAddress = block[6] & 0x8f;
1398
+ stream_if->bTerminalLink = block[8];
1399
+ stream_if->bStillCaptureMethod = block[9];
1400
+
1401
+ UVC_EXIT(UVC_SUCCESS);
1402
+ return UVC_SUCCESS;
1403
+ }
1404
+
1405
+ /** @internal
1406
+ * @brief Parse a VideoStreaming uncompressed format block.
1407
+ * @ingroup device
1408
+ */
1409
+ uvc_error_t uvc_parse_vs_format_uncompressed(uvc_streaming_interface_t *stream_if,
1410
+ const unsigned char *block,
1411
+ size_t block_size) {
1412
+ UVC_ENTER();
1413
+
1414
+ uvc_format_desc_t *format = calloc(1, sizeof(*format));
1415
+
1416
+ format->parent = stream_if;
1417
+ format->bDescriptorSubtype = block[2];
1418
+ format->bFormatIndex = block[3];
1419
+ //format->bmCapabilities = block[4];
1420
+ //format->bmFlags = block[5];
1421
+ memcpy(format->guidFormat, &block[5], 16);
1422
+ format->bBitsPerPixel = block[21];
1423
+ format->bDefaultFrameIndex = block[22];
1424
+ format->bAspectRatioX = block[23];
1425
+ format->bAspectRatioY = block[24];
1426
+ format->bmInterlaceFlags = block[25];
1427
+ format->bCopyProtect = block[26];
1428
+
1429
+ DL_APPEND(stream_if->format_descs, format);
1430
+
1431
+ UVC_EXIT(UVC_SUCCESS);
1432
+ return UVC_SUCCESS;
1433
+ }
1434
+
1435
+ /** @internal
1436
+ * @brief Parse a VideoStreaming frame format block.
1437
+ * @ingroup device
1438
+ */
1439
+ uvc_error_t uvc_parse_vs_frame_format(uvc_streaming_interface_t *stream_if,
1440
+ const unsigned char *block,
1441
+ size_t block_size) {
1442
+ UVC_ENTER();
1443
+
1444
+ uvc_format_desc_t *format = calloc(1, sizeof(*format));
1445
+
1446
+ format->parent = stream_if;
1447
+ format->bDescriptorSubtype = block[2];
1448
+ format->bFormatIndex = block[3];
1449
+ format->bNumFrameDescriptors = block[4];
1450
+ memcpy(format->guidFormat, &block[5], 16);
1451
+ format->bBitsPerPixel = block[21];
1452
+ format->bDefaultFrameIndex = block[22];
1453
+ format->bAspectRatioX = block[23];
1454
+ format->bAspectRatioY = block[24];
1455
+ format->bmInterlaceFlags = block[25];
1456
+ format->bCopyProtect = block[26];
1457
+ format->bVariableSize = block[27];
1458
+
1459
+ DL_APPEND(stream_if->format_descs, format);
1460
+
1461
+ UVC_EXIT(UVC_SUCCESS);
1462
+ return UVC_SUCCESS;
1463
+ }
1464
+
1465
+ /** @internal
1466
+ * @brief Parse a VideoStreaming MJPEG format block.
1467
+ * @ingroup device
1468
+ */
1469
+ uvc_error_t uvc_parse_vs_format_mjpeg(uvc_streaming_interface_t *stream_if,
1470
+ const unsigned char *block,
1471
+ size_t block_size) {
1472
+ UVC_ENTER();
1473
+
1474
+ uvc_format_desc_t *format = calloc(1, sizeof(*format));
1475
+
1476
+ format->parent = stream_if;
1477
+ format->bDescriptorSubtype = block[2];
1478
+ format->bFormatIndex = block[3];
1479
+ memcpy(format->fourccFormat, "MJPG", 4);
1480
+ format->bmFlags = block[5];
1481
+ format->bBitsPerPixel = 0;
1482
+ format->bDefaultFrameIndex = block[6];
1483
+ format->bAspectRatioX = block[7];
1484
+ format->bAspectRatioY = block[8];
1485
+ format->bmInterlaceFlags = block[9];
1486
+ format->bCopyProtect = block[10];
1487
+
1488
+ DL_APPEND(stream_if->format_descs, format);
1489
+
1490
+ UVC_EXIT(UVC_SUCCESS);
1491
+ return UVC_SUCCESS;
1492
+ }
1493
+
1494
+ /** @internal
1495
+ * @brief Parse a VideoStreaming uncompressed frame block.
1496
+ * @ingroup device
1497
+ */
1498
+ uvc_error_t uvc_parse_vs_frame_frame(uvc_streaming_interface_t *stream_if,
1499
+ const unsigned char *block,
1500
+ size_t block_size) {
1501
+ uvc_format_desc_t *format;
1502
+ uvc_frame_desc_t *frame;
1503
+
1504
+ const unsigned char *p;
1505
+ int i;
1506
+
1507
+ UVC_ENTER();
1508
+
1509
+ format = stream_if->format_descs->prev;
1510
+ frame = calloc(1, sizeof(*frame));
1511
+
1512
+ frame->parent = format;
1513
+
1514
+ frame->bDescriptorSubtype = block[2];
1515
+ frame->bFrameIndex = block[3];
1516
+ frame->bmCapabilities = block[4];
1517
+ frame->wWidth = block[5] + (block[6] << 8);
1518
+ frame->wHeight = block[7] + (block[8] << 8);
1519
+ frame->dwMinBitRate = DW_TO_INT(&block[9]);
1520
+ frame->dwMaxBitRate = DW_TO_INT(&block[13]);
1521
+ frame->dwDefaultFrameInterval = DW_TO_INT(&block[17]);
1522
+ frame->bFrameIntervalType = block[21];
1523
+ frame->dwBytesPerLine = DW_TO_INT(&block[22]);
1524
+
1525
+ if (block[21] == 0) {
1526
+ frame->dwMinFrameInterval = DW_TO_INT(&block[26]);
1527
+ frame->dwMaxFrameInterval = DW_TO_INT(&block[30]);
1528
+ frame->dwFrameIntervalStep = DW_TO_INT(&block[34]);
1529
+ } else {
1530
+ frame->intervals = calloc(block[21] + 1, sizeof(frame->intervals[0]));
1531
+ p = &block[26];
1532
+
1533
+ for (i = 0; i < block[21]; ++i) {
1534
+ frame->intervals[i] = DW_TO_INT(p);
1535
+ p += 4;
1536
+ }
1537
+ frame->intervals[block[21]] = 0;
1538
+ }
1539
+
1540
+ DL_APPEND(format->frame_descs, frame);
1541
+
1542
+ UVC_EXIT(UVC_SUCCESS);
1543
+ return UVC_SUCCESS;
1544
+ }
1545
+
1546
+ /** @internal
1547
+ * @brief Parse a VideoStreaming uncompressed frame block.
1548
+ * @ingroup device
1549
+ */
1550
+ uvc_error_t uvc_parse_vs_frame_uncompressed(uvc_streaming_interface_t *stream_if,
1551
+ const unsigned char *block,
1552
+ size_t block_size) {
1553
+ uvc_format_desc_t *format;
1554
+ uvc_frame_desc_t *frame;
1555
+
1556
+ const unsigned char *p;
1557
+ int i;
1558
+
1559
+ UVC_ENTER();
1560
+
1561
+ format = stream_if->format_descs->prev;
1562
+ frame = calloc(1, sizeof(*frame));
1563
+
1564
+ frame->parent = format;
1565
+
1566
+ frame->bDescriptorSubtype = block[2];
1567
+ frame->bFrameIndex = block[3];
1568
+ frame->bmCapabilities = block[4];
1569
+ frame->wWidth = block[5] + (block[6] << 8);
1570
+ frame->wHeight = block[7] + (block[8] << 8);
1571
+ frame->dwMinBitRate = DW_TO_INT(&block[9]);
1572
+ frame->dwMaxBitRate = DW_TO_INT(&block[13]);
1573
+ frame->dwMaxVideoFrameBufferSize = DW_TO_INT(&block[17]);
1574
+ frame->dwDefaultFrameInterval = DW_TO_INT(&block[21]);
1575
+ frame->bFrameIntervalType = block[25];
1576
+
1577
+ if (block[25] == 0) {
1578
+ frame->dwMinFrameInterval = DW_TO_INT(&block[26]);
1579
+ frame->dwMaxFrameInterval = DW_TO_INT(&block[30]);
1580
+ frame->dwFrameIntervalStep = DW_TO_INT(&block[34]);
1581
+ } else {
1582
+ frame->intervals = calloc(block[25] + 1, sizeof(frame->intervals[0]));
1583
+ p = &block[26];
1584
+
1585
+ for (i = 0; i < block[25]; ++i) {
1586
+ frame->intervals[i] = DW_TO_INT(p);
1587
+ p += 4;
1588
+ }
1589
+ frame->intervals[block[25]] = 0;
1590
+ }
1591
+
1592
+ DL_APPEND(format->frame_descs, frame);
1593
+
1594
+ UVC_EXIT(UVC_SUCCESS);
1595
+ return UVC_SUCCESS;
1596
+ }
1597
+
1598
+ /** @internal
1599
+ * @brief Parse a VideoStreaming still iamge frame
1600
+ * @ingroup device
1601
+ */
1602
+ uvc_error_t uvc_parse_vs_still_image_frame(uvc_streaming_interface_t *stream_if,
1603
+ const unsigned char *block,
1604
+ size_t block_size) {
1605
+
1606
+ struct uvc_still_frame_desc* frame;
1607
+ uvc_format_desc_t *format;
1608
+
1609
+ const unsigned char *p;
1610
+ int i;
1611
+
1612
+ UVC_ENTER();
1613
+
1614
+ format = stream_if->format_descs->prev;
1615
+ frame = calloc(1, sizeof(*frame));
1616
+
1617
+ frame->parent = format;
1618
+
1619
+ frame->bDescriptorSubtype = block[2];
1620
+ frame->bEndPointAddress = block[3];
1621
+ uint8_t numImageSizePatterns = block[4];
1622
+
1623
+ frame->imageSizePatterns = NULL;
1624
+
1625
+ p = &block[5];
1626
+
1627
+ for (i = 1; i <= numImageSizePatterns; ++i) {
1628
+ uvc_still_frame_res_t* res = calloc(1, sizeof(uvc_still_frame_res_t));
1629
+ res->bResolutionIndex = i;
1630
+ res->wWidth = SW_TO_SHORT(p);
1631
+ p += 2;
1632
+ res->wHeight = SW_TO_SHORT(p);
1633
+ p += 2;
1634
+
1635
+ DL_APPEND(frame->imageSizePatterns, res);
1636
+ }
1637
+
1638
+ p = &block[5+4*numImageSizePatterns];
1639
+ frame->bNumCompressionPattern = *p;
1640
+
1641
+ if(frame->bNumCompressionPattern)
1642
+ {
1643
+ frame->bCompression = calloc(frame->bNumCompressionPattern, sizeof(frame->bCompression[0]));
1644
+ for(i = 0; i < frame->bNumCompressionPattern; ++i)
1645
+ {
1646
+ ++p;
1647
+ frame->bCompression[i] = *p;
1648
+ }
1649
+ }
1650
+ else
1651
+ {
1652
+ frame->bCompression = NULL;
1653
+ }
1654
+
1655
+ DL_APPEND(format->still_frame_desc, frame);
1656
+
1657
+ UVC_EXIT(UVC_SUCCESS);
1658
+ return UVC_SUCCESS;
1659
+ }
1660
+
1661
+ /** @internal
1662
+ * Process a single VideoStreaming descriptor block
1663
+ * @ingroup device
1664
+ */
1665
+ uvc_error_t uvc_parse_vs(
1666
+ uvc_device_t *dev,
1667
+ uvc_device_info_t *info,
1668
+ uvc_streaming_interface_t *stream_if,
1669
+ const unsigned char *block, size_t block_size) {
1670
+ uvc_error_t ret;
1671
+ int descriptor_subtype;
1672
+
1673
+ UVC_ENTER();
1674
+
1675
+ ret = UVC_SUCCESS;
1676
+ descriptor_subtype = block[2];
1677
+
1678
+ switch (descriptor_subtype) {
1679
+ case UVC_VS_INPUT_HEADER:
1680
+ ret = uvc_parse_vs_input_header(stream_if, block, block_size);
1681
+ break;
1682
+ case UVC_VS_OUTPUT_HEADER:
1683
+ UVC_DEBUG("unsupported descriptor subtype VS_OUTPUT_HEADER");
1684
+ break;
1685
+ case UVC_VS_STILL_IMAGE_FRAME:
1686
+ ret = uvc_parse_vs_still_image_frame(stream_if, block, block_size);
1687
+ break;
1688
+ case UVC_VS_FORMAT_UNCOMPRESSED:
1689
+ ret = uvc_parse_vs_format_uncompressed(stream_if, block, block_size);
1690
+ break;
1691
+ case UVC_VS_FORMAT_MJPEG:
1692
+ ret = uvc_parse_vs_format_mjpeg(stream_if, block, block_size);
1693
+ break;
1694
+ case UVC_VS_FRAME_UNCOMPRESSED:
1695
+ case UVC_VS_FRAME_MJPEG:
1696
+ ret = uvc_parse_vs_frame_uncompressed(stream_if, block, block_size);
1697
+ break;
1698
+ case UVC_VS_FORMAT_MPEG2TS:
1699
+ UVC_DEBUG("unsupported descriptor subtype VS_FORMAT_MPEG2TS");
1700
+ break;
1701
+ case UVC_VS_FORMAT_DV:
1702
+ UVC_DEBUG("unsupported descriptor subtype VS_FORMAT_DV");
1703
+ break;
1704
+ case UVC_VS_COLORFORMAT:
1705
+ UVC_DEBUG("unsupported descriptor subtype VS_COLORFORMAT");
1706
+ break;
1707
+ case UVC_VS_FORMAT_FRAME_BASED:
1708
+ ret = uvc_parse_vs_frame_format ( stream_if, block, block_size );
1709
+ break;
1710
+ case UVC_VS_FRAME_FRAME_BASED:
1711
+ ret = uvc_parse_vs_frame_frame ( stream_if, block, block_size );
1712
+ break;
1713
+ case UVC_VS_FORMAT_STREAM_BASED:
1714
+ UVC_DEBUG("unsupported descriptor subtype VS_FORMAT_STREAM_BASED");
1715
+ break;
1716
+ default:
1717
+ /** @todo handle JPEG and maybe still frames or even DV... */
1718
+ //UVC_DEBUG("unsupported descriptor subtype: %d",descriptor_subtype);
1719
+ break;
1720
+ }
1721
+
1722
+ UVC_EXIT(ret);
1723
+ return ret;
1724
+ }
1725
+
1726
+ /** @internal
1727
+ * @brief Free memory associated with a UVC device
1728
+ * @pre Streaming must be stopped, and threads must have died
1729
+ */
1730
+ void uvc_free_devh(uvc_device_handle_t *devh) {
1731
+ UVC_ENTER();
1732
+
1733
+ if (devh->info)
1734
+ uvc_free_device_info(devh->info);
1735
+
1736
+ if (devh->status_xfer)
1737
+ libusb_free_transfer(devh->status_xfer);
1738
+
1739
+ free(devh);
1740
+
1741
+ UVC_EXIT_VOID();
1742
+ }
1743
+
1744
+ /** @brief Close a device
1745
+ *
1746
+ * @ingroup device
1747
+ *
1748
+ * Ends any stream that's in progress.
1749
+ *
1750
+ * The device handle and frame structures will be invalidated.
1751
+ */
1752
+ void uvc_close(uvc_device_handle_t *devh) {
1753
+ UVC_ENTER();
1754
+ uvc_context_t *ctx = devh->dev->ctx;
1755
+
1756
+ if (devh->streams)
1757
+ uvc_stop_streaming(devh);
1758
+
1759
+ uvc_release_if(devh, devh->info->ctrl_if.bInterfaceNumber);
1760
+
1761
+ /* If we are managing the libusb context and this is the last open device,
1762
+ * then we need to cancel the handler thread. When we call libusb_close,
1763
+ * it'll cause a return from the thread's libusb_handle_events call, after
1764
+ * which the handler thread will check the flag we set and then exit. */
1765
+ if (ctx->own_usb_ctx && ctx->open_devices == devh && devh->next == NULL) {
1766
+ ctx->kill_handler_thread = 1;
1767
+ libusb_close(devh->usb_devh);
1768
+ pthread_join(ctx->handler_thread, NULL);
1769
+ } else {
1770
+ libusb_close(devh->usb_devh);
1771
+ }
1772
+
1773
+ DL_DELETE(ctx->open_devices, devh);
1774
+
1775
+ uvc_unref_device(devh->dev);
1776
+
1777
+ uvc_free_devh(devh);
1778
+
1779
+ UVC_EXIT_VOID();
1780
+ }
1781
+
1782
+ /** @internal
1783
+ * @brief Get number of open devices
1784
+ */
1785
+ size_t uvc_num_devices(uvc_context_t *ctx) {
1786
+ size_t count = 0;
1787
+
1788
+ uvc_device_handle_t *devh;
1789
+
1790
+ UVC_ENTER();
1791
+
1792
+ DL_FOREACH(ctx->open_devices, devh) {
1793
+ count++;
1794
+ }
1795
+
1796
+ UVC_EXIT((int) count);
1797
+ return count;
1798
+ }
1799
+
1800
+ void uvc_process_control_status(uvc_device_handle_t *devh, unsigned char *data, int len) {
1801
+ enum uvc_status_class status_class;
1802
+ uint8_t originator = 0, selector = 0, event = 0;
1803
+ enum uvc_status_attribute attribute = UVC_STATUS_ATTRIBUTE_UNKNOWN;
1804
+ void *content = NULL;
1805
+ size_t content_len = 0;
1806
+ int found_entity = 0;
1807
+ struct uvc_input_terminal *input_terminal;
1808
+ struct uvc_processing_unit *processing_unit;
1809
+
1810
+ UVC_ENTER();
1811
+
1812
+ if (len < 5) {
1813
+ UVC_DEBUG("Short read of VideoControl status update (%d bytes)", len);
1814
+ UVC_EXIT_VOID();
1815
+ return;
1816
+ }
1817
+
1818
+ originator = data[1];
1819
+ event = data[2];
1820
+ selector = data[3];
1821
+
1822
+ if (originator == 0) {
1823
+ UVC_DEBUG("Unhandled update from VC interface");
1824
+ UVC_EXIT_VOID();
1825
+ return; /* @todo VideoControl virtual entity interface updates */
1826
+ }
1827
+
1828
+ if (event != 0) {
1829
+ UVC_DEBUG("Unhandled VC event %d", (int) event);
1830
+ UVC_EXIT_VOID();
1831
+ return;
1832
+ }
1833
+
1834
+ /* printf("bSelector: %d\n", selector); */
1835
+
1836
+ DL_FOREACH(devh->info->ctrl_if.input_term_descs, input_terminal) {
1837
+ if (input_terminal->bTerminalID == originator) {
1838
+ status_class = UVC_STATUS_CLASS_CONTROL_CAMERA;
1839
+ found_entity = 1;
1840
+ break;
1841
+ }
1842
+ }
1843
+
1844
+ if (!found_entity) {
1845
+ DL_FOREACH(devh->info->ctrl_if.processing_unit_descs, processing_unit) {
1846
+ if (processing_unit->bUnitID == originator) {
1847
+ status_class = UVC_STATUS_CLASS_CONTROL_PROCESSING;
1848
+ found_entity = 1;
1849
+ break;
1850
+ }
1851
+ }
1852
+ }
1853
+
1854
+ if (!found_entity) {
1855
+ UVC_DEBUG("Got status update for unknown VideoControl entity %d",
1856
+ (int) originator);
1857
+ UVC_EXIT_VOID();
1858
+ return;
1859
+ }
1860
+
1861
+ attribute = data[4];
1862
+ content = data + 5;
1863
+ content_len = len - 5;
1864
+
1865
+ UVC_DEBUG("Event: class=%d, event=%d, selector=%d, attribute=%d, content_len=%zd",
1866
+ status_class, event, selector, attribute, content_len);
1867
+
1868
+ if(devh->status_cb) {
1869
+ UVC_DEBUG("Running user-supplied status callback");
1870
+ devh->status_cb(status_class,
1871
+ event,
1872
+ selector,
1873
+ attribute,
1874
+ content, content_len,
1875
+ devh->status_user_ptr);
1876
+ }
1877
+
1878
+ UVC_EXIT_VOID();
1879
+ }
1880
+
1881
+ void uvc_process_streaming_status(uvc_device_handle_t *devh, unsigned char *data, int len) {
1882
+
1883
+ UVC_ENTER();
1884
+
1885
+ if (len < 3) {
1886
+ UVC_DEBUG("Invalid streaming status event received.\n");
1887
+ UVC_EXIT_VOID();
1888
+ return;
1889
+ }
1890
+
1891
+ if (data[2] == 0) {
1892
+ if (len < 4) {
1893
+ UVC_DEBUG("Short read of status update (%d bytes)", len);
1894
+ UVC_EXIT_VOID();
1895
+ return;
1896
+ }
1897
+ UVC_DEBUG("Button (intf %u) %s len %d\n", data[1], data[3] ? "pressed" : "released", len);
1898
+
1899
+ if(devh->button_cb) {
1900
+ UVC_DEBUG("Running user-supplied button callback");
1901
+ devh->button_cb(data[1],
1902
+ data[3],
1903
+ devh->button_user_ptr);
1904
+ }
1905
+ } else {
1906
+ UVC_DEBUG("Stream %u error event %02x %02x len %d.\n", data[1], data[2], data[3], len);
1907
+ }
1908
+
1909
+ UVC_EXIT_VOID();
1910
+ }
1911
+
1912
+ void uvc_process_status_xfer(uvc_device_handle_t *devh, struct libusb_transfer *transfer) {
1913
+
1914
+ UVC_ENTER();
1915
+
1916
+ /* printf("Got transfer of aLen = %d\n", transfer->actual_length); */
1917
+
1918
+ if (transfer->actual_length > 0) {
1919
+ switch (transfer->buffer[0] & 0x0f) {
1920
+ case 1: /* VideoControl interface */
1921
+ uvc_process_control_status(devh, transfer->buffer, transfer->actual_length);
1922
+ break;
1923
+ case 2: /* VideoStreaming interface */
1924
+ uvc_process_streaming_status(devh, transfer->buffer, transfer->actual_length);
1925
+ break;
1926
+ }
1927
+ }
1928
+
1929
+ UVC_EXIT_VOID();
1930
+ }
1931
+
1932
+ /** @internal
1933
+ * @brief Process asynchronous status updates from the device.
1934
+ */
1935
+ void LIBUSB_CALL _uvc_status_callback(struct libusb_transfer *transfer) {
1936
+ UVC_ENTER();
1937
+
1938
+ uvc_device_handle_t *devh = (uvc_device_handle_t *) transfer->user_data;
1939
+
1940
+ switch (transfer->status) {
1941
+ case LIBUSB_TRANSFER_ERROR:
1942
+ case LIBUSB_TRANSFER_CANCELLED:
1943
+ case LIBUSB_TRANSFER_NO_DEVICE:
1944
+ UVC_DEBUG("not processing/resubmitting, status = %d", transfer->status);
1945
+ UVC_EXIT_VOID();
1946
+ return;
1947
+ case LIBUSB_TRANSFER_COMPLETED:
1948
+ uvc_process_status_xfer(devh, transfer);
1949
+ break;
1950
+ case LIBUSB_TRANSFER_TIMED_OUT:
1951
+ case LIBUSB_TRANSFER_STALL:
1952
+ case LIBUSB_TRANSFER_OVERFLOW:
1953
+ UVC_DEBUG("retrying transfer, status = %d", transfer->status);
1954
+ break;
1955
+ }
1956
+
1957
+ #ifdef UVC_DEBUGGING
1958
+ uvc_error_t ret =
1959
+ #endif
1960
+ libusb_submit_transfer(transfer);
1961
+ UVC_DEBUG("libusb_submit_transfer() = %d", ret);
1962
+
1963
+ UVC_EXIT_VOID();
1964
+ }
1965
+
1966
+ /** @brief Set a callback function to receive status updates
1967
+ *
1968
+ * @ingroup device
1969
+ */
1970
+ void uvc_set_status_callback(uvc_device_handle_t *devh,
1971
+ uvc_status_callback_t cb,
1972
+ void *user_ptr) {
1973
+ UVC_ENTER();
1974
+
1975
+ devh->status_cb = cb;
1976
+ devh->status_user_ptr = user_ptr;
1977
+
1978
+ UVC_EXIT_VOID();
1979
+ }
1980
+
1981
+ /** @brief Set a callback function to receive button events
1982
+ *
1983
+ * @ingroup device
1984
+ */
1985
+ void uvc_set_button_callback(uvc_device_handle_t *devh,
1986
+ uvc_button_callback_t cb,
1987
+ void *user_ptr) {
1988
+ UVC_ENTER();
1989
+
1990
+ devh->button_cb = cb;
1991
+ devh->button_user_ptr = user_ptr;
1992
+
1993
+ UVC_EXIT_VOID();
1994
+ }
1995
+
1996
+ /**
1997
+ * @brief Get format descriptions for the open device.
1998
+ *
1999
+ * @note Do not modify the returned structure.
2000
+ *
2001
+ * @param devh Device handle to an open UVC device
2002
+ */
2003
+ const uvc_format_desc_t *uvc_get_format_descs(uvc_device_handle_t *devh) {
2004
+ return devh->info->stream_ifs->format_descs;
2005
+ }
collector/core/gripper/camera_service_src/third_party/libuvc/src/diag.c ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ /**
35
+ * @defgroup diag Diagnostics
36
+ * @brief Interpretation of devices, error codes and negotiated stream parameters
37
+ */
38
+
39
+ #include "libuvc/libuvc.h"
40
+ #include "libuvc/libuvc_internal.h"
41
+
42
+ /** @internal */
43
+ typedef struct _uvc_error_msg {
44
+ uvc_error_t err;
45
+ const char *msg;
46
+ } _uvc_error_msg_t;
47
+
48
+ static const _uvc_error_msg_t uvc_error_msgs[] = {
49
+ {UVC_SUCCESS, "Success"},
50
+ {UVC_ERROR_IO, "I/O error"},
51
+ {UVC_ERROR_INVALID_PARAM, "Invalid parameter"},
52
+ {UVC_ERROR_ACCESS, "Access denied"},
53
+ {UVC_ERROR_NO_DEVICE, "No such device"},
54
+ {UVC_ERROR_NOT_FOUND, "Not found"},
55
+ {UVC_ERROR_BUSY, "Busy"},
56
+ {UVC_ERROR_TIMEOUT, "Timeout"},
57
+ {UVC_ERROR_OVERFLOW, "Overflow"},
58
+ {UVC_ERROR_PIPE, "Pipe"},
59
+ {UVC_ERROR_INTERRUPTED, "Interrupted"},
60
+ {UVC_ERROR_NO_MEM, "Out of memory"},
61
+ {UVC_ERROR_NOT_SUPPORTED, "Not supported"},
62
+ {UVC_ERROR_INVALID_DEVICE, "Invalid device"},
63
+ {UVC_ERROR_INVALID_MODE, "Invalid mode"},
64
+ {UVC_ERROR_CALLBACK_EXISTS, "Callback exists"}
65
+ };
66
+
67
+ /** @brief Print a message explaining an error in the UVC driver
68
+ * @ingroup diag
69
+ *
70
+ * @param err UVC error code
71
+ * @param msg Optional custom message, prepended to output
72
+ */
73
+ void uvc_perror(uvc_error_t err, const char *msg) {
74
+ if (msg && *msg) {
75
+ fputs(msg, stderr);
76
+ fputs(": ", stderr);
77
+ }
78
+
79
+ fprintf(stderr, "%s (%d)\n", uvc_strerror(err), err);
80
+ }
81
+
82
+ /** @brief Return a string explaining an error in the UVC driver
83
+ * @ingroup diag
84
+ *
85
+ * @param err UVC error code
86
+ * @return error message
87
+ */
88
+ const char* uvc_strerror(uvc_error_t err) {
89
+ size_t idx;
90
+
91
+ for (idx = 0; idx < sizeof(uvc_error_msgs) / sizeof(*uvc_error_msgs); ++idx) {
92
+ if (uvc_error_msgs[idx].err == err) {
93
+ return uvc_error_msgs[idx].msg;
94
+ }
95
+ }
96
+
97
+ return "Unknown error";
98
+ }
99
+
100
+ /** @brief Print the values in a stream control block
101
+ * @ingroup diag
102
+ *
103
+ * @param devh UVC device
104
+ * @param stream Output stream (stderr if NULL)
105
+ */
106
+ void uvc_print_stream_ctrl(uvc_stream_ctrl_t *ctrl, FILE *stream) {
107
+ if (stream == NULL)
108
+ stream = stderr;
109
+
110
+ fprintf(stream, "bmHint: %04x\n", ctrl->bmHint);
111
+ fprintf(stream, "bFormatIndex: %d\n", ctrl->bFormatIndex);
112
+ fprintf(stream, "bFrameIndex: %d\n", ctrl->bFrameIndex);
113
+ fprintf(stream, "dwFrameInterval: %u\n", ctrl->dwFrameInterval);
114
+ fprintf(stream, "wKeyFrameRate: %d\n", ctrl->wKeyFrameRate);
115
+ fprintf(stream, "wPFrameRate: %d\n", ctrl->wPFrameRate);
116
+ fprintf(stream, "wCompQuality: %d\n", ctrl->wCompQuality);
117
+ fprintf(stream, "wCompWindowSize: %d\n", ctrl->wCompWindowSize);
118
+ fprintf(stream, "wDelay: %d\n", ctrl->wDelay);
119
+ fprintf(stream, "dwMaxVideoFrameSize: %u\n", ctrl->dwMaxVideoFrameSize);
120
+ fprintf(stream, "dwMaxPayloadTransferSize: %u\n", ctrl->dwMaxPayloadTransferSize);
121
+ fprintf(stream, "bInterfaceNumber: %d\n", ctrl->bInterfaceNumber);
122
+ }
123
+
124
+ static const char *_uvc_name_for_format_subtype(uint8_t subtype) {
125
+ switch (subtype) {
126
+ case UVC_VS_FORMAT_UNCOMPRESSED:
127
+ return "UncompressedFormat";
128
+ case UVC_VS_FORMAT_MJPEG:
129
+ return "MJPEGFormat";
130
+ case UVC_VS_FORMAT_FRAME_BASED:
131
+ return "FrameFormat";
132
+ default:
133
+ return "Unknown";
134
+ }
135
+ }
136
+
137
+ /** @brief Print camera capabilities and configuration.
138
+ * @ingroup diag
139
+ *
140
+ * @param devh UVC device
141
+ * @param stream Output stream (stderr if NULL)
142
+ */
143
+ void uvc_print_diag(uvc_device_handle_t *devh, FILE *stream) {
144
+ if (stream == NULL)
145
+ stream = stderr;
146
+
147
+ if (devh->info->ctrl_if.bcdUVC) {
148
+ uvc_streaming_interface_t *stream_if;
149
+ int stream_idx = 0;
150
+
151
+ uvc_device_descriptor_t *desc;
152
+ uvc_get_device_descriptor(devh->dev, &desc);
153
+
154
+ fprintf(stream, "DEVICE CONFIGURATION (%04x:%04x/%s) ---\n",
155
+ desc->idVendor, desc->idProduct,
156
+ desc->serialNumber ? desc->serialNumber : "[none]");
157
+
158
+ uvc_free_device_descriptor(desc);
159
+
160
+ fprintf(stream, "Status: %s\n", devh->streams ? "streaming" : "idle");
161
+
162
+ fprintf(stream, "VideoControl:\n"
163
+ "\tbcdUVC: 0x%04x\n",
164
+ devh->info->ctrl_if.bcdUVC);
165
+
166
+ DL_FOREACH(devh->info->stream_ifs, stream_if) {
167
+ uvc_format_desc_t *fmt_desc;
168
+
169
+ ++stream_idx;
170
+
171
+ fprintf(stream, "VideoStreaming(%d):\n"
172
+ "\tbEndpointAddress: %d\n\tFormats:\n",
173
+ stream_idx, stream_if->bEndpointAddress);
174
+
175
+ DL_FOREACH(stream_if->format_descs, fmt_desc) {
176
+ uvc_frame_desc_t *frame_desc;
177
+ int i;
178
+
179
+ switch (fmt_desc->bDescriptorSubtype) {
180
+ case UVC_VS_FORMAT_UNCOMPRESSED:
181
+ case UVC_VS_FORMAT_MJPEG:
182
+ case UVC_VS_FORMAT_FRAME_BASED:
183
+ fprintf(stream,
184
+ "\t\%s(%d)\n"
185
+ "\t\t bits per pixel: %d\n"
186
+ "\t\t GUID: ",
187
+ _uvc_name_for_format_subtype(fmt_desc->bDescriptorSubtype),
188
+ fmt_desc->bFormatIndex,
189
+ fmt_desc->bBitsPerPixel);
190
+
191
+ for (i = 0; i < 16; ++i)
192
+ fprintf(stream, "%02x", fmt_desc->guidFormat[i]);
193
+
194
+ fprintf(stream, " (%4s)\n", fmt_desc->fourccFormat );
195
+
196
+ fprintf(stream,
197
+ "\t\t default frame: %d\n"
198
+ "\t\t aspect ratio: %dx%d\n"
199
+ "\t\t interlace flags: %02x\n"
200
+ "\t\t copy protect: %02x\n",
201
+ fmt_desc->bDefaultFrameIndex,
202
+ fmt_desc->bAspectRatioX,
203
+ fmt_desc->bAspectRatioY,
204
+ fmt_desc->bmInterlaceFlags,
205
+ fmt_desc->bCopyProtect);
206
+
207
+ DL_FOREACH(fmt_desc->frame_descs, frame_desc) {
208
+ uint32_t *interval_ptr;
209
+
210
+ fprintf(stream,
211
+ "\t\t\tFrameDescriptor(%d)\n"
212
+ "\t\t\t capabilities: %02x\n"
213
+ "\t\t\t size: %dx%d\n"
214
+ "\t\t\t bit rate: %d-%d\n"
215
+ "\t\t\t max frame size: %d\n"
216
+ "\t\t\t default interval: 1/%d\n",
217
+ frame_desc->bFrameIndex,
218
+ frame_desc->bmCapabilities,
219
+ frame_desc->wWidth,
220
+ frame_desc->wHeight,
221
+ frame_desc->dwMinBitRate,
222
+ frame_desc->dwMaxBitRate,
223
+ frame_desc->dwMaxVideoFrameBufferSize,
224
+ 10000000 / frame_desc->dwDefaultFrameInterval);
225
+ if (frame_desc->intervals) {
226
+ for (interval_ptr = frame_desc->intervals;
227
+ *interval_ptr;
228
+ ++interval_ptr) {
229
+ fprintf(stream,
230
+ "\t\t\t interval[%d]: 1/%d\n",
231
+ (int) (interval_ptr - frame_desc->intervals),
232
+ 10000000 / *interval_ptr);
233
+ }
234
+ } else {
235
+ fprintf(stream,
236
+ "\t\t\t min interval[%d] = 1/%d\n"
237
+ "\t\t\t max interval[%d] = 1/%d\n",
238
+ frame_desc->dwMinFrameInterval,
239
+ 10000000 / frame_desc->dwMinFrameInterval,
240
+ frame_desc->dwMaxFrameInterval,
241
+ 10000000 / frame_desc->dwMaxFrameInterval);
242
+ if (frame_desc->dwFrameIntervalStep)
243
+ fprintf(stream,
244
+ "\t\t\t interval step[%d] = 1/%d\n",
245
+ frame_desc->dwFrameIntervalStep,
246
+ 10000000 / frame_desc->dwFrameIntervalStep);
247
+ }
248
+ }
249
+ if(fmt_desc->still_frame_desc)
250
+ {
251
+ uvc_still_frame_desc_t* still_frame_desc;
252
+ DL_FOREACH(fmt_desc->still_frame_desc, still_frame_desc)
253
+ {
254
+ fprintf(stream,
255
+ "\t\t\tStillFrameDescriptor\n"
256
+ "\t\t\t bEndPointAddress: %02x\n",
257
+ still_frame_desc->bEndPointAddress);
258
+ uvc_still_frame_res_t* imageSizePattern;
259
+ DL_FOREACH(still_frame_desc->imageSizePatterns, imageSizePattern) {
260
+ fprintf(stream,
261
+ "\t\t\t wWidth(%d) = %d\n"
262
+ "\t\t\t wHeight(%d) = %d\n",
263
+ imageSizePattern->bResolutionIndex,
264
+ imageSizePattern->wWidth,
265
+ imageSizePattern->bResolutionIndex,
266
+ imageSizePattern->wHeight);
267
+ }
268
+ }
269
+ }
270
+ break;
271
+ default:
272
+ fprintf(stream, "\t-UnknownFormat (%d)\n",
273
+ fmt_desc->bDescriptorSubtype );
274
+ }
275
+ }
276
+ }
277
+
278
+ fprintf(stream, "END DEVICE CONFIGURATION\n");
279
+ } else {
280
+ fprintf(stream, "uvc_print_diag: Device not configured!\n");
281
+ }
282
+ }
283
+
284
+ /** @brief Print all possible frame configuration.
285
+ * @ingroup diag
286
+ *
287
+ * @param devh UVC device
288
+ * @param stream Output stream (stderr if NULL)
289
+ */
290
+ void uvc_print_frameformats(uvc_device_handle_t *devh) {
291
+
292
+ if (devh->info->ctrl_if.bcdUVC) {
293
+ uvc_streaming_interface_t *stream_if;
294
+ int stream_idx = 0;
295
+ DL_FOREACH(devh->info->stream_ifs, stream_if) {
296
+ uvc_format_desc_t *fmt_desc;
297
+ ++stream_idx;
298
+
299
+ DL_FOREACH(stream_if->format_descs, fmt_desc) {
300
+ uvc_frame_desc_t *frame_desc;
301
+ int i;
302
+
303
+ switch (fmt_desc->bDescriptorSubtype) {
304
+ case UVC_VS_FORMAT_UNCOMPRESSED:
305
+ case UVC_VS_FORMAT_MJPEG:
306
+ case UVC_VS_FORMAT_FRAME_BASED:
307
+ printf(" \%s(%d)\n"
308
+ " bits per pixel: %d\n"
309
+ " GUID: ",
310
+ _uvc_name_for_format_subtype(fmt_desc->bDescriptorSubtype),
311
+ fmt_desc->bFormatIndex,
312
+ fmt_desc->bBitsPerPixel);
313
+
314
+ for (i = 0; i < 16; ++i)
315
+ printf("%02x", fmt_desc->guidFormat[i]);
316
+
317
+ printf(" (%4s)\n", fmt_desc->fourccFormat );
318
+
319
+ printf(" default frame: %d\n"
320
+ " aspect ratio: %dx%d\n"
321
+ " interlace flags: %02x\n"
322
+ " copy protect: %02x\n",
323
+ fmt_desc->bDefaultFrameIndex,
324
+ fmt_desc->bAspectRatioX,
325
+ fmt_desc->bAspectRatioY,
326
+ fmt_desc->bmInterlaceFlags,
327
+ fmt_desc->bCopyProtect);
328
+
329
+ DL_FOREACH(fmt_desc->frame_descs, frame_desc) {
330
+ uint32_t *interval_ptr;
331
+
332
+ printf(" FrameDescriptor(%d)\n"
333
+ " capabilities: %02x\n"
334
+ " size: %dx%d\n"
335
+ " bit rate: %d-%d\n"
336
+ " max frame size: %d\n"
337
+ " default interval: 1/%d\n",
338
+ frame_desc->bFrameIndex,
339
+ frame_desc->bmCapabilities,
340
+ frame_desc->wWidth,
341
+ frame_desc->wHeight,
342
+ frame_desc->dwMinBitRate,
343
+ frame_desc->dwMaxBitRate,
344
+ frame_desc->dwMaxVideoFrameBufferSize,
345
+ 10000000 / frame_desc->dwDefaultFrameInterval);
346
+ if (frame_desc->intervals) {
347
+ for (interval_ptr = frame_desc->intervals;
348
+ *interval_ptr;
349
+ ++interval_ptr) {
350
+ printf(" interval[%d]: 1/%d\n",
351
+ (int) (interval_ptr - frame_desc->intervals),
352
+ 10000000 / *interval_ptr);
353
+ }
354
+ } else {
355
+ printf(" min interval[%d] = 1/%d\n"
356
+ " max interval[%d] = 1/%d\n",
357
+ frame_desc->dwMinFrameInterval,
358
+ 10000000 / frame_desc->dwMinFrameInterval,
359
+ frame_desc->dwMaxFrameInterval,
360
+ 10000000 / frame_desc->dwMaxFrameInterval);
361
+ if (frame_desc->dwFrameIntervalStep)
362
+ printf(" interval step[%d] = 1/%d\n",
363
+ frame_desc->dwFrameIntervalStep,
364
+ 10000000 / frame_desc->dwFrameIntervalStep);
365
+ }
366
+ }
367
+ break;
368
+ default:
369
+ printf("\t-UnknownFormat (%d)\n",fmt_desc->bDescriptorSubtype );
370
+ }
371
+ }
372
+ }
373
+ } else {
374
+ printf("uvc_print_frameformats: Device not configured!\n");
375
+ }
376
+ }
collector/core/gripper/camera_service_src/third_party/libuvc/src/example.c ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "libuvc/libuvc.h"
2
+ #include <stdio.h>
3
+ #include <unistd.h>
4
+
5
+ /* This callback function runs once per frame. Use it to perform any
6
+ * quick processing you need, or have it put the frame into your application's
7
+ * input queue. If this function takes too long, you'll start losing frames. */
8
+ void cb(uvc_frame_t *frame, void *ptr) {
9
+ uvc_frame_t *bgr;
10
+ uvc_error_t ret;
11
+ enum uvc_frame_format *frame_format = (enum uvc_frame_format *)ptr;
12
+ /* FILE *fp;
13
+ * static int jpeg_count = 0;
14
+ * static const char *H264_FILE = "iOSDevLog.h264";
15
+ * static const char *MJPEG_FILE = ".jpeg";
16
+ * char filename[16]; */
17
+
18
+ /* We'll convert the image from YUV/JPEG to BGR, so allocate space */
19
+ bgr = uvc_allocate_frame(frame->width * frame->height * 3);
20
+ if (!bgr) {
21
+ printf("unable to allocate bgr frame!\n");
22
+ return;
23
+ }
24
+
25
+ printf("callback! frame_format = %d, width = %d, height = %d, length = %lu, ptr = %p\n",
26
+ frame->frame_format, frame->width, frame->height, frame->data_bytes, ptr);
27
+
28
+ switch (frame->frame_format) {
29
+ case UVC_FRAME_FORMAT_H264:
30
+ /* use `ffplay H264_FILE` to play */
31
+ /* fp = fopen(H264_FILE, "a");
32
+ * fwrite(frame->data, 1, frame->data_bytes, fp);
33
+ * fclose(fp); */
34
+ break;
35
+ case UVC_COLOR_FORMAT_MJPEG:
36
+ /* sprintf(filename, "%d%s", jpeg_count++, MJPEG_FILE);
37
+ * fp = fopen(filename, "w");
38
+ * fwrite(frame->data, 1, frame->data_bytes, fp);
39
+ * fclose(fp); */
40
+ break;
41
+ case UVC_COLOR_FORMAT_YUYV:
42
+ /* Do the BGR conversion */
43
+ ret = uvc_any2bgr(frame, bgr);
44
+ if (ret) {
45
+ uvc_perror(ret, "uvc_any2bgr");
46
+ uvc_free_frame(bgr);
47
+ return;
48
+ }
49
+ break;
50
+ default:
51
+ break;
52
+ }
53
+
54
+ if (frame->sequence % 30 == 0) {
55
+ printf(" * got image %u\n", frame->sequence);
56
+ }
57
+
58
+ /* Call a user function:
59
+ *
60
+ * my_type *my_obj = (*my_type) ptr;
61
+ * my_user_function(ptr, bgr);
62
+ * my_other_function(ptr, bgr->data, bgr->width, bgr->height);
63
+ */
64
+
65
+ /* Call a C++ method:
66
+ *
67
+ * my_type *my_obj = (*my_type) ptr;
68
+ * my_obj->my_func(bgr);
69
+ */
70
+
71
+ /* Use opencv.highgui to display the image:
72
+ *
73
+ * cvImg = cvCreateImageHeader(
74
+ * cvSize(bgr->width, bgr->height),
75
+ * IPL_DEPTH_8U,
76
+ * 3);
77
+ *
78
+ * cvSetData(cvImg, bgr->data, bgr->width * 3);
79
+ *
80
+ * cvNamedWindow("Test", CV_WINDOW_AUTOSIZE);
81
+ * cvShowImage("Test", cvImg);
82
+ * cvWaitKey(10);
83
+ *
84
+ * cvReleaseImageHeader(&cvImg);
85
+ */
86
+
87
+ uvc_free_frame(bgr);
88
+ }
89
+
90
+ int main(int argc, char **argv) {
91
+ uvc_context_t *ctx;
92
+ uvc_device_t *dev;
93
+ uvc_device_handle_t *devh;
94
+ uvc_stream_ctrl_t ctrl;
95
+ uvc_error_t res;
96
+
97
+ /* Initialize a UVC service context. Libuvc will set up its own libusb
98
+ * context. Replace NULL with a libusb_context pointer to run libuvc
99
+ * from an existing libusb context. */
100
+ res = uvc_init(&ctx, NULL);
101
+
102
+ if (res < 0) {
103
+ uvc_perror(res, "uvc_init");
104
+ return res;
105
+ }
106
+
107
+ puts("UVC initialized");
108
+
109
+ /* Locates the first attached UVC device, stores in dev */
110
+ res = uvc_find_device(
111
+ ctx, &dev,
112
+ 0, 0, NULL); /* filter devices: vendor_id, product_id, "serial_num" */
113
+
114
+ if (res < 0) {
115
+ uvc_perror(res, "uvc_find_device"); /* no devices found */
116
+ } else {
117
+ puts("Device found");
118
+
119
+ /* Try to open the device: requires exclusive access */
120
+ res = uvc_open(dev, &devh);
121
+
122
+ if (res < 0) {
123
+ uvc_perror(res, "uvc_open"); /* unable to open device */
124
+ } else {
125
+ puts("Device opened");
126
+
127
+ /* Print out a message containing all the information that libuvc
128
+ * knows about the device */
129
+ uvc_print_diag(devh, stderr);
130
+
131
+ const uvc_format_desc_t *format_desc = uvc_get_format_descs(devh);
132
+ const uvc_frame_desc_t *frame_desc = format_desc->frame_descs;
133
+ enum uvc_frame_format frame_format;
134
+ int width = 640;
135
+ int height = 480;
136
+ int fps = 30;
137
+
138
+ switch (format_desc->bDescriptorSubtype) {
139
+ case UVC_VS_FORMAT_MJPEG:
140
+ frame_format = UVC_COLOR_FORMAT_MJPEG;
141
+ break;
142
+ case UVC_VS_FORMAT_FRAME_BASED:
143
+ frame_format = UVC_FRAME_FORMAT_H264;
144
+ break;
145
+ default:
146
+ frame_format = UVC_FRAME_FORMAT_YUYV;
147
+ break;
148
+ }
149
+
150
+ if (frame_desc) {
151
+ width = frame_desc->wWidth;
152
+ height = frame_desc->wHeight;
153
+ fps = 10000000 / frame_desc->dwDefaultFrameInterval;
154
+ }
155
+
156
+ printf("\nFirst format: (%4s) %dx%d %dfps\n", format_desc->fourccFormat, width, height, fps);
157
+
158
+ /* Try to negotiate first stream profile */
159
+ res = uvc_get_stream_ctrl_format_size(
160
+ devh, &ctrl, /* result stored in ctrl */
161
+ frame_format,
162
+ width, height, fps /* width, height, fps */
163
+ );
164
+
165
+ /* Print out the result */
166
+ uvc_print_stream_ctrl(&ctrl, stderr);
167
+
168
+ if (res < 0) {
169
+ uvc_perror(res, "get_mode"); /* device doesn't provide a matching stream */
170
+ } else {
171
+ /* Start the video stream. The library will call user function cb:
172
+ * cb(frame, (void *) 12345)
173
+ */
174
+ res = uvc_start_streaming(devh, &ctrl, cb, (void *) 12345, 0);
175
+
176
+ if (res < 0) {
177
+ uvc_perror(res, "start_streaming"); /* unable to start stream */
178
+ } else {
179
+ puts("Streaming...");
180
+
181
+ /* enable auto exposure - see uvc_set_ae_mode documentation */
182
+ puts("Enabling auto exposure ...");
183
+ const uint8_t UVC_AUTO_EXPOSURE_MODE_AUTO = 2;
184
+ res = uvc_set_ae_mode(devh, UVC_AUTO_EXPOSURE_MODE_AUTO);
185
+ if (res == UVC_SUCCESS) {
186
+ puts(" ... enabled auto exposure");
187
+ } else if (res == UVC_ERROR_PIPE) {
188
+ /* this error indicates that the camera does not support the full AE mode;
189
+ * try again, using aperture priority mode (fixed aperture, variable exposure time) */
190
+ puts(" ... full AE not supported, trying aperture priority mode");
191
+ const uint8_t UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY = 8;
192
+ res = uvc_set_ae_mode(devh, UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY);
193
+ if (res < 0) {
194
+ uvc_perror(res, " ... uvc_set_ae_mode failed to enable aperture priority mode");
195
+ } else {
196
+ puts(" ... enabled aperture priority auto exposure mode");
197
+ }
198
+ } else {
199
+ uvc_perror(res, " ... uvc_set_ae_mode failed to enable auto exposure mode");
200
+ }
201
+
202
+ sleep(10); /* stream for 10 seconds */
203
+
204
+ /* End the stream. Blocks until last callback is serviced */
205
+ uvc_stop_streaming(devh);
206
+ puts("Done streaming.");
207
+ }
208
+ }
209
+
210
+ /* Release our handle on the device */
211
+ uvc_close(devh);
212
+ puts("Device closed");
213
+ }
214
+
215
+ /* Release the device descriptor */
216
+ uvc_unref_device(dev);
217
+ }
218
+
219
+ /* Close the UVC context. This closes and cleans up any existing device handles,
220
+ * and it closes the libusb context if one was not provided. */
221
+ uvc_exit(ctx);
222
+ puts("UVC exited");
223
+
224
+ return 0;
225
+ }
226
+
collector/core/gripper/camera_service_src/third_party/libuvc/src/frame-mjpeg.c ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2014 Robert Xiao
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+
35
+ /**
36
+ * @defgroup frame Frame processing
37
+ */
38
+ #include "libuvc/libuvc.h"
39
+ #include "libuvc/libuvc_internal.h"
40
+ #include <jpeglib.h>
41
+ #include <setjmp.h>
42
+
43
+ extern uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes);
44
+
45
+ struct error_mgr {
46
+ struct jpeg_error_mgr super;
47
+ jmp_buf jmp;
48
+ };
49
+
50
+ static void _error_exit(j_common_ptr dinfo) {
51
+ struct error_mgr *myerr = (struct error_mgr *)dinfo->err;
52
+ (*dinfo->err->output_message)(dinfo);
53
+ longjmp(myerr->jmp, 1);
54
+ }
55
+
56
+ /* ISO/IEC 10918-1:1993(E) K.3.3. Default Huffman tables used by MJPEG UVC devices
57
+ which don't specify a Huffman table in the JPEG stream. */
58
+ static const unsigned char dc_lumi_len[] =
59
+ {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
60
+ static const unsigned char dc_lumi_val[] =
61
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
62
+
63
+ static const unsigned char dc_chromi_len[] =
64
+ {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
65
+ static const unsigned char dc_chromi_val[] =
66
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
67
+
68
+ static const unsigned char ac_lumi_len[] =
69
+ {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};
70
+ static const unsigned char ac_lumi_val[] =
71
+ {0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
72
+ 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
73
+ 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
74
+ 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
75
+ 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
76
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
77
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
78
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
79
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
80
+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
81
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
82
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
83
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3,
84
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
85
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
86
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
87
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
88
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
89
+ static const unsigned char ac_chromi_len[] =
90
+ {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77};
91
+ static const unsigned char ac_chromi_val[] =
92
+ {0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31,
93
+ 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
94
+ 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
95
+ 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
96
+ 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
97
+ 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
98
+ 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47,
99
+ 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
100
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
101
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
102
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
103
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
104
+ 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
105
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
106
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
107
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
108
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
109
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
110
+
111
+ #define COPY_HUFF_TABLE(dinfo,tbl,name) do { \
112
+ if(dinfo->tbl == NULL) dinfo->tbl = jpeg_alloc_huff_table((j_common_ptr)dinfo); \
113
+ memcpy(dinfo->tbl->bits, name##_len, sizeof(name##_len)); \
114
+ memset(dinfo->tbl->huffval, 0, sizeof(dinfo->tbl->huffval)); \
115
+ memcpy(dinfo->tbl->huffval, name##_val, sizeof(name##_val)); \
116
+ } while(0)
117
+
118
+ static void insert_huff_tables(j_decompress_ptr dinfo) {
119
+ COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[0], dc_lumi);
120
+ COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[1], dc_chromi);
121
+ COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[0], ac_lumi);
122
+ COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[1], ac_chromi);
123
+ }
124
+
125
+ static uvc_error_t uvc_mjpeg_convert(uvc_frame_t *in, uvc_frame_t *out) {
126
+ struct jpeg_decompress_struct dinfo;
127
+ struct error_mgr jerr;
128
+ size_t lines_read;
129
+ dinfo.err = jpeg_std_error(&jerr.super);
130
+ jerr.super.error_exit = _error_exit;
131
+
132
+ if (setjmp(jerr.jmp)) {
133
+ goto fail;
134
+ }
135
+
136
+ jpeg_create_decompress(&dinfo);
137
+ jpeg_mem_src(&dinfo, in->data, in->data_bytes);
138
+ jpeg_read_header(&dinfo, TRUE);
139
+
140
+ if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
141
+ /* This frame is missing the Huffman tables: fill in the standard ones */
142
+ insert_huff_tables(&dinfo);
143
+ }
144
+
145
+ if (out->frame_format == UVC_FRAME_FORMAT_RGB)
146
+ dinfo.out_color_space = JCS_RGB;
147
+ else if (out->frame_format == UVC_FRAME_FORMAT_GRAY8)
148
+ dinfo.out_color_space = JCS_GRAYSCALE;
149
+ else
150
+ goto fail;
151
+
152
+ dinfo.dct_method = JDCT_IFAST;
153
+
154
+ jpeg_start_decompress(&dinfo);
155
+
156
+ lines_read = 0;
157
+ while (dinfo.output_scanline < dinfo.output_height) {
158
+ unsigned char *buffer[1] = {( unsigned char*) out->data + lines_read * out->step };
159
+ int num_scanlines;
160
+
161
+ num_scanlines = jpeg_read_scanlines(&dinfo, buffer, 1);
162
+ lines_read += num_scanlines;
163
+ }
164
+
165
+ jpeg_finish_decompress(&dinfo);
166
+ jpeg_destroy_decompress(&dinfo);
167
+ return 0;
168
+
169
+ fail:
170
+ jpeg_destroy_decompress(&dinfo);
171
+ return UVC_ERROR_OTHER;
172
+ }
173
+
174
+ /** @brief Convert an MJPEG frame to RGB
175
+ * @ingroup frame
176
+ *
177
+ * @param in MJPEG frame
178
+ * @param out RGB frame
179
+ */
180
+ uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
181
+ if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
182
+ return UVC_ERROR_INVALID_PARAM;
183
+
184
+ if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
185
+ return UVC_ERROR_NO_MEM;
186
+
187
+ out->width = in->width;
188
+ out->height = in->height;
189
+ out->frame_format = UVC_FRAME_FORMAT_RGB;
190
+ out->step = in->width * 3;
191
+ out->sequence = in->sequence;
192
+ out->capture_time = in->capture_time;
193
+ out->capture_time_finished = in->capture_time_finished;
194
+ out->source = in->source;
195
+
196
+ return uvc_mjpeg_convert(in, out);
197
+ }
198
+
199
+ /** @brief Convert an MJPEG frame to GRAY8
200
+ * @ingroup frame
201
+ *
202
+ * @param in MJPEG frame
203
+ * @param out GRAY8 frame
204
+ */
205
+ uvc_error_t uvc_mjpeg2gray(uvc_frame_t *in, uvc_frame_t *out) {
206
+ if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
207
+ return UVC_ERROR_INVALID_PARAM;
208
+
209
+ if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
210
+ return UVC_ERROR_NO_MEM;
211
+
212
+ out->width = in->width;
213
+ out->height = in->height;
214
+ out->frame_format = UVC_FRAME_FORMAT_GRAY8;
215
+ out->step = in->width;
216
+ out->sequence = in->sequence;
217
+ out->capture_time = in->capture_time;
218
+ out->capture_time_finished = in->capture_time_finished;
219
+ out->source = in->source;
220
+
221
+ return uvc_mjpeg_convert(in, out);
222
+ }
collector/core/gripper/camera_service_src/third_party/libuvc/src/frame.c ADDED
@@ -0,0 +1,475 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ /**
35
+ * @defgroup frame Frame processing
36
+ * @brief Tools for managing frame buffers and converting between image formats
37
+ */
38
+ #include "libuvc/libuvc.h"
39
+ #include "libuvc/libuvc_internal.h"
40
+
41
+ /** @internal */
42
+ uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes) {
43
+ if (frame->library_owns_data) {
44
+ if (!frame->data || frame->data_bytes != need_bytes) {
45
+ frame->data_bytes = need_bytes;
46
+ frame->data = realloc(frame->data, frame->data_bytes);
47
+ }
48
+ if (!frame->data)
49
+ return UVC_ERROR_NO_MEM;
50
+ return UVC_SUCCESS;
51
+ } else {
52
+ if (!frame->data || frame->data_bytes < need_bytes)
53
+ return UVC_ERROR_NO_MEM;
54
+ return UVC_SUCCESS;
55
+ }
56
+ }
57
+
58
+ /** @brief Allocate a frame structure
59
+ * @ingroup frame
60
+ *
61
+ * @param data_bytes Number of bytes to allocate, or zero
62
+ * @return New frame, or NULL on error
63
+ */
64
+ uvc_frame_t *uvc_allocate_frame(size_t data_bytes) {
65
+ uvc_frame_t *frame = malloc(sizeof(*frame));
66
+
67
+ if (!frame)
68
+ return NULL;
69
+
70
+ memset(frame, 0, sizeof(*frame));
71
+
72
+ frame->library_owns_data = 1;
73
+
74
+ if (data_bytes > 0) {
75
+ frame->data_bytes = data_bytes;
76
+ frame->data = malloc(data_bytes);
77
+
78
+ if (!frame->data) {
79
+ free(frame);
80
+ return NULL;
81
+ }
82
+ }
83
+
84
+ return frame;
85
+ }
86
+
87
+ /** @brief Free a frame structure
88
+ * @ingroup frame
89
+ *
90
+ * @param frame Frame to destroy
91
+ */
92
+ void uvc_free_frame(uvc_frame_t *frame) {
93
+ if (frame->library_owns_data)
94
+ {
95
+ if (frame->data_bytes > 0)
96
+ free(frame->data);
97
+ if (frame->metadata_bytes > 0)
98
+ free(frame->metadata);
99
+ }
100
+
101
+ free(frame);
102
+ }
103
+
104
+ static inline unsigned char sat(int i) {
105
+ return (unsigned char)( i >= 255 ? 255 : (i < 0 ? 0 : i));
106
+ }
107
+
108
+ /** @brief Duplicate a frame, preserving color format
109
+ * @ingroup frame
110
+ *
111
+ * @param in Original frame
112
+ * @param out Duplicate frame
113
+ */
114
+ uvc_error_t uvc_duplicate_frame(uvc_frame_t *in, uvc_frame_t *out) {
115
+ if (uvc_ensure_frame_size(out, in->data_bytes) < 0)
116
+ return UVC_ERROR_NO_MEM;
117
+
118
+ out->width = in->width;
119
+ out->height = in->height;
120
+ out->frame_format = in->frame_format;
121
+ out->step = in->step;
122
+ out->sequence = in->sequence;
123
+ out->capture_time = in->capture_time;
124
+ out->capture_time_finished = in->capture_time_finished;
125
+ out->source = in->source;
126
+
127
+ memcpy(out->data, in->data, in->data_bytes);
128
+
129
+ if (in->metadata && in->metadata_bytes > 0)
130
+ {
131
+ if (out->metadata_bytes < in->metadata_bytes)
132
+ {
133
+ out->metadata = realloc(out->metadata, in->metadata_bytes);
134
+ }
135
+ out->metadata_bytes = in->metadata_bytes;
136
+ memcpy(out->metadata, in->metadata, in->metadata_bytes);
137
+ }
138
+
139
+ return UVC_SUCCESS;
140
+ }
141
+
142
+ #define YUYV2RGB_2(pyuv, prgb) { \
143
+ float r = 1.402f * ((pyuv)[3]-128); \
144
+ float g = -0.34414f * ((pyuv)[1]-128) - 0.71414f * ((pyuv)[3]-128); \
145
+ float b = 1.772f * ((pyuv)[1]-128); \
146
+ (prgb)[0] = sat(pyuv[0] + r); \
147
+ (prgb)[1] = sat(pyuv[0] + g); \
148
+ (prgb)[2] = sat(pyuv[0] + b); \
149
+ (prgb)[3] = sat(pyuv[2] + r); \
150
+ (prgb)[4] = sat(pyuv[2] + g); \
151
+ (prgb)[5] = sat(pyuv[2] + b); \
152
+ }
153
+ #define IYUYV2RGB_2(pyuv, prgb) { \
154
+ int r = (22987 * ((pyuv)[3] - 128)) >> 14; \
155
+ int g = (-5636 * ((pyuv)[1] - 128) - 11698 * ((pyuv)[3] - 128)) >> 14; \
156
+ int b = (29049 * ((pyuv)[1] - 128)) >> 14; \
157
+ (prgb)[0] = sat(*(pyuv) + r); \
158
+ (prgb)[1] = sat(*(pyuv) + g); \
159
+ (prgb)[2] = sat(*(pyuv) + b); \
160
+ (prgb)[3] = sat((pyuv)[2] + r); \
161
+ (prgb)[4] = sat((pyuv)[2] + g); \
162
+ (prgb)[5] = sat((pyuv)[2] + b); \
163
+ }
164
+ #define IYUYV2RGB_16(pyuv, prgb) IYUYV2RGB_8(pyuv, prgb); IYUYV2RGB_8(pyuv + 16, prgb + 24);
165
+ #define IYUYV2RGB_8(pyuv, prgb) IYUYV2RGB_4(pyuv, prgb); IYUYV2RGB_4(pyuv + 8, prgb + 12);
166
+ #define IYUYV2RGB_4(pyuv, prgb) IYUYV2RGB_2(pyuv, prgb); IYUYV2RGB_2(pyuv + 4, prgb + 6);
167
+
168
+ /** @brief Convert a frame from YUYV to RGB
169
+ * @ingroup frame
170
+ *
171
+ * @param in YUYV frame
172
+ * @param out RGB frame
173
+ */
174
+ uvc_error_t uvc_yuyv2rgb(uvc_frame_t *in, uvc_frame_t *out) {
175
+ if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
176
+ return UVC_ERROR_INVALID_PARAM;
177
+
178
+ if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
179
+ return UVC_ERROR_NO_MEM;
180
+
181
+ out->width = in->width;
182
+ out->height = in->height;
183
+ out->frame_format = UVC_FRAME_FORMAT_RGB;
184
+ out->step = in->width * 3;
185
+ out->sequence = in->sequence;
186
+ out->capture_time = in->capture_time;
187
+ out->capture_time_finished = in->capture_time_finished;
188
+ out->source = in->source;
189
+
190
+ uint8_t *pyuv = in->data;
191
+ uint8_t *prgb = out->data;
192
+ uint8_t *prgb_end = prgb + out->data_bytes;
193
+
194
+ while (prgb < prgb_end) {
195
+ IYUYV2RGB_8(pyuv, prgb);
196
+
197
+ prgb += 3 * 8;
198
+ pyuv += 2 * 8;
199
+ }
200
+
201
+ return UVC_SUCCESS;
202
+ }
203
+
204
+ #define IYUYV2BGR_2(pyuv, pbgr) { \
205
+ int r = (22987 * ((pyuv)[3] - 128)) >> 14; \
206
+ int g = (-5636 * ((pyuv)[1] - 128) - 11698 * ((pyuv)[3] - 128)) >> 14; \
207
+ int b = (29049 * ((pyuv)[1] - 128)) >> 14; \
208
+ (pbgr)[0] = sat(*(pyuv) + b); \
209
+ (pbgr)[1] = sat(*(pyuv) + g); \
210
+ (pbgr)[2] = sat(*(pyuv) + r); \
211
+ (pbgr)[3] = sat((pyuv)[2] + b); \
212
+ (pbgr)[4] = sat((pyuv)[2] + g); \
213
+ (pbgr)[5] = sat((pyuv)[2] + r); \
214
+ }
215
+ #define IYUYV2BGR_16(pyuv, pbgr) IYUYV2BGR_8(pyuv, pbgr); IYUYV2BGR_8(pyuv + 16, pbgr + 24);
216
+ #define IYUYV2BGR_8(pyuv, pbgr) IYUYV2BGR_4(pyuv, pbgr); IYUYV2BGR_4(pyuv + 8, pbgr + 12);
217
+ #define IYUYV2BGR_4(pyuv, pbgr) IYUYV2BGR_2(pyuv, pbgr); IYUYV2BGR_2(pyuv + 4, pbgr + 6);
218
+
219
+ /** @brief Convert a frame from YUYV to BGR
220
+ * @ingroup frame
221
+ *
222
+ * @param in YUYV frame
223
+ * @param out BGR frame
224
+ */
225
+ uvc_error_t uvc_yuyv2bgr(uvc_frame_t *in, uvc_frame_t *out) {
226
+ if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
227
+ return UVC_ERROR_INVALID_PARAM;
228
+
229
+ if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
230
+ return UVC_ERROR_NO_MEM;
231
+
232
+ out->width = in->width;
233
+ out->height = in->height;
234
+ out->frame_format = UVC_FRAME_FORMAT_BGR;
235
+ out->step = in->width * 3;
236
+ out->sequence = in->sequence;
237
+ out->capture_time = in->capture_time;
238
+ out->capture_time_finished = in->capture_time_finished;
239
+ out->source = in->source;
240
+
241
+ uint8_t *pyuv = in->data;
242
+ uint8_t *pbgr = out->data;
243
+ uint8_t *pbgr_end = pbgr + out->data_bytes;
244
+
245
+ while (pbgr < pbgr_end) {
246
+ IYUYV2BGR_8(pyuv, pbgr);
247
+
248
+ pbgr += 3 * 8;
249
+ pyuv += 2 * 8;
250
+ }
251
+
252
+ return UVC_SUCCESS;
253
+ }
254
+
255
+ #define IYUYV2Y(pyuv, py) { \
256
+ (py)[0] = (pyuv[0]); \
257
+ }
258
+
259
+ /** @brief Convert a frame from YUYV to Y (GRAY8)
260
+ * @ingroup frame
261
+ *
262
+ * @param in YUYV frame
263
+ * @param out GRAY8 frame
264
+ */
265
+ uvc_error_t uvc_yuyv2y(uvc_frame_t *in, uvc_frame_t *out) {
266
+ if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
267
+ return UVC_ERROR_INVALID_PARAM;
268
+
269
+ if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
270
+ return UVC_ERROR_NO_MEM;
271
+
272
+ out->width = in->width;
273
+ out->height = in->height;
274
+ out->frame_format = UVC_FRAME_FORMAT_GRAY8;
275
+ out->step = in->width;
276
+ out->sequence = in->sequence;
277
+ out->capture_time = in->capture_time;
278
+ out->capture_time_finished = in->capture_time_finished;
279
+ out->source = in->source;
280
+
281
+ uint8_t *pyuv = in->data;
282
+ uint8_t *py = out->data;
283
+ uint8_t *py_end = py + out->data_bytes;
284
+
285
+ while (py < py_end) {
286
+ IYUYV2Y(pyuv, py);
287
+
288
+ py += 1;
289
+ pyuv += 2;
290
+ }
291
+
292
+ return UVC_SUCCESS;
293
+ }
294
+
295
+ #define IYUYV2UV(pyuv, puv) { \
296
+ (puv)[0] = (pyuv[1]); \
297
+ }
298
+
299
+ /** @brief Convert a frame from YUYV to UV (GRAY8)
300
+ * @ingroup frame
301
+ *
302
+ * @param in YUYV frame
303
+ * @param out GRAY8 frame
304
+ */
305
+ uvc_error_t uvc_yuyv2uv(uvc_frame_t *in, uvc_frame_t *out) {
306
+ if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
307
+ return UVC_ERROR_INVALID_PARAM;
308
+
309
+ if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
310
+ return UVC_ERROR_NO_MEM;
311
+
312
+ out->width = in->width;
313
+ out->height = in->height;
314
+ out->frame_format = UVC_FRAME_FORMAT_GRAY8;
315
+ out->step = in->width;
316
+ out->sequence = in->sequence;
317
+ out->capture_time = in->capture_time;
318
+ out->capture_time_finished = in->capture_time_finished;
319
+ out->source = in->source;
320
+
321
+ uint8_t *pyuv = in->data;
322
+ uint8_t *puv = out->data;
323
+ uint8_t *puv_end = puv + out->data_bytes;
324
+
325
+ while (puv < puv_end) {
326
+ IYUYV2UV(pyuv, puv);
327
+
328
+ puv += 1;
329
+ pyuv += 2;
330
+ }
331
+
332
+ return UVC_SUCCESS;
333
+ }
334
+
335
+ #define IUYVY2RGB_2(pyuv, prgb) { \
336
+ int r = (22987 * ((pyuv)[2] - 128)) >> 14; \
337
+ int g = (-5636 * ((pyuv)[0] - 128) - 11698 * ((pyuv)[2] - 128)) >> 14; \
338
+ int b = (29049 * ((pyuv)[0] - 128)) >> 14; \
339
+ (prgb)[0] = sat((pyuv)[1] + r); \
340
+ (prgb)[1] = sat((pyuv)[1] + g); \
341
+ (prgb)[2] = sat((pyuv)[1] + b); \
342
+ (prgb)[3] = sat((pyuv)[3] + r); \
343
+ (prgb)[4] = sat((pyuv)[3] + g); \
344
+ (prgb)[5] = sat((pyuv)[3] + b); \
345
+ }
346
+ #define IUYVY2RGB_16(pyuv, prgb) IUYVY2RGB_8(pyuv, prgb); IUYVY2RGB_8(pyuv + 16, prgb + 24);
347
+ #define IUYVY2RGB_8(pyuv, prgb) IUYVY2RGB_4(pyuv, prgb); IUYVY2RGB_4(pyuv + 8, prgb + 12);
348
+ #define IUYVY2RGB_4(pyuv, prgb) IUYVY2RGB_2(pyuv, prgb); IUYVY2RGB_2(pyuv + 4, prgb + 6);
349
+
350
+ /** @brief Convert a frame from UYVY to RGB
351
+ * @ingroup frame
352
+ * @param ini UYVY frame
353
+ * @param out RGB frame
354
+ */
355
+ uvc_error_t uvc_uyvy2rgb(uvc_frame_t *in, uvc_frame_t *out) {
356
+ if (in->frame_format != UVC_FRAME_FORMAT_UYVY)
357
+ return UVC_ERROR_INVALID_PARAM;
358
+
359
+ if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
360
+ return UVC_ERROR_NO_MEM;
361
+
362
+ out->width = in->width;
363
+ out->height = in->height;
364
+ out->frame_format = UVC_FRAME_FORMAT_RGB;
365
+ out->step = in->width *3;
366
+ out->sequence = in->sequence;
367
+ out->capture_time = in->capture_time;
368
+ out->capture_time_finished = in->capture_time_finished;
369
+ out->source = in->source;
370
+
371
+ uint8_t *pyuv = in->data;
372
+ uint8_t *prgb = out->data;
373
+ uint8_t *prgb_end = prgb + out->data_bytes;
374
+
375
+ while (prgb < prgb_end) {
376
+ IUYVY2RGB_8(pyuv, prgb);
377
+
378
+ prgb += 3 * 8;
379
+ pyuv += 2 * 8;
380
+ }
381
+
382
+ return UVC_SUCCESS;
383
+ }
384
+
385
+ #define IUYVY2BGR_2(pyuv, pbgr) { \
386
+ int r = (22987 * ((pyuv)[2] - 128)) >> 14; \
387
+ int g = (-5636 * ((pyuv)[0] - 128) - 11698 * ((pyuv)[2] - 128)) >> 14; \
388
+ int b = (29049 * ((pyuv)[0] - 128)) >> 14; \
389
+ (pbgr)[0] = sat((pyuv)[1] + b); \
390
+ (pbgr)[1] = sat((pyuv)[1] + g); \
391
+ (pbgr)[2] = sat((pyuv)[1] + r); \
392
+ (pbgr)[3] = sat((pyuv)[3] + b); \
393
+ (pbgr)[4] = sat((pyuv)[3] + g); \
394
+ (pbgr)[5] = sat((pyuv)[3] + r); \
395
+ }
396
+ #define IUYVY2BGR_16(pyuv, pbgr) IUYVY2BGR_8(pyuv, pbgr); IUYVY2BGR_8(pyuv + 16, pbgr + 24);
397
+ #define IUYVY2BGR_8(pyuv, pbgr) IUYVY2BGR_4(pyuv, pbgr); IUYVY2BGR_4(pyuv + 8, pbgr + 12);
398
+ #define IUYVY2BGR_4(pyuv, pbgr) IUYVY2BGR_2(pyuv, pbgr); IUYVY2BGR_2(pyuv + 4, pbgr + 6);
399
+
400
+ /** @brief Convert a frame from UYVY to BGR
401
+ * @ingroup frame
402
+ * @param ini UYVY frame
403
+ * @param out BGR frame
404
+ */
405
+ uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out) {
406
+ if (in->frame_format != UVC_FRAME_FORMAT_UYVY)
407
+ return UVC_ERROR_INVALID_PARAM;
408
+
409
+ if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
410
+ return UVC_ERROR_NO_MEM;
411
+
412
+ out->width = in->width;
413
+ out->height = in->height;
414
+ out->frame_format = UVC_FRAME_FORMAT_BGR;
415
+ out->step = in->width *3;
416
+ out->sequence = in->sequence;
417
+ out->capture_time = in->capture_time;
418
+ out->capture_time_finished = in->capture_time_finished;
419
+ out->source = in->source;
420
+
421
+ uint8_t *pyuv = in->data;
422
+ uint8_t *pbgr = out->data;
423
+ uint8_t *pbgr_end = pbgr + out->data_bytes;
424
+
425
+ while (pbgr < pbgr_end) {
426
+ IUYVY2BGR_8(pyuv, pbgr);
427
+
428
+ pbgr += 3 * 8;
429
+ pyuv += 2 * 8;
430
+ }
431
+
432
+ return UVC_SUCCESS;
433
+ }
434
+
435
+ /** @brief Convert a frame to RGB
436
+ * @ingroup frame
437
+ *
438
+ * @param in non-RGB frame
439
+ * @param out RGB frame
440
+ */
441
+ uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out) {
442
+ switch (in->frame_format) {
443
+ #ifdef LIBUVC_HAS_JPEG
444
+ case UVC_FRAME_FORMAT_MJPEG:
445
+ return uvc_mjpeg2rgb(in, out);
446
+ #endif
447
+ case UVC_FRAME_FORMAT_YUYV:
448
+ return uvc_yuyv2rgb(in, out);
449
+ case UVC_FRAME_FORMAT_UYVY:
450
+ return uvc_uyvy2rgb(in, out);
451
+ case UVC_FRAME_FORMAT_RGB:
452
+ return uvc_duplicate_frame(in, out);
453
+ default:
454
+ return UVC_ERROR_NOT_SUPPORTED;
455
+ }
456
+ }
457
+
458
+ /** @brief Convert a frame to BGR
459
+ * @ingroup frame
460
+ *
461
+ * @param in non-BGR frame
462
+ * @param out BGR frame
463
+ */
464
+ uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out) {
465
+ switch (in->frame_format) {
466
+ case UVC_FRAME_FORMAT_YUYV:
467
+ return uvc_yuyv2bgr(in, out);
468
+ case UVC_FRAME_FORMAT_UYVY:
469
+ return uvc_uyvy2bgr(in, out);
470
+ case UVC_FRAME_FORMAT_BGR:
471
+ return uvc_duplicate_frame(in, out);
472
+ default:
473
+ return UVC_ERROR_NOT_SUPPORTED;
474
+ }
475
+ }
collector/core/gripper/camera_service_src/third_party/libuvc/src/init.c ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ /**
35
+ \mainpage libuvc: a cross-platform library for USB video devices
36
+
37
+ \b libuvc is a library that supports enumeration, control and streaming
38
+ for USB Video Class (UVC) devices, such as consumer webcams.
39
+
40
+ \section features Features
41
+ \li UVC device \ref device "discovery and management" API
42
+ \li \ref streaming "Video streaming" (device to host) with asynchronous/callback and synchronous/polling modes
43
+ \li Read/write access to standard \ref ctrl "device settings"
44
+ \li \ref frame "Conversion" between various formats: RGB, YUV, JPEG, etc.
45
+ \li Tested on Mac and Linux, portable to Windows and some BSDs
46
+
47
+ \section roadmap Roadmap
48
+ \li Bulk-mode image capture
49
+ \li One-shot image capture
50
+ \li Improved support for standard settings
51
+ \li Support for "extended" (vendor-defined) settings
52
+
53
+ \section misc Misc.
54
+ \p The source code can be found at https://github.com/libuvc/libuvc/. To build
55
+ the library, install <a href="https://libusb.info/">libusb</a> 1.0+ and run:
56
+
57
+ \code
58
+ $ git clone https://github.com/libuvc/libuvc.git
59
+ $ cd libuvc
60
+ $ mkdir build
61
+ $ cd build
62
+ $ cmake -DCMAKE_BUILD_TYPE=Release ..
63
+ $ make && make install
64
+ \endcode
65
+
66
+ \section Example
67
+ In this example, libuvc is used to acquire images in a 30 fps, 640x480
68
+ YUV stream from a UVC device such as a standard webcam.
69
+
70
+ \include example.c
71
+
72
+ */
73
+
74
+ /**
75
+ * @defgroup init Library initialization/deinitialization
76
+ * @brief Setup routines used to construct UVC access contexts
77
+ */
78
+ #include "libuvc/libuvc.h"
79
+ #include "libuvc/libuvc_internal.h"
80
+
81
+ /** @internal
82
+ * @brief Event handler thread
83
+ * There's one of these per UVC context.
84
+ * @todo We shouldn't run this if we don't own the USB context
85
+ */
86
+ void *_uvc_handle_events(void *arg) {
87
+ uvc_context_t *ctx = (uvc_context_t *) arg;
88
+
89
+ while (!ctx->kill_handler_thread)
90
+ libusb_handle_events_completed(ctx->usb_ctx, &ctx->kill_handler_thread);
91
+ return NULL;
92
+ }
93
+
94
+ /** @brief Initializes the UVC context
95
+ * @ingroup init
96
+ *
97
+ * @note If you provide your own USB context, you must handle
98
+ * libusb event processing using a function such as libusb_handle_events.
99
+ *
100
+ * @param[out] pctx The location where the context reference should be stored.
101
+ * @param[in] usb_ctx Optional USB context to use
102
+ * @return Error opening context or UVC_SUCCESS
103
+ */
104
+ uvc_error_t uvc_init(uvc_context_t **pctx, struct libusb_context *usb_ctx) {
105
+ uvc_error_t ret = UVC_SUCCESS;
106
+ uvc_context_t *ctx = calloc(1, sizeof(*ctx));
107
+
108
+ if (usb_ctx == NULL) {
109
+ ret = libusb_init(&ctx->usb_ctx);
110
+ ctx->own_usb_ctx = 1;
111
+ if (ret != UVC_SUCCESS) {
112
+ free(ctx);
113
+ ctx = NULL;
114
+ }
115
+ } else {
116
+ ctx->own_usb_ctx = 0;
117
+ ctx->usb_ctx = usb_ctx;
118
+ }
119
+
120
+ if (ctx != NULL)
121
+ *pctx = ctx;
122
+
123
+ return ret;
124
+ }
125
+
126
+ /**
127
+ * @brief Closes the UVC context, shutting down any active cameras.
128
+ * @ingroup init
129
+ *
130
+ * @note This function invalides any existing references to the context's
131
+ * cameras.
132
+ *
133
+ * If no USB context was provided to #uvc_init, the UVC-specific USB
134
+ * context will be destroyed.
135
+ *
136
+ * @param ctx UVC context to shut down
137
+ */
138
+ void uvc_exit(uvc_context_t *ctx) {
139
+ uvc_device_handle_t *devh;
140
+
141
+ DL_FOREACH(ctx->open_devices, devh) {
142
+ uvc_close(devh);
143
+ }
144
+
145
+ if (ctx->own_usb_ctx)
146
+ libusb_exit(ctx->usb_ctx);
147
+
148
+ free(ctx);
149
+ }
150
+
151
+ /**
152
+ * @internal
153
+ * @brief Spawns a handler thread for the context
154
+ * @ingroup init
155
+ *
156
+ * This should be called at the end of a successful uvc_open if no devices
157
+ * are already open (and being handled).
158
+ */
159
+ void uvc_start_handler_thread(uvc_context_t *ctx) {
160
+ if (ctx->own_usb_ctx)
161
+ pthread_create(&ctx->handler_thread, NULL, _uvc_handle_events, (void*) ctx);
162
+ }
163
+
collector/core/gripper/camera_service_src/third_party/libuvc/src/misc.c ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ #include <string.h>
35
+ #include <stdlib.h>
36
+
37
+ #if __APPLE__
38
+ char *strndup(const char *s, size_t n) {
39
+ size_t src_n = 0;
40
+ const char *sp = s;
41
+ char *d;
42
+
43
+ while (*sp++)
44
+ src_n++;
45
+
46
+ if (src_n < n)
47
+ n = src_n;
48
+
49
+ d = malloc(n + 1);
50
+
51
+ memcpy(d, s, n);
52
+
53
+ d[n] = '\0';
54
+
55
+ return d;
56
+ }
57
+ #endif
58
+
collector/core/gripper/camera_service_src/third_party/libuvc/src/stream.c ADDED
@@ -0,0 +1,1752 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ /**
35
+ * @defgroup streaming Streaming control functions
36
+ * @brief Tools for creating, managing and consuming video streams
37
+ */
38
+
39
+ #include "libuvc/libuvc.h"
40
+ #include "libuvc/libuvc_internal.h"
41
+ #include "errno.h"
42
+
43
+ #ifdef _MSC_VER
44
+
45
+ #define DELTA_EPOCH_IN_MICROSECS 116444736000000000Ui64
46
+
47
+ // gettimeofday - get time of day for Windows;
48
+ // A gettimeofday implementation for Microsoft Windows;
49
+ // Public domain code, author "ponnada";
50
+ int gettimeofday(struct timeval *tv, struct timezone *tz)
51
+ {
52
+ FILETIME ft;
53
+ unsigned __int64 tmpres = 0;
54
+ static int tzflag = 0;
55
+ if (NULL != tv)
56
+ {
57
+ GetSystemTimeAsFileTime(&ft);
58
+ tmpres |= ft.dwHighDateTime;
59
+ tmpres <<= 32;
60
+ tmpres |= ft.dwLowDateTime;
61
+ tmpres /= 10;
62
+ tmpres -= DELTA_EPOCH_IN_MICROSECS;
63
+ tv->tv_sec = (long)(tmpres / 1000000UL);
64
+ tv->tv_usec = (long)(tmpres % 1000000UL);
65
+ }
66
+ return 0;
67
+ }
68
+ #endif // _MSC_VER
69
+ uvc_frame_desc_t *uvc_find_frame_desc_stream(uvc_stream_handle_t *strmh,
70
+ uint16_t format_id, uint16_t frame_id);
71
+ uvc_frame_desc_t *uvc_find_frame_desc(uvc_device_handle_t *devh,
72
+ uint16_t format_id, uint16_t frame_id);
73
+ void *_uvc_user_caller(void *arg);
74
+ void _uvc_populate_frame(uvc_stream_handle_t *strmh);
75
+
76
+ static uvc_streaming_interface_t *_uvc_get_stream_if(uvc_device_handle_t *devh, int interface_idx);
77
+ static uvc_stream_handle_t *_uvc_get_stream_by_interface(uvc_device_handle_t *devh, int interface_idx);
78
+ static enum uvc_frame_format uvc_frame_format_for_guid(uint8_t guid[16]);
79
+
80
+ /*
81
+ * The project cameras advertise a larger UVC payload than they need for the
82
+ * production MJPEG modes. The workaround must update the UVC COMMIT control
83
+ * before the host selects an altsetting; changing only libusb's transfer
84
+ * geometry leaves the camera's negotiated payload at its oversized value.
85
+ * This is deliberately an exact VID/PID + format + size + frame-rate match.
86
+ */
87
+ struct ksq_altsetting_quirk {
88
+ uint16_t vid;
89
+ uint16_t pid;
90
+ uint8_t streaming_interface;
91
+ uint8_t forced_altsetting;
92
+ uint16_t payload;
93
+ uint16_t width;
94
+ uint16_t height;
95
+ };
96
+
97
+ static const struct ksq_altsetting_quirk ksq_altsetting_quirks[] = {
98
+ /* 2026-08-28 alt-3 verification: Sightac alt4/1600 -> alt3/800 (5-cam USB
99
+ * budget). Revert this line to {0x0c45, 0x636f, 1, 4, 1600, 640, 480} to
100
+ * restore the production 2-cam-per-set mode. */
101
+ {0x0c45, 0x636f, 1, 3, 800, 640, 480},
102
+ /* 2026-09-15 DECXIN default is alt6/944, the largest single-transaction
103
+ * setting. It is the safe fallback, not the preferred mode: it only fits
104
+ * 8 x 32 x 944 = 241664 B per frame against a measured worst case of
105
+ * 234148 B, so a busier scene truncates frames, while alt7/1280 fits
106
+ * 327680 B. The service therefore pins alt7/1280 per device through
107
+ * uvc_set_altsetting_override() on controllers that can carry it, and
108
+ * drops back to this entry when it cannot. alt7 is a high-bandwidth
109
+ * isochronous setting (2 transactions per microframe) that stalls the AMD
110
+ * 1022:15b7 controller within 45..130 s, every time. */
111
+ {0x1bcf, 0x2d4f, 1, 6, 944, 1280, 960},
112
+ };
113
+
114
+ /* The altsetting/payload pair a stream should be opened with, either from the
115
+ * caller's per-device override or, failing that, from the table above. */
116
+ struct ksq_altsetting_choice {
117
+ uint16_t vid;
118
+ uint16_t pid;
119
+ uint8_t altsetting;
120
+ uint16_t payload;
121
+ int from_override;
122
+ };
123
+
124
+ /* Returns 1 and fills @p out when a setting was resolved, 0 when the stream
125
+ * should be opened with libuvc's own altsetting search. */
126
+ static int _ksq_resolve_altsetting_for_ctrl(
127
+ uvc_device_handle_t *devh, const uvc_stream_ctrl_t *ctrl,
128
+ enum uvc_frame_format frame_format, uvc_frame_desc_t *frame_desc,
129
+ struct ksq_altsetting_choice *out) {
130
+ struct libusb_device_descriptor descriptor;
131
+ int have_descriptor;
132
+ size_t index;
133
+
134
+ if (devh == NULL || ctrl == NULL || frame_desc == NULL || out == NULL) {
135
+ return 0;
136
+ }
137
+
138
+ /* An explicit override wins over the table: the table is a per-model
139
+ * default, the override is a per-machine measurement of what this host
140
+ * controller can carry. It is deliberately not gated on format/size/
141
+ * interval -- the caller already validated the mode it asked for, and the
142
+ * endpoint check in uvc_stream_start() still rejects an altsetting that the
143
+ * streaming interface does not actually have. */
144
+ if (devh->altsetting_override_valid) {
145
+ have_descriptor =
146
+ libusb_get_device_descriptor(devh->dev->usb_dev, &descriptor) == 0;
147
+ out->vid = have_descriptor ? descriptor.idVendor : 0;
148
+ out->pid = have_descriptor ? descriptor.idProduct : 0;
149
+ out->altsetting = devh->altsetting_override_altsetting;
150
+ out->payload = devh->altsetting_override_payload;
151
+ out->from_override = 1;
152
+ return 1;
153
+ }
154
+
155
+ if (frame_format != UVC_FRAME_FORMAT_MJPEG ||
156
+ ctrl->dwFrameInterval < 330000 || ctrl->dwFrameInterval > 340000 ||
157
+ frame_desc->parent == NULL || frame_desc->parent->parent == NULL ||
158
+ libusb_get_device_descriptor(devh->dev->usb_dev, &descriptor) != 0) {
159
+ return 0;
160
+ }
161
+
162
+ for (index = 0;
163
+ index < sizeof(ksq_altsetting_quirks) /
164
+ sizeof(ksq_altsetting_quirks[0]);
165
+ ++index) {
166
+ const struct ksq_altsetting_quirk *quirk = &ksq_altsetting_quirks[index];
167
+ if (descriptor.idVendor == quirk->vid &&
168
+ descriptor.idProduct == quirk->pid &&
169
+ frame_desc->wWidth == quirk->width &&
170
+ frame_desc->wHeight == quirk->height &&
171
+ frame_desc->parent->parent->bInterfaceNumber ==
172
+ quirk->streaming_interface) {
173
+ out->vid = quirk->vid;
174
+ out->pid = quirk->pid;
175
+ out->altsetting = quirk->forced_altsetting;
176
+ out->payload = quirk->payload;
177
+ out->from_override = 0;
178
+ return 1;
179
+ }
180
+ }
181
+ return 0;
182
+ }
183
+
184
+ struct format_table_entry {
185
+ enum uvc_frame_format format;
186
+ uint8_t abstract_fmt;
187
+ uint8_t guid[16];
188
+ int children_count;
189
+ enum uvc_frame_format *children;
190
+ };
191
+
192
+ struct format_table_entry *_get_format_entry(enum uvc_frame_format format) {
193
+ #define ABS_FMT(_fmt, _num, ...) \
194
+ case _fmt: { \
195
+ static enum uvc_frame_format _fmt##_children[] = __VA_ARGS__; \
196
+ static struct format_table_entry _fmt##_entry = { \
197
+ _fmt, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, _num, _fmt##_children }; \
198
+ return &_fmt##_entry; }
199
+
200
+ #define FMT(_fmt, ...) \
201
+ case _fmt: { \
202
+ static struct format_table_entry _fmt##_entry = { \
203
+ _fmt, 0, __VA_ARGS__, 0, NULL }; \
204
+ return &_fmt##_entry; }
205
+
206
+ switch(format) {
207
+ /* Define new formats here */
208
+ ABS_FMT(UVC_FRAME_FORMAT_ANY, 2,
209
+ {UVC_FRAME_FORMAT_UNCOMPRESSED, UVC_FRAME_FORMAT_COMPRESSED})
210
+
211
+ ABS_FMT(UVC_FRAME_FORMAT_UNCOMPRESSED, 8,
212
+ {UVC_FRAME_FORMAT_YUYV, UVC_FRAME_FORMAT_UYVY, UVC_FRAME_FORMAT_GRAY8,
213
+ UVC_FRAME_FORMAT_GRAY16, UVC_FRAME_FORMAT_NV12, UVC_FRAME_FORMAT_P010,
214
+ UVC_FRAME_FORMAT_BGR, UVC_FRAME_FORMAT_RGB})
215
+ FMT(UVC_FRAME_FORMAT_YUYV,
216
+ {'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
217
+ FMT(UVC_FRAME_FORMAT_UYVY,
218
+ {'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
219
+ FMT(UVC_FRAME_FORMAT_GRAY8,
220
+ {'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
221
+ FMT(UVC_FRAME_FORMAT_GRAY16,
222
+ {'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
223
+ FMT(UVC_FRAME_FORMAT_NV12,
224
+ {'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
225
+ FMT(UVC_FRAME_FORMAT_P010,
226
+ {'P', '0', '1', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
227
+ FMT(UVC_FRAME_FORMAT_BGR,
228
+ {0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70})
229
+ FMT(UVC_FRAME_FORMAT_RGB,
230
+ {0x7e, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70})
231
+ FMT(UVC_FRAME_FORMAT_BY8,
232
+ {'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
233
+ FMT(UVC_FRAME_FORMAT_BA81,
234
+ {'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
235
+ FMT(UVC_FRAME_FORMAT_SGRBG8,
236
+ {'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
237
+ FMT(UVC_FRAME_FORMAT_SGBRG8,
238
+ {'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
239
+ FMT(UVC_FRAME_FORMAT_SRGGB8,
240
+ {'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
241
+ FMT(UVC_FRAME_FORMAT_SBGGR8,
242
+ {'B', 'G', 'G', 'R', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
243
+ ABS_FMT(UVC_FRAME_FORMAT_COMPRESSED, 2,
244
+ {UVC_FRAME_FORMAT_MJPEG, UVC_FRAME_FORMAT_H264})
245
+ FMT(UVC_FRAME_FORMAT_MJPEG,
246
+ {'M', 'J', 'P', 'G'})
247
+ FMT(UVC_FRAME_FORMAT_H264,
248
+ {'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
249
+
250
+ default:
251
+ return NULL;
252
+ }
253
+
254
+ #undef ABS_FMT
255
+ #undef FMT
256
+ }
257
+
258
+ static uint8_t _uvc_frame_format_matches_guid(enum uvc_frame_format fmt, uint8_t guid[16]) {
259
+ struct format_table_entry *format;
260
+ int child_idx;
261
+
262
+ format = _get_format_entry(fmt);
263
+ if (!format)
264
+ return 0;
265
+
266
+ if (!format->abstract_fmt && !memcmp(guid, format->guid, 16))
267
+ return 1;
268
+
269
+ for (child_idx = 0; child_idx < format->children_count; child_idx++) {
270
+ if (_uvc_frame_format_matches_guid(format->children[child_idx], guid))
271
+ return 1;
272
+ }
273
+
274
+ return 0;
275
+ }
276
+
277
+ static enum uvc_frame_format uvc_frame_format_for_guid(uint8_t guid[16]) {
278
+ struct format_table_entry *format;
279
+ enum uvc_frame_format fmt;
280
+
281
+ for (fmt = 0; fmt < UVC_FRAME_FORMAT_COUNT; ++fmt) {
282
+ format = _get_format_entry(fmt);
283
+ if (!format || format->abstract_fmt)
284
+ continue;
285
+ if (!memcmp(format->guid, guid, 16))
286
+ return format->format;
287
+ }
288
+
289
+ return UVC_FRAME_FORMAT_UNKNOWN;
290
+ }
291
+
292
+ /** @internal
293
+ * Run a streaming control query
294
+ * @param[in] devh UVC device
295
+ * @param[in,out] ctrl Control block
296
+ * @param[in] probe Whether this is a probe query or a commit query
297
+ * @param[in] req Query type
298
+ */
299
+ uvc_error_t uvc_query_stream_ctrl(
300
+ uvc_device_handle_t *devh,
301
+ uvc_stream_ctrl_t *ctrl,
302
+ uint8_t probe,
303
+ enum uvc_req_code req) {
304
+ uint8_t buf[34];
305
+ size_t len;
306
+ uvc_error_t err;
307
+
308
+ memset(buf, 0, sizeof(buf));
309
+
310
+ if (devh->info->ctrl_if.bcdUVC >= 0x0110)
311
+ len = 34;
312
+ else
313
+ len = 26;
314
+
315
+ /* prepare for a SET transfer */
316
+ if (req == UVC_SET_CUR) {
317
+ SHORT_TO_SW(ctrl->bmHint, buf);
318
+ buf[2] = ctrl->bFormatIndex;
319
+ buf[3] = ctrl->bFrameIndex;
320
+ INT_TO_DW(ctrl->dwFrameInterval, buf + 4);
321
+ SHORT_TO_SW(ctrl->wKeyFrameRate, buf + 8);
322
+ SHORT_TO_SW(ctrl->wPFrameRate, buf + 10);
323
+ SHORT_TO_SW(ctrl->wCompQuality, buf + 12);
324
+ SHORT_TO_SW(ctrl->wCompWindowSize, buf + 14);
325
+ SHORT_TO_SW(ctrl->wDelay, buf + 16);
326
+ INT_TO_DW(ctrl->dwMaxVideoFrameSize, buf + 18);
327
+ INT_TO_DW(ctrl->dwMaxPayloadTransferSize, buf + 22);
328
+
329
+ if (len == 34) {
330
+ INT_TO_DW ( ctrl->dwClockFrequency, buf + 26 );
331
+ buf[30] = ctrl->bmFramingInfo;
332
+ buf[31] = ctrl->bPreferredVersion;
333
+ buf[32] = ctrl->bMinVersion;
334
+ buf[33] = ctrl->bMaxVersion;
335
+ /** @todo support UVC 1.1 */
336
+ }
337
+ }
338
+
339
+ /* do the transfer */
340
+ err = libusb_control_transfer(
341
+ devh->usb_devh,
342
+ req == UVC_SET_CUR ? 0x21 : 0xA1,
343
+ req,
344
+ probe ? (UVC_VS_PROBE_CONTROL << 8) : (UVC_VS_COMMIT_CONTROL << 8),
345
+ ctrl->bInterfaceNumber,
346
+ buf, len, 0
347
+ );
348
+
349
+ if (err <= 0) {
350
+ return err;
351
+ }
352
+
353
+ /* now decode following a GET transfer */
354
+ if (req != UVC_SET_CUR) {
355
+ ctrl->bmHint = SW_TO_SHORT(buf);
356
+ ctrl->bFormatIndex = buf[2];
357
+ ctrl->bFrameIndex = buf[3];
358
+ ctrl->dwFrameInterval = DW_TO_INT(buf + 4);
359
+ ctrl->wKeyFrameRate = SW_TO_SHORT(buf + 8);
360
+ ctrl->wPFrameRate = SW_TO_SHORT(buf + 10);
361
+ ctrl->wCompQuality = SW_TO_SHORT(buf + 12);
362
+ ctrl->wCompWindowSize = SW_TO_SHORT(buf + 14);
363
+ ctrl->wDelay = SW_TO_SHORT(buf + 16);
364
+ ctrl->dwMaxVideoFrameSize = DW_TO_INT(buf + 18);
365
+ ctrl->dwMaxPayloadTransferSize = DW_TO_INT(buf + 22);
366
+
367
+ if (len == 34) {
368
+ ctrl->dwClockFrequency = DW_TO_INT ( buf + 26 );
369
+ ctrl->bmFramingInfo = buf[30];
370
+ ctrl->bPreferredVersion = buf[31];
371
+ ctrl->bMinVersion = buf[32];
372
+ ctrl->bMaxVersion = buf[33];
373
+ /** @todo support UVC 1.1 */
374
+ }
375
+ else
376
+ ctrl->dwClockFrequency = devh->info->ctrl_if.dwClockFrequency;
377
+
378
+ /* fix up block for cameras that fail to set dwMax* */
379
+ if (ctrl->dwMaxVideoFrameSize == 0) {
380
+ uvc_frame_desc_t *frame = uvc_find_frame_desc(devh, ctrl->bFormatIndex, ctrl->bFrameIndex);
381
+
382
+ if (frame) {
383
+ ctrl->dwMaxVideoFrameSize = frame->dwMaxVideoFrameBufferSize;
384
+ }
385
+ }
386
+ }
387
+
388
+ return UVC_SUCCESS;
389
+ }
390
+
391
+ /** @internal
392
+ * Run a streaming control query
393
+ * @param[in] devh UVC device
394
+ * @param[in,out] ctrl Control block
395
+ * @param[in] probe Whether this is a probe query or a commit query
396
+ * @param[in] req Query type
397
+ */
398
+ uvc_error_t uvc_query_still_ctrl(
399
+ uvc_device_handle_t *devh,
400
+ uvc_still_ctrl_t *still_ctrl,
401
+ uint8_t probe,
402
+ enum uvc_req_code req) {
403
+
404
+ uint8_t buf[11];
405
+ const size_t len = 11;
406
+ uvc_error_t err;
407
+
408
+ memset(buf, 0, sizeof(buf));
409
+
410
+ if (req == UVC_SET_CUR) {
411
+ /* prepare for a SET transfer */
412
+ buf[0] = still_ctrl->bFormatIndex;
413
+ buf[1] = still_ctrl->bFrameIndex;
414
+ buf[2] = still_ctrl->bCompressionIndex;
415
+ INT_TO_DW(still_ctrl->dwMaxVideoFrameSize, buf + 3);
416
+ INT_TO_DW(still_ctrl->dwMaxPayloadTransferSize, buf + 7);
417
+ }
418
+
419
+ /* do the transfer */
420
+ err = libusb_control_transfer(
421
+ devh->usb_devh,
422
+ req == UVC_SET_CUR ? 0x21 : 0xA1,
423
+ req,
424
+ probe ? (UVC_VS_STILL_PROBE_CONTROL << 8) : (UVC_VS_STILL_COMMIT_CONTROL << 8),
425
+ still_ctrl->bInterfaceNumber,
426
+ buf, len, 0
427
+ );
428
+
429
+ if (err <= 0) {
430
+ return err;
431
+ }
432
+
433
+ /* now decode following a GET transfer */
434
+ if (req != UVC_SET_CUR) {
435
+ still_ctrl->bFormatIndex = buf[0];
436
+ still_ctrl->bFrameIndex = buf[1];
437
+ still_ctrl->bCompressionIndex = buf[2];
438
+ still_ctrl->dwMaxVideoFrameSize = DW_TO_INT(buf + 3);
439
+ still_ctrl->dwMaxPayloadTransferSize = DW_TO_INT(buf + 7);
440
+ }
441
+
442
+ return UVC_SUCCESS;
443
+ }
444
+
445
+ /** Initiate a method 2 (in stream) still capture
446
+ * @ingroup streaming
447
+ *
448
+ * @param[in] devh Device handle
449
+ * @param[in] still_ctrl Still capture control block
450
+ */
451
+ uvc_error_t uvc_trigger_still(
452
+ uvc_device_handle_t *devh,
453
+ uvc_still_ctrl_t *still_ctrl) {
454
+ uvc_stream_handle_t* stream;
455
+ uvc_streaming_interface_t* stream_if;
456
+ uint8_t buf;
457
+ uvc_error_t err;
458
+
459
+ /* Stream must be running for method 2 to work */
460
+ stream = _uvc_get_stream_by_interface(devh, still_ctrl->bInterfaceNumber);
461
+ if (!stream || !stream->running)
462
+ return UVC_ERROR_NOT_SUPPORTED;
463
+
464
+ /* Only method 2 is supported */
465
+ stream_if = _uvc_get_stream_if(devh, still_ctrl->bInterfaceNumber);
466
+ if(!stream_if || stream_if->bStillCaptureMethod != 2)
467
+ return UVC_ERROR_NOT_SUPPORTED;
468
+
469
+ /* prepare for a SET transfer */
470
+ buf = 1;
471
+
472
+ /* do the transfer */
473
+ err = libusb_control_transfer(
474
+ devh->usb_devh,
475
+ 0x21, //type set
476
+ UVC_SET_CUR,
477
+ (UVC_VS_STILL_IMAGE_TRIGGER_CONTROL << 8),
478
+ still_ctrl->bInterfaceNumber,
479
+ &buf, 1, 0);
480
+
481
+ if (err <= 0) {
482
+ return err;
483
+ }
484
+
485
+ return UVC_SUCCESS;
486
+ }
487
+
488
+ /** @brief Reconfigure stream with a new stream format.
489
+ * @ingroup streaming
490
+ *
491
+ * This may be executed whether or not the stream is running.
492
+ *
493
+ * @param[in] strmh Stream handle
494
+ * @param[in] ctrl Control block, processed using {uvc_probe_stream_ctrl} or
495
+ * {uvc_get_stream_ctrl_format_size}
496
+ */
497
+ uvc_error_t uvc_stream_ctrl(uvc_stream_handle_t *strmh, uvc_stream_ctrl_t *ctrl) {
498
+ uvc_error_t ret;
499
+ uvc_frame_desc_t *frame_desc;
500
+ enum uvc_frame_format frame_format = UVC_FRAME_FORMAT_UNKNOWN;
501
+ struct ksq_altsetting_choice choice;
502
+
503
+ if (strmh->stream_if->bInterfaceNumber != ctrl->bInterfaceNumber)
504
+ return UVC_ERROR_INVALID_PARAM;
505
+
506
+ /* @todo Allow the stream to be modified without restarting the stream */
507
+ if (strmh->running)
508
+ return UVC_ERROR_BUSY;
509
+
510
+ /*
511
+ * Apply the device-specific limit before COMMIT_CONTROL is sent. The
512
+ * later altsetting override uses the same value, so the camera's negotiated
513
+ * payload and libusb's ISO packet geometry remain consistent.
514
+ */
515
+ frame_desc = uvc_find_frame_desc_stream(strmh, ctrl->bFormatIndex,
516
+ ctrl->bFrameIndex);
517
+ if (frame_desc != NULL && frame_desc->parent != NULL) {
518
+ frame_format = uvc_frame_format_for_guid(frame_desc->parent->guidFormat);
519
+ }
520
+ if (_ksq_resolve_altsetting_for_ctrl(strmh->devh, ctrl, frame_format,
521
+ frame_desc, &choice) &&
522
+ ctrl->dwMaxPayloadTransferSize > choice.payload) {
523
+ fprintf(stderr,
524
+ "[LIBUVC-QUIRK] COMMIT payload %u -> %u for VID:PID %04x:%04x%s\n",
525
+ ctrl->dwMaxPayloadTransferSize, choice.payload,
526
+ choice.vid, choice.pid,
527
+ choice.from_override ? " (altsetting override)" : "");
528
+ ctrl->dwMaxPayloadTransferSize = choice.payload;
529
+ }
530
+
531
+ ret = uvc_query_stream_ctrl(strmh->devh, ctrl, 0, UVC_SET_CUR);
532
+ if (ret != UVC_SUCCESS)
533
+ return ret;
534
+
535
+ strmh->cur_ctrl = *ctrl;
536
+ return UVC_SUCCESS;
537
+ }
538
+
539
+ /** @internal
540
+ * @brief Find the descriptor for a specific frame configuration
541
+ * @param stream_if Stream interface
542
+ * @param format_id Index of format class descriptor
543
+ * @param frame_id Index of frame descriptor
544
+ */
545
+ static uvc_frame_desc_t *_uvc_find_frame_desc_stream_if(uvc_streaming_interface_t *stream_if,
546
+ uint16_t format_id, uint16_t frame_id) {
547
+
548
+ uvc_format_desc_t *format = NULL;
549
+ uvc_frame_desc_t *frame = NULL;
550
+
551
+ DL_FOREACH(stream_if->format_descs, format) {
552
+ if (format->bFormatIndex == format_id) {
553
+ DL_FOREACH(format->frame_descs, frame) {
554
+ if (frame->bFrameIndex == frame_id)
555
+ return frame;
556
+ }
557
+ }
558
+ }
559
+
560
+ return NULL;
561
+ }
562
+
563
+ uvc_frame_desc_t *uvc_find_frame_desc_stream(uvc_stream_handle_t *strmh,
564
+ uint16_t format_id, uint16_t frame_id) {
565
+ return _uvc_find_frame_desc_stream_if(strmh->stream_if, format_id, frame_id);
566
+ }
567
+
568
+ /** @internal
569
+ * @brief Find the descriptor for a specific frame configuration
570
+ * @param devh UVC device
571
+ * @param format_id Index of format class descriptor
572
+ * @param frame_id Index of frame descriptor
573
+ */
574
+ uvc_frame_desc_t *uvc_find_frame_desc(uvc_device_handle_t *devh,
575
+ uint16_t format_id, uint16_t frame_id) {
576
+
577
+ uvc_streaming_interface_t *stream_if;
578
+ uvc_frame_desc_t *frame;
579
+
580
+ DL_FOREACH(devh->info->stream_ifs, stream_if) {
581
+ frame = _uvc_find_frame_desc_stream_if(stream_if, format_id, frame_id);
582
+ if (frame)
583
+ return frame;
584
+ }
585
+
586
+ return NULL;
587
+ }
588
+
589
+ /** Get a negotiated streaming control block for some common parameters.
590
+ * @ingroup streaming
591
+ *
592
+ * @param[in] devh Device handle
593
+ * @param[in,out] ctrl Control block
594
+ * @param[in] format_class Type of streaming format
595
+ * @param[in] width Desired frame width
596
+ * @param[in] height Desired frame height
597
+ * @param[in] fps Frame rate, frames per second
598
+ */
599
+ uvc_error_t uvc_get_stream_ctrl_format_size(
600
+ uvc_device_handle_t *devh,
601
+ uvc_stream_ctrl_t *ctrl,
602
+ enum uvc_frame_format cf,
603
+ int width, int height,
604
+ int fps) {
605
+ uvc_streaming_interface_t *stream_if;
606
+
607
+ /* find a matching frame descriptor and interval */
608
+ DL_FOREACH(devh->info->stream_ifs, stream_if) {
609
+ uvc_format_desc_t *format;
610
+
611
+ DL_FOREACH(stream_if->format_descs, format) {
612
+ uvc_frame_desc_t *frame;
613
+
614
+ if (!_uvc_frame_format_matches_guid(cf, format->guidFormat))
615
+ continue;
616
+
617
+ DL_FOREACH(format->frame_descs, frame) {
618
+ if (frame->wWidth != width || frame->wHeight != height)
619
+ continue;
620
+
621
+ uint32_t *interval;
622
+
623
+ ctrl->bInterfaceNumber = stream_if->bInterfaceNumber;
624
+ UVC_DEBUG("claiming streaming interface %d", stream_if->bInterfaceNumber );
625
+ uvc_claim_if(devh, ctrl->bInterfaceNumber);
626
+ /* get the max values */
627
+ uvc_query_stream_ctrl( devh, ctrl, 1, UVC_GET_MAX);
628
+
629
+ if (frame->intervals) {
630
+ for (interval = frame->intervals; *interval; ++interval) {
631
+ // allow a fps rate of zero to mean "accept first rate available"
632
+ if (10000000 / *interval == (unsigned int) fps || fps == 0) {
633
+
634
+ ctrl->bmHint = (1 << 0); /* don't negotiate interval */
635
+ ctrl->bFormatIndex = format->bFormatIndex;
636
+ ctrl->bFrameIndex = frame->bFrameIndex;
637
+ ctrl->dwFrameInterval = *interval;
638
+
639
+ goto found;
640
+ }
641
+ }
642
+ } else {
643
+ uint32_t interval_100ns = 10000000 / fps;
644
+ uint32_t interval_offset = interval_100ns - frame->dwMinFrameInterval;
645
+
646
+ if (interval_100ns >= frame->dwMinFrameInterval
647
+ && interval_100ns <= frame->dwMaxFrameInterval
648
+ && !(interval_offset
649
+ && (interval_offset % frame->dwFrameIntervalStep))) {
650
+
651
+ ctrl->bmHint = (1 << 0);
652
+ ctrl->bFormatIndex = format->bFormatIndex;
653
+ ctrl->bFrameIndex = frame->bFrameIndex;
654
+ ctrl->dwFrameInterval = interval_100ns;
655
+
656
+ goto found;
657
+ }
658
+ }
659
+ }
660
+ }
661
+ }
662
+
663
+ return UVC_ERROR_INVALID_MODE;
664
+
665
+ found:
666
+ return uvc_probe_stream_ctrl(devh, ctrl);
667
+ }
668
+
669
+ /** Get a negotiated still control block for some common parameters.
670
+ * @ingroup streaming
671
+ *
672
+ * @param[in] devh Device handle
673
+ * @param[in] ctrl Control block
674
+ * @param[in, out] still_ctrl Still capture control block
675
+ * @param[in] width Desired frame width
676
+ * @param[in] height Desired frame height
677
+ */
678
+ uvc_error_t uvc_get_still_ctrl_format_size(
679
+ uvc_device_handle_t *devh,
680
+ uvc_stream_ctrl_t *ctrl,
681
+ uvc_still_ctrl_t *still_ctrl,
682
+ int width, int height) {
683
+ uvc_streaming_interface_t *stream_if;
684
+ uvc_still_frame_desc_t *still;
685
+ uvc_format_desc_t *format;
686
+ uvc_still_frame_res_t *sizePattern;
687
+
688
+ stream_if = _uvc_get_stream_if(devh, ctrl->bInterfaceNumber);
689
+
690
+ /* Only method 2 is supported */
691
+ if(!stream_if || stream_if->bStillCaptureMethod != 2)
692
+ return UVC_ERROR_NOT_SUPPORTED;
693
+
694
+ DL_FOREACH(stream_if->format_descs, format) {
695
+
696
+ if (ctrl->bFormatIndex != format->bFormatIndex)
697
+ continue;
698
+
699
+ /* get the max values */
700
+ uvc_query_still_ctrl(devh, still_ctrl, 1, UVC_GET_MAX);
701
+
702
+ //look for still format
703
+ DL_FOREACH(format->still_frame_desc, still) {
704
+ DL_FOREACH(still->imageSizePatterns, sizePattern) {
705
+
706
+ if (sizePattern->wWidth != width || sizePattern->wHeight != height)
707
+ continue;
708
+
709
+ still_ctrl->bInterfaceNumber = ctrl->bInterfaceNumber;
710
+ still_ctrl->bFormatIndex = format->bFormatIndex;
711
+ still_ctrl->bFrameIndex = sizePattern->bResolutionIndex;
712
+ still_ctrl->bCompressionIndex = 0; //TODO support compression index
713
+ goto found;
714
+ }
715
+ }
716
+ }
717
+
718
+ return UVC_ERROR_INVALID_MODE;
719
+
720
+ found:
721
+ return uvc_probe_still_ctrl(devh, still_ctrl);
722
+ }
723
+
724
+ static int _uvc_stream_params_negotiated(
725
+ uvc_stream_ctrl_t *required,
726
+ uvc_stream_ctrl_t *actual) {
727
+ return required->bFormatIndex == actual->bFormatIndex &&
728
+ required->bFrameIndex == actual->bFrameIndex &&
729
+ required->dwMaxPayloadTransferSize >= actual->dwMaxPayloadTransferSize;
730
+ }
731
+
732
+ /** @internal
733
+ * Negotiate streaming parameters with the device
734
+ *
735
+ * @param[in] devh UVC device
736
+ * @param[in,out] ctrl Control block
737
+ */
738
+ uvc_error_t uvc_probe_stream_ctrl(
739
+ uvc_device_handle_t *devh,
740
+ uvc_stream_ctrl_t *ctrl) {
741
+ uvc_stream_ctrl_t required_ctrl = *ctrl;
742
+
743
+ uvc_query_stream_ctrl( devh, ctrl, 1, UVC_SET_CUR );
744
+ uvc_query_stream_ctrl( devh, ctrl, 1, UVC_GET_CUR );
745
+
746
+ if(!_uvc_stream_params_negotiated(&required_ctrl, ctrl)) {
747
+ UVC_DEBUG("Unable to negotiate streaming format");
748
+ return UVC_ERROR_INVALID_MODE;
749
+ }
750
+
751
+ return UVC_SUCCESS;
752
+ }
753
+
754
+ /** @internal
755
+ * Negotiate still parameters with the device
756
+ *
757
+ * @param[in] devh UVC device
758
+ * @param[in,out] still_ctrl Still capture control block
759
+ */
760
+ uvc_error_t uvc_probe_still_ctrl(
761
+ uvc_device_handle_t *devh,
762
+ uvc_still_ctrl_t *still_ctrl) {
763
+
764
+ int res = uvc_query_still_ctrl(
765
+ devh, still_ctrl, 1, UVC_SET_CUR
766
+ );
767
+
768
+ if(res == UVC_SUCCESS) {
769
+ res = uvc_query_still_ctrl(
770
+ devh, still_ctrl, 1, UVC_GET_CUR
771
+ );
772
+
773
+ if(res == UVC_SUCCESS) {
774
+ res = uvc_query_still_ctrl(
775
+ devh, still_ctrl, 0, UVC_SET_CUR
776
+ );
777
+ }
778
+ }
779
+
780
+ return res;
781
+ }
782
+
783
+ /** @internal
784
+ * @brief Swap the working buffer with the presented buffer and notify consumers
785
+ */
786
+ void _uvc_swap_buffers(uvc_stream_handle_t *strmh) {
787
+ uint8_t *tmp_buf;
788
+
789
+ pthread_mutex_lock(&strmh->cb_mutex);
790
+
791
+ (void)clock_gettime(CLOCK_MONOTONIC, &strmh->capture_time_finished);
792
+
793
+ /* swap the buffers */
794
+ tmp_buf = strmh->holdbuf;
795
+ strmh->hold_bytes = strmh->got_bytes;
796
+ strmh->holdbuf = strmh->outbuf;
797
+ strmh->outbuf = tmp_buf;
798
+ strmh->hold_last_scr = strmh->last_scr;
799
+ strmh->hold_pts = strmh->pts;
800
+ strmh->hold_seq = strmh->seq;
801
+
802
+ /* swap metadata buffer */
803
+ tmp_buf = strmh->meta_holdbuf;
804
+ strmh->meta_holdbuf = strmh->meta_outbuf;
805
+ strmh->meta_outbuf = tmp_buf;
806
+ strmh->meta_hold_bytes = strmh->meta_got_bytes;
807
+
808
+ pthread_cond_broadcast(&strmh->cb_cond);
809
+ pthread_mutex_unlock(&strmh->cb_mutex);
810
+
811
+ strmh->seq++;
812
+ strmh->got_bytes = 0;
813
+ strmh->meta_got_bytes = 0;
814
+ strmh->last_scr = 0;
815
+ strmh->pts = 0;
816
+ }
817
+
818
+ /** @internal
819
+ * @brief Process a payload transfer
820
+ *
821
+ * Processes stream, places frames into buffer, signals listeners
822
+ * (such as user callback thread and any polling thread) on new frame
823
+ *
824
+ * @param payload Contents of the payload transfer, either a packet (isochronous) or a full
825
+ * transfer (bulk mode)
826
+ * @param payload_len Length of the payload transfer
827
+ */
828
+ void _uvc_process_payload(uvc_stream_handle_t *strmh, uint8_t *payload, size_t payload_len) {
829
+ size_t header_len;
830
+ uint8_t header_info;
831
+ size_t data_len;
832
+
833
+ /* magic numbers for identifying header packets from some iSight cameras */
834
+ static uint8_t isight_tag[] = {
835
+ 0x11, 0x22, 0x33, 0x44,
836
+ 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xfa, 0xce
837
+ };
838
+
839
+ /* ignore empty payload transfers */
840
+ if (payload_len == 0)
841
+ return;
842
+
843
+ /* Certain iSight cameras have strange behavior: They send header
844
+ * information in a packet with no image data, and then the following
845
+ * packets have only image data, with no more headers until the next frame.
846
+ *
847
+ * The iSight header: len(1), flags(1 or 2), 0x11223344(4),
848
+ * 0xdeadbeefdeadface(8), ??(16)
849
+ */
850
+
851
+ if (strmh->devh->is_isight &&
852
+ (payload_len < 14 || memcmp(isight_tag, payload + 2, sizeof(isight_tag))) &&
853
+ (payload_len < 15 || memcmp(isight_tag, payload + 3, sizeof(isight_tag)))) {
854
+ /* The payload transfer doesn't have any iSight magic, so it's all image data */
855
+ header_len = 0;
856
+ data_len = payload_len;
857
+ } else {
858
+ header_len = payload[0];
859
+
860
+ if (header_len > payload_len) {
861
+ UVC_DEBUG("bogus packet: actual_len=%zd, header_len=%zd\n", payload_len, header_len);
862
+ return;
863
+ }
864
+
865
+ if (strmh->devh->is_isight)
866
+ data_len = 0;
867
+ else
868
+ data_len = payload_len - header_len;
869
+ }
870
+
871
+ if (header_len < 2) {
872
+ header_info = 0;
873
+ } else {
874
+ /** @todo we should be checking the end-of-header bit */
875
+ size_t variable_offset = 2;
876
+
877
+ header_info = payload[1];
878
+
879
+ if (header_info & 0x40) {
880
+ UVC_DEBUG("bad packet: error bit set");
881
+ return;
882
+ }
883
+
884
+ if (strmh->fid != (header_info & 1) && strmh->got_bytes != 0) {
885
+ /* The frame ID bit was flipped, but we have image data sitting
886
+ around from prior transfers. This means the camera didn't send
887
+ an EOF for the last transfer of the previous frame. */
888
+ _uvc_swap_buffers(strmh);
889
+ }
890
+
891
+ strmh->fid = header_info & 1;
892
+
893
+ if (header_info & (1 << 2)) {
894
+ strmh->pts = DW_TO_INT(payload + variable_offset);
895
+ variable_offset += 4;
896
+ }
897
+
898
+ if (header_info & (1 << 3)) {
899
+ /** @todo read the SOF token counter */
900
+ strmh->last_scr = DW_TO_INT(payload + variable_offset);
901
+ variable_offset += 6;
902
+ }
903
+
904
+ if (header_len > variable_offset) {
905
+ // Metadata is attached to header
906
+ size_t meta_len = header_len - variable_offset;
907
+ if (strmh->meta_got_bytes + meta_len > LIBUVC_XFER_META_BUF_SIZE)
908
+ meta_len = LIBUVC_XFER_META_BUF_SIZE - strmh->meta_got_bytes; /* Avoid overflow. */
909
+ memcpy(strmh->meta_outbuf + strmh->meta_got_bytes, payload + variable_offset, meta_len);
910
+ strmh->meta_got_bytes += meta_len;
911
+ }
912
+ }
913
+
914
+ if (data_len > 0) {
915
+ if (strmh->got_bytes + data_len > strmh->cur_ctrl.dwMaxVideoFrameSize)
916
+ data_len = strmh->cur_ctrl.dwMaxVideoFrameSize - strmh->got_bytes; /* Avoid overflow. */
917
+ memcpy(strmh->outbuf + strmh->got_bytes, payload + header_len, data_len);
918
+ strmh->got_bytes += data_len;
919
+ if (header_info & (1 << 1) || strmh->got_bytes == strmh->cur_ctrl.dwMaxVideoFrameSize) {
920
+ /* The EOF bit is set, so publish the complete frame */
921
+ _uvc_swap_buffers(strmh);
922
+ }
923
+ }
924
+ }
925
+
926
+ /** @internal
927
+ * @brief Stream transfer callback
928
+ *
929
+ * Processes stream, places frames into buffer, signals listeners
930
+ * (such as user callback thread and any polling thread) on new frame
931
+ *
932
+ * @param transfer Active transfer
933
+ */
934
+ void LIBUSB_CALL _uvc_stream_callback(struct libusb_transfer *transfer) {
935
+ uvc_stream_handle_t *strmh = transfer->user_data;
936
+
937
+ int resubmit = 1;
938
+
939
+ switch (transfer->status) {
940
+ case LIBUSB_TRANSFER_COMPLETED:
941
+ if (transfer->num_iso_packets == 0) {
942
+ /* This is a bulk mode transfer, so it just has one payload transfer */
943
+ _uvc_process_payload(strmh, transfer->buffer, transfer->actual_length);
944
+ } else {
945
+ /* This is an isochronous mode transfer, so each packet has a payload transfer */
946
+ int packet_id;
947
+
948
+ for (packet_id = 0; packet_id < transfer->num_iso_packets; ++packet_id) {
949
+ uint8_t *pktbuf;
950
+ struct libusb_iso_packet_descriptor *pkt;
951
+
952
+ pkt = transfer->iso_packet_desc + packet_id;
953
+
954
+ if (pkt->status != 0) {
955
+ UVC_DEBUG("bad packet (isochronous transfer); status: %d", pkt->status);
956
+ continue;
957
+ }
958
+
959
+ pktbuf = libusb_get_iso_packet_buffer_simple(transfer, packet_id);
960
+
961
+ _uvc_process_payload(strmh, pktbuf, pkt->actual_length);
962
+
963
+ }
964
+ }
965
+ break;
966
+ case LIBUSB_TRANSFER_CANCELLED:
967
+ case LIBUSB_TRANSFER_ERROR:
968
+ case LIBUSB_TRANSFER_NO_DEVICE: {
969
+ int i;
970
+ UVC_DEBUG("not retrying transfer, status = %d", transfer->status);
971
+ pthread_mutex_lock(&strmh->cb_mutex);
972
+
973
+ /* Mark transfer as deleted. */
974
+ for(i=0; i < LIBUVC_NUM_TRANSFER_BUFS; i++) {
975
+ if(strmh->transfers[i] == transfer) {
976
+ UVC_DEBUG("Freeing transfer %d (%p)", i, transfer);
977
+ free(transfer->buffer);
978
+ libusb_free_transfer(transfer);
979
+ strmh->transfers[i] = NULL;
980
+ break;
981
+ }
982
+ }
983
+ if(i == LIBUVC_NUM_TRANSFER_BUFS ) {
984
+ UVC_DEBUG("transfer %p not found; not freeing!", transfer);
985
+ }
986
+
987
+ resubmit = 0;
988
+
989
+ pthread_cond_broadcast(&strmh->cb_cond);
990
+ pthread_mutex_unlock(&strmh->cb_mutex);
991
+
992
+ break;
993
+ }
994
+ case LIBUSB_TRANSFER_TIMED_OUT:
995
+ case LIBUSB_TRANSFER_STALL:
996
+ case LIBUSB_TRANSFER_OVERFLOW:
997
+ UVC_DEBUG("retrying transfer, status = %d", transfer->status);
998
+ break;
999
+ }
1000
+
1001
+ if ( resubmit ) {
1002
+ if ( strmh->running ) {
1003
+ int libusbRet = libusb_submit_transfer(transfer);
1004
+ if (libusbRet < 0)
1005
+ {
1006
+ int i;
1007
+ pthread_mutex_lock(&strmh->cb_mutex);
1008
+
1009
+ /* Mark transfer as deleted. */
1010
+ for (i = 0; i < LIBUVC_NUM_TRANSFER_BUFS; i++) {
1011
+ if (strmh->transfers[i] == transfer) {
1012
+ UVC_DEBUG("Freeing failed transfer %d (%p)", i, transfer);
1013
+ free(transfer->buffer);
1014
+ libusb_free_transfer(transfer);
1015
+ strmh->transfers[i] = NULL;
1016
+ break;
1017
+ }
1018
+ }
1019
+ if (i == LIBUVC_NUM_TRANSFER_BUFS) {
1020
+ UVC_DEBUG("failed transfer %p not found; not freeing!", transfer);
1021
+ }
1022
+
1023
+ pthread_cond_broadcast(&strmh->cb_cond);
1024
+ pthread_mutex_unlock(&strmh->cb_mutex);
1025
+ }
1026
+ } else {
1027
+ int i;
1028
+ pthread_mutex_lock(&strmh->cb_mutex);
1029
+
1030
+ /* Mark transfer as deleted. */
1031
+ for(i=0; i < LIBUVC_NUM_TRANSFER_BUFS; i++) {
1032
+ if(strmh->transfers[i] == transfer) {
1033
+ UVC_DEBUG("Freeing orphan transfer %d (%p)", i, transfer);
1034
+ free(transfer->buffer);
1035
+ libusb_free_transfer(transfer);
1036
+ strmh->transfers[i] = NULL;
1037
+ break;
1038
+ }
1039
+ }
1040
+ if(i == LIBUVC_NUM_TRANSFER_BUFS ) {
1041
+ UVC_DEBUG("orphan transfer %p not found; not freeing!", transfer);
1042
+ }
1043
+
1044
+ pthread_cond_broadcast(&strmh->cb_cond);
1045
+ pthread_mutex_unlock(&strmh->cb_mutex);
1046
+ }
1047
+ }
1048
+ }
1049
+
1050
+ /** Begin streaming video from the camera into the callback function.
1051
+ * @ingroup streaming
1052
+ *
1053
+ * @param devh UVC device
1054
+ * @param ctrl Control block, processed using {uvc_probe_stream_ctrl} or
1055
+ * {uvc_get_stream_ctrl_format_size}
1056
+ * @param cb User callback function. See {uvc_frame_callback_t} for restrictions.
1057
+ * @param flags Stream setup flags, currently undefined. Set this to zero. The lower bit
1058
+ * is reserved for backward compatibility.
1059
+ */
1060
+ uvc_error_t uvc_start_streaming(
1061
+ uvc_device_handle_t *devh,
1062
+ uvc_stream_ctrl_t *ctrl,
1063
+ uvc_frame_callback_t *cb,
1064
+ void *user_ptr,
1065
+ uint8_t flags
1066
+ ) {
1067
+ uvc_error_t ret;
1068
+ uvc_stream_handle_t *strmh;
1069
+
1070
+ ret = uvc_stream_open_ctrl(devh, &strmh, ctrl);
1071
+ if (ret != UVC_SUCCESS)
1072
+ return ret;
1073
+
1074
+ ret = uvc_stream_start(strmh, cb, user_ptr, flags);
1075
+ if (ret != UVC_SUCCESS) {
1076
+ uvc_stream_close(strmh);
1077
+ return ret;
1078
+ }
1079
+
1080
+ return UVC_SUCCESS;
1081
+ }
1082
+
1083
+ /** Begin streaming video from the camera into the callback function.
1084
+ * @ingroup streaming
1085
+ *
1086
+ * @deprecated The stream type (bulk vs. isochronous) will be determined by the
1087
+ * type of interface associated with the uvc_stream_ctrl_t parameter, regardless
1088
+ * of whether the caller requests isochronous streaming. Please switch to
1089
+ * uvc_start_streaming().
1090
+ *
1091
+ * @param devh UVC device
1092
+ * @param ctrl Control block, processed using {uvc_probe_stream_ctrl} or
1093
+ * {uvc_get_stream_ctrl_format_size}
1094
+ * @param cb User callback function. See {uvc_frame_callback_t} for restrictions.
1095
+ */
1096
+ uvc_error_t uvc_start_iso_streaming(
1097
+ uvc_device_handle_t *devh,
1098
+ uvc_stream_ctrl_t *ctrl,
1099
+ uvc_frame_callback_t *cb,
1100
+ void *user_ptr
1101
+ ) {
1102
+ return uvc_start_streaming(devh, ctrl, cb, user_ptr, 0);
1103
+ }
1104
+
1105
+ static uvc_stream_handle_t *_uvc_get_stream_by_interface(uvc_device_handle_t *devh, int interface_idx) {
1106
+ uvc_stream_handle_t *strmh;
1107
+
1108
+ DL_FOREACH(devh->streams, strmh) {
1109
+ if (strmh->stream_if->bInterfaceNumber == interface_idx)
1110
+ return strmh;
1111
+ }
1112
+
1113
+ return NULL;
1114
+ }
1115
+
1116
+ static uvc_streaming_interface_t *_uvc_get_stream_if(uvc_device_handle_t *devh, int interface_idx) {
1117
+ uvc_streaming_interface_t *stream_if;
1118
+
1119
+ DL_FOREACH(devh->info->stream_ifs, stream_if) {
1120
+ if (stream_if->bInterfaceNumber == interface_idx)
1121
+ return stream_if;
1122
+ }
1123
+
1124
+ return NULL;
1125
+ }
1126
+
1127
+ /** Open a new video stream.
1128
+ * @ingroup streaming
1129
+ *
1130
+ * @param devh UVC device
1131
+ * @param ctrl Control block, processed using {uvc_probe_stream_ctrl} or
1132
+ * {uvc_get_stream_ctrl_format_size}
1133
+ */
1134
+ uvc_error_t uvc_stream_open_ctrl(uvc_device_handle_t *devh, uvc_stream_handle_t **strmhp, uvc_stream_ctrl_t *ctrl) {
1135
+ /* Chosen frame and format descriptors */
1136
+ uvc_stream_handle_t *strmh = NULL;
1137
+ uvc_streaming_interface_t *stream_if;
1138
+ uvc_error_t ret;
1139
+
1140
+ UVC_ENTER();
1141
+
1142
+ if (_uvc_get_stream_by_interface(devh, ctrl->bInterfaceNumber) != NULL) {
1143
+ ret = UVC_ERROR_BUSY; /* Stream is already opened */
1144
+ goto fail;
1145
+ }
1146
+
1147
+ stream_if = _uvc_get_stream_if(devh, ctrl->bInterfaceNumber);
1148
+ if (!stream_if) {
1149
+ ret = UVC_ERROR_INVALID_PARAM;
1150
+ goto fail;
1151
+ }
1152
+
1153
+ strmh = calloc(1, sizeof(*strmh));
1154
+ if (!strmh) {
1155
+ ret = UVC_ERROR_NO_MEM;
1156
+ goto fail;
1157
+ }
1158
+ strmh->devh = devh;
1159
+ strmh->stream_if = stream_if;
1160
+ strmh->frame.library_owns_data = 1;
1161
+
1162
+ ret = uvc_claim_if(strmh->devh, strmh->stream_if->bInterfaceNumber);
1163
+ if (ret != UVC_SUCCESS)
1164
+ goto fail;
1165
+
1166
+ ret = uvc_stream_ctrl(strmh, ctrl);
1167
+ if (ret != UVC_SUCCESS)
1168
+ goto fail;
1169
+
1170
+ // Set up the streaming status and data space
1171
+ strmh->running = 0;
1172
+
1173
+ strmh->outbuf = malloc( ctrl->dwMaxVideoFrameSize );
1174
+ strmh->holdbuf = malloc( ctrl->dwMaxVideoFrameSize );
1175
+
1176
+ strmh->meta_outbuf = malloc( LIBUVC_XFER_META_BUF_SIZE );
1177
+ strmh->meta_holdbuf = malloc( LIBUVC_XFER_META_BUF_SIZE );
1178
+
1179
+ pthread_mutex_init(&strmh->cb_mutex, NULL);
1180
+ pthread_cond_init(&strmh->cb_cond, NULL);
1181
+
1182
+ DL_APPEND(devh->streams, strmh);
1183
+
1184
+ *strmhp = strmh;
1185
+
1186
+ UVC_EXIT(0);
1187
+ return UVC_SUCCESS;
1188
+
1189
+ fail:
1190
+ if(strmh)
1191
+ free(strmh);
1192
+ UVC_EXIT(ret);
1193
+ return ret;
1194
+ }
1195
+
1196
+ /** Begin streaming video from the stream into the callback function.
1197
+ * @ingroup streaming
1198
+ *
1199
+ * @param strmh UVC stream
1200
+ * @param cb User callback function. See {uvc_frame_callback_t} for restrictions.
1201
+ * @param flags Stream setup flags, currently undefined. Set this to zero. The lower bit
1202
+ * is reserved for backward compatibility.
1203
+ */
1204
+ uvc_error_t uvc_stream_start(
1205
+ uvc_stream_handle_t *strmh,
1206
+ uvc_frame_callback_t *cb,
1207
+ void *user_ptr,
1208
+ uint8_t flags
1209
+ ) {
1210
+ /* USB interface we'll be using */
1211
+ const struct libusb_interface *interface;
1212
+ int interface_id;
1213
+ char isochronous;
1214
+ uvc_frame_desc_t *frame_desc;
1215
+ uvc_format_desc_t *format_desc;
1216
+ uvc_stream_ctrl_t *ctrl;
1217
+ uvc_error_t ret;
1218
+ struct ksq_altsetting_choice choice;
1219
+ /* Total amount of data per transfer */
1220
+ size_t total_transfer_size = 0;
1221
+ struct libusb_transfer *transfer;
1222
+ int transfer_id;
1223
+
1224
+ ctrl = &strmh->cur_ctrl;
1225
+
1226
+ UVC_ENTER();
1227
+
1228
+ if (strmh->running) {
1229
+ UVC_EXIT(UVC_ERROR_BUSY);
1230
+ return UVC_ERROR_BUSY;
1231
+ }
1232
+
1233
+ strmh->running = 1;
1234
+ strmh->seq = 1;
1235
+ strmh->fid = 0;
1236
+ strmh->pts = 0;
1237
+ strmh->last_scr = 0;
1238
+
1239
+ frame_desc = uvc_find_frame_desc_stream(strmh, ctrl->bFormatIndex, ctrl->bFrameIndex);
1240
+ if (!frame_desc) {
1241
+ ret = UVC_ERROR_INVALID_PARAM;
1242
+ goto fail;
1243
+ }
1244
+ format_desc = frame_desc->parent;
1245
+
1246
+ strmh->frame_format = uvc_frame_format_for_guid(format_desc->guidFormat);
1247
+ if (strmh->frame_format == UVC_FRAME_FORMAT_UNKNOWN) {
1248
+ ret = UVC_ERROR_NOT_SUPPORTED;
1249
+ goto fail;
1250
+ }
1251
+
1252
+ // Get the interface that provides the chosen format and frame configuration
1253
+ interface_id = strmh->stream_if->bInterfaceNumber;
1254
+ interface = &strmh->devh->info->config->interface[interface_id];
1255
+
1256
+ /* A VS interface uses isochronous transfers iff it has multiple altsettings.
1257
+ * (UVC 1.5: 2.4.3. VideoStreaming Interface) */
1258
+ isochronous = interface->num_altsetting > 1;
1259
+
1260
+ if (isochronous) {
1261
+ /* For isochronous streaming, we choose an appropriate altsetting for the endpoint
1262
+ * and set up several transfers */
1263
+ const struct libusb_interface_descriptor *altsetting = 0;
1264
+ const struct libusb_endpoint_descriptor *endpoint = 0;
1265
+ /* The greatest number of bytes that the device might provide, per packet, in this
1266
+ * configuration */
1267
+ size_t config_bytes_per_packet;
1268
+ /* Number of packets per transfer */
1269
+ size_t packets_per_transfer = 0;
1270
+ /* Size of packet transferable from the chosen endpoint */
1271
+ size_t endpoint_bytes_per_packet = 0;
1272
+ /* Index of the altsetting */
1273
+ int alt_idx, ep_idx;
1274
+ const struct ksq_altsetting_quirk *quirk;
1275
+
1276
+ config_bytes_per_packet = strmh->cur_ctrl.dwMaxPayloadTransferSize;
1277
+
1278
+ /* Go through the altsettings and find one whose packets are at least
1279
+ * as big as our format's maximum per-packet usage. Assume that the
1280
+ * packet sizes are increasing. */
1281
+ for (alt_idx = 0; alt_idx < interface->num_altsetting; alt_idx++) {
1282
+ altsetting = interface->altsetting + alt_idx;
1283
+ endpoint_bytes_per_packet = 0;
1284
+
1285
+ /* Find the endpoint with the number specified in the VS header */
1286
+ for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) {
1287
+ endpoint = altsetting->endpoint + ep_idx;
1288
+
1289
+ struct libusb_ss_endpoint_companion_descriptor *ep_comp = 0;
1290
+ libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
1291
+ if (ep_comp)
1292
+ {
1293
+ endpoint_bytes_per_packet = ep_comp->wBytesPerInterval;
1294
+ libusb_free_ss_endpoint_companion_descriptor(ep_comp);
1295
+ break;
1296
+ }
1297
+ else
1298
+ {
1299
+ if (endpoint->bEndpointAddress == format_desc->parent->bEndpointAddress) {
1300
+ endpoint_bytes_per_packet = endpoint->wMaxPacketSize;
1301
+ // wMaxPacketSize: [unused:2 (multiplier-1):3 size:11]
1302
+ endpoint_bytes_per_packet = (endpoint_bytes_per_packet & 0x07ff) *
1303
+ (((endpoint_bytes_per_packet >> 11) & 3) + 1);
1304
+ break;
1305
+ }
1306
+ }
1307
+ }
1308
+
1309
+ if (endpoint_bytes_per_packet >= config_bytes_per_packet) {
1310
+ /* Transfers will be at most one frame long: Divide the maximum frame size
1311
+ * by the size of the endpoint and round up */
1312
+ packets_per_transfer = (ctrl->dwMaxVideoFrameSize +
1313
+ endpoint_bytes_per_packet - 1) / endpoint_bytes_per_packet;
1314
+
1315
+ /* But keep a reasonable limit: Otherwise we start dropping data */
1316
+ if (packets_per_transfer > 32)
1317
+ packets_per_transfer = 32;
1318
+
1319
+ total_transfer_size = packets_per_transfer * endpoint_bytes_per_packet;
1320
+ break;
1321
+ }
1322
+ }
1323
+
1324
+ if (_ksq_resolve_altsetting_for_ctrl(strmh->devh, ctrl, strmh->frame_format,
1325
+ frame_desc, &choice)) {
1326
+ int forced_alt_idx = -1;
1327
+
1328
+ for (alt_idx = 0; alt_idx < interface->num_altsetting; ++alt_idx) {
1329
+ const struct libusb_interface_descriptor *candidate =
1330
+ interface->altsetting + alt_idx;
1331
+ if (candidate->bAlternateSetting == choice.altsetting) {
1332
+ forced_alt_idx = alt_idx;
1333
+ altsetting = candidate;
1334
+ endpoint_bytes_per_packet = 0;
1335
+ for (ep_idx = 0; ep_idx < candidate->bNumEndpoints; ++ep_idx) {
1336
+ endpoint = candidate->endpoint + ep_idx;
1337
+ if (endpoint->bEndpointAddress ==
1338
+ format_desc->parent->bEndpointAddress) {
1339
+ endpoint_bytes_per_packet = endpoint->wMaxPacketSize;
1340
+ endpoint_bytes_per_packet =
1341
+ (endpoint_bytes_per_packet & 0x07ff) *
1342
+ (((endpoint_bytes_per_packet >> 11) & 3) + 1);
1343
+ break;
1344
+ }
1345
+ }
1346
+ break;
1347
+ }
1348
+ }
1349
+
1350
+ if (forced_alt_idx < 0 ||
1351
+ endpoint_bytes_per_packet < choice.payload) {
1352
+ fprintf(stderr,
1353
+ "[LIBUVC-QUIRK] VID:PID %04x:%04x alt=%u "
1354
+ "payload=%u unavailable endpoint=%zu%s\n",
1355
+ choice.vid, choice.pid,
1356
+ choice.altsetting, choice.payload,
1357
+ endpoint_bytes_per_packet,
1358
+ choice.from_override ? " (altsetting override)" : "");
1359
+ ret = UVC_ERROR_INVALID_MODE;
1360
+ goto fail;
1361
+ }
1362
+
1363
+ /* Recompute transfer geometry for the forced endpoint. */
1364
+ packets_per_transfer = (ctrl->dwMaxVideoFrameSize +
1365
+ endpoint_bytes_per_packet - 1) /
1366
+ endpoint_bytes_per_packet;
1367
+ if (packets_per_transfer > 32)
1368
+ packets_per_transfer = 32;
1369
+ total_transfer_size = packets_per_transfer * endpoint_bytes_per_packet;
1370
+ fprintf(stderr,
1371
+ "[LIBUVC-QUIRK] VID:PID %04x:%04x alt=%u "
1372
+ "payload=%u endpoint=%zu frame=%ux%u interval=%u"
1373
+ " xfers=%d xfer_bytes=%zu%s\n",
1374
+ choice.vid, choice.pid,
1375
+ choice.altsetting, choice.payload,
1376
+ endpoint_bytes_per_packet, frame_desc->wWidth,
1377
+ frame_desc->wHeight, ctrl->dwFrameInterval,
1378
+ packets_per_transfer, total_transfer_size,
1379
+ choice.from_override ? " (altsetting override)" : "");
1380
+ alt_idx = forced_alt_idx;
1381
+ }
1382
+
1383
+ /* If we searched through all the altsettings and found nothing usable */
1384
+ if (alt_idx == interface->num_altsetting) {
1385
+ ret = UVC_ERROR_INVALID_MODE;
1386
+ goto fail;
1387
+ }
1388
+
1389
+ /* Select the altsetting */
1390
+ ret = libusb_set_interface_alt_setting(strmh->devh->usb_devh,
1391
+ altsetting->bInterfaceNumber,
1392
+ altsetting->bAlternateSetting);
1393
+ if (ret != UVC_SUCCESS) {
1394
+ UVC_DEBUG("libusb_set_interface_alt_setting failed");
1395
+ goto fail;
1396
+ }
1397
+
1398
+ /* Set up the transfers */
1399
+ for (transfer_id = 0; transfer_id < LIBUVC_NUM_TRANSFER_BUFS; ++transfer_id) {
1400
+ transfer = libusb_alloc_transfer(packets_per_transfer);
1401
+ strmh->transfers[transfer_id] = transfer;
1402
+ strmh->transfer_bufs[transfer_id] = malloc(total_transfer_size);
1403
+
1404
+ libusb_fill_iso_transfer(
1405
+ transfer, strmh->devh->usb_devh, format_desc->parent->bEndpointAddress,
1406
+ strmh->transfer_bufs[transfer_id],
1407
+ total_transfer_size, packets_per_transfer, _uvc_stream_callback, (void*) strmh, 5000);
1408
+
1409
+ libusb_set_iso_packet_lengths(transfer, endpoint_bytes_per_packet);
1410
+ }
1411
+ } else {
1412
+ for (transfer_id = 0; transfer_id < LIBUVC_NUM_TRANSFER_BUFS;
1413
+ ++transfer_id) {
1414
+ transfer = libusb_alloc_transfer(0);
1415
+ strmh->transfers[transfer_id] = transfer;
1416
+ strmh->transfer_bufs[transfer_id] = malloc (
1417
+ strmh->cur_ctrl.dwMaxPayloadTransferSize );
1418
+ libusb_fill_bulk_transfer ( transfer, strmh->devh->usb_devh,
1419
+ format_desc->parent->bEndpointAddress,
1420
+ strmh->transfer_bufs[transfer_id],
1421
+ strmh->cur_ctrl.dwMaxPayloadTransferSize, _uvc_stream_callback,
1422
+ ( void* ) strmh, 5000 );
1423
+ }
1424
+ }
1425
+
1426
+ strmh->user_cb = cb;
1427
+ strmh->user_ptr = user_ptr;
1428
+
1429
+ /* If the user wants it, set up a thread that calls the user's function
1430
+ * with the contents of each frame.
1431
+ */
1432
+ if (cb) {
1433
+ pthread_create(&strmh->cb_thread, NULL, _uvc_user_caller, (void*) strmh);
1434
+ }
1435
+
1436
+ for (transfer_id = 0; transfer_id < LIBUVC_NUM_TRANSFER_BUFS;
1437
+ transfer_id++) {
1438
+ ret = libusb_submit_transfer(strmh->transfers[transfer_id]);
1439
+ if (ret != UVC_SUCCESS) {
1440
+ UVC_DEBUG("libusb_submit_transfer failed: %d",ret);
1441
+ break;
1442
+ }
1443
+ }
1444
+
1445
+ if ( ret != UVC_SUCCESS && transfer_id >= 0 ) {
1446
+ for ( ; transfer_id < LIBUVC_NUM_TRANSFER_BUFS; transfer_id++) {
1447
+ free ( strmh->transfers[transfer_id]->buffer );
1448
+ libusb_free_transfer ( strmh->transfers[transfer_id]);
1449
+ strmh->transfers[transfer_id] = 0;
1450
+ }
1451
+ ret = UVC_SUCCESS;
1452
+ }
1453
+
1454
+ UVC_EXIT(ret);
1455
+ return ret;
1456
+ fail:
1457
+ strmh->running = 0;
1458
+ UVC_EXIT(ret);
1459
+ return ret;
1460
+ }
1461
+
1462
+ /** Begin streaming video from the stream into the callback function.
1463
+ * @ingroup streaming
1464
+ *
1465
+ * @deprecated The stream type (bulk vs. isochronous) will be determined by the
1466
+ * type of interface associated with the uvc_stream_ctrl_t parameter, regardless
1467
+ * of whether the caller requests isochronous streaming. Please switch to
1468
+ * uvc_stream_start().
1469
+ *
1470
+ * @param strmh UVC stream
1471
+ * @param cb User callback function. See {uvc_frame_callback_t} for restrictions.
1472
+ */
1473
+ uvc_error_t uvc_stream_start_iso(
1474
+ uvc_stream_handle_t *strmh,
1475
+ uvc_frame_callback_t *cb,
1476
+ void *user_ptr
1477
+ ) {
1478
+ return uvc_stream_start(strmh, cb, user_ptr, 0);
1479
+ }
1480
+
1481
+ /** @internal
1482
+ * @brief User callback runner thread
1483
+ * @note There should be at most one of these per currently streaming device
1484
+ * @param arg Device handle
1485
+ */
1486
+ void *_uvc_user_caller(void *arg) {
1487
+ uvc_stream_handle_t *strmh = (uvc_stream_handle_t *) arg;
1488
+
1489
+ uint32_t last_seq = 0;
1490
+
1491
+ do {
1492
+ pthread_mutex_lock(&strmh->cb_mutex);
1493
+
1494
+ while (strmh->running && last_seq == strmh->hold_seq) {
1495
+ pthread_cond_wait(&strmh->cb_cond, &strmh->cb_mutex);
1496
+ }
1497
+
1498
+ if (!strmh->running) {
1499
+ pthread_mutex_unlock(&strmh->cb_mutex);
1500
+ break;
1501
+ }
1502
+
1503
+ last_seq = strmh->hold_seq;
1504
+ _uvc_populate_frame(strmh);
1505
+
1506
+ pthread_mutex_unlock(&strmh->cb_mutex);
1507
+
1508
+ strmh->user_cb(&strmh->frame, strmh->user_ptr);
1509
+ } while(1);
1510
+
1511
+ return NULL; // return value ignored
1512
+ }
1513
+
1514
+ /** @internal
1515
+ * @brief Populate the fields of a frame to be handed to user code
1516
+ * must be called with stream cb lock held!
1517
+ */
1518
+ void _uvc_populate_frame(uvc_stream_handle_t *strmh) {
1519
+ uvc_frame_t *frame = &strmh->frame;
1520
+ uvc_frame_desc_t *frame_desc;
1521
+
1522
+ /** @todo this stuff that hits the main config cache should really happen
1523
+ * in start() so that only one thread hits these data. all of this stuff
1524
+ * is going to be reopen_on_change anyway
1525
+ */
1526
+
1527
+ frame_desc = uvc_find_frame_desc(strmh->devh, strmh->cur_ctrl.bFormatIndex,
1528
+ strmh->cur_ctrl.bFrameIndex);
1529
+
1530
+ frame->frame_format = strmh->frame_format;
1531
+
1532
+ frame->width = frame_desc->wWidth;
1533
+ frame->height = frame_desc->wHeight;
1534
+
1535
+ switch (frame->frame_format) {
1536
+ case UVC_FRAME_FORMAT_BGR:
1537
+ frame->step = frame->width * 3;
1538
+ break;
1539
+ case UVC_FRAME_FORMAT_YUYV:
1540
+ frame->step = frame->width * 2;
1541
+ break;
1542
+ case UVC_FRAME_FORMAT_NV12:
1543
+ frame->step = frame->width;
1544
+ break;
1545
+ case UVC_FRAME_FORMAT_P010:
1546
+ frame->step = frame->width * 2;
1547
+ break;
1548
+ case UVC_FRAME_FORMAT_MJPEG:
1549
+ frame->step = 0;
1550
+ break;
1551
+ case UVC_FRAME_FORMAT_H264:
1552
+ frame->step = 0;
1553
+ break;
1554
+ default:
1555
+ frame->step = 0;
1556
+ break;
1557
+ }
1558
+
1559
+ frame->sequence = strmh->hold_seq;
1560
+ frame->capture_time_finished = strmh->capture_time_finished;
1561
+
1562
+ /* copy the image data from the hold buffer to the frame (unnecessary extra buf?) */
1563
+ if (frame->data_bytes < strmh->hold_bytes) {
1564
+ frame->data = realloc(frame->data, strmh->hold_bytes);
1565
+ }
1566
+ frame->data_bytes = strmh->hold_bytes;
1567
+ memcpy(frame->data, strmh->holdbuf, frame->data_bytes);
1568
+
1569
+ if (strmh->meta_hold_bytes > 0)
1570
+ {
1571
+ if (frame->metadata_bytes < strmh->meta_hold_bytes)
1572
+ {
1573
+ frame->metadata = realloc(frame->metadata, strmh->meta_hold_bytes);
1574
+ }
1575
+ frame->metadata_bytes = strmh->meta_hold_bytes;
1576
+ memcpy(frame->metadata, strmh->meta_holdbuf, frame->metadata_bytes);
1577
+ }
1578
+ }
1579
+
1580
+ /** Poll for a frame
1581
+ * @ingroup streaming
1582
+ *
1583
+ * @param devh UVC device
1584
+ * @param[out] frame Location to store pointer to captured frame (NULL on error)
1585
+ * @param timeout_us >0: Wait at most N microseconds; 0: Wait indefinitely; -1: return immediately
1586
+ */
1587
+ uvc_error_t uvc_stream_get_frame(uvc_stream_handle_t *strmh,
1588
+ uvc_frame_t **frame,
1589
+ int32_t timeout_us) {
1590
+ time_t add_secs;
1591
+ time_t add_nsecs;
1592
+ struct timespec ts;
1593
+
1594
+ if (!strmh->running)
1595
+ return UVC_ERROR_INVALID_PARAM;
1596
+
1597
+ if (strmh->user_cb)
1598
+ return UVC_ERROR_CALLBACK_EXISTS;
1599
+
1600
+ pthread_mutex_lock(&strmh->cb_mutex);
1601
+
1602
+ if (strmh->last_polled_seq < strmh->hold_seq) {
1603
+ _uvc_populate_frame(strmh);
1604
+ *frame = &strmh->frame;
1605
+ strmh->last_polled_seq = strmh->hold_seq;
1606
+ } else if (timeout_us != -1) {
1607
+ if (timeout_us == 0) {
1608
+ pthread_cond_wait(&strmh->cb_cond, &strmh->cb_mutex);
1609
+ } else {
1610
+ add_secs = timeout_us / 1000000;
1611
+ add_nsecs = (timeout_us % 1000000) * 1000;
1612
+ ts.tv_sec = 0;
1613
+ ts.tv_nsec = 0;
1614
+
1615
+ #if _POSIX_TIMERS > 0
1616
+ clock_gettime(CLOCK_REALTIME, &ts);
1617
+ #else
1618
+ struct timeval tv;
1619
+ gettimeofday(&tv, NULL);
1620
+ ts.tv_sec = tv.tv_sec;
1621
+ ts.tv_nsec = tv.tv_usec * 1000;
1622
+ #endif
1623
+
1624
+ ts.tv_sec += add_secs;
1625
+ ts.tv_nsec += add_nsecs;
1626
+
1627
+ /* pthread_cond_timedwait FAILS with EINVAL if ts.tv_nsec > 1000000000 (1 billion)
1628
+ * Since we are just adding values to the timespec, we have to increment the seconds if nanoseconds is greater than 1 billion,
1629
+ * and then re-adjust the nanoseconds in the correct range.
1630
+ * */
1631
+ ts.tv_sec += ts.tv_nsec / 1000000000;
1632
+ ts.tv_nsec = ts.tv_nsec % 1000000000;
1633
+
1634
+ int err = pthread_cond_timedwait(&strmh->cb_cond, &strmh->cb_mutex, &ts);
1635
+
1636
+ //TODO: How should we handle EINVAL?
1637
+ if (err) {
1638
+ *frame = NULL;
1639
+ pthread_mutex_unlock(&strmh->cb_mutex);
1640
+ return err == ETIMEDOUT ? UVC_ERROR_TIMEOUT : UVC_ERROR_OTHER;
1641
+ }
1642
+ }
1643
+
1644
+ if (strmh->last_polled_seq < strmh->hold_seq) {
1645
+ _uvc_populate_frame(strmh);
1646
+ *frame = &strmh->frame;
1647
+ strmh->last_polled_seq = strmh->hold_seq;
1648
+ } else {
1649
+ *frame = NULL;
1650
+ }
1651
+ } else {
1652
+ *frame = NULL;
1653
+ }
1654
+
1655
+ pthread_mutex_unlock(&strmh->cb_mutex);
1656
+
1657
+ return UVC_SUCCESS;
1658
+ }
1659
+
1660
+ /** @brief Stop streaming video
1661
+ * @ingroup streaming
1662
+ *
1663
+ * Closes all streams, ends threads and cancels pollers
1664
+ *
1665
+ * @param devh UVC device
1666
+ */
1667
+ void uvc_stop_streaming(uvc_device_handle_t *devh) {
1668
+ uvc_stream_handle_t *strmh, *strmh_tmp;
1669
+
1670
+ DL_FOREACH_SAFE(devh->streams, strmh, strmh_tmp) {
1671
+ uvc_stream_close(strmh);
1672
+ }
1673
+ }
1674
+
1675
+ /** @brief Stop stream.
1676
+ * @ingroup streaming
1677
+ *
1678
+ * Stops stream, ends threads and cancels pollers
1679
+ *
1680
+ * @param devh UVC device
1681
+ */
1682
+ uvc_error_t uvc_stream_stop(uvc_stream_handle_t *strmh) {
1683
+ int i;
1684
+
1685
+ if (!strmh->running)
1686
+ return UVC_ERROR_INVALID_PARAM;
1687
+
1688
+ strmh->running = 0;
1689
+
1690
+ pthread_mutex_lock(&strmh->cb_mutex);
1691
+
1692
+ /* Attempt to cancel any running transfers, we can't free them just yet because they aren't
1693
+ * necessarily completed but they will be free'd in _uvc_stream_callback().
1694
+ */
1695
+ for(i=0; i < LIBUVC_NUM_TRANSFER_BUFS; i++) {
1696
+ if(strmh->transfers[i] != NULL)
1697
+ libusb_cancel_transfer(strmh->transfers[i]);
1698
+ }
1699
+
1700
+ /* Wait for transfers to complete/cancel */
1701
+ do {
1702
+ for(i=0; i < LIBUVC_NUM_TRANSFER_BUFS; i++) {
1703
+ if(strmh->transfers[i] != NULL)
1704
+ break;
1705
+ }
1706
+ if(i == LIBUVC_NUM_TRANSFER_BUFS )
1707
+ break;
1708
+ pthread_cond_wait(&strmh->cb_cond, &strmh->cb_mutex);
1709
+ } while(1);
1710
+ // Kick the user thread awake
1711
+ pthread_cond_broadcast(&strmh->cb_cond);
1712
+ pthread_mutex_unlock(&strmh->cb_mutex);
1713
+
1714
+ /** @todo stop the actual stream, camera side? */
1715
+
1716
+ if (strmh->user_cb) {
1717
+ /* wait for the thread to stop (triggered by
1718
+ * LIBUSB_TRANSFER_CANCELLED transfer) */
1719
+ pthread_join(strmh->cb_thread, NULL);
1720
+ }
1721
+
1722
+ return UVC_SUCCESS;
1723
+ }
1724
+
1725
+ /** @brief Close stream.
1726
+ * @ingroup streaming
1727
+ *
1728
+ * Closes stream, frees handle and all streaming resources.
1729
+ *
1730
+ * @param strmh UVC stream handle
1731
+ */
1732
+ void uvc_stream_close(uvc_stream_handle_t *strmh) {
1733
+ if (strmh->running)
1734
+ uvc_stream_stop(strmh);
1735
+
1736
+ uvc_release_if(strmh->devh, strmh->stream_if->bInterfaceNumber);
1737
+
1738
+ if (strmh->frame.data)
1739
+ free(strmh->frame.data);
1740
+
1741
+ free(strmh->outbuf);
1742
+ free(strmh->holdbuf);
1743
+
1744
+ free(strmh->meta_outbuf);
1745
+ free(strmh->meta_holdbuf);
1746
+
1747
+ pthread_cond_destroy(&strmh->cb_cond);
1748
+ pthread_mutex_destroy(&strmh->cb_mutex);
1749
+
1750
+ DL_DELETE(strmh->devh->streams, strmh);
1751
+ free(strmh);
1752
+ }
collector/core/gripper/camera_service_src/third_party/libuvc/src/test.c ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*********************************************************************
2
+ * Software License Agreement (BSD License)
3
+ *
4
+ * Copyright (C) 2010-2012 Ken Tossell
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following
15
+ * disclaimer in the documentation and/or other materials provided
16
+ * with the distribution.
17
+ * * Neither the name of the author nor other contributors may be
18
+ * used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ *********************************************************************/
34
+ #include <stdio.h>
35
+ #include <opencv2/highgui/highgui_c.h>
36
+
37
+ #include "libuvc/libuvc.h"
38
+
39
+ void cb(uvc_frame_t *frame, void *ptr) {
40
+ uvc_frame_t *bgr;
41
+ uvc_error_t ret;
42
+ IplImage* cvImg;
43
+
44
+ printf("callback! length = %u, ptr = %d\n", frame->data_bytes, (int) ptr);
45
+
46
+ bgr = uvc_allocate_frame(frame->width * frame->height * 3);
47
+ if (!bgr) {
48
+ printf("unable to allocate bgr frame!");
49
+ return;
50
+ }
51
+
52
+ ret = uvc_any2bgr(frame, bgr);
53
+ if (ret) {
54
+ uvc_perror(ret, "uvc_any2bgr");
55
+ uvc_free_frame(bgr);
56
+ return;
57
+ }
58
+
59
+ cvImg = cvCreateImageHeader(
60
+ cvSize(bgr->width, bgr->height),
61
+ IPL_DEPTH_8U,
62
+ 3);
63
+
64
+ cvSetData(cvImg, bgr->data, bgr->width * 3);
65
+
66
+ cvNamedWindow("Test", CV_WINDOW_AUTOSIZE);
67
+ cvShowImage("Test", cvImg);
68
+ cvWaitKey(10);
69
+
70
+ cvReleaseImageHeader(&cvImg);
71
+
72
+ uvc_free_frame(bgr);
73
+ }
74
+
75
+ int main(int argc, char **argv) {
76
+ uvc_context_t *ctx;
77
+ uvc_error_t res;
78
+ uvc_device_t *dev;
79
+ uvc_device_handle_t *devh;
80
+ uvc_stream_ctrl_t ctrl;
81
+
82
+ res = uvc_init(&ctx, NULL);
83
+
84
+ if (res < 0) {
85
+ uvc_perror(res, "uvc_init");
86
+ return res;
87
+ }
88
+
89
+ puts("UVC initialized");
90
+
91
+ res = uvc_find_device(
92
+ ctx, &dev,
93
+ 0, 0, NULL);
94
+
95
+ if (res < 0) {
96
+ uvc_perror(res, "uvc_find_device");
97
+ } else {
98
+ puts("Device found");
99
+
100
+ res = uvc_open(dev, &devh);
101
+
102
+ if (res < 0) {
103
+ uvc_perror(res, "uvc_open");
104
+ } else {
105
+ puts("Device opened");
106
+
107
+ uvc_print_diag(devh, stderr);
108
+
109
+ res = uvc_get_stream_ctrl_format_size(
110
+ devh, &ctrl, UVC_FRAME_FORMAT_YUYV, 640, 480, 30
111
+ );
112
+
113
+ uvc_print_stream_ctrl(&ctrl, stderr);
114
+
115
+ if (res < 0) {
116
+ uvc_perror(res, "get_mode");
117
+ } else {
118
+ res = uvc_start_streaming(devh, &ctrl, cb, 12345, 0);
119
+
120
+ if (res < 0) {
121
+ uvc_perror(res, "start_streaming");
122
+ } else {
123
+ puts("Streaming for 10 seconds...");
124
+ uvc_error_t resAEMODE = uvc_set_ae_mode(devh, 1);
125
+ uvc_perror(resAEMODE, "set_ae_mode");
126
+ int i;
127
+ for (i = 1; i <= 10; i++) {
128
+ /* uvc_error_t resPT = uvc_set_pantilt_abs(devh, i * 20 * 3600, 0); */
129
+ /* uvc_perror(resPT, "set_pt_abs"); */
130
+ uvc_error_t resEXP = uvc_set_exposure_abs(devh, 20 + i * 5);
131
+ uvc_perror(resEXP, "set_exp_abs");
132
+
133
+ sleep(1);
134
+ }
135
+ sleep(10);
136
+ uvc_stop_streaming(devh);
137
+ puts("Done streaming.");
138
+ }
139
+ }
140
+
141
+ uvc_close(devh);
142
+ puts("Device closed");
143
+ }
144
+
145
+ uvc_unref_device(dev);
146
+ }
147
+
148
+ uvc_exit(ctx);
149
+ puts("UVC exited");
150
+
151
+ return 0;
152
+ }
153
+
collector/core/gripper/camera_service_src/third_party/libuvc/standard-units.yaml ADDED
@@ -0,0 +1,518 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ units:
2
+ camera_terminal:
3
+ type: standard
4
+ description: Standard camera input terminal (captures images from sensor)
5
+ control_prefix: CT
6
+ controls:
7
+ scanning_mode:
8
+ control: SCANNING_MODE
9
+ length: 1
10
+ fields:
11
+ mode:
12
+ type: int
13
+ position: 0
14
+ length: 1
15
+ doc: '0: interlaced, 1: progressive'
16
+ ae_mode:
17
+ control: AE_MODE
18
+ length: 1
19
+ fields:
20
+ mode:
21
+ type: int
22
+ position: 0
23
+ length: 1
24
+ doc: '1: manual mode; 2: auto mode; 4: shutter priority mode; 8: aperture
25
+ priority mode'
26
+ doc:
27
+ get: |-
28
+ @brief Reads camera's auto-exposure mode.
29
+
30
+ See uvc_set_ae_mode() for a description of the available modes.
31
+ set: |-
32
+ @brief Sets camera's auto-exposure mode.
33
+
34
+ Cameras may support any of the following AE modes:
35
+ * UVC_AUTO_EXPOSURE_MODE_MANUAL (1) - manual exposure time, manual iris
36
+ * UVC_AUTO_EXPOSURE_MODE_AUTO (2) - auto exposure time, auto iris
37
+ * UVC_AUTO_EXPOSURE_MODE_SHUTTER_PRIORITY (4) - manual exposure time, auto iris
38
+ * UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY (8) - auto exposure time, manual iris
39
+
40
+ Most cameras provide manual mode and aperture priority mode.
41
+ ae_priority:
42
+ control: AE_PRIORITY
43
+ length: 1
44
+ fields:
45
+ priority:
46
+ type: int
47
+ position: 0
48
+ length: 1
49
+ doc: '0: frame rate must remain constant; 1: frame rate may be varied
50
+ for AE purposes'
51
+ doc:
52
+ get: |-
53
+ @brief Checks whether the camera may vary the frame rate for exposure control reasons.
54
+ See uvc_set_ae_priority() for a description of the `priority` field.
55
+ set: |-
56
+ @brief Chooses whether the camera may vary the frame rate for exposure control reasons.
57
+ A `priority` value of zero means the camera may not vary its frame rate. A value of 1
58
+ means the frame rate is variable. This setting has no effect outside of the `auto` and
59
+ `shutter_priority` auto-exposure modes.
60
+ exposure_abs:
61
+ control: EXPOSURE_TIME_ABSOLUTE
62
+ length: 4
63
+ fields:
64
+ time:
65
+ type: int
66
+ position: 0
67
+ length: 4
68
+ doc: ''
69
+ doc:
70
+ get: |-
71
+ @brief Gets the absolute exposure time.
72
+
73
+ See uvc_set_exposure_abs() for a description of the `time` field.
74
+ set: |-
75
+ @brief Sets the absolute exposure time.
76
+
77
+ The `time` parameter should be provided in units of 0.0001 seconds (e.g., use the value 100
78
+ for a 10ms exposure period). Auto exposure should be set to `manual` or `shutter_priority`
79
+ before attempting to change this setting.
80
+ exposure_rel:
81
+ control: EXPOSURE_TIME_RELATIVE
82
+ length: 1
83
+ fields:
84
+ step:
85
+ type: int
86
+ position: 0
87
+ length: 1
88
+ signed: true
89
+ doc: number of steps by which to change the exposure time, or zero to
90
+ set the default exposure time
91
+ doc: '@brief {gets_sets} the exposure time relative to the current setting.'
92
+ focus_abs:
93
+ control: FOCUS_ABSOLUTE
94
+ length: 2
95
+ fields:
96
+ focus:
97
+ type: int
98
+ position: 0
99
+ length: 2
100
+ doc: focal target distance in millimeters
101
+ doc: '@brief {gets_sets} the distance at which an object is optimally focused.'
102
+ focus_rel:
103
+ control: FOCUS_RELATIVE
104
+ length: 2
105
+ fields:
106
+ focus_rel:
107
+ type: int
108
+ position: 0
109
+ length: 1
110
+ signed: true
111
+ doc: TODO
112
+ speed:
113
+ type: int
114
+ position: 1
115
+ length: 1
116
+ doc: TODO
117
+ focus_simple_range:
118
+ control: FOCUS_SIMPLE
119
+ length: 1
120
+ fields:
121
+ focus:
122
+ type: int
123
+ position: 0
124
+ length: 1
125
+ doc: TODO
126
+ focus_auto:
127
+ control: FOCUS_AUTO
128
+ length: 1
129
+ fields:
130
+ state:
131
+ type: int
132
+ position: 0
133
+ length: 1
134
+ doc: TODO
135
+ iris_abs:
136
+ control: IRIS_ABSOLUTE
137
+ length: 2
138
+ fields:
139
+ iris:
140
+ type: int
141
+ position: 0
142
+ length: 2
143
+ doc: TODO
144
+ iris_rel:
145
+ control: IRIS_RELATIVE
146
+ length: 1
147
+ fields:
148
+ iris_rel:
149
+ type: int
150
+ position: 0
151
+ length: 1
152
+ doc: TODO
153
+ zoom_abs:
154
+ control: ZOOM_ABSOLUTE
155
+ length: 2
156
+ fields:
157
+ focal_length:
158
+ type: int
159
+ position: 0
160
+ length: 2
161
+ doc: TODO
162
+ zoom_rel:
163
+ control: ZOOM_RELATIVE
164
+ length: 3
165
+ fields:
166
+ zoom_rel:
167
+ type: int
168
+ position: 0
169
+ length: 1
170
+ signed: true
171
+ doc: TODO
172
+ digital_zoom:
173
+ type: int
174
+ position: 1
175
+ length: 1
176
+ doc: TODO
177
+ speed:
178
+ type: int
179
+ position: 2
180
+ length: 1
181
+ doc: TODO
182
+ pantilt_abs:
183
+ control: PANTILT_ABSOLUTE
184
+ length: 8
185
+ fields:
186
+ pan:
187
+ type: int
188
+ position: 0
189
+ length: 4
190
+ signed: true
191
+ doc: TODO
192
+ tilt:
193
+ type: int
194
+ position: 4
195
+ length: 4
196
+ signed: true
197
+ doc: TODO
198
+ pantilt_rel:
199
+ control: PANTILT_RELATIVE
200
+ length: 4
201
+ fields:
202
+ pan_rel:
203
+ type: int
204
+ position: 0
205
+ length: 1
206
+ signed: true
207
+ doc: TODO
208
+ pan_speed:
209
+ type: int
210
+ position: 1
211
+ length: 1
212
+ doc: TODO
213
+ tilt_rel:
214
+ type: int
215
+ position: 2
216
+ length: 1
217
+ signed: true
218
+ doc: TODO
219
+ tilt_speed:
220
+ type: int
221
+ position: 3
222
+ length: 1
223
+ doc: TODO
224
+ roll_abs:
225
+ control: ROLL_ABSOLUTE
226
+ length: 2
227
+ fields:
228
+ roll:
229
+ type: int
230
+ position: 0
231
+ length: 2
232
+ signed: true
233
+ doc: TODO
234
+ roll_rel:
235
+ control: ROLL_RELATIVE
236
+ length: 2
237
+ fields:
238
+ roll_rel:
239
+ type: int
240
+ position: 0
241
+ length: 1
242
+ signed: true
243
+ doc: TODO
244
+ speed:
245
+ type: int
246
+ position: 1
247
+ length: 1
248
+ doc: TODO
249
+ privacy:
250
+ control: PRIVACY
251
+ length: 1
252
+ fields:
253
+ privacy:
254
+ type: int
255
+ position: 0
256
+ length: 1
257
+ doc: TODO
258
+ digital_window:
259
+ control: DIGITAL_WINDOW
260
+ length: 12
261
+ fields:
262
+ window_top:
263
+ type: int
264
+ position: 0
265
+ length: 2
266
+ doc: TODO
267
+ window_left:
268
+ type: int
269
+ position: 2
270
+ length: 2
271
+ doc: TODO
272
+ window_bottom:
273
+ type: int
274
+ position: 4
275
+ length: 2
276
+ doc: TODO
277
+ window_right:
278
+ type: int
279
+ position: 6
280
+ length: 2
281
+ doc: TODO
282
+ num_steps:
283
+ type: int
284
+ position: 8
285
+ length: 2
286
+ doc: TODO
287
+ num_steps_units:
288
+ type: int
289
+ position: 10
290
+ length: 2
291
+ doc: TODO
292
+ digital_roi:
293
+ control: REGION_OF_INTEREST
294
+ length: 10
295
+ fields:
296
+ roi_top:
297
+ type: int
298
+ position: 0
299
+ length: 2
300
+ doc: TODO
301
+ roi_left:
302
+ type: int
303
+ position: 2
304
+ length: 2
305
+ doc: TODO
306
+ roi_bottom:
307
+ type: int
308
+ position: 4
309
+ length: 2
310
+ doc: TODO
311
+ roi_right:
312
+ type: int
313
+ position: 6
314
+ length: 2
315
+ doc: TODO
316
+ auto_controls:
317
+ type: int
318
+ position: 8
319
+ length: 2
320
+ doc: TODO
321
+ processing_unit:
322
+ type: standard
323
+ description: Standard processing unit (processes images between other units)
324
+ control_prefix: PU
325
+ controls:
326
+ backlight_compensation:
327
+ control: BACKLIGHT_COMPENSATION
328
+ length: 2
329
+ fields:
330
+ backlight_compensation:
331
+ type: int
332
+ position: 0
333
+ length: 2
334
+ doc: device-dependent backlight compensation mode; zero means backlight
335
+ compensation is disabled
336
+ brightness:
337
+ control: BRIGHTNESS
338
+ length: 2
339
+ fields:
340
+ brightness:
341
+ type: int
342
+ position: 0
343
+ length: 2
344
+ signed: true
345
+ doc: TODO
346
+ contrast:
347
+ control: CONTRAST
348
+ length: 2
349
+ fields:
350
+ contrast:
351
+ type: int
352
+ position: 0
353
+ length: 2
354
+ doc: TODO
355
+ contrast_auto:
356
+ control: CONTRAST_AUTO
357
+ length: 1
358
+ fields:
359
+ contrast_auto:
360
+ type: int
361
+ position: 0
362
+ length: 1
363
+ doc: TODO
364
+ gain:
365
+ control: GAIN
366
+ length: 2
367
+ fields:
368
+ gain:
369
+ type: int
370
+ position: 0
371
+ length: 2
372
+ doc: TODO
373
+ power_line_frequency:
374
+ control: POWER_LINE_FREQUENCY
375
+ length: 1
376
+ fields:
377
+ power_line_frequency:
378
+ type: int
379
+ position: 0
380
+ length: 1
381
+ doc: TODO
382
+ hue:
383
+ control: HUE
384
+ length: 2
385
+ fields:
386
+ hue:
387
+ type: int
388
+ position: 0
389
+ length: 2
390
+ signed: true
391
+ doc: TODO
392
+ hue_auto:
393
+ control: HUE_AUTO
394
+ length: 1
395
+ fields:
396
+ hue_auto:
397
+ type: int
398
+ position: 0
399
+ length: 1
400
+ doc: TODO
401
+ saturation:
402
+ control: SATURATION
403
+ length: 2
404
+ fields:
405
+ saturation:
406
+ type: int
407
+ position: 0
408
+ length: 2
409
+ doc: TODO
410
+ sharpness:
411
+ control: SHARPNESS
412
+ length: 2
413
+ fields:
414
+ sharpness:
415
+ type: int
416
+ position: 0
417
+ length: 2
418
+ doc: TODO
419
+ gamma:
420
+ control: GAMMA
421
+ length: 2
422
+ fields:
423
+ gamma:
424
+ type: int
425
+ position: 0
426
+ length: 2
427
+ doc: TODO
428
+ white_balance_temperature:
429
+ control: WHITE_BALANCE_TEMPERATURE
430
+ length: 2
431
+ fields:
432
+ temperature:
433
+ type: int
434
+ position: 0
435
+ length: 2
436
+ doc: TODO
437
+ white_balance_temperature_auto:
438
+ control: WHITE_BALANCE_TEMPERATURE_AUTO
439
+ length: 1
440
+ fields:
441
+ temperature_auto:
442
+ type: int
443
+ position: 0
444
+ length: 1
445
+ doc: TODO
446
+ white_balance_component:
447
+ control: WHITE_BALANCE_COMPONENT
448
+ length: 4
449
+ fields:
450
+ blue:
451
+ type: int
452
+ position: 0
453
+ length: 2
454
+ doc: TODO
455
+ red:
456
+ type: int
457
+ position: 2
458
+ length: 2
459
+ doc: TODO
460
+ white_balance_component_auto:
461
+ control: WHITE_BALANCE_COMPONENT_AUTO
462
+ length: 1
463
+ fields:
464
+ white_balance_component_auto:
465
+ type: int
466
+ position: 0
467
+ length: 1
468
+ doc: TODO
469
+ digital_multiplier:
470
+ control: DIGITAL_MULTIPLIER
471
+ length: 2
472
+ fields:
473
+ multiplier_step:
474
+ type: int
475
+ position: 0
476
+ length: 2
477
+ doc: TODO
478
+ digital_multiplier_limit:
479
+ control: DIGITAL_MULTIPLIER_LIMIT
480
+ length: 2
481
+ fields:
482
+ multiplier_step:
483
+ type: int
484
+ position: 0
485
+ length: 2
486
+ doc: TODO
487
+ analog_video_standard:
488
+ control: ANALOG_VIDEO_STANDARD
489
+ length: 1
490
+ fields:
491
+ video_standard:
492
+ type: int
493
+ position: 0
494
+ length: 1
495
+ doc: TODO
496
+ analog_video_lock_status:
497
+ control: ANALOG_LOCK_STATUS
498
+ length: 1
499
+ fields:
500
+ status:
501
+ type: int
502
+ position: 0
503
+ length: 1
504
+ doc: TODO
505
+ selector_unit:
506
+ type: standard
507
+ description: Standard selector unit (controls connectivity between other units)
508
+ control_prefix: SU
509
+ controls:
510
+ input_select:
511
+ control: INPUT_SELECT
512
+ length: 1
513
+ fields:
514
+ selector:
515
+ type: int
516
+ position: 0
517
+ length: 1
518
+ doc: TODO
collector/core/gripper/camera_service_src/tools/discover_uvc_config.c ADDED
@@ -0,0 +1,1463 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Minimal user-space discovery demo for Sightac + DECXIN.
3
+ *
4
+ * Scope is intentionally limited to:
5
+ * Sightac: 0c45:636f, 640x480 MJPEG @ 30
6
+ * DECXIN : 1bcf:2d4f, 1280x960 MJPEG @ 30
7
+ *
8
+ * Fays is not enumerated as a supported candidate and is never opened by
9
+ * this program. The demo uses libuvc for UVC enumeration/negotiation and
10
+ * libusb for USB topology/descriptors and the read-only Sonix XU6 probe.
11
+ * It does not start a video stream and it does not write/erase Flash.
12
+ */
13
+ #include <ctype.h>
14
+ #include <errno.h>
15
+ #include <libusb-1.0/libusb.h>
16
+ #include <libuvc/libuvc.h>
17
+ #include <limits.h>
18
+ #include <math.h>
19
+ #include <stdint.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+ #include <unistd.h>
24
+
25
+ #define MAX_CANDIDATES 32
26
+ #define MAX_GROUPS 16
27
+ #define MAX_PORT_PATH 64
28
+ #define MAX_TEXT 128
29
+
30
+ #define SIGHTAC_VID 0x0c45
31
+ #define SIGHTAC_PID 0x636f
32
+ #define DECXIN_VID 0x1bcf
33
+ #define DECXIN_PID 0x2d4f
34
+
35
+ #define XU_GET_CUR 0x81
36
+ #define XU_SET_CUR 0x01
37
+ #define XU_CTRL_GET 0xa1
38
+ #define XU_CTRL_SET 0x21
39
+ #define XU_ASIC_SELECTOR 0x01
40
+ #define XU_FLASH_XU6_SELECTOR 0x06
41
+ #define CTRL_TIMEOUT_MS 2000
42
+ #define FLASH_PROBE_ATTEMPTS 3
43
+ #define FLASH_RETRY_DELAY_US 25000
44
+ #define FLASH_MAX_ADDRESS 0x4ffff
45
+ #define SF_XU64_EU_ADDR 0x335
46
+ #define SF_XU64_RW_START_ADDR 0x337
47
+ #define SF_XU64_RW_END_ADDR 0x33b
48
+
49
+ typedef struct {
50
+ int vid;
51
+ int pid;
52
+ int width;
53
+ int height;
54
+ int fps;
55
+ int expected_altsetting;
56
+ int forced_payload;
57
+ const char *kind;
58
+ } mode_profile_t;
59
+
60
+ typedef struct {
61
+ uvc_device_t *uvc_device;
62
+ libusb_device *usb_device;
63
+ int vid;
64
+ int pid;
65
+ int bus;
66
+ char port[MAX_PORT_PATH];
67
+ char usb_serial[MAX_TEXT];
68
+ char device_type[MAX_TEXT];
69
+ char side[16];
70
+ char flash_serial[MAX_TEXT];
71
+ int control_interface;
72
+ int streaming_interface;
73
+ int altsetting;
74
+ unsigned int descriptor_payload;
75
+ unsigned int negotiated_payload;
76
+ int mode_ok;
77
+ int flash_ok;
78
+ int flash_params_ok;
79
+ double fx_params[5];
80
+ double fy_params[5];
81
+ double fz_params[21];
82
+ double ft_params[20];
83
+ double fw_params[9];
84
+ int opened_ok;
85
+ char error[MAX_TEXT];
86
+ } camera_candidate_t;
87
+
88
+ typedef struct {
89
+ int sightac[2];
90
+ int decxin;
91
+ int bus;
92
+ char outer_path[MAX_PORT_PATH];
93
+ } camera_group_t;
94
+
95
+ typedef enum {
96
+ FLASH_MODE_FULL = 0,
97
+ FLASH_MODE_IDENTITY = 1,
98
+ FLASH_MODE_NONE = 2,
99
+ FLASH_MODE_TOPOLOGY_ONLY = 3,
100
+ } flash_mode_t;
101
+
102
+ static const mode_profile_t *profile_for(int vid, int pid) {
103
+ static const mode_profile_t sightac = {
104
+ SIGHTAC_VID, SIGHTAC_PID, 640, 480, 30, 3, 800, "sightac"
105
+ };
106
+ /* The scanner reports the camera's *preferred* altsetting -- the one the
107
+ * descriptor advertises, which gives frames the most room: alt7/1280
108
+ * (2 transactions per microframe) fits 8 x 32 x 1280 = 327680 B per frame,
109
+ * while alt6/944 fits only 241664 B against a measured worst case of
110
+ * 234148 B.
111
+ *
112
+ * This value is *reported*, not used as the starting rung. Measured
113
+ * 2026-09-15: alt7 stalls every 45-130 s while all three cameras stream,
114
+ * on both host controllers tried, and it delivers the same 30.00 fps as
115
+ * alt6 -- so the extra per-frame headroom buys nothing and the app starts
116
+ * at the most conservative pair instead (uvc_camera_service.py,
117
+ * _starting_mode). Keeping the scanner honest about the descriptor matters
118
+ * even so: the app checks this pair against the service's mode table, and a
119
+ * mismatch means scanner and service were built apart from each other. */
120
+ static const mode_profile_t decxin = {
121
+ DECXIN_VID, DECXIN_PID, 1280, 960, 30, 7, 1280, "decxin"
122
+ };
123
+ if (vid == SIGHTAC_VID && pid == SIGHTAC_PID) {
124
+ return &sightac;
125
+ }
126
+ if (vid == DECXIN_VID && pid == DECXIN_PID) {
127
+ return &decxin;
128
+ }
129
+ return NULL;
130
+ }
131
+
132
+ static const char *usb_error_text(int result) {
133
+ return result < 0 ? libusb_strerror((enum libusb_error)result) :
134
+ libusb_strerror((enum libusb_error)result);
135
+ }
136
+
137
+ static void copy_text(char *destination, size_t size, const char *source) {
138
+ size_t length;
139
+ if (size == 0) {
140
+ return;
141
+ }
142
+ if (source == NULL) {
143
+ destination[0] = '\0';
144
+ return;
145
+ }
146
+ length = strlen(source);
147
+ if (length >= size) {
148
+ length = size - 1;
149
+ }
150
+ memcpy(destination, source, length);
151
+ destination[length] = '\0';
152
+ }
153
+
154
+ static void write_json_string(FILE *out, const char *value) {
155
+ fputc('"', out);
156
+ for (const unsigned char *cursor = (const unsigned char *)(value ? value : "");
157
+ *cursor != '\0'; ++cursor) {
158
+ switch (*cursor) {
159
+ case '"':
160
+ fputs("\\\"", out);
161
+ break;
162
+ case '\\':
163
+ fputs("\\\\", out);
164
+ break;
165
+ case '\b':
166
+ fputs("\\b", out);
167
+ break;
168
+ case '\f':
169
+ fputs("\\f", out);
170
+ break;
171
+ case '\n':
172
+ fputs("\\n", out);
173
+ break;
174
+ case '\r':
175
+ fputs("\\r", out);
176
+ break;
177
+ case '\t':
178
+ fputs("\\t", out);
179
+ break;
180
+ default:
181
+ if (*cursor < 0x20) {
182
+ fprintf(out, "\\u%04x", (unsigned int)*cursor);
183
+ } else {
184
+ fputc(*cursor, out);
185
+ }
186
+ break;
187
+ }
188
+ }
189
+ fputc('"', out);
190
+ }
191
+
192
+ static int format_uvc_port_path(uvc_device_t *device, char *out,
193
+ size_t out_size) {
194
+ uint8_t ports[8];
195
+ int count = uvc_get_port_numbers(device, ports, sizeof(ports));
196
+ size_t used = 0;
197
+ if (count < 0 || out_size == 0) {
198
+ return count < 0 ? count : LIBUSB_ERROR_INVALID_PARAM;
199
+ }
200
+ out[0] = '\0';
201
+ for (int index = 0; index < count; ++index) {
202
+ int written = snprintf(out + used, out_size - used, "%s%u",
203
+ index == 0 ? "" : ".", ports[index]);
204
+ if (written < 0 || (size_t)written >= out_size - used) {
205
+ return LIBUSB_ERROR_OVERFLOW;
206
+ }
207
+ used += (size_t)written;
208
+ }
209
+ return 0;
210
+ }
211
+
212
+ static int format_libusb_port_path(libusb_device *device, char *out,
213
+ size_t out_size) {
214
+ uint8_t ports[8];
215
+ int count = libusb_get_port_numbers(device, ports, sizeof(ports));
216
+ size_t used = 0;
217
+ if (count < 0 || out_size == 0) {
218
+ return count < 0 ? count : LIBUSB_ERROR_INVALID_PARAM;
219
+ }
220
+ out[0] = '\0';
221
+ for (int index = 0; index < count; ++index) {
222
+ int written = snprintf(out + used, out_size - used, "%s%u",
223
+ index == 0 ? "" : ".", ports[index]);
224
+ if (written < 0 || (size_t)written >= out_size - used) {
225
+ return LIBUSB_ERROR_OVERFLOW;
226
+ }
227
+ used += (size_t)written;
228
+ }
229
+ return 0;
230
+ }
231
+
232
+ static int find_control_interface(libusb_device *device) {
233
+ struct libusb_config_descriptor *config = NULL;
234
+ int result = libusb_get_active_config_descriptor(device, &config);
235
+ if (result != 0) {
236
+ return result;
237
+ }
238
+ int found = LIBUSB_ERROR_NOT_FOUND;
239
+ for (int i = 0; i < config->bNumInterfaces && found < 0; ++i) {
240
+ for (int j = 0; j < config->interface[i].num_altsetting; ++j) {
241
+ const struct libusb_interface_descriptor *alt =
242
+ &config->interface[i].altsetting[j];
243
+ if (alt->bInterfaceClass == LIBUSB_CLASS_VIDEO &&
244
+ alt->bInterfaceSubClass == 1) {
245
+ found = alt->bInterfaceNumber;
246
+ break;
247
+ }
248
+ }
249
+ }
250
+ libusb_free_config_descriptor(config);
251
+ return found;
252
+ }
253
+
254
+ static unsigned int endpoint_payload(const struct libusb_endpoint_descriptor *ep) {
255
+ unsigned int payload = ep->wMaxPacketSize & 0x07ffu;
256
+ payload *= 1u + ((ep->wMaxPacketSize >> 11) & 0x03u);
257
+ return payload;
258
+ }
259
+
260
+ static int find_stream_mode(libusb_device *device, int expected_altsetting,
261
+ unsigned int minimum_payload,
262
+ int *interface_number, int *altsetting,
263
+ unsigned int *payload) {
264
+ struct libusb_config_descriptor *config = NULL;
265
+ int result = libusb_get_active_config_descriptor(device, &config);
266
+ if (result != 0) {
267
+ return result;
268
+ }
269
+ int found = LIBUSB_ERROR_NOT_FOUND;
270
+ unsigned int selected_payload = 0;
271
+ int selected_interface = -1;
272
+ for (int i = 0; i < config->bNumInterfaces; ++i) {
273
+ for (int j = 0; j < config->interface[i].num_altsetting; ++j) {
274
+ const struct libusb_interface_descriptor *alt =
275
+ &config->interface[i].altsetting[j];
276
+ if (alt->bInterfaceClass != LIBUSB_CLASS_VIDEO ||
277
+ alt->bInterfaceSubClass != 2) {
278
+ continue;
279
+ }
280
+ if (alt->bAlternateSetting != expected_altsetting) {
281
+ continue;
282
+ }
283
+ for (int k = 0; k < alt->bNumEndpoints; ++k) {
284
+ const struct libusb_endpoint_descriptor *ep = &alt->endpoint[k];
285
+ unsigned int transfer_type = ep->bmAttributes &
286
+ LIBUSB_TRANSFER_TYPE_MASK;
287
+ if ((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) !=
288
+ LIBUSB_ENDPOINT_IN ||
289
+ (transfer_type != LIBUSB_TRANSFER_TYPE_ISOCHRONOUS &&
290
+ transfer_type != LIBUSB_TRANSFER_TYPE_BULK)) {
291
+ continue;
292
+ }
293
+ unsigned int current_payload = endpoint_payload(ep);
294
+ if (current_payload >= minimum_payload &&
295
+ current_payload > selected_payload) {
296
+ selected_payload = current_payload;
297
+ selected_interface = alt->bInterfaceNumber;
298
+ found = 0;
299
+ }
300
+ }
301
+ }
302
+ }
303
+ libusb_free_config_descriptor(config);
304
+ if (found == 0) {
305
+ *interface_number = selected_interface;
306
+ *altsetting = expected_altsetting;
307
+ *payload = selected_payload;
308
+ }
309
+ if (found == 0 && *interface_number < 0) {
310
+ found = LIBUSB_ERROR_NOT_FOUND;
311
+ }
312
+ return found;
313
+ }
314
+
315
+ static libusb_device *find_raw_device(libusb_device **devices, ssize_t count,
316
+ int vid, int pid, int bus,
317
+ const char *wanted_port) {
318
+ for (ssize_t index = 0; index < count; ++index) {
319
+ struct libusb_device_descriptor descriptor;
320
+ char port[MAX_PORT_PATH];
321
+ if (libusb_get_device_descriptor(devices[index], &descriptor) != 0 ||
322
+ descriptor.idVendor != (uint16_t)vid ||
323
+ descriptor.idProduct != (uint16_t)pid ||
324
+ (int)libusb_get_bus_number(devices[index]) != bus ||
325
+ format_libusb_port_path(devices[index], port, sizeof(port)) != 0 ||
326
+ strcmp(port, wanted_port) != 0) {
327
+ continue;
328
+ }
329
+ return devices[index];
330
+ }
331
+ return NULL;
332
+ }
333
+
334
+ static int xu_control(libusb_device_handle *handle, int interface_number,
335
+ uint8_t unit, uint8_t selector, int get,
336
+ uint8_t *data, uint16_t size) {
337
+ uint8_t request_type = get ? XU_CTRL_GET : XU_CTRL_SET;
338
+ uint8_t request = get ? XU_GET_CUR : XU_SET_CUR;
339
+ uint16_t value = (uint16_t)selector << 8;
340
+ uint16_t index = ((uint16_t)unit << 8) | (uint16_t)interface_number;
341
+ return libusb_control_transfer(handle, request_type, request, value, index,
342
+ data, size, CTRL_TIMEOUT_MS);
343
+ }
344
+
345
+ static int asic_read(libusb_device_handle *handle, int interface_number,
346
+ uint8_t unit, uint16_t address, uint8_t *value) {
347
+ uint8_t data[4] = {
348
+ (uint8_t)(address & 0xff), (uint8_t)(address >> 8), 0, 0xff
349
+ };
350
+ int result = xu_control(handle, interface_number, unit,
351
+ XU_ASIC_SELECTOR, 0, data, sizeof(data));
352
+ if (result != (int)sizeof(data)) {
353
+ return result < 0 ? result : LIBUSB_ERROR_IO;
354
+ }
355
+ data[3] = 0;
356
+ result = xu_control(handle, interface_number, unit, XU_ASIC_SELECTOR, 1,
357
+ data, sizeof(data));
358
+ if (result != (int)sizeof(data)) {
359
+ return result < 0 ? result : LIBUSB_ERROR_IO;
360
+ }
361
+ *value = data[2];
362
+ return 0;
363
+ }
364
+
365
+ static int asic_write(libusb_device_handle *handle, int interface_number,
366
+ uint8_t unit, uint16_t address, uint8_t value) {
367
+ uint8_t data[4] = {
368
+ (uint8_t)(address & 0xff), (uint8_t)(address >> 8), value, 0
369
+ };
370
+ int result = xu_control(handle, interface_number, unit,
371
+ XU_ASIC_SELECTOR, 0, data, sizeof(data));
372
+ if (result != (int)sizeof(data)) {
373
+ return result < 0 ? result : LIBUSB_ERROR_IO;
374
+ }
375
+ return 0;
376
+ }
377
+
378
+ static int known_chip(uint8_t chip) {
379
+ switch (chip) {
380
+ case 0x15: case 0x16: case 0x22: case 0x23: case 0x25:
381
+ case 0x32: case 0x33: case 0x56: case 0x70: case 0x71:
382
+ case 0x75: case 0x76: case 0x83: case 0x85: case 0x86:
383
+ case 0x87: case 0x88: case 0x89: case 0x90: case 0x92:
384
+ case 0x98: case 0x99:
385
+ return 1;
386
+ default:
387
+ return 0;
388
+ }
389
+ }
390
+
391
+ static int find_xu_unit(libusb_device_handle *handle, int interface_number,
392
+ uint8_t *unit) {
393
+ for (uint8_t candidate = 3; candidate <= 4; ++candidate) {
394
+ uint8_t raw[4] = {0x1f, 0x10, 0, 0xff};
395
+ int set_result = xu_control(handle, interface_number, candidate,
396
+ XU_ASIC_SELECTOR, 0, raw, sizeof(raw));
397
+ int get_result = -1;
398
+ if (set_result == (int)sizeof(raw)) {
399
+ raw[3] = 0;
400
+ get_result = xu_control(handle, interface_number, candidate,
401
+ XU_ASIC_SELECTOR, 1, raw, sizeof(raw));
402
+ }
403
+ uint8_t value = get_result == (int)sizeof(raw) ? raw[2] : 0;
404
+ if (value == 0xaa && get_result == (int)sizeof(raw)) {
405
+ uint8_t id80f0 = 0;
406
+ uint8_t id80f1 = 0;
407
+ uint8_t id80f3 = 0;
408
+ int r0 = asic_read(handle, interface_number, candidate, 0x80f0,
409
+ &id80f0);
410
+ int r1 = asic_read(handle, interface_number, candidate, 0x80f1,
411
+ &id80f1);
412
+ int r3 = asic_read(handle, interface_number, candidate, 0x80f3,
413
+ &id80f3);
414
+ if (r0 == 0 && r1 == 0 && r3 == 0 &&
415
+ (known_chip(id80f0) ||
416
+ (id80f0 == 0x00 && id80f1 == 0x02 && id80f3 == 0x24) ||
417
+ (id80f0 == 0x01 && id80f1 == 0x02 && id80f3 == 0x23) ||
418
+ (id80f0 == 0x04 && id80f1 == 0x02 && id80f3 == 0x24))) {
419
+ value = id80f0;
420
+ }
421
+ }
422
+ if (set_result == (int)sizeof(raw) &&
423
+ get_result == (int)sizeof(raw) &&
424
+ (known_chip(value) || value == 0x00 || value == 0x01 ||
425
+ value == 0x04)) {
426
+ *unit = candidate;
427
+ return 0;
428
+ }
429
+ }
430
+ return LIBUSB_ERROR_NOT_FOUND;
431
+ }
432
+
433
+ static int sf_xu6_write_config(libusb_device_handle *handle,
434
+ int interface_number, uint8_t unit,
435
+ uint32_t start_address, uint32_t data_size,
436
+ uint8_t buffer_size) {
437
+ uint8_t data[64] = {0};
438
+ data[0] = (uint8_t)(start_address & 0xff);
439
+ data[1] = (uint8_t)((start_address >> 8) & 0xff);
440
+ data[2] = (uint8_t)((start_address >> 16) & 0xff);
441
+ data[3] = (uint8_t)((start_address >> 24) & 0xff);
442
+ data[4] = 2u << 6;
443
+ data[5] = buffer_size;
444
+ uint32_t end_address = start_address + data_size;
445
+ data[6] = (uint8_t)(end_address & 0xff);
446
+ data[7] = (uint8_t)((end_address >> 8) & 0xff);
447
+ data[8] = (uint8_t)((end_address >> 16) & 0xff);
448
+ data[9] = (uint8_t)((end_address >> 24) & 0xff);
449
+ data[10] = 0x0b;
450
+ data[11] = 0x01;
451
+ int result = xu_control(handle, interface_number, unit,
452
+ XU_FLASH_XU6_SELECTOR, 0, data, sizeof(data));
453
+ return result == (int)sizeof(data) ? 0 :
454
+ (result < 0 ? result : LIBUSB_ERROR_IO);
455
+ }
456
+
457
+ static int sf_xu6_stop(libusb_device_handle *handle, int interface_number,
458
+ uint8_t unit) {
459
+ for (uint16_t i = 0; i < 4; ++i) {
460
+ int result = asic_write(handle, interface_number, unit,
461
+ SF_XU64_RW_START_ADDR + i, 0);
462
+ if (result != 0) {
463
+ return result;
464
+ }
465
+ result = asic_write(handle, interface_number, unit,
466
+ SF_XU64_RW_END_ADDR + i, 0);
467
+ if (result != 0) {
468
+ return result;
469
+ }
470
+ }
471
+ return asic_write(handle, interface_number, unit, SF_XU64_EU_ADDR, 0);
472
+ }
473
+
474
+ static int sf_xu6_read_block(libusb_device_handle *handle, int interface_number,
475
+ uint8_t unit, uint32_t address, uint8_t *out,
476
+ uint8_t length) {
477
+ if (length == 0 || length > 64 || address > FLASH_MAX_ADDRESS ||
478
+ address + length < address) {
479
+ return LIBUSB_ERROR_INVALID_PARAM;
480
+ }
481
+ int result = sf_xu6_stop(handle, interface_number, unit);
482
+ if (result != 0) {
483
+ return result;
484
+ }
485
+ result = sf_xu6_write_config(handle, interface_number, unit, address,
486
+ length, length);
487
+ if (result != 0) {
488
+ return result;
489
+ }
490
+ uint8_t data[64] = {0};
491
+ result = xu_control(handle, interface_number, unit,
492
+ XU_FLASH_XU6_SELECTOR, 1, data, sizeof(data));
493
+ if (result != (int)sizeof(data)) {
494
+ return result < 0 ? result : LIBUSB_ERROR_IO;
495
+ }
496
+ memcpy(out, data, length);
497
+ return 0;
498
+ }
499
+
500
+ static int sf_xu6_read(libusb_device_handle *handle, int interface_number,
501
+ uint8_t unit, uint32_t address, uint8_t *out,
502
+ size_t length) {
503
+ while (length > 0) {
504
+ uint8_t chunk = length > 64 ? 64 : (uint8_t)length;
505
+ int result = sf_xu6_read_block(handle, interface_number, unit, address,
506
+ out, chunk);
507
+ if (result != 0) {
508
+ return result;
509
+ }
510
+ address += chunk;
511
+ out += chunk;
512
+ length -= chunk;
513
+ }
514
+ return 0;
515
+ }
516
+
517
+ static int sf_xu6_prepare_290(libusb_device_handle *handle,
518
+ int interface_number, uint8_t unit) {
519
+ int result = asic_write(handle, interface_number, unit, 0x8045, 10);
520
+ if (result != 0) {
521
+ return result;
522
+ }
523
+ return asic_write(handle, interface_number, unit, 0x8e10, 1);
524
+ }
525
+
526
+ static void sleep_for_probe(size_t attempt) {
527
+ useconds_t delay = FLASH_RETRY_DELAY_US *
528
+ (useconds_t)(attempt + 1U);
529
+ usleep(delay);
530
+ }
531
+
532
+ static void decode_flash_text(const uint8_t *raw, size_t length,
533
+ char *out, size_t out_size) {
534
+ size_t used = 0;
535
+ if (out_size == 0) {
536
+ return;
537
+ }
538
+ for (size_t i = 0; i < length && used + 1 < out_size; ++i) {
539
+ if (raw[i] == 0 || raw[i] == 0xff) {
540
+ break;
541
+ }
542
+ out[used++] = isprint(raw[i]) ? (char)raw[i] : '.';
543
+ }
544
+ while (used > 0 && isspace((unsigned char)out[used - 1])) {
545
+ --used;
546
+ }
547
+ out[used] = '\0';
548
+ }
549
+
550
+ static void decode_flash_serial(const uint8_t *raw, size_t length,
551
+ char *out, size_t out_size) {
552
+ size_t used = 0;
553
+ if (out_size == 0) {
554
+ return;
555
+ }
556
+ /* Sonix parameter-table strings use the same UTF-16LE-like layout as
557
+ * the vendor SDK: length in bytes at [0], characters at [2], [4]... . */
558
+ if (length >= 2 && raw[0] >= 2 && raw[0] <= length * 2 &&
559
+ (raw[0] & 1u) == 0) {
560
+ size_t chars = (raw[0] - 2) / 2;
561
+ for (size_t index = 0; index < chars &&
562
+ 2 + index * 2 < length && used + 1 < out_size; ++index) {
563
+ uint8_t value = raw[2 + index * 2];
564
+ if (value == 0 || value == 0xff) {
565
+ break;
566
+ }
567
+ out[used++] = isprint(value) ? (char)value : '.';
568
+ }
569
+ } else {
570
+ decode_flash_text(raw, length, out, out_size);
571
+ return;
572
+ }
573
+ while (used > 0 && isspace((unsigned char)out[used - 1])) {
574
+ --used;
575
+ }
576
+ out[used] = '\0';
577
+ }
578
+
579
+ static void reset_flash_identity(camera_candidate_t *candidate) {
580
+ memset(candidate->device_type, 0, sizeof(candidate->device_type));
581
+ memset(candidate->side, 0, sizeof(candidate->side));
582
+ memset(candidate->flash_serial, 0, sizeof(candidate->flash_serial));
583
+ memset(candidate->fx_params, 0, sizeof(candidate->fx_params));
584
+ memset(candidate->fy_params, 0, sizeof(candidate->fy_params));
585
+ memset(candidate->fz_params, 0, sizeof(candidate->fz_params));
586
+ memset(candidate->fw_params, 0, sizeof(candidate->fw_params));
587
+ memset(candidate->ft_params, 0, sizeof(candidate->ft_params));
588
+ candidate->flash_ok = 0;
589
+ candidate->flash_params_ok = 0;
590
+ candidate->error[0] = '\0';
591
+ }
592
+
593
+ static int read_flash_identity_once(camera_candidate_t *candidate,
594
+ libusb_device_handle *handle,
595
+ int read_calibration) {
596
+ uint8_t unit = 0;
597
+ int result = find_xu_unit(handle, candidate->control_interface, &unit);
598
+ if (result != 0) {
599
+ snprintf(candidate->error, sizeof(candidate->error),
600
+ "XU unit: %s", usb_error_text(result));
601
+ return result;
602
+ }
603
+ result = sf_xu6_prepare_290(handle, candidate->control_interface, unit);
604
+ if (result != 0) {
605
+ snprintf(candidate->error, sizeof(candidate->error),
606
+ "XU6 prepare: %s", usb_error_text(result));
607
+ return result;
608
+ }
609
+
610
+ char params[5][MAX_TEXT];
611
+ memset(params, 0, sizeof(params));
612
+ for (size_t index = 0; index < 5; ++index) {
613
+ uint8_t raw[8] = {0};
614
+ result = sf_xu6_read(handle, candidate->control_interface, unit,
615
+ 0x45000 + (uint32_t)(index * sizeof(raw)), raw,
616
+ sizeof(raw));
617
+ if (result != 0) {
618
+ snprintf(candidate->error, sizeof(candidate->error),
619
+ "Flash device_params[%zu]: %s", index,
620
+ usb_error_text(result));
621
+ return result;
622
+ }
623
+ decode_flash_text(raw, sizeof(raw), params[index], sizeof(params[index]));
624
+ }
625
+ copy_text(candidate->device_type, sizeof(candidate->device_type), params[0]);
626
+ copy_text(candidate->side, sizeof(candidate->side), params[1]);
627
+ copy_text(candidate->flash_serial, sizeof(candidate->flash_serial), params[2]);
628
+ if (!(strcmp(candidate->device_type, "planar") == 0 ||
629
+ strcmp(candidate->device_type, "curved") == 0 ||
630
+ strcmp(candidate->device_type, "bevel") == 0)) {
631
+ char message[MAX_TEXT + 32];
632
+ snprintf(message, sizeof(message), "Flash device_type is %s",
633
+ candidate->device_type[0] ? candidate->device_type : "empty");
634
+ copy_text(candidate->error, sizeof(candidate->error), message);
635
+ return LIBUSB_ERROR_INVALID_PARAM;
636
+ }
637
+ uint32_t parameter_start = 0x8000;
638
+ uint8_t table[0x2b] = {0};
639
+ int table_result = sf_xu6_read(handle, candidate->control_interface,
640
+ unit, 0x160, table, sizeof(table));
641
+ if (table_result != 0) {
642
+ snprintf(candidate->error, sizeof(candidate->error),
643
+ "Flash parameter_table: %s", usb_error_text(table_result));
644
+ return table_result;
645
+ }
646
+ if (table[0x0f] == 0xff) {
647
+ snprintf(candidate->error, sizeof(candidate->error),
648
+ "Flash parameter start address is blank");
649
+ return LIBUSB_ERROR_INVALID_PARAM;
650
+ }
651
+ parameter_start = ((uint32_t)table[0x0f] << 24) |
652
+ ((uint32_t)table[0x10] << 16) |
653
+ ((uint32_t)table[0x11] << 8) | table[0x12];
654
+
655
+ uint8_t serial_raw[64] = {0};
656
+ int serial_result = sf_xu6_read(handle, candidate->control_interface,
657
+ unit, parameter_start + 0xc0, serial_raw,
658
+ sizeof(serial_raw));
659
+ if (serial_result != 0) {
660
+ snprintf(candidate->error, sizeof(candidate->error),
661
+ "Flash device_serial: %s", usb_error_text(serial_result));
662
+ return serial_result;
663
+ }
664
+ char flash_serial[MAX_TEXT] = {0};
665
+ decode_flash_serial(serial_raw, sizeof(serial_raw), flash_serial,
666
+ sizeof(flash_serial));
667
+ if (flash_serial[0] == '\0') {
668
+ snprintf(candidate->error, sizeof(candidate->error),
669
+ "Flash device_serial is empty");
670
+ return LIBUSB_ERROR_INVALID_PARAM;
671
+ }
672
+ copy_text(candidate->flash_serial, sizeof(candidate->flash_serial),
673
+ flash_serial);
674
+ for (char *cursor = candidate->side; *cursor != '\0'; ++cursor) {
675
+ *cursor = (char)tolower((unsigned char)*cursor);
676
+ }
677
+ if (strcmp(candidate->side, "left") != 0 &&
678
+ strcmp(candidate->side, "right") != 0) {
679
+ snprintf(candidate->error, sizeof(candidate->error),
680
+ "Flash side is %s", candidate->side[0] ? candidate->side : "empty");
681
+ return LIBUSB_ERROR_INVALID_PARAM;
682
+ }
683
+ candidate->flash_ok = 1;
684
+ if (!read_calibration) {
685
+ return 0;
686
+ }
687
+
688
+ struct {
689
+ uint32_t address;
690
+ double *values;
691
+ size_t count;
692
+ const char *name;
693
+ } calibration[] = {
694
+ {0x41000, candidate->fx_params, 5, "fx"},
695
+ {0x42000, candidate->fy_params, 5, "fy"},
696
+ {0x43000, candidate->fz_params, 21, "fz"},
697
+ {0x47000, candidate->ft_params, 20, "ft"},
698
+ {0x44000, candidate->fw_params, 9, "fw"},
699
+ };
700
+ for (size_t table_index = 0;
701
+ table_index < sizeof(calibration) / sizeof(calibration[0]);
702
+ ++table_index) {
703
+ /* Each XU6 read pays the setup cost of stop/config/control transfers.
704
+ * Read each contiguous calibration table in 64-byte blocks instead
705
+ * of issuing one transfer per double. */
706
+ uint8_t raw[21 * sizeof(double)] = {0};
707
+ size_t raw_size = calibration[table_index].count * sizeof(double);
708
+ result = sf_xu6_read(
709
+ handle, candidate->control_interface, unit,
710
+ calibration[table_index].address, raw, raw_size);
711
+ if (result != 0) {
712
+ snprintf(candidate->error, sizeof(candidate->error),
713
+ "Flash %s: %s", calibration[table_index].name,
714
+ usb_error_text(result));
715
+ return result;
716
+ }
717
+ for (size_t value_index = 0;
718
+ value_index < calibration[table_index].count; ++value_index) {
719
+ const uint8_t *slot = raw + value_index * sizeof(double);
720
+ int erased = 1;
721
+ for (size_t byte = 0; byte < sizeof(double); ++byte) {
722
+ if (slot[byte] != 0xff) erased = 0;
723
+ }
724
+ if (erased && (strcmp(calibration[table_index].name, "ft") == 0 ||
725
+ (strcmp(calibration[table_index].name, "fz") == 0 && value_index >= 8))) {
726
+ /* Match 0902 _default_force_calibration_params for erased
727
+ * extension slots only. Required coefficients and I/O errors
728
+ * remain fail-closed. FT's first/fourth defaults are 1, not 0. */
729
+ calibration[table_index].values[value_index] =
730
+ (strcmp(calibration[table_index].name, "ft") == 0 &&
731
+ (value_index == 0 || value_index == 3)) ? 1.0 : 0.0;
732
+ continue;
733
+ }
734
+ memcpy(&calibration[table_index].values[value_index], slot,
735
+ sizeof(double));
736
+ if (!isfinite(calibration[table_index].values[value_index]) &&
737
+ !(strcmp(calibration[table_index].name, "fw") == 0 &&
738
+ value_index >= 5)) {
739
+ snprintf(candidate->error, sizeof(candidate->error),
740
+ "Flash %s[%zu] is not finite",
741
+ calibration[table_index].name, value_index);
742
+ return LIBUSB_ERROR_INVALID_PARAM;
743
+ }
744
+ }
745
+ }
746
+ candidate->flash_params_ok = 1;
747
+ candidate->flash_ok = 1;
748
+ return 0;
749
+ }
750
+
751
+ static int flash_double_equal(double first, double second) {
752
+ if (isnan(first) && isnan(second)) {
753
+ return 1;
754
+ }
755
+ return first == second;
756
+ }
757
+
758
+ static int flash_double_array_equal(const double *first, const double *second,
759
+ size_t count) {
760
+ for (size_t index = 0; index < count; ++index) {
761
+ if (!flash_double_equal(first[index], second[index])) {
762
+ return 0;
763
+ }
764
+ }
765
+ return 1;
766
+ }
767
+
768
+ static int flash_readout_equal(const camera_candidate_t *first,
769
+ const camera_candidate_t *second,
770
+ int compare_calibration) {
771
+ if (strcmp(first->device_type, second->device_type) != 0 ||
772
+ strcmp(first->side, second->side) != 0 ||
773
+ strcmp(first->flash_serial, second->flash_serial) != 0) {
774
+ return 0;
775
+ }
776
+ if (!compare_calibration) {
777
+ return 1;
778
+ }
779
+ return
780
+ strcmp(first->side, second->side) == 0 &&
781
+ strcmp(first->flash_serial, second->flash_serial) == 0 &&
782
+ flash_double_array_equal(first->fx_params, second->fx_params, 5) &&
783
+ flash_double_array_equal(first->fy_params, second->fy_params, 5) &&
784
+ flash_double_array_equal(first->fz_params, second->fz_params, 21) &&
785
+ flash_double_array_equal(first->ft_params, second->ft_params, 20) &&
786
+ flash_double_array_equal(first->fw_params, second->fw_params, 9);
787
+ }
788
+
789
+ static int read_flash_identity_verified(camera_candidate_t *candidate,
790
+ libusb_device_handle *handle,
791
+ int read_calibration) {
792
+ char last_error[MAX_TEXT] = "";
793
+ int last_result = LIBUSB_ERROR_IO;
794
+
795
+ for (int attempt = 0; attempt < FLASH_PROBE_ATTEMPTS; ++attempt) {
796
+ camera_candidate_t verified;
797
+ int result;
798
+
799
+ reset_flash_identity(candidate);
800
+ result = read_flash_identity_once(candidate, handle,
801
+ read_calibration);
802
+ if (result != 0) {
803
+ copy_text(last_error, sizeof(last_error), candidate->error);
804
+ last_result = result;
805
+ if (attempt + 1 < FLASH_PROBE_ATTEMPTS) {
806
+ sleep_for_probe((size_t)attempt);
807
+ }
808
+ continue;
809
+ }
810
+
811
+ /* A single XU6 transfer can complete while its small DMA/control
812
+ * state was disturbed by USB arbitration. Read the immutable tables
813
+ * into an independent structure and require bit-stable identity and
814
+ * calibration values before accepting them as complete. */
815
+ memset(&verified, 0, sizeof(verified));
816
+ verified.control_interface = candidate->control_interface;
817
+ result = read_flash_identity_once(&verified, handle,
818
+ read_calibration);
819
+ if (result == 0) {
820
+ if (flash_readout_equal(candidate, &verified,
821
+ read_calibration)) {
822
+ return 0;
823
+ }
824
+ snprintf(candidate->error, sizeof(candidate->error),
825
+ "Flash readback verification mismatch");
826
+ } else {
827
+ char message[MAX_TEXT + 40];
828
+ snprintf(message, sizeof(message),
829
+ "Flash readback verification: %s", verified.error);
830
+ copy_text(candidate->error, sizeof(candidate->error), message);
831
+ }
832
+ copy_text(last_error, sizeof(last_error), candidate->error);
833
+ last_result = result == 0 ? LIBUSB_ERROR_IO : result;
834
+ if (attempt + 1 < FLASH_PROBE_ATTEMPTS) {
835
+ sleep_for_probe((size_t)attempt);
836
+ }
837
+ }
838
+
839
+ candidate->error[0] = '\0';
840
+ copy_text(candidate->error, sizeof(candidate->error),
841
+ last_error[0] ? last_error : "Flash probe exhausted retries");
842
+ candidate->flash_ok = 0;
843
+ candidate->flash_params_ok = 0;
844
+ return last_result;
845
+ }
846
+
847
+ static int inspect_candidate(camera_candidate_t *candidate,
848
+ flash_mode_t flash_mode) {
849
+ const mode_profile_t *profile = profile_for(candidate->vid, candidate->pid);
850
+ if (candidate->usb_device == NULL) {
851
+ copy_text(candidate->error, sizeof(candidate->error),
852
+ "libusb device disappeared");
853
+ candidate->mode_ok = 0;
854
+ return -1;
855
+ }
856
+ candidate->control_interface = find_control_interface(candidate->usb_device);
857
+ if (candidate->control_interface < 0) {
858
+ snprintf(candidate->error, sizeof(candidate->error),
859
+ "control interface: %s", usb_error_text(candidate->control_interface));
860
+ candidate->mode_ok = 0;
861
+ return -1;
862
+ }
863
+ int descriptor_interface = -1;
864
+ int descriptor_alt = -1;
865
+ unsigned int descriptor_payload = 0;
866
+ int descriptor_result = find_stream_mode(
867
+ candidate->usb_device, profile->expected_altsetting,
868
+ (unsigned int)profile->forced_payload, &descriptor_interface,
869
+ &descriptor_alt, &descriptor_payload);
870
+ if (descriptor_result != 0) {
871
+ snprintf(candidate->error, sizeof(candidate->error),
872
+ "stream altsetting: %s", usb_error_text(descriptor_result));
873
+ candidate->mode_ok = 0;
874
+ return -1;
875
+ }
876
+ candidate->streaming_interface = descriptor_interface;
877
+ candidate->altsetting = descriptor_alt;
878
+ candidate->descriptor_payload = descriptor_payload;
879
+
880
+ uvc_device_handle_t *uvc_handle = NULL;
881
+ uvc_error_t uvc_result = uvc_open(candidate->uvc_device, &uvc_handle);
882
+ if (uvc_result != UVC_SUCCESS || uvc_handle == NULL) {
883
+ snprintf(candidate->error, sizeof(candidate->error),
884
+ "uvc_open: %s", uvc_strerror(uvc_result));
885
+ candidate->mode_ok = -1;
886
+ return -1;
887
+ }
888
+ candidate->opened_ok = 1;
889
+ libusb_device_handle *usb_handle = uvc_get_libusb_handle(uvc_handle);
890
+
891
+ uvc_stream_ctrl_t control;
892
+ memset(&control, 0, sizeof(control));
893
+ uvc_result = uvc_get_stream_ctrl_format_size(
894
+ uvc_handle, &control, UVC_FRAME_FORMAT_MJPEG,
895
+ profile->width, profile->height, profile->fps);
896
+ if (uvc_result != UVC_SUCCESS) {
897
+ snprintf(candidate->error, sizeof(candidate->error),
898
+ "MJPEG %dx%d@%d: %s", profile->width, profile->height,
899
+ profile->fps, uvc_strerror(uvc_result));
900
+ candidate->mode_ok = 0;
901
+ uvc_close(uvc_handle);
902
+ return -1;
903
+ }
904
+ candidate->streaming_interface = control.bInterfaceNumber;
905
+ candidate->negotiated_payload = control.dwMaxPayloadTransferSize;
906
+ candidate->mode_ok = candidate->altsetting == profile->expected_altsetting;
907
+ int result = 0;
908
+ if (!candidate->mode_ok) {
909
+ snprintf(candidate->error, sizeof(candidate->error),
910
+ "alt=%d expected=%d", candidate->altsetting,
911
+ profile->expected_altsetting);
912
+ uvc_close(uvc_handle);
913
+ return -1;
914
+ }
915
+ if ((flash_mode == FLASH_MODE_FULL ||
916
+ flash_mode == FLASH_MODE_IDENTITY) &&
917
+ candidate->vid == SIGHTAC_VID &&
918
+ candidate->pid == SIGHTAC_PID) {
919
+ result = read_flash_identity_verified(
920
+ candidate, usb_handle, flash_mode == FLASH_MODE_FULL);
921
+ if (result != 0) {
922
+ uvc_close(uvc_handle);
923
+ return -1;
924
+ }
925
+ }
926
+ uvc_close(uvc_handle);
927
+ return 0;
928
+ }
929
+
930
+ static int same_outer_parent(const camera_candidate_t *left,
931
+ const camera_candidate_t *right) {
932
+ char left_parent[MAX_PORT_PATH];
933
+ char right_parent[MAX_PORT_PATH];
934
+ const char *left_dot = strrchr(left->port, '.');
935
+ const char *right_dot = strrchr(right->port, '.');
936
+ if (left_dot == NULL || right_dot == NULL || left->bus != right->bus) {
937
+ return 0;
938
+ }
939
+ size_t left_size = (size_t)(left_dot - left->port);
940
+ size_t right_size = (size_t)(right_dot - right->port);
941
+ if (left_size == 0 || left_size >= sizeof(left_parent) ||
942
+ right_size == 0 || right_size >= sizeof(right_parent)) {
943
+ return 0;
944
+ }
945
+ memcpy(left_parent, left->port, left_size);
946
+ left_parent[left_size] = '\0';
947
+ memcpy(right_parent, right->port, right_size);
948
+ right_parent[right_size] = '\0';
949
+ return strcmp(left_parent, right_parent) == 0;
950
+ }
951
+
952
+ static int port_has_prefix(const char *port, const char *prefix) {
953
+ size_t prefix_size = strlen(prefix);
954
+ return strncmp(port, prefix, prefix_size) == 0 &&
955
+ port[prefix_size] == '.';
956
+ }
957
+
958
+ static int build_groups(const camera_candidate_t *candidates, size_t count,
959
+ camera_group_t *groups, size_t *group_count) {
960
+ int used[MAX_CANDIDATES] = {0};
961
+ size_t output_count = 0;
962
+ for (size_t i = 0; i < count; ++i) {
963
+ if (candidates[i].vid != SIGHTAC_VID || used[i]) {
964
+ continue;
965
+ }
966
+ int matches[2] = {-1, -1};
967
+ size_t match_count = 0;
968
+ for (size_t j = i; j < count; ++j) {
969
+ if (candidates[j].vid == SIGHTAC_VID &&
970
+ same_outer_parent(&candidates[i], &candidates[j])) {
971
+ if (match_count < 2) {
972
+ matches[match_count] = (int)j;
973
+ }
974
+ ++match_count;
975
+ }
976
+ }
977
+ if (match_count != 2) {
978
+ fprintf(stderr, "[DISCOVERY] ambiguous Sightac group bus=%d parent of %s: %zu node(s)\n",
979
+ candidates[i].bus, candidates[i].port, match_count);
980
+ continue;
981
+ }
982
+ char outer_path[MAX_PORT_PATH];
983
+ const char *dot = strrchr(candidates[matches[0]].port, '.');
984
+ size_t outer_size = (size_t)(dot - candidates[matches[0]].port);
985
+ if (outer_size == 0 || outer_size >= sizeof(outer_path)) {
986
+ continue;
987
+ }
988
+ memcpy(outer_path, candidates[matches[0]].port, outer_size);
989
+ outer_path[outer_size] = '\0';
990
+
991
+ int decxin = -1;
992
+ size_t decxin_count = 0;
993
+ for (size_t j = 0; j < count; ++j) {
994
+ if (candidates[j].vid == DECXIN_VID &&
995
+ candidates[j].pid == DECXIN_PID &&
996
+ candidates[j].bus == candidates[i].bus &&
997
+ port_has_prefix(candidates[j].port, outer_path)) {
998
+ decxin = (int)j;
999
+ ++decxin_count;
1000
+ }
1001
+ }
1002
+ if (decxin_count != 1 || output_count >= MAX_GROUPS) {
1003
+ fprintf(stderr, "[DISCOVERY] bus=%d outer=%s DECXIN match count=%zu; group rejected\n",
1004
+ candidates[i].bus, outer_path, decxin_count);
1005
+ continue;
1006
+ }
1007
+ groups[output_count].sightac[0] = matches[0];
1008
+ groups[output_count].sightac[1] = matches[1];
1009
+ groups[output_count].decxin = decxin;
1010
+ groups[output_count].bus = candidates[i].bus;
1011
+ copy_text(groups[output_count].outer_path,
1012
+ sizeof(groups[output_count].outer_path), outer_path);
1013
+ used[matches[0]] = 1;
1014
+ used[matches[1]] = 1;
1015
+ used[decxin] = 1;
1016
+ ++output_count;
1017
+ }
1018
+ *group_count = output_count;
1019
+ for (size_t i = 0; i < count; ++i) {
1020
+ if (!used[i]) {
1021
+ fprintf(stderr, "[DISCOVERY] ungrouped %s %04x:%04x bus=%d port=%s\n",
1022
+ profile_for(candidates[i].vid, candidates[i].pid)->kind,
1023
+ candidates[i].vid, candidates[i].pid, candidates[i].bus,
1024
+ candidates[i].port);
1025
+ }
1026
+ }
1027
+ return output_count > 0 ? 0 : -1;
1028
+ }
1029
+
1030
+ static const camera_candidate_t *candidate_by_side(
1031
+ const camera_candidate_t *candidates, const camera_group_t *group,
1032
+ const char *side) {
1033
+ for (size_t i = 0; i < 2; ++i) {
1034
+ const camera_candidate_t *candidate = &candidates[group->sightac[i]];
1035
+ if (strcmp(candidate->side, side) == 0) {
1036
+ return candidate;
1037
+ }
1038
+ }
1039
+ return NULL;
1040
+ }
1041
+
1042
+ static int group_sides_ok(const camera_candidate_t *candidates,
1043
+ const camera_group_t *group,
1044
+ int require_calibration) {
1045
+ const camera_candidate_t *left = candidate_by_side(candidates, group, "left");
1046
+ const camera_candidate_t *right = candidate_by_side(candidates, group, "right");
1047
+ const camera_candidate_t *decxin = &candidates[group->decxin];
1048
+ return left != NULL && right != NULL && left != right &&
1049
+ candidates[group->sightac[0]].flash_ok &&
1050
+ candidates[group->sightac[1]].flash_ok &&
1051
+ (!require_calibration ||
1052
+ (candidates[group->sightac[0]].flash_params_ok &&
1053
+ candidates[group->sightac[1]].flash_params_ok)) &&
1054
+ left->mode_ok > 0 && right->mode_ok > 0 &&
1055
+ decxin->mode_ok > 0;
1056
+ }
1057
+
1058
+ static void print_candidate(const camera_candidate_t *candidate,
1059
+ flash_mode_t flash_mode) {
1060
+ const mode_profile_t *profile = profile_for(candidate->vid, candidate->pid);
1061
+ const char *mode_status = candidate->mode_ok > 0 ? "ok" :
1062
+ (candidate->mode_ok < 0 ? "unknown" : "failed");
1063
+ fprintf(stderr,
1064
+ "[DISCOVERY] %-7s vidpid=%04x:%04x bus=%d port=%s usb_serial=%s "
1065
+ "control_if=%d stream_if=%d alt=%d descriptor_payload=%u "
1066
+ "negotiated_payload=%u mode=%s",
1067
+ profile->kind, candidate->vid, candidate->pid, candidate->bus,
1068
+ candidate->port, candidate->usb_serial[0] ? candidate->usb_serial : "<none>",
1069
+ candidate->control_interface, candidate->streaming_interface,
1070
+ candidate->altsetting, candidate->descriptor_payload,
1071
+ candidate->negotiated_payload, mode_status);
1072
+ if (candidate->vid == SIGHTAC_VID &&
1073
+ (flash_mode == FLASH_MODE_FULL ||
1074
+ flash_mode == FLASH_MODE_IDENTITY)) {
1075
+ const char *calibration = flash_mode == FLASH_MODE_IDENTITY
1076
+ ? "skipped"
1077
+ : (candidate->flash_params_ok
1078
+ ? "ok" : "failed");
1079
+ fprintf(stderr, " flash=%s calibration=%s side=%s serial=%s type=%s",
1080
+ candidate->flash_ok ? "ok" : "failed",
1081
+ calibration,
1082
+ candidate->side[0] ? candidate->side : "<none>",
1083
+ candidate->flash_serial[0] ? candidate->flash_serial : "<none>",
1084
+ candidate->device_type[0] ? candidate->device_type : "<none>");
1085
+ }
1086
+ if (candidate->error[0]) {
1087
+ fprintf(stderr, " error=%s", candidate->error);
1088
+ }
1089
+ fputc('\n', stderr);
1090
+ }
1091
+
1092
+ static void write_json_candidate(FILE *out,
1093
+ const camera_candidate_t *candidate,
1094
+ int include_flash,
1095
+ int include_calibration) {
1096
+ const mode_profile_t *profile = profile_for(candidate->vid, candidate->pid);
1097
+ fprintf(out,
1098
+ "{\"kind\":");
1099
+ write_json_string(out, profile->kind);
1100
+ fprintf(out,
1101
+ ",\"vid\":%d,\"pid\":%d,\"bus\":%d,\"port\":",
1102
+ candidate->vid, candidate->pid, candidate->bus);
1103
+ write_json_string(out, candidate->port);
1104
+ fprintf(out,
1105
+ ",\"usb_serial\":");
1106
+ write_json_string(out, candidate->usb_serial);
1107
+ fprintf(out,
1108
+ ",\"control_interface\":%d,\"streaming_interface\":%d,"
1109
+ "\"altsetting\":%d,\"descriptor_payload\":%u,"
1110
+ "\"negotiated_payload\":%u,\"mode_ok\":%s",
1111
+ candidate->control_interface, candidate->streaming_interface,
1112
+ candidate->altsetting, candidate->descriptor_payload,
1113
+ candidate->negotiated_payload,
1114
+ candidate->mode_ok > 0 ? "true" : "false");
1115
+ if (include_flash) {
1116
+ fprintf(out, ",\"flash_ok\":%s,\"flash_params_ok\":%s,\"side\":",
1117
+ candidate->flash_ok ? "true" : "false",
1118
+ candidate->flash_params_ok ? "true" : "false");
1119
+ write_json_string(out, candidate->side);
1120
+ fprintf(out, ",\"flash_serial\":");
1121
+ write_json_string(out, candidate->flash_serial);
1122
+ fprintf(out, ",\"device_type\":");
1123
+ write_json_string(out, candidate->device_type);
1124
+ if (!include_calibration) {
1125
+ goto candidate_error;
1126
+ }
1127
+ fprintf(out, ",\"flash_params\":{\"device_type\":");
1128
+ write_json_string(out, candidate->device_type);
1129
+ fprintf(out, ",\"fx_params\":[");
1130
+ for (size_t i = 0; i < 5; ++i) {
1131
+ if (i != 0) fputc(',', out);
1132
+ fprintf(out, "%.17g", candidate->fx_params[i]);
1133
+ }
1134
+ fprintf(out, "],\"fy_params\":[");
1135
+ for (size_t i = 0; i < 5; ++i) {
1136
+ if (i != 0) fputc(',', out);
1137
+ fprintf(out, "%.17g", candidate->fy_params[i]);
1138
+ }
1139
+ fprintf(out, "],\"fz_params\":[");
1140
+ for (size_t i = 0; i < 21; ++i) {
1141
+ if (i != 0) fputc(',', out);
1142
+ fprintf(out, "%.17g", candidate->fz_params[i]);
1143
+ }
1144
+ fprintf(out, "],\"ft_params\":[");
1145
+ for (size_t i = 0; i < 20; ++i) {
1146
+ if (i != 0) fputc(',', out);
1147
+ fprintf(out, "%.17g", candidate->ft_params[i]);
1148
+ }
1149
+ fprintf(out, "],\"fw_params\":[");
1150
+ for (size_t i = 0; i < 9; ++i) {
1151
+ if (i != 0) fputc(',', out);
1152
+ if (isfinite(candidate->fw_params[i])) {
1153
+ fprintf(out, "%.17g", candidate->fw_params[i]);
1154
+ } else {
1155
+ /* The bevel firmware reserves fw[5..8]; current ROI/line
1156
+ * code consumes only fw[0..4]. Keep the JSON valid. */
1157
+ fputs("null", out);
1158
+ }
1159
+ }
1160
+ fprintf(out, "],\"flash_state\":\"programmed\","
1161
+ "\"calibration_source\":\"hardware\"}");
1162
+ }
1163
+ candidate_error:
1164
+ fprintf(out, ",\"error\":");
1165
+ write_json_string(out, candidate->error);
1166
+ fputc('}', out);
1167
+ }
1168
+
1169
+ static void write_camera_section(FILE *out, const camera_candidate_t *candidate,
1170
+ int group_number, const char *name,
1171
+ const char *socket_name) {
1172
+ const mode_profile_t *profile = profile_for(candidate->vid, candidate->pid);
1173
+ fprintf(out,
1174
+ "[%s]\n"
1175
+ "vid=0x%04x\n"
1176
+ "pid=0x%04x\n"
1177
+ "usb_bus=%d\n"
1178
+ "usb_port_path=%s\n"
1179
+ "streaming_interface=%d\n"
1180
+ "forced_altsetting=%d\n"
1181
+ "forced_payload=%d\n"
1182
+ "width=%d\n"
1183
+ "height=%d\n"
1184
+ "fps=%d\n"
1185
+ "format=MJPEG\n"
1186
+ "socket_path=/tmp/ksq-camera-service-unit-%d-%s.sock\n\n",
1187
+ name, candidate->vid, candidate->pid, candidate->bus, candidate->port,
1188
+ candidate->streaming_interface, candidate->altsetting,
1189
+ profile->forced_payload, profile->width, profile->height,
1190
+ profile->fps, group_number, socket_name);
1191
+ }
1192
+
1193
+ static int write_generated_config(FILE *out, const camera_candidate_t *candidates,
1194
+ const camera_group_t *groups,
1195
+ size_t group_count) {
1196
+ for (size_t index = 0; index < group_count; ++index) {
1197
+ if (!group_sides_ok(candidates, &groups[index], 1)) {
1198
+ fprintf(stderr, "[DISCOVERY] group %zu rejected: mode or left/right Flash identity is incomplete\n",
1199
+ index + 1);
1200
+ return -1;
1201
+ }
1202
+ }
1203
+ fprintf(out,
1204
+ "# Generated by discover-uvc-config.\n"
1205
+ "# Scope: Sightac + DECXIN only; Fays is intentionally excluded.\n"
1206
+ "# Bus/port/interface/alt are from the current libusb/libuvc scan.\n\n");
1207
+ for (size_t index = 0; index < group_count; ++index) {
1208
+ const camera_candidate_t *left =
1209
+ candidate_by_side(candidates, &groups[index], "left");
1210
+ const camera_candidate_t *right =
1211
+ candidate_by_side(candidates, &groups[index], "right");
1212
+ const camera_candidate_t *decxin = &candidates[groups[index].decxin];
1213
+ char name[64];
1214
+ snprintf(name, sizeof(name), "unit_%zu_sightac_left", index + 1);
1215
+ write_camera_section(out, left, (int)(index + 1), name,
1216
+ "sightac-left");
1217
+ snprintf(name, sizeof(name), "unit_%zu_sightac_right", index + 1);
1218
+ write_camera_section(out, right, (int)(index + 1), name,
1219
+ "sightac-right");
1220
+ snprintf(name, sizeof(name), "unit_%zu_decxin", index + 1);
1221
+ write_camera_section(out, decxin, (int)(index + 1), name, "decxin");
1222
+ }
1223
+ return 0;
1224
+ }
1225
+
1226
+ static int write_json_report(FILE *out, const camera_candidate_t *candidates,
1227
+ const camera_group_t *groups, size_t group_count,
1228
+ flash_mode_t flash_mode) {
1229
+ const int include_flash = flash_mode == FLASH_MODE_FULL ||
1230
+ flash_mode == FLASH_MODE_IDENTITY;
1231
+ const int include_calibration = flash_mode == FLASH_MODE_FULL;
1232
+ const int require_calibration = flash_mode == FLASH_MODE_FULL;
1233
+ fprintf(out, "{\"groups\":[");
1234
+ for (size_t index = 0; index < group_count; ++index) {
1235
+ const camera_group_t *group = &groups[index];
1236
+ if (index != 0) {
1237
+ fputc(',', out);
1238
+ }
1239
+ fprintf(out, "{\"bus\":%d,\"outer_path\":", group->bus);
1240
+ write_json_string(out, group->outer_path);
1241
+ fprintf(out, ",\"sightac\":[");
1242
+ write_json_candidate(out, &candidates[group->sightac[0]],
1243
+ include_flash, include_calibration);
1244
+ fputc(',', out);
1245
+ write_json_candidate(out, &candidates[group->sightac[1]],
1246
+ include_flash, include_calibration);
1247
+ fprintf(out, "],\"decxin\":");
1248
+ write_json_candidate(out, &candidates[group->decxin], 0, 0);
1249
+ fprintf(out, ",\"valid\":%s}",
1250
+ group_sides_ok(candidates, group,
1251
+ require_calibration) ? "true" : "false");
1252
+ }
1253
+ fprintf(out, "]}\n");
1254
+ return ferror(out) ? -1 : 0;
1255
+ }
1256
+
1257
+ static void print_usage(const char *program) {
1258
+ fprintf(stderr,
1259
+ "usage: %s [--emit-config PATH] [--json] [--skip-flash|--identity-only|--topology-only] [--bus N --port-prefix P]\n"
1260
+ " default: scan Sightac/DECXIN and read Sightac Flash side/serial\n"
1261
+ " --emit-config PATH: write a generated camera-service INI\n"
1262
+ " --json: write machine-readable UVC groups to stdout\n"
1263
+ " --skip-flash: topology/mode report only; never emits a usable INI\n"
1264
+ " --identity-only: read Flash side/serial without calibration tables\n"
1265
+ " --topology-only: USB topology only; does not open UVC streams\n"
1266
+ " --bus N --port-prefix P: inspect only this physical USB group\n",
1267
+ program);
1268
+ }
1269
+
1270
+ int main(int argc, char **argv) {
1271
+ const char *config_path = NULL;
1272
+ int json_output = 0;
1273
+ flash_mode_t flash_mode = FLASH_MODE_FULL;
1274
+ int only_bus = -1;
1275
+ const char *only_port = NULL;
1276
+ for (int index = 1; index < argc; ++index) {
1277
+ if (strcmp(argv[index], "--emit-config") == 0 && index + 1 < argc) {
1278
+ config_path = argv[++index];
1279
+ } else if (strcmp(argv[index], "--bus") == 0 && index + 1 < argc) {
1280
+ const char *value = argv[++index];
1281
+ if (!*value || strlen(value) > 3 || strspn(value, "0123456789") != strlen(value)) return 2;
1282
+ only_bus = atoi(value);
1283
+ if (only_bus <= 0 || only_bus > 255) return 2;
1284
+ } else if (strcmp(argv[index], "--port-prefix") == 0 && index + 1 < argc) {
1285
+ only_port = argv[++index];
1286
+ if (!*only_port || strspn(only_port, "0123456789.") != strlen(only_port)) return 2;
1287
+ } else if (strcmp(argv[index], "--json") == 0) {
1288
+ json_output = 1;
1289
+ } else if (strcmp(argv[index], "--skip-flash") == 0) {
1290
+ flash_mode = FLASH_MODE_NONE;
1291
+ } else if (strcmp(argv[index], "--identity-only") == 0) {
1292
+ flash_mode = FLASH_MODE_IDENTITY;
1293
+ } else if (strcmp(argv[index], "--topology-only") == 0) {
1294
+ flash_mode = FLASH_MODE_TOPOLOGY_ONLY;
1295
+ } else {
1296
+ print_usage(argv[0]);
1297
+ return 2;
1298
+ }
1299
+ }
1300
+
1301
+ if ((only_bus > 0) != (only_port != NULL)) return 2;
1302
+
1303
+ uvc_context_t *uvc_context = NULL;
1304
+ uvc_error_t uvc_result = uvc_init(&uvc_context, NULL);
1305
+ if (uvc_result != UVC_SUCCESS) {
1306
+ fprintf(stderr, "[DISCOVERY] uvc_init failed: %s\n",
1307
+ uvc_strerror(uvc_result));
1308
+ return 1;
1309
+ }
1310
+ uvc_device_t **devices = NULL;
1311
+ uvc_result = uvc_get_device_list(uvc_context, &devices);
1312
+ if (uvc_result != UVC_SUCCESS) {
1313
+ fprintf(stderr, "[DISCOVERY] uvc_get_device_list failed: %s\n",
1314
+ uvc_strerror(uvc_result));
1315
+ uvc_exit(uvc_context);
1316
+ return 1;
1317
+ }
1318
+ libusb_context *usb_context = NULL;
1319
+ int usb_result = libusb_init(&usb_context);
1320
+ if (usb_result != 0) {
1321
+ fprintf(stderr, "[DISCOVERY] libusb_init failed: %s\n",
1322
+ usb_error_text(usb_result));
1323
+ uvc_free_device_list(devices, 1);
1324
+ uvc_exit(uvc_context);
1325
+ return 1;
1326
+ }
1327
+ libusb_device **raw_devices = NULL;
1328
+ ssize_t raw_count = libusb_get_device_list(usb_context, &raw_devices);
1329
+ if (raw_count < 0) {
1330
+ fprintf(stderr, "[DISCOVERY] libusb_get_device_list failed: %s\n",
1331
+ usb_error_text((int)raw_count));
1332
+ libusb_exit(usb_context);
1333
+ uvc_free_device_list(devices, 1);
1334
+ uvc_exit(uvc_context);
1335
+ return 1;
1336
+ }
1337
+
1338
+ camera_candidate_t candidates[MAX_CANDIDATES];
1339
+ memset(candidates, 0, sizeof(candidates));
1340
+ size_t candidate_count = 0;
1341
+ for (size_t index = 0; devices[index] != NULL; ++index) {
1342
+ /* Filter physical scope BEFORE descriptors/Flash/open operations.
1343
+ * A second rig must never open cameras already streaming for the first. */
1344
+ if (only_port) {
1345
+ char port[MAX_TEXT] = {0};
1346
+ size_t length = strlen(only_port);
1347
+ if ((int)uvc_get_bus_number(devices[index]) != only_bus ||
1348
+ format_uvc_port_path(devices[index], port, sizeof(port)) != 0 ||
1349
+ strncmp(port, only_port, length) != 0 ||
1350
+ (port[length] != '\0' && port[length] != '.')) continue;
1351
+ }
1352
+ uvc_device_descriptor_t *descriptor = NULL;
1353
+ if (uvc_get_device_descriptor(devices[index], &descriptor) != UVC_SUCCESS ||
1354
+ descriptor == NULL) {
1355
+ continue;
1356
+ }
1357
+ const mode_profile_t *profile =
1358
+ profile_for(descriptor->idVendor, descriptor->idProduct);
1359
+ if (profile == NULL || candidate_count >= MAX_CANDIDATES) {
1360
+ uvc_free_device_descriptor(descriptor);
1361
+ continue;
1362
+ }
1363
+ camera_candidate_t *candidate = &candidates[candidate_count++];
1364
+ candidate->uvc_device = devices[index];
1365
+ candidate->control_interface = -1;
1366
+ candidate->streaming_interface = -1;
1367
+ candidate->altsetting = -1;
1368
+ candidate->mode_ok = -1;
1369
+ candidate->vid = descriptor->idVendor;
1370
+ candidate->pid = descriptor->idProduct;
1371
+ copy_text(candidate->usb_serial, sizeof(candidate->usb_serial),
1372
+ descriptor->serialNumber);
1373
+ if (format_uvc_port_path(devices[index], candidate->port,
1374
+ sizeof(candidate->port)) != 0) {
1375
+ copy_text(candidate->error, sizeof(candidate->error),
1376
+ "cannot read USB port path");
1377
+ }
1378
+ candidate->bus = uvc_get_bus_number(devices[index]);
1379
+ candidate->usb_device = find_raw_device(
1380
+ raw_devices, raw_count, candidate->vid, candidate->pid,
1381
+ candidate->bus, candidate->port);
1382
+ int status = 0;
1383
+ if (flash_mode != FLASH_MODE_TOPOLOGY_ONLY) {
1384
+ status = inspect_candidate(candidate, flash_mode);
1385
+ }
1386
+ if (status != 0 && candidate->error[0] == '\0') {
1387
+ copy_text(candidate->error, sizeof(candidate->error), "inspection failed");
1388
+ }
1389
+ print_candidate(candidate, flash_mode);
1390
+ uvc_free_device_descriptor(descriptor);
1391
+ }
1392
+
1393
+ camera_group_t groups[MAX_GROUPS];
1394
+ memset(groups, 0, sizeof(groups));
1395
+ size_t group_count = 0;
1396
+ if (candidate_count == 0 ||
1397
+ build_groups(candidates, candidate_count, groups, &group_count) != 0) {
1398
+ fprintf(stderr, "[DISCOVERY] no complete Sightac + DECXIN topology group\n");
1399
+ libusb_free_device_list(raw_devices, 1);
1400
+ libusb_exit(usb_context);
1401
+ uvc_free_device_list(devices, 1);
1402
+ uvc_exit(uvc_context);
1403
+ return 3;
1404
+ }
1405
+ fprintf(stderr, "[DISCOVERY] complete group(s)=%zu\n", group_count);
1406
+
1407
+ int result = 0;
1408
+ if (config_path != NULL && json_output) {
1409
+ fprintf(stderr, "[DISCOVERY] refusing --emit-config with --json\n");
1410
+ result = 2;
1411
+ } else if (json_output) {
1412
+ if (write_json_report(stdout, candidates, groups, group_count,
1413
+ flash_mode) != 0) {
1414
+ result = 1;
1415
+ }
1416
+ } else if (config_path != NULL) {
1417
+ if (flash_mode != FLASH_MODE_FULL) {
1418
+ fprintf(stderr, "[DISCOVERY] refusing --emit-config without full Flash mode\n");
1419
+ result = 2;
1420
+ } else {
1421
+ char temporary_path[PATH_MAX];
1422
+ int path_result = snprintf(temporary_path, sizeof(temporary_path),
1423
+ "%s.tmp.%ld", config_path,
1424
+ (long)getpid());
1425
+ if (path_result < 0 || (size_t)path_result >= sizeof(temporary_path)) {
1426
+ fprintf(stderr, "[DISCOVERY] config path is too long: %s\n",
1427
+ config_path);
1428
+ result = 1;
1429
+ goto cleanup;
1430
+ }
1431
+ FILE *out = fopen(temporary_path, "w");
1432
+ if (out == NULL) {
1433
+ fprintf(stderr, "[DISCOVERY] cannot write %s: %s\n",
1434
+ config_path, strerror(errno));
1435
+ result = 1;
1436
+ } else {
1437
+ int write_result = write_generated_config(
1438
+ out, candidates, groups, group_count);
1439
+ int close_result = fclose(out);
1440
+ if (write_result != 0 || close_result != 0 ||
1441
+ rename(temporary_path, config_path) != 0) {
1442
+ fprintf(stderr, "[DISCOVERY] failed to generate %s\n",
1443
+ config_path);
1444
+ unlink(temporary_path);
1445
+ result = 1;
1446
+ } else {
1447
+ fprintf(stderr, "[DISCOVERY] generated config: %s\n",
1448
+ config_path);
1449
+ }
1450
+ }
1451
+ }
1452
+ } else if (flash_mode == FLASH_MODE_FULL) {
1453
+ if (write_generated_config(stdout, candidates, groups, group_count) != 0) {
1454
+ result = 1;
1455
+ }
1456
+ }
1457
+ cleanup:
1458
+ libusb_free_device_list(raw_devices, 1);
1459
+ libusb_exit(usb_context);
1460
+ uvc_free_device_list(devices, 1);
1461
+ uvc_exit(uvc_context);
1462
+ return result;
1463
+ }
collector/core/gripper/camera_service_src/tools/sonix_flash_probe.c ADDED
@@ -0,0 +1,618 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Read-only Sonix XU/Serial-Flash probe.
3
+ *
4
+ * This is the libusb equivalent of the source SDK's
5
+ * UVCIOC_CTRL_QUERY(UVC_SET_CUR/UVC_GET_CUR) path. It never issues a
6
+ * serial-flash write or erase command. The SET_CUR requests below only set
7
+ * the address for the following read, exactly as XU_ReadDataFormFlash().
8
+ */
9
+ #include <libusb-1.0/libusb.h>
10
+
11
+ #include <ctype.h>
12
+ #include <errno.h>
13
+ #include <math.h>
14
+ #include <stdint.h>
15
+ #include <stdio.h>
16
+ #include <stdlib.h>
17
+ #include <string.h>
18
+
19
+ #define SONIX_VID 0x0c45
20
+ #define SONIX_PID 0x636f
21
+ #define XU_GET_CUR 0x81
22
+ #define XU_SET_CUR 0x01
23
+ #define XU_CTRL_GET 0xa1
24
+ #define XU_CTRL_SET 0x21
25
+ #define XU_ASIC_SELECTOR 0x01
26
+ #define XU_FLASH_SELECTOR 0x03
27
+ #define XU_FLASH_XU6_SELECTOR 0x06
28
+ #define CTRL_TIMEOUT_MS 2000
29
+ #define FLASH_MAX_ADDRESS 0x4ffff
30
+ #define SF_XU64_EU_ADDR 0x335
31
+ #define SF_XU64_RW_START_ADDR 0x337
32
+ #define SF_XU64_RW_END_ADDR 0x33b
33
+
34
+ static void print_hex(const uint8_t *data, size_t length) {
35
+ for (size_t i = 0; i < length; ++i) {
36
+ printf("%02x%s", data[i], (i + 1 == length) ? "" : " ");
37
+ }
38
+ }
39
+
40
+ static void print_ascii(const uint8_t *data, size_t length) {
41
+ putchar('"');
42
+ for (size_t i = 0; i < length; ++i) {
43
+ putchar(isprint(data[i]) ? (int)data[i] : '.');
44
+ }
45
+ puts("\"");
46
+ }
47
+
48
+ static int port_path(libusb_device *device, char *out, size_t out_size) {
49
+ uint8_t ports[8];
50
+ int count = libusb_get_port_numbers(device, ports, sizeof(ports));
51
+ size_t used = 0;
52
+ if (count < 0) {
53
+ return count;
54
+ }
55
+ out[0] = '\0';
56
+ for (int i = 0; i < count; ++i) {
57
+ int written = snprintf(out + used, out_size - used, "%s%u",
58
+ i == 0 ? "" : ".", ports[i]);
59
+ if (written < 0 || (size_t)written >= out_size - used) {
60
+ return LIBUSB_ERROR_OVERFLOW;
61
+ }
62
+ used += (size_t)written;
63
+ }
64
+ return 0;
65
+ }
66
+
67
+ static int control_interface(libusb_device *device) {
68
+ struct libusb_config_descriptor *config = NULL;
69
+ int result = libusb_get_active_config_descriptor(device, &config);
70
+ if (result != 0) {
71
+ return result;
72
+ }
73
+ int found = LIBUSB_ERROR_NOT_FOUND;
74
+ for (int i = 0; i < config->bNumInterfaces && found < 0; ++i) {
75
+ for (int j = 0; j < config->interface[i].num_altsetting; ++j) {
76
+ const struct libusb_interface_descriptor *alt =
77
+ &config->interface[i].altsetting[j];
78
+ if (alt->bInterfaceClass == LIBUSB_CLASS_VIDEO &&
79
+ alt->bInterfaceSubClass == 1) {
80
+ found = alt->bInterfaceNumber;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ libusb_free_config_descriptor(config);
86
+ return found;
87
+ }
88
+
89
+ static int xu_control(libusb_device_handle *handle, int interface_number,
90
+ uint8_t unit, uint8_t selector, int get,
91
+ uint8_t *data, uint16_t size) {
92
+ uint8_t request_type = get ? XU_CTRL_GET : XU_CTRL_SET;
93
+ uint8_t request = get ? XU_GET_CUR : XU_SET_CUR;
94
+ uint16_t value = (uint16_t)selector << 8;
95
+ uint16_t index = ((uint16_t)unit << 8) | (uint16_t)interface_number;
96
+ return libusb_control_transfer(handle, request_type, request, value, index,
97
+ data, size, CTRL_TIMEOUT_MS);
98
+ }
99
+
100
+ static int asic_read(libusb_device_handle *handle, int interface_number,
101
+ uint8_t unit, uint16_t address, uint8_t *value) {
102
+ uint8_t data[4] = {
103
+ (uint8_t)(address & 0xff), (uint8_t)(address >> 8), 0, 0xff
104
+ };
105
+ int result = xu_control(handle, interface_number, unit, XU_ASIC_SELECTOR,
106
+ 0, data, sizeof(data));
107
+ if (result != (int)sizeof(data)) {
108
+ return result < 0 ? result : LIBUSB_ERROR_IO;
109
+ }
110
+ data[3] = 0;
111
+ result = xu_control(handle, interface_number, unit, XU_ASIC_SELECTOR,
112
+ 1, data, sizeof(data));
113
+ if (result != (int)sizeof(data)) {
114
+ return result < 0 ? result : LIBUSB_ERROR_IO;
115
+ }
116
+ *value = data[2];
117
+ return 0;
118
+ }
119
+
120
+ static int asic_write(libusb_device_handle *handle, int interface_number,
121
+ uint8_t unit, uint16_t address, uint8_t value) {
122
+ uint8_t data[4] = {
123
+ (uint8_t)(address & 0xff), (uint8_t)(address >> 8), value, 0
124
+ };
125
+ int result = xu_control(handle, interface_number, unit, XU_ASIC_SELECTOR,
126
+ 0, data, sizeof(data));
127
+ if (result != (int)sizeof(data)) {
128
+ return result < 0 ? result : LIBUSB_ERROR_IO;
129
+ }
130
+ return 0;
131
+ }
132
+
133
+ static int sf_xu6_write_config(libusb_device_handle *handle,
134
+ int interface_number, uint8_t unit,
135
+ uint32_t start_address, uint32_t data_size,
136
+ uint8_t buffer_size) {
137
+ /* This is the packed XU6Data structure used by SetReadInfo_SFXU6(). */
138
+ uint8_t data[64] = {0};
139
+ data[0] = (uint8_t)(start_address & 0xff);
140
+ data[1] = (uint8_t)((start_address >> 8) & 0xff);
141
+ data[2] = (uint8_t)((start_address >> 16) & 0xff);
142
+ data[3] = (uint8_t)((start_address >> 24) & 0xff);
143
+ data[4] = 2u << 6; /* dummy write */
144
+ data[5] = buffer_size;
145
+ uint32_t end_address = start_address + data_size;
146
+ data[6] = (uint8_t)(end_address & 0xff);
147
+ data[7] = (uint8_t)((end_address >> 8) & 0xff);
148
+ data[8] = (uint8_t)((end_address >> 16) & 0xff);
149
+ data[9] = (uint8_t)((end_address >> 24) & 0xff);
150
+ data[10] = 0x0b; /* SDK default read command */
151
+ data[11] = 0x01; /* SF output mode */
152
+ int result = xu_control(handle, interface_number, unit,
153
+ XU_FLASH_XU6_SELECTOR, 0, data, sizeof(data));
154
+ if (result != (int)sizeof(data)) {
155
+ return result < 0 ? result : LIBUSB_ERROR_IO;
156
+ }
157
+ return 0;
158
+ }
159
+
160
+ static int sf_xu6_stop(libusb_device_handle *handle, int interface_number,
161
+ uint8_t unit) {
162
+ int result;
163
+ for (uint16_t i = 0; i < 4; ++i) {
164
+ result = asic_write(handle, interface_number, unit,
165
+ SF_XU64_RW_START_ADDR + i, 0);
166
+ if (result != 0) {
167
+ return result;
168
+ }
169
+ result = asic_write(handle, interface_number, unit,
170
+ SF_XU64_RW_END_ADDR + i, 0);
171
+ if (result != 0) {
172
+ return result;
173
+ }
174
+ }
175
+ return asic_write(handle, interface_number, unit, SF_XU64_EU_ADDR, 0);
176
+ }
177
+
178
+ static int sf_xu6_read_block(libusb_device_handle *handle, int interface_number,
179
+ uint8_t unit, uint32_t address, uint8_t *out,
180
+ uint8_t length) {
181
+ if (length == 0 || length > 64 || address > FLASH_MAX_ADDRESS ||
182
+ address + length < address) {
183
+ return LIBUSB_ERROR_INVALID_PARAM;
184
+ }
185
+ int result = sf_xu6_stop(handle, interface_number, unit);
186
+ if (result != 0) {
187
+ return result;
188
+ }
189
+ result = sf_xu6_write_config(handle, interface_number, unit, address,
190
+ length, length);
191
+ if (result != 0) {
192
+ return result;
193
+ }
194
+ uint8_t data[64] = {0};
195
+ result = xu_control(handle, interface_number, unit,
196
+ XU_FLASH_XU6_SELECTOR, 1, data, sizeof(data));
197
+ if (result != (int)sizeof(data)) {
198
+ return result < 0 ? result : LIBUSB_ERROR_IO;
199
+ }
200
+ memcpy(out, data, length);
201
+ return 0;
202
+ }
203
+
204
+ static int sf_xu6_read(libusb_device_handle *handle, int interface_number,
205
+ uint8_t unit, uint32_t address, uint8_t *out,
206
+ size_t length) {
207
+ while (length > 0) {
208
+ uint8_t chunk = length > 64 ? 64 : (uint8_t)length;
209
+ int result = sf_xu6_read_block(handle, interface_number, unit, address,
210
+ out, chunk);
211
+ if (result != 0) {
212
+ return result;
213
+ }
214
+ address += chunk;
215
+ out += chunk;
216
+ length -= chunk;
217
+ }
218
+ return 0;
219
+ }
220
+
221
+ static int sf_xu6_prepare_290(libusb_device_handle *handle,
222
+ int interface_number, uint8_t unit) {
223
+ /* SetSFControllerSCK() for ROM290 in the vendor source. */
224
+ int result = asic_write(handle, interface_number, unit, 0x8045, 10);
225
+ if (result != 0) {
226
+ return result;
227
+ }
228
+ return asic_write(handle, interface_number, unit, 0x8e10, 1);
229
+ }
230
+
231
+ static int known_chip(uint8_t chip) {
232
+ switch (chip) {
233
+ case 0x15: case 0x16: case 0x22: case 0x23: case 0x25:
234
+ case 0x32: case 0x33: case 0x56: case 0x70: case 0x71:
235
+ case 0x75: case 0x76: case 0x83: case 0x85: case 0x86:
236
+ case 0x87: case 0x88: case 0x89: case 0x90: case 0x92:
237
+ case 0x98: case 0x99:
238
+ return 1;
239
+ default:
240
+ return 0;
241
+ }
242
+ }
243
+
244
+ static int find_xu_unit(libusb_device_handle *handle, int interface_number,
245
+ uint8_t *unit, uint8_t *chip) {
246
+ /* The vendor source deliberately probes units 3 and 4 in this order. */
247
+ for (uint8_t candidate = 3; candidate <= 4; ++candidate) {
248
+ uint8_t value = 0;
249
+ uint8_t raw[4] = {
250
+ 0x1f, 0x10, 0, 0xff
251
+ };
252
+ int set_result = xu_control(handle, interface_number, candidate,
253
+ XU_ASIC_SELECTOR, 0, raw, sizeof(raw));
254
+ int get_result = -1;
255
+ if (set_result == (int)sizeof(raw)) {
256
+ raw[3] = 0;
257
+ get_result = xu_control(handle, interface_number, candidate,
258
+ XU_ASIC_SELECTOR, 1, raw, sizeof(raw));
259
+ if (get_result == (int)sizeof(raw)) {
260
+ value = raw[2];
261
+ }
262
+ }
263
+ fprintf(stderr, " xu_probe unit=%u set=%d get=%d data=",
264
+ candidate, set_result, get_result);
265
+ print_hex(raw, sizeof(raw));
266
+ fputc('\n', stderr);
267
+ if (value == 0xaa && get_result == (int)sizeof(raw)) {
268
+ uint8_t id80f0 = 0, id80f1 = 0, id80f3 = 0;
269
+ int r0 = asic_read(handle, interface_number, candidate, 0x80f0,
270
+ &id80f0);
271
+ int r1 = asic_read(handle, interface_number, candidate, 0x80f1,
272
+ &id80f1);
273
+ int r3 = asic_read(handle, interface_number, candidate, 0x80f3,
274
+ &id80f3);
275
+ fprintf(stderr, " xu_probe fallback 80f0=%02x(%d) 80f1=%02x(%d) "
276
+ "80f3=%02x(%d)\n",
277
+ id80f0, r0, id80f1, r1, id80f3, r3);
278
+ if (r0 == 0 && r1 == 0 && r3 == 0 &&
279
+ (known_chip(id80f0) ||
280
+ (id80f0 == 0x00 && id80f1 == 0x02 && id80f3 == 0x24) ||
281
+ (id80f0 == 0x01 && id80f1 == 0x02 && id80f3 == 0x23) ||
282
+ (id80f0 == 0x04 && id80f1 == 0x02 && id80f3 == 0x24))) {
283
+ value = id80f0;
284
+ }
285
+ }
286
+ if (set_result == (int)sizeof(raw) &&
287
+ get_result == (int)sizeof(raw) &&
288
+ (known_chip(value) || value == 0x00 || value == 0x01 ||
289
+ value == 0x04)) {
290
+ *unit = candidate;
291
+ *chip = value;
292
+ return 0;
293
+ }
294
+ }
295
+ return LIBUSB_ERROR_NOT_FOUND;
296
+ }
297
+
298
+ static int flash_read_block(libusb_device_handle *handle, int interface_number,
299
+ uint8_t unit, uint32_t address, uint8_t *out,
300
+ uint8_t length) {
301
+ if (length == 0 || length > 8 || address > FLASH_MAX_ADDRESS) {
302
+ return LIBUSB_ERROR_INVALID_PARAM;
303
+ }
304
+ uint8_t data[11] = {0};
305
+ data[0] = (uint8_t)address;
306
+ data[1] = (uint8_t)(address >> 8);
307
+ uint8_t command = address < 0x10000 ? 0x88 :
308
+ address < 0x20000 ? 0x98 :
309
+ address < 0x30000 ? 0xa8 : 0xb8;
310
+ data[2] = (uint8_t)((command & 0xf0) | length);
311
+ int result = xu_control(handle, interface_number, unit,
312
+ XU_FLASH_SELECTOR, 0, data, sizeof(data));
313
+ if (result != (int)sizeof(data)) {
314
+ return result < 0 ? result : LIBUSB_ERROR_IO;
315
+ }
316
+ result = xu_control(handle, interface_number, unit, XU_FLASH_SELECTOR, 1,
317
+ data, sizeof(data));
318
+ if (result != (int)sizeof(data)) {
319
+ return result < 0 ? result : LIBUSB_ERROR_IO;
320
+ }
321
+ memcpy(out, data + 3, length);
322
+ return 0;
323
+ }
324
+
325
+ static int flash_read(libusb_device_handle *handle, int interface_number,
326
+ uint8_t unit, uint32_t address, uint8_t *out,
327
+ size_t length) {
328
+ while (length > 0) {
329
+ uint8_t chunk = length > 8 ? 8 : (uint8_t)length;
330
+ int result = flash_read_block(handle, interface_number, unit, address,
331
+ out, chunk);
332
+ if (result != 0) {
333
+ return result;
334
+ }
335
+ address += chunk;
336
+ out += chunk;
337
+ length -= chunk;
338
+ }
339
+ return 0;
340
+ }
341
+
342
+ static int rom_read(libusb_device_handle *handle, int interface_number,
343
+ uint8_t unit, uint16_t address, uint8_t *out) {
344
+ uint8_t data[11] = {0};
345
+ data[0] = (uint8_t)address;
346
+ data[1] = (uint8_t)(address >> 8);
347
+ data[2] = 8;
348
+ int result = xu_control(handle, interface_number, unit, 0x04, 0, data,
349
+ sizeof(data));
350
+ if (result != (int)sizeof(data)) {
351
+ return result < 0 ? result : LIBUSB_ERROR_IO;
352
+ }
353
+ result = xu_control(handle, interface_number, unit, 0x04, 1, data,
354
+ sizeof(data));
355
+ if (result != (int)sizeof(data)) {
356
+ return result < 0 ? result : LIBUSB_ERROR_IO;
357
+ }
358
+ memcpy(out, data + 3, 8);
359
+ return 0;
360
+ }
361
+
362
+ static int looks_like_rom(const uint8_t *data) {
363
+ return isdigit(data[0]) && isdigit(data[1]) && isdigit(data[2]) &&
364
+ data[3] == 'R' && data[4] == '0';
365
+ }
366
+
367
+ static void print_setting(const char *label, const uint8_t *data, size_t size) {
368
+ printf(" %s raw=", label);
369
+ print_hex(data, size);
370
+ printf(" ascii=");
371
+ print_ascii(data, size);
372
+ if (data[0] >= 2 && (data[0] & 1) == 0 && data[0] <= size * 2) {
373
+ size_t chars = (data[0] - 2) / 2;
374
+ printf(" %s decoded=\"", label);
375
+ for (size_t i = 0; i < chars; ++i) {
376
+ putchar(isprint(data[2 + i * 2]) ? data[2 + i * 2] : '.');
377
+ }
378
+ puts("\"");
379
+ }
380
+ }
381
+
382
+ typedef int (*flash_reader_fn)(libusb_device_handle *, int, uint8_t,
383
+ uint32_t, uint8_t *, size_t);
384
+
385
+ static void print_double_group(libusb_device_handle *handle, int interface_number,
386
+ uint8_t unit, const char *label,
387
+ uint32_t address, size_t count,
388
+ flash_reader_fn reader) {
389
+ printf(" %s @0x%05x:", label, address);
390
+ for (size_t i = 0; i < count; ++i) {
391
+ uint8_t raw[8] = {0};
392
+ int result = reader(handle, interface_number, unit,
393
+ address + (uint32_t)(i * sizeof(raw)), raw,
394
+ sizeof(raw));
395
+ if (result != 0) {
396
+ printf(" [%zu]=<read:%s>", i, libusb_strerror(result));
397
+ continue;
398
+ }
399
+ if (memcmp(raw, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0) {
400
+ printf(" [%zu]=<unburned>", i);
401
+ continue;
402
+ }
403
+ double value = 0.0;
404
+ memcpy(&value, raw, sizeof(value));
405
+ if (isfinite(value)) {
406
+ printf(" [%zu]=%.12g", i, value);
407
+ } else {
408
+ printf(" [%zu]=<nonfinite>", i);
409
+ }
410
+ }
411
+ putchar('\n');
412
+ }
413
+
414
+ static void print_device_params(libusb_device_handle *handle,
415
+ int interface_number, uint8_t unit,
416
+ flash_reader_fn reader) {
417
+ printf(" device_params @0x45000:");
418
+ for (size_t i = 0; i < 5; ++i) {
419
+ uint8_t raw[8] = {0};
420
+ int result = reader(handle, interface_number, unit,
421
+ 0x45000 + (uint32_t)(i * sizeof(raw)), raw,
422
+ sizeof(raw));
423
+ if (result != 0) {
424
+ printf(" [%zu]=<read:%s>", i, libusb_strerror(result));
425
+ continue;
426
+ }
427
+ char text[9];
428
+ memcpy(text, raw, sizeof(raw));
429
+ text[8] = '\0';
430
+ for (size_t j = 0; j < sizeof(raw); ++j) {
431
+ if (text[j] == '\0' || text[j] == (char)0xff) {
432
+ text[j] = '\0';
433
+ break;
434
+ }
435
+ if (!isprint((unsigned char)text[j])) {
436
+ text[j] = '.';
437
+ }
438
+ }
439
+ printf(" [%zu]=%s", i, text[0] == '\0' ? "<empty>" : text);
440
+ }
441
+ putchar('\n');
442
+ }
443
+
444
+ static int probe_device(libusb_device *device, const char *wanted_port) {
445
+ struct libusb_device_descriptor descriptor;
446
+ char port[64];
447
+ if (libusb_get_device_descriptor(device, &descriptor) != 0 ||
448
+ descriptor.idVendor != SONIX_VID || descriptor.idProduct != SONIX_PID ||
449
+ port_path(device, port, sizeof(port)) != 0 ||
450
+ (wanted_port != NULL && strcmp(port, wanted_port) != 0)) {
451
+ return 0;
452
+ }
453
+
454
+ libusb_device_handle *handle = NULL;
455
+ int result = libusb_open(device, &handle);
456
+ if (result != 0) {
457
+ fprintf(stderr, "port=%s open failed: %s\n", port,
458
+ libusb_strerror(result));
459
+ return -1;
460
+ }
461
+ int interface_number = control_interface(device);
462
+ if (interface_number < 0) {
463
+ fprintf(stderr, "port=%s control interface lookup failed: %s\n", port,
464
+ libusb_strerror(interface_number));
465
+ libusb_close(handle);
466
+ return -1;
467
+ }
468
+
469
+ int was_attached = libusb_kernel_driver_active(handle, interface_number);
470
+ if (was_attached == 1) {
471
+ result = libusb_detach_kernel_driver(handle, interface_number);
472
+ if (result != 0) {
473
+ fprintf(stderr, "port=%s detach interface=%d failed: %s\n", port,
474
+ interface_number, libusb_strerror(result));
475
+ libusb_close(handle);
476
+ return -1;
477
+ }
478
+ }
479
+ result = libusb_claim_interface(handle, interface_number);
480
+ if (result != 0) {
481
+ fprintf(stderr, "port=%s claim interface=%d failed: %s\n", port,
482
+ interface_number, libusb_strerror(result));
483
+ if (was_attached == 1) {
484
+ libusb_attach_kernel_driver(handle, interface_number);
485
+ }
486
+ libusb_close(handle);
487
+ return -1;
488
+ }
489
+
490
+ uint8_t unit = 0, chip = 0;
491
+ result = find_xu_unit(handle, interface_number, &unit, &chip);
492
+ printf("port=%s interface=%d xu_unit=%s", port, interface_number,
493
+ result == 0 ? "found" : "not-found");
494
+ if (result == 0) {
495
+ printf("(%u) chip=0x%02x\n", unit, chip);
496
+ uint8_t roms[6][8];
497
+ const uint16_t addresses[6] = {
498
+ 0x9ff8, 0xd2b2, 0xdff8, 0xbff8, 0xc7f8, 0xaff8
499
+ };
500
+ int rom_found = 0;
501
+ for (size_t i = 0; i < 6; ++i) {
502
+ memset(roms[i], 0xff, sizeof(roms[i]));
503
+ int read_result = rom_read(handle, interface_number, unit,
504
+ addresses[i], roms[i]);
505
+ if (read_result == 0) {
506
+ printf(" ROM[0x%04x]=", addresses[i]);
507
+ print_hex(roms[i], sizeof(roms[i]));
508
+ printf(" ascii=");
509
+ print_ascii(roms[i], sizeof(roms[i]));
510
+ if (looks_like_rom(roms[i])) {
511
+ rom_found = 1;
512
+ }
513
+ } else {
514
+ printf(" ROM[0x%04x] read failed: %s\n", addresses[i],
515
+ libusb_strerror(read_result));
516
+ }
517
+ }
518
+
519
+ uint8_t raw[64];
520
+ if (flash_read(handle, interface_number, unit, 0, raw, sizeof(raw)) == 0) {
521
+ printf(" FLASH[0x0000..0x003f]=");
522
+ print_hex(raw, sizeof(raw));
523
+ putchar('\n');
524
+ }
525
+
526
+ /* The source SDK's default table fallback is 0x8000. */
527
+ uint32_t parameter_start = 0x8000;
528
+ uint8_t rom[8] = {0};
529
+ for (size_t i = 0; i < 6; ++i) {
530
+ if (looks_like_rom(roms[i])) {
531
+ memcpy(rom, roms[i], sizeof(rom));
532
+ break;
533
+ }
534
+ }
535
+ if (memcmp(rom, "232R0", 4) == 0 && rom[5] == 1) {
536
+ parameter_start = 0xc000;
537
+ } else if (memcmp(rom, "232R0", 4) == 0 && rom[5] == 2) {
538
+ parameter_start = 0xc000;
539
+ } else if (memcmp(rom, "276R0", 4) == 0 && rom[5] == 1) {
540
+ parameter_start = 0xc000;
541
+ } else if (memcmp(rom, "216R0", 4) == 0) {
542
+ parameter_start = 0x5800;
543
+ } else if (rom[0] >= '2' && rom[0] <= '9') {
544
+ /* Newer Sonix layouts store the table address in sectorTable. */
545
+ uint8_t table[0x2b];
546
+ if (flash_read(handle, interface_number, unit, 0x160, table,
547
+ sizeof(table)) == 0 && table[0x0f] != 0xff) {
548
+ parameter_start = ((uint32_t)table[0x0f] << 24) |
549
+ ((uint32_t)table[0x10] << 16) |
550
+ ((uint32_t)table[0x11] << 8) | table[0x12];
551
+ }
552
+ }
553
+ printf(" parameter_table_start=0x%08x (rom_probe=%s)\n",
554
+ parameter_start, rom_found ? "matched" : "unknown");
555
+ uint8_t setting[64];
556
+ if (flash_read(handle, interface_number, unit, parameter_start + 0xc0,
557
+ setting, sizeof(setting)) == 0) {
558
+ print_setting("serial", setting, sizeof(setting));
559
+ } else {
560
+ printf(" serial read failed at 0x%08x\n",
561
+ parameter_start + 0xc0);
562
+ }
563
+ int xu6_prepare = sf_xu6_prepare_290(handle, interface_number, unit);
564
+ printf(" XU6 calibration channel prepare=%s\n",
565
+ xu6_prepare == 0 ? "ok" : libusb_strerror(xu6_prepare));
566
+ if (xu6_prepare == 0) {
567
+ print_double_group(handle, interface_number, unit, "fx_params",
568
+ 0x41000, 5, sf_xu6_read);
569
+ print_double_group(handle, interface_number, unit, "fy_params",
570
+ 0x42000, 5, sf_xu6_read);
571
+ print_double_group(handle, interface_number, unit, "fz_params",
572
+ 0x43000, 8, sf_xu6_read);
573
+ print_double_group(handle, interface_number, unit, "fw_params",
574
+ 0x44000, 9, sf_xu6_read);
575
+ print_device_params(handle, interface_number, unit, sf_xu6_read);
576
+ }
577
+ } else {
578
+ printf("\n");
579
+ }
580
+
581
+ libusb_release_interface(handle, interface_number);
582
+ if (was_attached == 1) {
583
+ libusb_attach_kernel_driver(handle, interface_number);
584
+ }
585
+ libusb_close(handle);
586
+ return 1;
587
+ }
588
+
589
+ int main(int argc, char **argv) {
590
+ const char *wanted_port = argc > 1 ? argv[1] : NULL;
591
+ libusb_context *context = NULL;
592
+ int result = libusb_init(&context);
593
+ if (result != 0) {
594
+ fprintf(stderr, "libusb_init failed: %s\n", libusb_strerror(result));
595
+ return 1;
596
+ }
597
+ libusb_device **devices = NULL;
598
+ ssize_t count = libusb_get_device_list(context, &devices);
599
+ if (count < 0) {
600
+ fprintf(stderr, "get device list failed: %s\n", libusb_strerror((int)count));
601
+ libusb_exit(context);
602
+ return 1;
603
+ }
604
+ int matched = 0;
605
+ for (ssize_t i = 0; i < count; ++i) {
606
+ int status = probe_device(devices[i], wanted_port);
607
+ if (status > 0) {
608
+ matched++;
609
+ }
610
+ }
611
+ libusb_free_device_list(devices, 1);
612
+ libusb_exit(context);
613
+ if (wanted_port != NULL && matched == 0) {
614
+ fprintf(stderr, "no Sonix 0c45:636f device at port %s\n", wanted_port);
615
+ return 2;
616
+ }
617
+ return matched > 0 ? 0 : 2;
618
+ }
collector/core/gripper/devices/gripper_serial.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  from __future__ import annotations
4
 
 
5
  import threading
6
  import time
7
  from typing import Callable, Optional
@@ -21,7 +22,9 @@ class GripperSerial:
21
  CONNECT_BAUD = 115200
22
  CONNECT_TIMEOUT = 0.5
23
  CONNECT_WRITE_TIMEOUT = 0.5
24
- CONNECT_BOOT_DELAY = 2.0
 
 
25
  CONNECT_ATTEMPTS = 8
26
  CONNECT_RETRY_DELAY = 0.3
27
  COMMAND_TIMEOUT = 1.0
@@ -65,21 +68,28 @@ class GripperSerial:
65
  return self._last_error
66
 
67
  def connect(self, port: str, baud: int = CONNECT_BAUD) -> bool:
68
- """打开串口并用原有的八次 ``?`` 握手确认主控在线。"""
69
  with self._io_lock:
70
  self._disconnect_locked()
71
  self._last_error = None
72
  try:
 
 
73
  opened = self._serial_factory(
74
  port,
75
  baud,
76
  timeout=self.CONNECT_TIMEOUT,
77
  write_timeout=self.CONNECT_WRITE_TIMEOUT,
 
78
  )
79
  self._serial = opened
80
- self._sleep(self.CONNECT_BOOT_DELAY)
81
  opened.reset_input_buffer()
 
 
82
  for attempt in range(self.CONNECT_ATTEMPTS):
 
 
 
83
  opened.write(b"?\r\n")
84
  line = opened.readline().decode(
85
  errors="ignore").strip()
@@ -89,16 +99,18 @@ class GripperSerial:
89
  )
90
  if line.startswith("STATE"):
91
  return True
92
- self._sleep(self.CONNECT_RETRY_DELAY)
 
93
  except Exception as exc:
94
  self._last_error = (
95
  f"serial open/handshake failed: {exc}"
96
  )
97
  self._disconnect_locked()
98
  return False
 
99
  self._last_error = (
100
  "serial handshake timeout after "
101
- f"{self.CONNECT_ATTEMPTS} attempts"
102
  )
103
  self._disconnect_locked()
104
  return False
@@ -135,6 +147,30 @@ class GripperSerial:
135
  # 关闭失败时也不能把已经失效的句柄重新暴露给调用方。
136
  pass
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  def send(self, command: str) -> str:
139
  """发送一条文本命令并返回匹配的完整响应行。"""
140
  with self._io_lock:
@@ -149,16 +185,32 @@ class GripperSerial:
149
  except Exception:
150
  pass
151
  opened.write((str(command) + "\r\n").encode())
152
- expected = {
153
- "?": ("STATE",),
154
- "G": ("AS5048A", "AS5048A ERR"),
155
- "C": ("OK CONNECT", "ERR"),
156
- "I": ("OK INIT", "ERR"),
157
- "F": ("OK READY", "ERR"),
158
- "E": ("OK ERROR", "ERR"),
159
- "R": ("OK ASR", "AS5048A ERR"),
160
- "S": ("OK START", "ERR"),
161
- }.get(str(command)[:1], ())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  deadline = self._clock() + self.COMMAND_TIMEOUT
163
  last_line = ""
164
  while self._clock() < deadline:
 
2
 
3
  from __future__ import annotations
4
 
5
+ import re
6
  import threading
7
  import time
8
  from typing import Callable, Optional
 
22
  CONNECT_BAUD = 115200
23
  CONNECT_TIMEOUT = 0.5
24
  CONNECT_WRITE_TIMEOUT = 0.5
25
+ # 握手不再固定白等 2 秒:在最长 CONNECT_BOOT_TIMEOUT 内反复发 ``?``,
26
+ # 收到 STATE 立刻返回。刚上电的 ESP32 仍在窗口内,已就绪的不必空等。
27
+ CONNECT_BOOT_TIMEOUT = 2.0
28
  CONNECT_ATTEMPTS = 8
29
  CONNECT_RETRY_DELAY = 0.3
30
  COMMAND_TIMEOUT = 1.0
 
68
  return self._last_error
69
 
70
  def connect(self, port: str, baud: int = CONNECT_BAUD) -> bool:
71
+ """独占打开串口,在有限窗口内用 ``?`` 握手确认主控在线。"""
72
  with self._io_lock:
73
  self._disconnect_locked()
74
  self._last_error = None
75
  try:
76
+ # 独占模式:串口被其他进程占用时立刻失败,而不是两个进程
77
+ # 各自读走半条响应,把「被占用」伪装成「握手超时」。
78
  opened = self._serial_factory(
79
  port,
80
  baud,
81
  timeout=self.CONNECT_TIMEOUT,
82
  write_timeout=self.CONNECT_WRITE_TIMEOUT,
83
+ exclusive=True,
84
  )
85
  self._serial = opened
 
86
  opened.reset_input_buffer()
87
+ deadline = self._clock() + self.CONNECT_BOOT_TIMEOUT
88
+ attempts_made = 0
89
  for attempt in range(self.CONNECT_ATTEMPTS):
90
+ if attempt and self._clock() >= deadline:
91
+ break
92
+ attempts_made = attempt + 1
93
  opened.write(b"?\r\n")
94
  line = opened.readline().decode(
95
  errors="ignore").strip()
 
99
  )
100
  if line.startswith("STATE"):
101
  return True
102
+ if self._clock() < deadline:
103
+ self._sleep(self.CONNECT_RETRY_DELAY)
104
  except Exception as exc:
105
  self._last_error = (
106
  f"serial open/handshake failed: {exc}"
107
  )
108
  self._disconnect_locked()
109
  return False
110
+ # 报实际尝试次数,不报上限:被抢占/占用时上限是误导
111
  self._last_error = (
112
  "serial handshake timeout after "
113
+ f"{attempts_made} attempts"
114
  )
115
  self._disconnect_locked()
116
  return False
 
147
  # 关闭失败时也不能把已经失效的句柄重新暴露给调用方。
148
  pass
149
 
150
+ def query_fays_serial(self) -> str:
151
+ """读取 ESP32 NVS 中绑定的 Fays 产品序列号;未绑定/无效返回空串。"""
152
+ response = self.send("QF")
153
+ prefix = "FAYS_SERIAL:"
154
+ if not response.startswith(prefix):
155
+ return ""
156
+ return response[len(prefix):].strip()
157
+
158
+ def set_fays_serial(self, serial: str) -> bool:
159
+ """写入并持久化 ESP32 绑定的 Fays 产品序列号。"""
160
+ value = str(serial or "").strip()
161
+ if (
162
+ not value
163
+ or len(value) > 64
164
+ or re.fullmatch(r"[A-Za-z0-9._-]+", value) is None
165
+ ):
166
+ raise ValueError("Fays 序列号只能是 1-64 位字母、数字、点、下划线或短横线")
167
+ response = self.send(f"WF:{value}")
168
+ if response.startswith("OK FAYS_SERIAL_SET:"):
169
+ return True
170
+ if response.startswith("ERR "):
171
+ raise RuntimeError(f"ESP32 写入 Fays 序列号失败: {response}")
172
+ raise RuntimeError(f"ESP32 写入 Fays 序列号无有效响应: {response or '<empty>'}")
173
+
174
  def send(self, command: str) -> str:
175
  """发送一条文本命令并返回匹配的完整响应行。"""
176
  with self._io_lock:
 
185
  except Exception:
186
  pass
187
  opened.write((str(command) + "\r\n").encode())
188
+ command_text = str(command)
189
+ if command_text.startswith("WF:"):
190
+ # 写绑定:三种终态都算「本条命令的响应」,其余行继续等,
191
+ # 免得把固件周期性的 STATE 当成写入结果。
192
+ expected = (
193
+ "OK FAYS_SERIAL_SET:",
194
+ "ERR FAYS_SERIAL_INVALID",
195
+ "ERR FAYS_SERIAL_SAVE",
196
+ )
197
+ else:
198
+ table = {
199
+ "QF": ("FAYS_SERIAL:", "ERR FAYS_SERIAL_NOT_SET"),
200
+ "?": ("STATE",),
201
+ "G": ("AS5048A", "AS5048A ERR"),
202
+ "C": ("OK CONNECT", "ERR"),
203
+ "I": ("OK INIT", "ERR"),
204
+ "F": ("OK READY", "ERR"),
205
+ "E": ("OK ERROR", "ERR"),
206
+ "R": ("OK ASR", "AS5048A ERR"),
207
+ "S": ("OK START", "ERR"),
208
+ }
209
+ # 先按完整命令查(QF 是两字符命令),再退回首字符。
210
+ # 只按 [:1] 查会让 "QF" 这条永远命中不到,等于宣布
211
+ # 「第一行就是响应」——固件周期性的 STATE 会顶替真响应。
212
+ expected = table.get(command_text, table.get(
213
+ command_text[:1], ()))
214
  deadline = self._clock() + self.COMMAND_TIMEOUT
215
  last_line = ""
216
  while self._clock() < deadline:
collector/core/gripper/devices/uvc_camera_service.py CHANGED
@@ -25,6 +25,7 @@ import sys
25
  import cv2
26
 
27
  from core.gripper.fays_runtime import PROJECT_ROOT
 
28
  from core.gripper.runtime.device_access import device_access_guard
29
 
30
  # camera_service/python is a checkout-local transport module, not an ambient
@@ -68,12 +69,23 @@ _LIBUVC_DIR = Path(
68
  PROJECT_ROOT, "camera_service", "build", "third_party", "libuvc")
69
 
70
 
71
- def _native_env():
 
 
 
 
 
72
  env = dict(os.environ)
73
- existing = env.get("LD_LIBRARY_PATH", "")
74
- if _LIBUVC_DIR.is_dir() and str(_LIBUVC_DIR) not in existing:
75
- env["LD_LIBRARY_PATH"] = (
76
- str(_LIBUVC_DIR) + (f":{existing}" if existing else ""))
 
 
 
 
 
 
77
  return env
78
 
79
 
@@ -81,11 +93,87 @@ class UvcCameraServiceError(RuntimeError):
81
  """The live libusb/libuvc camera set cannot be used."""
82
 
83
 
84
- def _root_port(physical_path):
85
- text = str(physical_path or "").strip()
86
- if "-" not in text:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  return ""
88
- return text.split("-", 1)[1].split(".", 1)[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
 
91
  def _path_contains(bus, outer_path, child_path):
@@ -323,7 +411,17 @@ class UvcCameraServiceManager:
323
  self._lock = threading.RLock()
324
  self._services = {}
325
 
326
- def _run_discovery(self, *, usb_bus=None, port_prefix=None):
 
 
 
 
 
 
 
 
 
 
327
  if not self._discovery_binary.is_file():
328
  raise UvcCameraServiceError(
329
  f"libusb/libuvc 发现程序不存在: {self._discovery_binary}"
@@ -332,16 +430,27 @@ class UvcCameraServiceManager:
332
  raise UvcCameraServiceError(
333
  f"libusb/libuvc 发现程序不可执行: {self._discovery_binary}"
334
  )
 
 
 
 
 
335
  command = [str(self._discovery_binary), "--json"]
336
  if usb_bus is not None and port_prefix is not None:
337
  command += ["--bus", str(usb_bus), "--port-prefix", str(port_prefix)]
 
 
 
 
 
 
338
  completed = subprocess.run(
339
  command,
340
  capture_output=True,
341
  text=True,
342
  timeout=DISCOVERY_TIMEOUT_S,
343
  check=False,
344
- env=_native_env(),
345
  )
346
  if completed.returncode != 0:
347
  details = "\n".join(
@@ -368,25 +477,27 @@ class UvcCameraServiceManager:
368
  def _assignment_identity(assignment):
369
  if not isinstance(assignment, dict):
370
  raise UvcCameraServiceError(
371
- "Fays 尚未完成 device_setup 身份分配"
372
  )
373
  esp = assignment.get("esp32") or {}
374
  fays = assignment.get("fays") or {}
375
  esp_serial = str(esp.get("serial") or "").strip()
376
  fays_serial = str(fays.get("product_serial") or "").strip()
377
- fays_path = str(
378
- fays.get("physical_usb_path") or ""
379
- ).strip()
380
- if not esp_serial or not fays_serial or not fays_path:
381
  raise UvcCameraServiceError(
382
- "Fays 当前分配缺少 ESP32 serial、Fays serial 或物理路径"
383
  )
384
- return esp_serial, fays_serial, fays_path
385
 
386
  def _associate_group(self, group, assignment, live_esp):
387
- esp_serial, fays_serial, fays_path = self._assignment_identity(
388
- assignment
389
- )
 
 
 
 
 
390
  bus = int(group.get("bus", -1))
391
  outer_path = str(group.get("outer_path") or "").strip()
392
  matching_esp = [
@@ -401,15 +512,6 @@ class UvcCameraServiceManager:
401
  f"serial={esp_serial} matches={len(matching_esp)} "
402
  f"group={bus}-{outer_path}"
403
  )
404
- # Fays is USB3/FT602 and may be reported on a different libusb bus;
405
- # the existing topology rule intentionally correlates its root port.
406
- if _root_port(fays_path) != str(outer_path).split(".", 1)[0].split(
407
- "-", 1
408
- )[-1]:
409
- raise UvcCameraServiceError(
410
- "当前 UVC 组与已分配 Fays 不在同一根端口: "
411
- f"fays={fays_path} group={bus}-{outer_path}"
412
- )
413
  normalized = {
414
  "bus": bus,
415
  "outer_path": outer_path,
@@ -453,7 +555,7 @@ class UvcCameraServiceManager:
453
 
454
  def _discovery_scope(self, assignment, live_esp=None):
455
  from core.gripper.fays_runtime import discover_esp32_devices
456
- serial, _, _ = self._assignment_identity(assignment)
457
  devices = tuple(discover_esp32_devices()) if live_esp is None else live_esp
458
  matches = [d for d in devices if str(d.get("serial", "")).strip() == serial]
459
  if len(matches) != 1:
@@ -479,7 +581,7 @@ class UvcCameraServiceManager:
479
  except UvcCameraServiceError:
480
  continue
481
  if len(matches) != 1:
482
- esp_serial, fays_serial, _ = self._assignment_identity(assignment)
483
  raise UvcCameraServiceError(
484
  "当前设备清单身份与动态 UVC 拓扑无法唯一配对: "
485
  f"esp32={esp_serial} fays={fays_serial} "
@@ -493,6 +595,10 @@ class UvcCameraServiceManager:
493
  (
494
  int(record["bus"]),
495
  record["outer_path"],
 
 
 
 
496
  tuple(sorted(
497
  (side, str(candidate["port"]))
498
  for side, candidate in record["sightac"].items()
@@ -502,6 +608,44 @@ class UvcCameraServiceManager:
502
  for record in records
503
  ))
504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  def _write_config(self, records):
506
  runtime_dir = Path(tempfile.mkdtemp(prefix="ksq-camera-service-"))
507
  lines = [
@@ -511,12 +655,14 @@ class UvcCameraServiceManager:
511
  ]
512
  sockets = {}
513
  for index, record in enumerate(records, 1):
 
514
  for role in ("left", "right", "decxin"):
515
  candidate = (
516
  record["sightac"][role]
517
  if role in {"left", "right"}
518
  else record["decxin"]
519
  )
 
520
  name = f"unit_{index}_{role}"
521
  socket_path = runtime_dir / f"{name}.sock"
522
  sockets[(index, role)] = str(socket_path)
@@ -527,9 +673,22 @@ class UvcCameraServiceManager:
527
  f"usb_bus={int(record['bus'])}",
528
  f"usb_port_path={candidate['port']}",
529
  f"streaming_interface={int(candidate['streaming_interface'])}",
530
- f"forced_altsetting={int(candidate['altsetting'])}",
531
- "forced_payload=800" if role in {"left", "right"}
532
- else "forced_payload=1280",
 
 
 
 
 
 
 
 
 
 
 
 
 
533
  "width=640" if role in {"left", "right"}
534
  else "width=1280",
535
  "height=480" if role in {"left", "right"}
@@ -575,7 +734,7 @@ class UvcCameraServiceManager:
575
  stdout=subprocess.DEVNULL,
576
  stderr=service_log,
577
  start_new_session=True,
578
- env=_native_env(),
579
  )
580
  finally:
581
  service_log.close()
 
25
  import cv2
26
 
27
  from core.gripper.fays_runtime import PROJECT_ROOT
28
+ from core.gripper.paths import CAMERA_MODE_STATE_DIR
29
  from core.gripper.runtime.device_access import device_access_guard
30
 
31
  # camera_service/python is a checkout-local transport module, not an ambient
 
69
  PROJECT_ROOT, "camera_service", "build", "third_party", "libuvc")
70
 
71
 
72
+ def _native_env(binary=None):
73
+ """只给这个子进程用交付目录里的 libuvc,绝不动主进程的环境。
74
+
75
+ ``binary`` 自带 ``third_party/libuvc`` 时优先用它(KSQ_UVC_*_BINARY
76
+ 被指向别处的构建树时仍然自洽),再兜底交付目录内的副本。
77
+ """
78
  env = dict(os.environ)
79
+ directories = []
80
+ if binary is not None:
81
+ directories.append(
82
+ str(Path(binary).resolve().parent / "third_party" / "libuvc"))
83
+ directories.append(str(_LIBUVC_DIR))
84
+ directories.extend(
85
+ part for part in env.get("LD_LIBRARY_PATH", "").split(os.pathsep)
86
+ if part
87
+ )
88
+ env["LD_LIBRARY_PATH"] = os.pathsep.join(dict.fromkeys(directories))
89
  return env
90
 
91
 
 
93
  """The live libusb/libuvc camera set cannot be used."""
94
 
95
 
96
+ # 每个机型允许的档位对(altsetting, payload),按从好到差排列,必须与服务端
97
+ # camera_service.c 的档位表逐项一致。服务认不出的档位对会直接 rc=2 退出,
98
+ # 把整个夹爪一起带走,所以这里必须先挡一道,把「配置写错」变成一条看得懂的
99
+ # 报错,而不是一个哑掉的服务进程。
100
+ _MODE_LADDERS = {
101
+ (0x0C45, 0x636F): ((3, 800),),
102
+ (0x1BCF, 0x2D4F): ((7, 1280), (6, 944)),
103
+ }
104
+
105
+ # 起始档位一律取档位表里最保守的那一档(=表的最后一档),不认控制器。
106
+ #
107
+ # 曾经这里有一张「已知扛不住的控制器 → 起始档位」的表(0000:74:00.4 → alt6)。
108
+ # 2026-09-15 实测把它推翻了:alt7 停摆不是某块控制器的毛病,0000:0a:00.0 上
109
+ # 整机三路一起出流时一样在 78 秒内停摆(两次独立运行、共 3 次停摆,全落在
110
+ # 68~116 秒)。当初判它「总线 1 没事」是拿一次根本没真的跑在 alt7 上的运行
111
+ # 当基准——那时 ini 里的 forced_* 还是死的,服务只是把 ini 的值原样打进了
112
+ # 日志。控制器不是变量,就没必要按机器写死。
113
+
114
+
115
+ def _usb_controller_for_bus(bus):
116
+ """这台相机所在 USB 控制器的 PCI 路径,例如 ``0000:0a:00.0``。
117
+
118
+ ``/sys/bus/usb/devices/usbN`` 是指向根 Hub 的符号链接,解开的上一级就是
119
+ 控制器;用 PCI 路径而不是总线号,因为总线号会随插口变。
120
+
121
+ 它只进落盘键,不参与「选哪一档」的判断——**控制器是不是变量并没有定论**
122
+ (2026-09-15 实测 alt7 在 74:00.4 与 0a:00.0 上都停摆,但机制没查清),所
123
+ 以不拿它做任何决策。键里带上它只是取保守:学到的东西严格绑在「学它的那条
124
+ 物理路径」上,换机器/换口自然是新键。代价为零——新键没有记忆值,就退回档
125
+ 位表里最保守的那一档,那本来就是我们要的默认。取不到返回空串,调用方退化
126
+ 成「不区分控制器」,功能不受影响。
127
+ """
128
+ link = Path(f"/sys/bus/usb/devices/usb{int(bus)}")
129
+ try:
130
+ return link.resolve(strict=True).parent.name
131
+ except (OSError, ValueError):
132
  return ""
133
+
134
+
135
+ def _mode_state_key(vid, pid, controller, serial):
136
+ """「这台相机 × 这条物理路径」的落盘键,规则必须与 C 侧 ``mode_state_key``
137
+ 逐字一致:只保留 ``[A-Za-z0-9-]``,其余一律换成 ``_``。"""
138
+ raw = (
139
+ f"{int(vid):04x}_{int(pid):04x}_"
140
+ f"{controller or 'unknown'}_{serial or 'noserial'}"
141
+ )
142
+ return "".join(
143
+ char if (char.isascii() and (char.isalnum() or char == "-")) else "_"
144
+ for char in raw
145
+ )
146
+
147
+
148
+ def _pair_is_known(vid, pid, pair):
149
+ return pair in _MODE_LADDERS.get((int(vid), int(pid)), ())
150
+
151
+
152
+ def _read_learned_mode(state_dir, vid, pid, controller, serial):
153
+ """读服务上一轮学到的档位。文件坏了 / 越界了一律当没学到。"""
154
+ if not state_dir:
155
+ return None
156
+ path = Path(state_dir) / (
157
+ _mode_state_key(vid, pid, controller, serial) + ".mode"
158
+ )
159
+ try:
160
+ text = path.read_text(encoding="utf-8")
161
+ except OSError:
162
+ return None
163
+ values = {}
164
+ for line in text.splitlines():
165
+ line = line.strip()
166
+ if not line or line.startswith("#") or "=" not in line:
167
+ continue
168
+ key, _, value = line.partition("=")
169
+ try:
170
+ values[key.strip()] = int(value.strip())
171
+ except ValueError:
172
+ return None
173
+ pair = (values.get("altsetting"), values.get("payload"))
174
+ if not _pair_is_known(vid, pid, pair):
175
+ return None
176
+ return pair
177
 
178
 
179
  def _path_contains(bus, outer_path, child_path):
 
411
  self._lock = threading.RLock()
412
  self._services = {}
413
 
414
+ def _run_discovery(self, *, usb_bus=None, port_prefix=None,
415
+ skip_flash=False, identity_only=False,
416
+ topology_only=False):
417
+ """Run the live libusb/libuvc discovery pass.
418
+
419
+ Three depths, mutually exclusive: ``topology_only`` (enumeration
420
+ only), ``identity_only`` (also opens UVC control, verifies mode and
421
+ reads Flash side/serial, skipping the five calibration tables) and
422
+ the default full read. ``skip_flash`` is the diagnostic alias for
423
+ the first two. Only the full mode can emit a usable config.
424
+ """
425
  if not self._discovery_binary.is_file():
426
  raise UvcCameraServiceError(
427
  f"libusb/libuvc 发现程序不存在: {self._discovery_binary}"
 
430
  raise UvcCameraServiceError(
431
  f"libusb/libuvc 发现程序不可执行: {self._discovery_binary}"
432
  )
433
+ if sum(bool(flag) for flag in (
434
+ skip_flash, identity_only, topology_only)) > 1:
435
+ raise UvcCameraServiceError(
436
+ "discover-uvc-config 的扫描深度参数互斥,只能选一个"
437
+ )
438
  command = [str(self._discovery_binary), "--json"]
439
  if usb_bus is not None and port_prefix is not None:
440
  command += ["--bus", str(usb_bus), "--port-prefix", str(port_prefix)]
441
+ if topology_only:
442
+ command.append("--topology-only")
443
+ elif identity_only:
444
+ command.append("--identity-only")
445
+ elif skip_flash:
446
+ command.append("--skip-flash")
447
  completed = subprocess.run(
448
  command,
449
  capture_output=True,
450
  text=True,
451
  timeout=DISCOVERY_TIMEOUT_S,
452
  check=False,
453
+ env=_native_env(self._discovery_binary),
454
  )
455
  if completed.returncode != 0:
456
  details = "\n".join(
 
477
  def _assignment_identity(assignment):
478
  if not isinstance(assignment, dict):
479
  raise UvcCameraServiceError(
480
+ "Fays 尚未完成身份分配"
481
  )
482
  esp = assignment.get("esp32") or {}
483
  fays = assignment.get("fays") or {}
484
  esp_serial = str(esp.get("serial") or "").strip()
485
  fays_serial = str(fays.get("product_serial") or "").strip()
486
+ if not esp_serial or not fays_serial:
 
 
 
487
  raise UvcCameraServiceError(
488
+ "Fays 当前分配缺少 ESP32 serial 或 Fays serial"
489
  )
490
+ return esp_serial, fays_serial
491
 
492
  def _associate_group(self, group, assignment, live_esp):
493
+ """UVC 组只按 ESP32 serial + bus/outer_path 关联。
494
+
495
+ Fays 归属由 ESP32 NVS 里的绑定序列号决定(见 SingleFaysLease),
496
+ 这里不再比较 Fays 的 USB 根端口:Fays 是 USB3/FT602,插在 USB3 口
497
+ 时走 5000M 伴生总线,与触觉/RGB 的 480M 总线 bus 号不同;多控制器
498
+ 机器上两套 rig 还常落在同号根端口,按端口关联只会互相误配。
499
+ """
500
+ esp_serial, fays_serial = self._assignment_identity(assignment)
501
  bus = int(group.get("bus", -1))
502
  outer_path = str(group.get("outer_path") or "").strip()
503
  matching_esp = [
 
512
  f"serial={esp_serial} matches={len(matching_esp)} "
513
  f"group={bus}-{outer_path}"
514
  )
 
 
 
 
 
 
 
 
 
515
  normalized = {
516
  "bus": bus,
517
  "outer_path": outer_path,
 
555
 
556
  def _discovery_scope(self, assignment, live_esp=None):
557
  from core.gripper.fays_runtime import discover_esp32_devices
558
+ serial, _ = self._assignment_identity(assignment)
559
  devices = tuple(discover_esp32_devices()) if live_esp is None else live_esp
560
  matches = [d for d in devices if str(d.get("serial", "")).strip() == serial]
561
  if len(matches) != 1:
 
581
  except UvcCameraServiceError:
582
  continue
583
  if len(matches) != 1:
584
+ esp_serial, fays_serial = self._assignment_identity(assignment)
585
  raise UvcCameraServiceError(
586
  "当前设备清单身份与动态 UVC 拓扑无法唯一配对: "
587
  f"esp32={esp_serial} fays={fays_serial} "
 
595
  (
596
  int(record["bus"]),
597
  record["outer_path"],
598
+ # ini 里那一行 `usb_controller=` 就是它,而它参与落盘键,所以
599
+ # 「这份配置长什么样」含控制器:换控制器必须重写 ini,不能复用
600
+ # 上一个进程。
601
+ _usb_controller_for_bus(record["bus"]),
602
  tuple(sorted(
603
  (side, str(candidate["port"]))
604
  for side, candidate in record["sightac"].items()
 
608
  for record in records
609
  ))
610
 
611
+ @staticmethod
612
+ def _starting_mode(candidate, controller):
613
+ """这台相机从哪一档开始。
614
+
615
+ 优先级:上一轮学到的 > 档位表里最保守的那一档 > 扫描程序报的首选档。
616
+
617
+ 为什么默认不是首选档:实测 DECXIN 的 alt7(10.24 MB/s)在整机三路一起
618
+ 出流时每 68~116 秒必停摆一次,alt6(7.552 MB/s)同样三路下 30.00 fps
619
+ 长跑不停,而两档出帧率一模一样——首选档多出来的那点每帧余量(327680
620
+ 对 241664 字节)不值一次停摆,用户要的「稳定帧数」也不允许开机就故意
621
+ 赔一次。要那点余量就把 ini 里 forced_altsetting 改回 alt7:真撑不住
622
+ 时服务停两次后会自己退回 alt6 并把结论落盘,下次开机直接用(见
623
+ camera_service.c 的 maybe_downgrade_altsetting)。学到的值就在这里读
624
+ 回来。"""
625
+ vid = int(candidate["vid"])
626
+ pid = int(candidate["pid"])
627
+ preferred = (int(candidate["altsetting"]),
628
+ int(candidate["descriptor_payload"]))
629
+ if not _pair_is_known(vid, pid, preferred):
630
+ # 服务对认不出的档位对是 rc=2 直接退出,整个夹爪一起挂。先查
631
+ # 一遍扫描程序的输出:扫描程序与服务端档位表脱节(比如只装了新
632
+ # 扫描程序、没重编服务)必须报出来,不能被下面的记忆值盖过去。
633
+ raise UvcCameraServiceError(
634
+ f"扫描程序报出服务端不认识的档位 {vid:04x}:{pid:04x} "
635
+ f"alt={preferred[0]} payload={preferred[1]};"
636
+ "扫描程序与服务端档位表已经脱节,需要一起重编"
637
+ )
638
+ serial = str(candidate.get("usb_serial") or "").strip()
639
+ learned = _read_learned_mode(
640
+ CAMERA_MODE_STATE_DIR, vid, pid, controller, serial
641
+ )
642
+ if learned is not None:
643
+ return learned, "learned"
644
+ ladder = _MODE_LADDERS[(vid, pid)]
645
+ if ladder[-1] != preferred:
646
+ return ladder[-1], "conservative"
647
+ return preferred, "preferred"
648
+
649
  def _write_config(self, records):
650
  runtime_dir = Path(tempfile.mkdtemp(prefix="ksq-camera-service-"))
651
  lines = [
 
655
  ]
656
  sockets = {}
657
  for index, record in enumerate(records, 1):
658
+ controller = _usb_controller_for_bus(record["bus"])
659
  for role in ("left", "right", "decxin"):
660
  candidate = (
661
  record["sightac"][role]
662
  if role in {"left", "right"}
663
  else record["decxin"]
664
  )
665
+ mode, mode_source = self._starting_mode(candidate, controller)
666
  name = f"unit_{index}_{role}"
667
  socket_path = runtime_dir / f"{name}.sock"
668
  sockets[(index, role)] = str(socket_path)
 
673
  f"usb_bus={int(record['bus'])}",
674
  f"usb_port_path={candidate['port']}",
675
  f"streaming_interface={int(candidate['streaming_interface'])}",
676
+ # altsetting 和 payload 是一个整体(alt7 的端点就是
677
+ # 1280 B/包),必须成对来自同一处:要么都是扫描程序实测的
678
+ # 端点描述符,要么都是服务上一轮学到的结论。拆开配会得到
679
+ # 一个自相矛盾的档位——2026-09-15 主程序连不上夹爪就是这
680
+ # 么来的(alt 取自扫描程序、payload 却是硬编码)。
681
+ #
682
+ # 这两项现在是**生效的**:服务打开设备后会把它们交给
683
+ # libuvc 的 uvc_set_altsetting_override()。在此之前它们
684
+ # 只是校验和日志,真正决定档位的是 libuvc 的编译期表,
685
+ # 所以「改 ini」曾经完全不改变行为。
686
+ f"forced_altsetting={mode[0]}",
687
+ f"forced_payload={mode[1]}",
688
+ f"# 起始档位来源: {mode_source}",
689
+ f"usb_serial={str(candidate.get('usb_serial') or '').strip()}",
690
+ f"usb_controller={controller}",
691
+ f"state_dir={CAMERA_MODE_STATE_DIR}",
692
  "width=640" if role in {"left", "right"}
693
  else "width=1280",
694
  "height=480" if role in {"left", "right"}
 
734
  stdout=subprocess.DEVNULL,
735
  stderr=service_log,
736
  start_new_session=True,
737
+ env=_native_env(self._service_binary),
738
  )
739
  finally:
740
  service_log.close()
collector/core/gripper/fays_serial_probe.py CHANGED
@@ -87,9 +87,14 @@ def probe_product_serial(
87
  probe_binary: Optional[str] = None,
88
  timeout: float = 60.0,
89
  environment: Optional[Mapping[str, str]] = None,
 
90
  ) -> str:
91
  """Run the official calibration probe and return ``device.serial``.
92
 
 
 
 
 
93
  timeout 同时是 SDK 全局初始化锁的等待上限与子进程运行上限:双夹爪
94
  并发打开时,第二台的探针要等第一台 SLAM 初始化(最长 45s)释放锁,
95
  20s 会在等待期间误报超时,故放宽到 60s。
@@ -113,15 +118,31 @@ def probe_product_serial(
113
  # and the device_setup manifest below.
114
  with device_access_guard(FAYS_SDK_INITIALIZATION_LOCK, timeout=timeout), \
115
  fays_device_guard(ports["stereo_dev_port"]):
 
 
 
 
116
  completed = subprocess.run(
117
- [executable, config_path], capture_output=True, text=True,
118
  timeout=timeout,
119
  env=dict(os.environ if environment is None else environment),
120
  check=False,
121
  )
122
  except subprocess.TimeoutExpired as exc:
 
 
 
 
 
 
 
 
 
 
 
123
  raise RuntimeError(
124
- f"Fays 标定探测超时: {ports} ({exc.timeout}s)"
 
125
  ) from exc
126
  output = (
127
  (completed.stdout or "") + "\n" + (completed.stderr or "")
 
87
  probe_binary: Optional[str] = None,
88
  timeout: float = 60.0,
89
  environment: Optional[Mapping[str, str]] = None,
90
+ serial_only_fast: bool = False,
91
  ) -> str:
92
  """Run the official calibration probe and return ``device.serial``.
93
 
94
+ ``serial_only_fast`` 只允许用于身份扫描:探针读一次 SDK 设备信息、停掉
95
+ 自己持有的 IMU 流后直接退出进程,跳过厂商 SDK 较慢的 handle 析构。标定
96
+ 与运行路径必须走完整生命周期,不得使用该参数。
97
+
98
  timeout 同时是 SDK 全局初始化锁的等待上限与子进程运行上限:双夹爪
99
  并发打开时,第二台的探针要等第一台 SLAM 初始化(最长 45s)释放锁,
100
  20s 会在等待期间误报超时,故放宽到 60s。
 
118
  # and the device_setup manifest below.
119
  with device_access_guard(FAYS_SDK_INITIALIZATION_LOCK, timeout=timeout), \
120
  fays_device_guard(ports["stereo_dev_port"]):
121
+ command = [executable]
122
+ if serial_only_fast:
123
+ command.append("--serial-only-fast")
124
+ command.append(config_path)
125
  completed = subprocess.run(
126
+ command, capture_output=True, text=True,
127
  timeout=timeout,
128
  env=dict(os.environ if environment is None else environment),
129
  check=False,
130
  )
131
  except subprocess.TimeoutExpired as exc:
132
+ # TimeoutExpired 在 text=True 下也可能带着 bytes。超时发生在
133
+ # SDK 释放阶段时,前半段(身份/序列号)往往已经成功,把子进程
134
+ # 最后 20 行留下来,别让一句「超时」把底层证据丢掉。
135
+ def _text(value):
136
+ return (
137
+ value.decode("utf-8", errors="replace")
138
+ if isinstance(value, bytes) else (value or "")
139
+ )
140
+ diagnostic = "\n".join(
141
+ (_text(exc.stdout) + "\n" + _text(exc.stderr)).splitlines()[-20:]
142
+ )
143
  raise RuntimeError(
144
+ f"Fays 标定探测超时(含 SDK 资源释放): {ports} "
145
+ f"({exc.timeout}s)\n{diagnostic}"
146
  ) from exc
147
  output = (
148
  (completed.stdout or "") + "\n" + (completed.stderr or "")
collector/core/gripper/fays_single.py CHANGED
@@ -1,16 +1,21 @@
1
  """单夹爪场景的 Fays S80M 租约(无 device_setup 清单版本)。
2
 
3
  主程序一次只服务一套夹爪 rig,设备身份全部来自运行时探测:
4
- 1. ESP32 串口(VID/PID + USB serial)唯一匹配;
5
- 2. discover_fays_device_groups() 发现且仅发现一台完整 S80M;
6
- 3. USB 链路速度 >= FAYS_MIN_USB_SPEED_MBPS,否则拒绝(提示换 USB3 口);
7
- 4. probe_product_serial() 通过官方 SDK 探针读取真实产品序列号;
8
- 5. 按序列号定位 fays_config/fays_vikit_{serial}.yaml 与
 
 
 
 
 
9
  dist/fays_opencv48/s80m_{serial}_stereo_inertial.yaml;缺任一个就**现场
10
  用厂商导出程序从这只夹爪读出厂标定补齐**(见 calibration.py),不必再
11
  人工跑上位机 device_setup + 导入;
12
- 6. flock 租约 /tmp/ksq-gripper-fays-locks/{serial}.lock 防多开;
13
- 7. materialize 当前端口的运行时 SDK yaml,并在 /dev/shm 建 IPC 目录。
14
 
15
  返回的 selected 字典携带 SlamProcessController 与相机服务组合所需字段
16
  (ports/runtime_config/ipc_dir/trajectory/settings/executable/...)。
@@ -29,6 +34,7 @@ import time
29
 
30
  from config import settings
31
  from core.gripper import calibration, paths
 
32
  from core.gripper.fays_runtime import (
33
  FAYS_MIN_USB_SPEED_MBPS,
34
  build_fays_probe_env,
@@ -37,8 +43,10 @@ from core.gripper.fays_runtime import (
37
  discover_fays_device_groups,
38
  materialize_fays_device_config,
39
  validate_fays_sdk_access,
 
40
  )
41
  from core.gripper.fays_serial_probe import probe_product_serial
 
42
 
43
  _INSTANCE_IPC_FILES = (
44
  "orb_pose.json.tmp", "orb_pose.json", "orb_meta.json",
@@ -138,11 +146,15 @@ class SingleFaysLease:
138
  )
139
 
140
  def _match_esp(self, esp_serial):
141
- """按 USB serial 唯一匹配 ESP32 控制板,返回其 tty 设备路径。"""
 
 
 
 
142
  devices = discover_esp32_devices()
143
  matches = [
144
  info for info in devices
145
- if str(info.get("serial") or "").strip() == str(esp_serial).strip()
146
  ]
147
  if len(matches) != 1:
148
  available = ", ".join(
@@ -150,68 +162,154 @@ class SingleFaysLease:
150
  )
151
  raise GripperFaysError(
152
  "ESP32 控制板未唯一匹配: 期望 serial={} 当前=[{}]".format(
153
- esp_serial, available)
154
  )
155
  return matches[0]
156
 
157
- def _discover_unique_fays_group(self, esp):
158
- """按 ESP 的根端口关联 rig 内的 S80M,要求唯一命中。
159
-
160
- Fays 是 USB3/FT602:插在 USB3 口时走 5000M 伴生总线,与 ESP/
161
- 触觉相机的 480M 总线 bus 号不同(如 ESP=7-2、Fays=8-2 是同一
162
- 物理口的双总线伴生),因此原程序的拓扑规则只按根端口关联
163
- (见 uvc_camera_service._associate_group 的同名注释)。
164
- 同一台机器可能还插着主程序自己的独立 S80M(不同根端口),
165
- 必须按夹爪 rig 的拓扑范围区分,不能全机枚举;多台命中即报错
166
- 不猜归属。rig 内仍只允许 1 台完整 S80M。
167
- 多控制器机器(双夹爪)还必须带控制器身份比较:两套 rig 可能
168
- 都插在各自控制器的同号根端口上(实测都是根端口 2,控制器
169
- 0000:0a:00.0 与 0000:74:00.4),只比端口号会互相误配。
170
  """
171
- esp_controller, esp_root = self._bus_root(
172
- str(esp.get("physical_usb_path") or ""))
173
- if not esp_controller or not esp_root:
174
  raise GripperFaysError(
175
- "ESP32 物理 USB 路径无效: {!r}".format(
176
- esp.get("physical_usb_path")))
177
- groups = tuple(discover_fays_device_groups())
178
- same_rig = [
179
- group for group in groups
180
- if self._bus_root(group["physical_usb_path"])
181
- == (esp_controller, esp_root)
182
- ]
183
- if len(same_rig) != 1:
184
- found = ", ".join(
185
- str(g["physical_usb_path"]) for g in same_rig)
186
  raise GripperFaysError(
187
- "夹爪 rig(控制器 {} 根端口 {})内发现 {} 台 Fays S80M,"
188
- "只允许 1 台: [{}]".format(
189
- esp_controller, esp_root, len(same_rig), found))
190
- return same_rig[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
  @staticmethod
193
- def _bus_root(physical):
194
- """"1-3.4.1" → (controller, "3")。
195
-
196
- controller 取 /sys/bus/usb/devices/usb{bus} 的 realpath 父路径
197
- (usbN 节点之上的 PCI devpath,如 .../0000:0a:00.0)——多控制器
198
- 机器上不同控制器的同号根端口必须区分;USB2/USB3 伴生双总线
199
- (同一物理口 ESP=7-2、Fays=8-2)仍只按控制器+根端口关联,
200
- 不比较总线号,伴生容忍不变。
201
  """
202
- bus, separator, ports = str(physical or "").partition("-")
203
- root = ports.split(".")[0] if separator else ""
204
- if not separator:
205
- return "", ""
206
  try:
207
- real = os.path.realpath(
208
- os.path.join("/sys", "bus", "usb", "devices", f"usb{bus}"))
209
- except OSError:
210
- return f"bus-{bus}", root # sysfs 不可读时退回总线区分
211
- return os.path.dirname(real), root
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
- def _probe_serial(self, group):
214
- """官方 SDK 探针读取产品序列号;USB 速度不足时给出换口提示。"""
 
215
  try:
216
  speed = validate_fays_sdk_access(group)
217
  except Exception as exc:
@@ -234,6 +332,13 @@ class SingleFaysLease:
234
  raise GripperFaysError(
235
  f"Fays SDK 产品序列号探测失败: {exc}"
236
  ) from exc
 
 
 
 
 
 
 
237
  return serial, speed
238
 
239
  def _ensure_calibration(self, serial, group):
@@ -273,8 +378,9 @@ class SingleFaysLease:
273
  """
274
  with self._lock:
275
  esp = self._match_esp(esp_serial)
276
- group = self._discover_unique_fays_group(esp)
277
- serial, _speed = self._probe_serial(group)
 
278
  self._logger(
279
  f"[Gripper-Fays] 正在重新读取 {serial} 的厂商出厂标定…"
280
  )
@@ -293,8 +399,8 @@ class SingleFaysLease:
293
  return dict(self._selected)
294
  self.release()
295
  esp = self._match_esp(esp_serial)
296
- group = self._discover_unique_fays_group(esp)
297
- serial, speed = self._probe_serial(group)
298
  sdk_yaml, orb_yaml = self._ensure_calibration(serial, group)
299
 
300
  os.makedirs(paths.FAYS_LOCK_DIR, mode=0o700, exist_ok=True)
@@ -385,23 +491,6 @@ class SingleFaysLease:
385
  stream.close()
386
  raise
387
 
388
- def resolve_assignment(self, esp_serial):
389
- """相机服务所需的身份 assignment(不探测、不锁租约、不校验速度)。
390
-
391
- UvcCameraServiceManager 只把 fays identity 用作同根端口关联与
392
- 错误文案,从不打开 Fays 相机;此处用实时拓扑推导的物理路径即可,
393
- S80M 的官方 SDK 串行探测留给 acquire()(P3 全链,含 USB3 校验)。
394
- """
395
- esp = self._match_esp(esp_serial)
396
- group = self._discover_unique_fays_group(esp)
397
- return {
398
- "esp32": {"serial": str(esp["serial"])},
399
- "fays": {
400
- "product_serial": "runtime-unprobed",
401
- "physical_usb_path": group["physical_usb_path"],
402
- },
403
- }
404
-
405
  def snapshot(self):
406
  with self._lock:
407
  return (
 
1
  """单夹爪场景的 Fays S80M 租约(无 device_setup 清单版本)。
2
 
3
  主程序一次只服务一套夹爪 rig,设备身份全部来自运行时探测:
4
+ 1. ESP32 按 USB serial 唯一匹配(不看 /dev/ttyACMN 编号);
5
+ 2. 从该 ESP32 的 NVS 读它绑定的 Fays 产品序列号(串口命令 QF);
6
+ 3. 枚举在线完整 S80M,先逐台做 USB SuperSpeed 预检,再用官方 SDK 的
7
+ serial-only-fast 读出真实产品序列号(FT602 描述符和枚举顺序都不算
8
+ 身份);
9
+ 4. 绑定的序列号必须唯一命中一台在线 Fays —— **不按根端口猜归属**;
10
+ 被其他会话占用的 Fays 不参与匹配,但要写进错误文案;
11
+ 5. 对选中的那台再走一次完整 SDK 生命周期,复核序列号与 ESP32 绑定值
12
+ 一致(Connect 路径的完整校验);
13
+ 6. 按序列号定位 fays_config/fays_vikit_{serial}.yaml 与
14
  dist/fays_opencv48/s80m_{serial}_stereo_inertial.yaml;缺任一个就**现场
15
  用厂商导出程序从这只夹爪读出厂标定补齐**(见 calibration.py),不必再
16
  人工跑上位机 device_setup + 导入;
17
+ 7. flock 租约 /tmp/ksq-gripper-fays-locks/{serial}.lock 防多开;
18
+ 8. materialize 当前端口的运行时 SDK yaml,并在 /dev/shm 建 IPC 目录。
19
 
20
  返回的 selected 字典携带 SlamProcessController 与相机服务组合所需字段
21
  (ports/runtime_config/ipc_dir/trajectory/settings/executable/...)。
 
34
 
35
  from config import settings
36
  from core.gripper import calibration, paths
37
+ from core.gripper.devices.gripper_serial import GripperSerial
38
  from core.gripper.fays_runtime import (
39
  FAYS_MIN_USB_SPEED_MBPS,
40
  build_fays_probe_env,
 
43
  discover_fays_device_groups,
44
  materialize_fays_device_config,
45
  validate_fays_sdk_access,
46
+ validate_fays_superspeed,
47
  )
48
  from core.gripper.fays_serial_probe import probe_product_serial
49
+ from core.gripper.runtime.device_access import fays_device_guard
50
 
51
  _INSTANCE_IPC_FILES = (
52
  "orb_pose.json.tmp", "orb_pose.json", "orb_meta.json",
 
146
  )
147
 
148
  def _match_esp(self, esp_serial):
149
+ """按 USB serial 唯一匹配 ESP32 控制板,返回其设备信息。"""
150
+ wanted = str(esp_serial or "").strip()
151
+ if not wanted:
152
+ raise GripperFaysError(
153
+ "未提供 ESP32 USB serial,拒绝按端口号或枚举顺序猜测控制板")
154
  devices = discover_esp32_devices()
155
  matches = [
156
  info for info in devices
157
+ if str(info.get("serial") or "").strip() == wanted
158
  ]
159
  if len(matches) != 1:
160
  available = ", ".join(
 
162
  )
163
  raise GripperFaysError(
164
  "ESP32 控制板未唯一匹配: 期望 serial={} 当前=[{}]".format(
165
+ wanted, available)
166
  )
167
  return matches[0]
168
 
169
+ def _query_esp_bound_fays_serial(self, esp):
170
+ """读 ESP32 NVS 里绑定的 Fays 产品序列号(串口命令 ``QF``)。
171
+
172
+ 串口是独占资源:查询完立刻归还,随后运行时的桥接还要独占打开。
173
+ 未绑定、空值、ERR 一律失败关闭 —— 不允许回退到拓扑猜测。
 
 
 
 
 
 
 
 
174
  """
175
+ device = str(esp.get("device") or "").strip()
176
+ esp_serial = str(esp.get("serial") or "<unknown>").strip()
177
+ if not device:
178
  raise GripperFaysError(
179
+ "ESP32 {} 缺少串口节点,无法查询绑定的 Fays 序列号".format(
180
+ esp_serial))
181
+ bridge = GripperSerial(logger=self._logger)
182
+ if not bridge.connect(device):
 
 
 
 
 
 
 
183
  raise GripperFaysError(
184
+ "ESP32 {} 串口连接失败,无法查询绑定的 Fays 序列号: {}".format(
185
+ esp_serial, bridge.last_error or "unknown error"))
186
+ try:
187
+ response = ""
188
+ for attempt in range(3):
189
+ response = bridge.send("QF")
190
+ if response.startswith(("FAYS_SERIAL:", "ERR FAYS_SERIAL")):
191
+ break
192
+ if response.startswith("STATE") and attempt < 2:
193
+ # 固件周期性状态行插在命令响应前面:重试,别把串口
194
+ # 收发竞态误判成「没有绑定」。
195
+ time.sleep(0.05)
196
+ continue
197
+ break
198
+ finally:
199
+ bridge.disconnect()
200
+ prefix = "FAYS_SERIAL:"
201
+ if response.startswith(prefix):
202
+ serial = response[len(prefix):].strip()
203
+ if serial:
204
+ return serial
205
+ if response.startswith("ERR FAYS_SERIAL_NOT_SET"):
206
+ raise GripperFaysError(
207
+ "ESP32 {} 尚未写入 Fays 序列号,拒绝按端口猜测配对;"
208
+ "请先使用 WF:<serial> 写入后再扫描".format(esp_serial))
209
+ raise GripperFaysError(
210
+ "ESP32 {} 查询 Fays 序列号失败: {}".format(
211
+ esp_serial, response or "<empty>"))
212
 
213
  @staticmethod
214
+ def _device_in_use(group):
215
+ """这台 Fays 是否已被运行中的会话独占(另一套 rig 的 SLAM)。
216
+
217
+ 双夹爪时另一套 rig 的 SLAM 会把本设备锁一直持有到会话结束,
218
+ 它按定义不可能是本次要打开的夹爪,但探测不了就得如实记下来。
 
 
 
219
  """
220
+ port = str((group.get("ports") or {}).get("stereo_dev_port") or "")
221
+ if re.fullmatch(r"/dev/video[0-9]+", port) is None:
222
+ return False # 节点无效留给后面的 SDK 预检去报错
 
223
  try:
224
+ with fays_device_guard(port, timeout=0.0):
225
+ return False
226
+ except RuntimeError:
227
+ return True
228
+
229
+ def _probe_fays_groups_by_serial(self, groups):
230
+ """SuperSpeed 预检 + ``serial-only-fast`` 读出每台 Fays 的产品序列号。
231
+
232
+ 预检在启动 SDK **之前**逐台做(只读 sysfs):降级到 USB2 的设备
233
+ 根本不该进 SDK。返回 ``(by_serial, skipped)``:skipped 是被其他
234
+ 会话占用的设备,它们不参与匹配,但要写进错误文案。
235
+ """
236
+ for group in groups:
237
+ try:
238
+ validate_fays_superspeed(group)
239
+ except Exception as exc:
240
+ raise GripperFaysError(
241
+ "Fays USB 链路预检失败,拒绝启动 SDK: "
242
+ "physical={} error={}".format(
243
+ group.get("physical_usb_path"), exc)) from exc
244
+ by_serial = {}
245
+ skipped = []
246
+ for group in groups:
247
+ if self._device_in_use(group):
248
+ skipped.append(group)
249
+ continue
250
+ ports = dict(group.get("ports") or {})
251
+ if not ports:
252
+ raise GripperFaysError(
253
+ "Fays 设备组缺少 SDK 端口: {!r}".format(group))
254
+ try:
255
+ serial = str(probe_product_serial(
256
+ ports,
257
+ environment=build_fays_probe_env(),
258
+ serial_only_fast=True,
259
+ ) or "").strip()
260
+ except Exception as exc:
261
+ raise GripperFaysError(
262
+ "Fays SDK 产品序列号探测失败,拒绝回退到拓扑猜测: "
263
+ "physical={} error={}".format(
264
+ group.get("physical_usb_path"), exc)) from exc
265
+ if not serial:
266
+ raise GripperFaysError(
267
+ "Fays SDK 返回空产品序列号,拒绝继续: physical={}".format(
268
+ group.get("physical_usb_path")))
269
+ if serial in by_serial:
270
+ raise GripperFaysError(
271
+ "Fays SDK 返回重复产品序列号,拒绝猜测归属: "
272
+ "serial={}".format(serial))
273
+ by_serial[serial] = group
274
+ return by_serial, skipped
275
+
276
+ def _resolve_fays_group(self, esp):
277
+ """唯一 ESP32 → ``QF`` 绑定序列号 → 按 SDK serial 唯一匹配 Fays。
278
+
279
+ 返回 ``(group, bound_serial)``。**不再按 USB 根端口关联**:Fays 是
280
+ USB3/FT602,插在 USB3 口时走 5000M 伴生总线,bus 号与 ESP/触觉
281
+ 相机的 480M 总线不同;多控制器机器上两套 rig 又经常落在同号根
282
+ 端口,按端口关联只会互相误配。
283
+ """
284
+ groups = tuple(discover_fays_device_groups())
285
+ if not groups:
286
+ raise GripperFaysError(
287
+ "未发现完整的 Fays S80M(stereo + IMU 两个节点必须同时在线)")
288
+ bound = self._query_esp_bound_fays_serial(esp)
289
+ by_serial, skipped = self._probe_fays_groups_by_serial(groups)
290
+ group = by_serial.get(bound)
291
+ if group is None:
292
+ online = ", ".join(sorted(by_serial)) or "<无>"
293
+ detail = ""
294
+ if skipped:
295
+ detail = ";另有正在被占用的 Fays 未能探测: [{}]".format(
296
+ ", ".join(
297
+ "{}({})".format(
298
+ item.get("physical_usb_path"),
299
+ (item.get("ports") or {}).get("stereo_dev_port"))
300
+ for item in skipped))
301
+ raise GripperFaysError(
302
+ "ESP32 {} 绑定的 Fays 序列号 {} 不在当前在线的 Fays 中,"
303
+ "拒绝按端口或枚举顺序猜测配对:在线 serial=[{}]{}".format(
304
+ esp.get("serial"), bound, online, detail))
305
+ return group, bound
306
+
307
+ def _probe_serial(self, group, expected_serial=None):
308
+ """官方 SDK 完整生命周期读序列号;USB 速度不足时给出换口提示。
309
 
310
+ ``expected_serial`` 是 ESP32 NVS 里的绑定值:Connect 路径必须复核
311
+ 两者一致,不允许一台「碰巧在线」的 Fays 顶替绑定设备。
312
+ """
313
  try:
314
  speed = validate_fays_sdk_access(group)
315
  except Exception as exc:
 
332
  raise GripperFaysError(
333
  f"Fays SDK 产品序列号探测失败: {exc}"
334
  ) from exc
335
+ if expected_serial is not None and \
336
+ str(serial).strip() != str(expected_serial).strip():
337
+ raise GripperFaysError(
338
+ "Fays SDK 序列号与 ESP32 绑定值不一致,拒绝连接: "
339
+ "physical={} bound={} actual={}".format(
340
+ group.get("physical_usb_path"),
341
+ expected_serial, serial))
342
  return serial, speed
343
 
344
  def _ensure_calibration(self, serial, group):
 
378
  """
379
  with self._lock:
380
  esp = self._match_esp(esp_serial)
381
+ group, bound = self._resolve_fays_group(esp)
382
+ serial, _speed = self._probe_serial(
383
+ group, expected_serial=bound)
384
  self._logger(
385
  f"[Gripper-Fays] 正在重新读取 {serial} 的厂商出厂标定…"
386
  )
 
399
  return dict(self._selected)
400
  self.release()
401
  esp = self._match_esp(esp_serial)
402
+ group, bound = self._resolve_fays_group(esp)
403
+ serial, speed = self._probe_serial(group, expected_serial=bound)
404
  sdk_yaml, orb_yaml = self._ensure_calibration(serial, group)
405
 
406
  os.makedirs(paths.FAYS_LOCK_DIR, mode=0o700, exist_ok=True)
 
491
  stream.close()
492
  raise
493
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  def snapshot(self):
495
  with self._lock:
496
  return (
collector/core/gripper/paths.py CHANGED
@@ -48,6 +48,12 @@ CAMERA_SERVICE_BINARY = os.path.join(
48
  DISCOVER_UVC_CONFIG_BINARY = os.path.join(
49
  CAMERA_SERVICE_DIR, "build", "discover-uvc-config",
50
  )
 
 
 
 
 
 
51
  SIGHTAC_SDK_ROOT = os.path.abspath(os.environ.get(
52
  "KSQ_SIGHTAC_ROOT",
53
  os.path.join(PACKAGE_ROOT, "sightac_sdk"),
 
48
  DISCOVER_UVC_CONFIG_BINARY = os.path.join(
49
  CAMERA_SERVICE_DIR, "build", "discover-uvc-config",
50
  )
51
+ # 相机服务学到的等时档位就存在这里:按「机型 × 控制器 PCI 路径 × 相机序列号」
52
+ # 一个键一个文件。放在 GRIPPER_DIR 下而不是服务的 runtime_dir 里,因为后者
53
+ # 每次租约释放都会被整个删掉(见 uvc_camera_service._release_lease),存那儿
54
+ # 等于没存。C 侧按 state_dir 这个 ini 键收到它,见 camera_service.c 的
55
+ # persist_mode_choice。
56
+ CAMERA_MODE_STATE_DIR = os.path.join(GRIPPER_DIR, "camera_modes")
57
  SIGHTAC_SDK_ROOT = os.path.abspath(os.environ.get(
58
  "KSQ_SIGHTAC_ROOT",
59
  os.path.join(PACKAGE_ROOT, "sightac_sdk"),