Skip to content

Commit 2af4497

Browse files
committed
Refactor and enhance V4L2 test suite
- Removed obsolete test scripts: run_ci.py, test_fps.py, test_fw_version.py. - Updated conftest.py to include new resolution discovery functions for depth, RGB, and IR. - Enhanced constants.py to define known driver names for better driver validation. - Improved discovery.py to support camera discovery via symlinks on Tegra platforms. - Modified test_controls.py to add tests for auto-exposure mode switching and manual exposure control. - Updated test_discovery.py to validate driver names against known constants. - Enhanced test_error_handling.py to gracefully handle unsupported resolutions and zero FPS settings. - Improved test_metadata.py to configure metadata capture with error handling for fixed formats. - Added concurrent streaming tests in test_streaming.py for depth, RGB, and IR streams. - Updated device.py to handle ioctl errors gracefully for tegra-video driver. - Added new ioctl constants in ioctls.py for exposure control.
1 parent a024987 commit 2af4497

14 files changed

Lines changed: 647 additions & 255 deletions

setup_workspace.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ echo
7373
# Clone L4T kernel source repo
7474
cd $DEVDIR
7575

76-
# Check if local tar ball exists in ~/nvidia_sources_cache
77-
NVIDIA_CACHE_DIR="$HOME/nvidia_sources_cache"
76+
# Check if local tar ball exists in /home/nvidia_sources_cache
77+
NVIDIA_CACHE_DIR="/home/nvidia_sources_cache"
7878
TARBALL_NAME="backup_sources_$1.tar.gz"
7979
TARBALL_PATH="$NVIDIA_CACHE_DIR/$TARBALL_NAME"
8080

test/run_ci.py

Lines changed: 0 additions & 86 deletions
This file was deleted.

test/test_fps.py

Lines changed: 0 additions & 97 deletions
This file was deleted.

test/test_fw_version.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

test/v4l2_test/conftest.py

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .d4xx.discovery import discover_cameras
99
from .d4xx import constants as C
1010
from .v4l2.device import V4L2Device
11+
from .v4l2 import ioctls
1112
from .report import D4xxReportPlugin
1213

1314

@@ -63,13 +64,16 @@ def camera(all_cameras, request):
6364
def fw_version(camera):
6465
"""Cached firmware version as (raw_int, version_string) tuple."""
6566
with V4L2Device(camera.depth_path) as dev:
66-
ctrl = dev.get_ctrl(C.DS5_CAMERA_CID_FW_VERSION)
67-
raw = ctrl.value
68-
major = (raw >> 24) & 0xFF
69-
minor = (raw >> 16) & 0xFF
70-
patch = (raw >> 8) & 0xFF
71-
build = raw & 0xFF
72-
return raw, f"{major}.{minor}.{patch}.{build}"
67+
try:
68+
ctrl = dev.get_ctrl(C.DS5_CAMERA_CID_FW_VERSION)
69+
raw = ctrl.value
70+
major = (raw >> 24) & 0xFF
71+
minor = (raw >> 16) & 0xFF
72+
patch = (raw >> 8) & 0xFF
73+
build = raw & 0xFF
74+
return raw, f"{major}.{minor}.{patch}.{build}"
75+
except OSError:
76+
pytest.skip("FW version control not available (tegra-video driver)")
7377

7478

7579
# ---- Function-scoped device fixtures ----
@@ -108,3 +112,130 @@ def depth_md_device(camera):
108112
dev.open()
109113
yield dev
110114
dev.close()
115+
116+
117+
def _discrete_sizes(dev, pixfmt):
118+
"""Return set of (w, h) for discrete frame sizes."""
119+
return {
120+
(s.discrete.width, s.discrete.height)
121+
for s in dev.enum_framesizes(pixfmt)
122+
if s.type == ioctls.V4L2_FRMSIZE_TYPE_DISCRETE
123+
}
124+
125+
126+
# ---- Cached common resolution discovery (used by pytest_generate_tests) ----
127+
128+
_common_res_cache = None
129+
130+
131+
def _discover_common_resolutions():
132+
"""Discover resolutions shared by depth (Z16) and RGB.
133+
134+
Returns ([(w,h), ...], rgb_pixfmt) or ([], None) if unavailable.
135+
Cached after first call.
136+
"""
137+
global _common_res_cache
138+
if _common_res_cache is not None:
139+
return _common_res_cache
140+
141+
cameras = discover_cameras()
142+
if not cameras:
143+
_common_res_cache = ([], None)
144+
return _common_res_cache
145+
146+
cam = cameras[0]
147+
try:
148+
with V4L2Device(cam.depth_path) as ddev:
149+
depth_sizes = _discrete_sizes(ddev, ioctls.V4L2_PIX_FMT_Z16)
150+
151+
with V4L2Device(cam.rgb_path) as rdev:
152+
rgb_formats = rdev.enum_formats()
153+
if not rgb_formats:
154+
_common_res_cache = ([], None)
155+
return _common_res_cache
156+
rgb_pixfmt = rgb_formats[0].pixelformat
157+
rgb_sizes = _discrete_sizes(rdev, rgb_pixfmt)
158+
159+
common = sorted(depth_sizes & rgb_sizes, key=lambda wh: wh[0] * wh[1])
160+
_common_res_cache = (common, rgb_pixfmt)
161+
except (OSError, Exception):
162+
_common_res_cache = ([], None)
163+
164+
return _common_res_cache
165+
166+
167+
@pytest.fixture(scope="session")
168+
def common_depth_rgb_resolutions(camera):
169+
"""Resolutions supported by both depth (Z16) and RGB on this camera."""
170+
resolutions, rgb_pixfmt = _discover_common_resolutions()
171+
if not resolutions:
172+
pytest.skip("No common resolutions between depth and RGB")
173+
return resolutions, rgb_pixfmt
174+
175+
176+
# ---- Cached common depth+RGB+IR resolution discovery ----
177+
178+
_common_all_res_cache = None
179+
180+
181+
def _discover_common_all_resolutions():
182+
"""Discover resolutions shared by depth (Z16), RGB, and IR (GREY).
183+
184+
Returns ([(w,h), ...], rgb_pixfmt) or ([], None) if unavailable.
185+
Cached after first call.
186+
"""
187+
global _common_all_res_cache
188+
if _common_all_res_cache is not None:
189+
return _common_all_res_cache
190+
191+
cameras = discover_cameras()
192+
if not cameras:
193+
_common_all_res_cache = ([], None)
194+
return _common_all_res_cache
195+
196+
cam = cameras[0]
197+
try:
198+
with V4L2Device(cam.depth_path) as ddev:
199+
depth_sizes = _discrete_sizes(ddev, ioctls.V4L2_PIX_FMT_Z16)
200+
201+
with V4L2Device(cam.rgb_path) as rdev:
202+
rgb_formats = rdev.enum_formats()
203+
if not rgb_formats:
204+
_common_all_res_cache = ([], None)
205+
return _common_all_res_cache
206+
rgb_pixfmt = rgb_formats[0].pixelformat
207+
rgb_sizes = _discrete_sizes(rdev, rgb_pixfmt)
208+
209+
with V4L2Device(cam.ir_path) as idev:
210+
ir_sizes = _discrete_sizes(idev, ioctls.V4L2_PIX_FMT_GREY)
211+
212+
common = sorted(
213+
depth_sizes & rgb_sizes & ir_sizes,
214+
key=lambda wh: wh[0] * wh[1],
215+
)
216+
_common_all_res_cache = (common, rgb_pixfmt)
217+
except (OSError, Exception):
218+
_common_all_res_cache = ([], None)
219+
220+
return _common_all_res_cache
221+
222+
223+
@pytest.fixture(scope="session")
224+
def common_depth_rgb_ir_resolutions(camera):
225+
"""Resolutions supported by depth (Z16), RGB, and IR (GREY)."""
226+
resolutions, rgb_pixfmt = _discover_common_all_resolutions()
227+
if not resolutions:
228+
pytest.skip("No common resolutions between depth, RGB, and IR")
229+
return resolutions, rgb_pixfmt
230+
231+
232+
def pytest_generate_tests(metafunc):
233+
"""Dynamically parametrize resolution fixtures from hardware enumeration."""
234+
if "resolution" in metafunc.fixturenames:
235+
resolutions, _ = _discover_common_resolutions()
236+
ids = [f"{w}x{h}" for w, h in resolutions]
237+
metafunc.parametrize("resolution", resolutions, ids=ids)
238+
if "tri_resolution" in metafunc.fixturenames:
239+
resolutions, _ = _discover_common_all_resolutions()
240+
ids = [f"{w}x{h}" for w, h in resolutions]
241+
metafunc.parametrize("tri_resolution", resolutions, ids=ids)

0 commit comments

Comments
 (0)