Skip to content

Commit 7902cde

Browse files
committed
Libcamera_cam/run.sh: minimal runner, DT gating, clear summaries
- Source camera utils; keep main script small and readable. - Fast DT gating: print per-pattern matches; skip only when none found. - Treat cam -l/-I WARN/ERROR noise as non-fatal when cameras enumerate. - Support indices: auto | all | comma-separated; per-camera PASS/FAIL with an overall verdict and summary file. - Use --file correctly for directory or explicit filename targets. - ShellCheck fixes (SC1090/SC2015): dynamic source directives and proper if/else usage. - Add structured logging and stable, deterministic exit codes. Signed-off-by: Srikanth Muppandam <[email protected]>
1 parent baeabd3 commit 7902cde

File tree

1 file changed

+304
-0
lines changed
  • Runner/suites/Multimedia/Camera/Libcamera_cam

1 file changed

+304
-0
lines changed
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#!/bin/sh
2+
# Copyright (c) Qualcomm Technologies, Inc.
3+
# SPDX-License-Identifier: BSD-3-Clause-Clear
4+
# libcamera 'cam' runner with strong post-capture validation (CLI-config only)
5+
# ---------- Repo env + helpers (single-pass) ----------
6+
SCRIPT_DIR=$(cd "$(dirname "$0")" || exit 1; pwd)
7+
SEARCH="$SCRIPT_DIR"
8+
INIT_ENV="${INIT_ENV:-}"
9+
LIBCAM_PATH="${LIBCAM_PATH:-}"
10+
11+
# Find init_env quickly (single upward walk)
12+
while [ "$SEARCH" != "/" ] && [ -z "$INIT_ENV" ]; do
13+
[ -f "$SEARCH/init_env" ] && INIT_ENV="$SEARCH/init_env" && break
14+
SEARCH=${SEARCH%/*}
15+
done
16+
17+
if [ -z "$INIT_ENV" ]; then
18+
printf '%s\n' "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2
19+
exit 1
20+
fi
21+
22+
# shellcheck disable=SC1090
23+
. "$INIT_ENV"
24+
# shellcheck disable=SC1091
25+
. "$TOOLS/functestlib.sh"
26+
27+
# Prefer direct repo-root locations for lib_camera.sh
28+
if [ -z "$LIBCAM_PATH" ]; then
29+
REPO_ROOT=$(dirname "$INIT_ENV")
30+
for cand in \
31+
"$REPO_ROOT/Runner/utils/camera/lib_camera.sh" \
32+
"$REPO_ROOT/utils/camera/lib_camera.sh"
33+
do
34+
[ -f "$cand" ] && { LIBCAM_PATH="$cand"; break; }
35+
done
36+
fi
37+
38+
# Fallback upward walk only if still not found
39+
if [ -z "$LIBCAM_PATH" ]; then
40+
SEARCH="$SCRIPT_DIR"
41+
while [ "$SEARCH" != "/" ]; do
42+
for cand in \
43+
"$SEARCH/Runner/utils/camera/lib_camera.sh" \
44+
"$SEARCH/utils/camera/lib_camera.sh"
45+
do
46+
[ -f "$cand" ] && { LIBCAM_PATH="$cand"; break 2; }
47+
done
48+
SEARCH=${SEARCH%/*}
49+
done
50+
fi
51+
52+
if [ -z "$LIBCAM_PATH" ]; then
53+
if command -v log_error >/dev/null 2>&1; then
54+
log_error "lib_camera.sh not found (searched under Runner/utils/camera and utils/camera)"
55+
else
56+
printf '%s\n' "ERROR: lib_camera.sh not found (searched under Runner/utils/camera and utils/camera)" >&2
57+
fi
58+
exit 1
59+
fi
60+
61+
# shellcheck source=../../../../utils/camera/lib_camera.sh disable=SC1091
62+
. "$LIBCAM_PATH"
63+
64+
TESTNAME="Libcamera_cam"
65+
RES_FILE="./${TESTNAME}.res"
66+
: > "$RES_FILE"
67+
68+
# ---------- Defaults (override via CLI only) ----------
69+
CAM_INDEX="auto" # --index <n>|all|n,m,k ; auto = first from `cam -l`
70+
CAPTURE_COUNT="10" # --count <n>
71+
OUT_DIR="./cam_out" # --out <dir>
72+
SAVE_AS_PPM="no" # --ppm | --bin
73+
CAM_EXTRA_ARGS="" # --args "<cam args>"
74+
75+
# Validation knobs
76+
SEQ_STRICT="yes" # --no-strict to relax
77+
ERR_STRICT="yes" # --no-strict to relax
78+
DUP_MAX_RATIO="0.5" # --dup-max-ratio <0..1>
79+
BIN_TOL_PCT="5" # --bin-tol-pct <int %>
80+
PPM_SAMPLE_BYTES="65536"
81+
BIN_SAMPLE_BYTES="65536"
82+
83+
print_usage() {
84+
cat <<EOF
85+
Usage: $0 [options]
86+
87+
Options:
88+
--index N|all|n,m Camera index (default: auto from 'cam -l'; 'all' = run every camera)
89+
--count N Frames to capture (default: 10)
90+
--out DIR Output directory (default: ./cam_out)
91+
--ppm Save as PPM files (frame-#.ppm)
92+
--bin Save as BIN files (default; frame-#.bin)
93+
--args "STR" Extra arguments passed to 'cam' (e.g. -s width=1280,height=720,role=viewfinder)
94+
--strict Enforce strict validation (default)
95+
--no-strict Relax validation (no seq/err strictness)
96+
--dup-max-ratio R Fail if max duplicate bucket / total > R (default: 0.5)
97+
--bin-tol-pct P BIN size tolerance vs bytesused in % (default: 5)
98+
-h, --help Show this help
99+
EOF
100+
}
101+
102+
# ---------- CLI ----------
103+
while [ $# -gt 0 ]; do
104+
case "$1" in
105+
--index) shift; CAM_INDEX="$1" ;;
106+
--count) shift; CAPTURE_COUNT="$1" ;;
107+
--out) shift; OUT_DIR="$1" ;;
108+
--ppm) SAVE_AS_PPM="yes" ;;
109+
--bin) SAVE_AS_PPM="no" ;;
110+
--args) shift; CAM_EXTRA_ARGS="$1" ;;
111+
--strict) SEQ_STRICT="yes"; ERR_STRICT="yes" ;;
112+
--no-strict) SEQ_STRICT="no"; ERR_STRICT="no" ;;
113+
--dup-max-ratio) shift; DUP_MAX_RATIO="$1" ;;
114+
--bin-tol-pct) shift; BIN_TOL_PCT="$1" ;;
115+
-h|--help) print_usage; exit 0 ;;
116+
*) log_warn "Unknown option: $1"; print_usage; exit 2 ;;
117+
esac
118+
shift
119+
done
120+
121+
# ---------- DT / platform readiness ----------
122+
# Print both sensor and CAMSS/ISP matches if they exist; skip only if neither is present.
123+
log_info "Verifying the availability of DT nodes, this process may take some time."
124+
125+
PATTERNS="sony,imx577 imx577 isp cam camss"
126+
found_any=0
127+
missing_list=""
128+
129+
for pat in $PATTERNS; do
130+
out="$(dt_confirm_node_or_compatible "$pat" 2>/dev/null || true)"
131+
if [ -n "$out" ]; then
132+
printf '%s\n' "$out"
133+
found_any=1
134+
else
135+
[ -n "$missing_list" ] && missing_list="$missing_list, $pat" || missing_list="$pat"
136+
fi
137+
done
138+
139+
if [ "$found_any" -eq 1 ]; then
140+
log_info "DT nodes present (see matches above)."
141+
else
142+
log_skip "$TESTNAME SKIP – missing DT patterns: $missing_list"
143+
echo "$TESTNAME SKIP" >"$RES_FILE"
144+
exit 0
145+
fi
146+
147+
# ---------- Dependencies ----------
148+
log_info "Reviewing the dependencies needed to run the cam test."
149+
check_dependencies cam || {
150+
log_error "cam utility not found"
151+
echo "$TESTNAME FAIL" > "$RES_FILE"
152+
exit 1
153+
}
154+
# nice-to-haves for validation
155+
check_dependencies awk sed grep sort cut tr wc find stat head tail dd || true
156+
(check_dependencies sha256sum || check_dependencies md5sum) || true
157+
158+
# ---------- Setup ----------
159+
mkdir -p "$OUT_DIR" 2>/dev/null || true
160+
RUN_TS="$(date -u +%Y%m%d-%H%M%S)"
161+
162+
log_info "Test: $TESTNAME"
163+
log_info "OUT_DIR=$OUT_DIR | COUNT=$CAPTURE_COUNT | SAVE_AS_PPM=$SAVE_AS_PPM"
164+
log_info "Extra args: ${CAM_EXTRA_ARGS:-<none>}"
165+
166+
# ---- IPA workaround: disable simple/uncalibrated to avoid buffer allocation failures ----
167+
UNCALIB="/usr/share/libcamera/ipa/simple/uncalibrated.yaml"
168+
if [ -f "$UNCALIB" ]; then
169+
log_info "Renaming $UNCALIB -> ${UNCALIB}.bk to avoid IPA buffer allocation issues"
170+
mv "$UNCALIB" "${UNCALIB}.bk" 2>/dev/null || log_warn "Failed to rename $UNCALIB (continuing)"
171+
elif [ -f "${UNCALIB}.bk" ]; then
172+
# Already renamed in a previous run; just log for clarity
173+
log_info "IPA workaround already applied: ${UNCALIB}.bk present"
174+
fi
175+
176+
# ---------- Sensor presence ----------
177+
SENSOR_COUNT="$(libcam_list_sensors_count 2>/dev/null)"
178+
# harden: ensure numeric
179+
case "$SENSOR_COUNT" in ''|*[!0-9]*) SENSOR_COUNT=0 ;; esac
180+
log_info "[cam -l] detected ${SENSOR_COUNT} camera(s)"
181+
182+
if [ "$SENSOR_COUNT" -lt 1 ]; then
183+
log_skip "No sensors reported by 'cam -l' - marking SKIP"
184+
echo "$TESTNAME SKIP" > "$RES_FILE"
185+
exit 0
186+
fi
187+
188+
189+
# ---------- Resolve indices (supports: auto | all | 0,2,5) ----------
190+
INDICES="$(libcam_resolve_indices "$CAM_INDEX")"
191+
if [ -z "$INDICES" ]; then
192+
log_skip "No valid camera indices resolved (cam -l empty?) - SKIP"
193+
echo "$TESTNAME SKIP" > "$RES_FILE"
194+
exit 0
195+
fi
196+
log_info "Resolved indices: $INDICES"
197+
198+
OVERALL_PASS=1
199+
ANY_RC_NONZERO=0
200+
PASS_LIST=""
201+
FAIL_LIST=""
202+
: > "$OUT_DIR/summary.txt"
203+
204+
for IDX in $INDICES; do
205+
# Per-camera logs & output dir
206+
CAM_DIR="${OUT_DIR%/}/cam${IDX}"
207+
mkdir -p "$CAM_DIR" 2>/dev/null || true
208+
RUN_LOG="${CAM_DIR%/}/cam-run-${RUN_TS}-cam${IDX}.log"
209+
INFO_LOG="${CAM_DIR%/}/cam-info-${RUN_TS}-cam${IDX}.log"
210+
211+
log_info "---- Camera idx: $IDX ----"
212+
{
213+
echo "== cam -l =="
214+
cam -l || true
215+
echo
216+
echo "== cam -I (index $IDX) =="
217+
cam -c "$IDX" -I || true
218+
} >"$INFO_LOG" 2>&1
219+
220+
# Capture
221+
FILE_TARGET="$CAM_DIR/"
222+
[ "$SAVE_AS_PPM" = "yes" ] && FILE_TARGET="$CAM_DIR/frame-#.ppm"
223+
224+
log_info "cmd:"
225+
log_info " cam -c $IDX --capture=$CAPTURE_COUNT \\"
226+
log_info " --file=\"$FILE_TARGET\" ${CAM_EXTRA_ARGS:+\\}"
227+
[ -n "$CAM_EXTRA_ARGS" ] && log_info " $CAM_EXTRA_ARGS"
228+
229+
# shellcheck disable=SC2086
230+
( cam -c "$IDX" --capture="$CAPTURE_COUNT" --file="$FILE_TARGET" $CAM_EXTRA_ARGS ) \
231+
>"$RUN_LOG" 2>&1
232+
RC=$?
233+
234+
tail -n 50 "$RUN_LOG" | sed "s/^/[cam idx $IDX] /"
235+
236+
# Per-camera validation
237+
BIN_COUNT=$(find "$CAM_DIR" -maxdepth 1 -type f -name 'frame-*.bin' | wc -l | tr -d ' ')
238+
PPM_COUNT=$(find "$CAM_DIR" -maxdepth 1 -type f -name 'frame-*.ppm' | wc -l | tr -d ' ')
239+
TOTAL=$((BIN_COUNT + PPM_COUNT))
240+
log_info "[idx $IDX] Produced files: bin=$BIN_COUNT ppm=$PPM_COUNT total=$TOTAL (requested $CAPTURE_COUNT)"
241+
242+
PASS=1
243+
[ "$TOTAL" -ge "$CAPTURE_COUNT" ] || { log_warn "[idx $IDX] Fewer files than requested"; PASS=0; }
244+
245+
SEQ_REPORT="$(libcam_log_seqs "$RUN_LOG" | wc -l | tr -d ' ')"
246+
[ "$SEQ_REPORT" -ge "$CAPTURE_COUNT" ] || { log_warn "[idx $IDX] cam log shows fewer seq lines ($SEQ_REPORT) than requested ($CAPTURE_COUNT)"; PASS=0; }
247+
248+
if [ "$SEQ_STRICT" = "yes" ]; then
249+
CSUM="$(libcam_log_seqs "$RUN_LOG" | libcam_check_contiguous 2>&1)"
250+
echo "$CSUM" | sed 's/^/[seq] /'
251+
echo "$CSUM" | grep -q 'MISSING=0' || { log_warn "[idx $IDX] non-contiguous sequences in log"; PASS=0; }
252+
fi
253+
254+
libcam_files_and_seq "$CAM_DIR" "$SEQ_STRICT" || PASS=0
255+
libcam_validate_content "$CAM_DIR" "$RUN_LOG" "$PPM_SAMPLE_BYTES" "$BIN_SAMPLE_BYTES" "$BIN_TOL_PCT" "$DUP_MAX_RATIO" || PASS=0
256+
libcam_scan_errors "$RUN_LOG" "$ERR_STRICT" || PASS=0
257+
258+
[ $RC -eq 0 ] || { ANY_RC_NONZERO=1; PASS=0; }
259+
260+
if [ "$PASS" -eq 1 ]; then
261+
log_pass "[idx $IDX] PASS"
262+
PASS_LIST="$PASS_LIST $IDX"
263+
echo "cam$IDX PASS" >> "$OUT_DIR/summary.txt"
264+
else
265+
log_fail "[idx $IDX] FAIL"
266+
FAIL_LIST="$FAIL_LIST $IDX"
267+
echo "cam$IDX FAIL" >> "$OUT_DIR/summary.txt"
268+
OVERALL_PASS=0
269+
fi
270+
done
271+
272+
# ---------- Per-camera summary (always printed) ----------
273+
pass_trim="$(printf '%s' "$PASS_LIST" | sed 's/^ //')"
274+
fail_trim="$(printf '%s' "$FAIL_LIST" | sed 's/^ //')"
275+
log_info "---------- Per-camera summary ----------"
276+
if [ -n "$pass_trim" ]; then
277+
log_info "PASS: $pass_trim"
278+
else
279+
log_info "PASS: (none)"
280+
fi
281+
if [ -n "$fail_trim" ]; then
282+
log_info "FAIL: $fail_trim"
283+
else
284+
log_info "FAIL: (none)"
285+
fi
286+
log_info "Summary file: $OUT_DIR/summary.txt"
287+
288+
# ---------- Final verdict ----------
289+
if [ "$OVERALL_PASS" -eq 1 ] && [ $ANY_RC_NONZERO -eq 0 ]; then
290+
echo "$TESTNAME PASS" > "$RES_FILE"
291+
log_pass "$TESTNAME PASS"
292+
exit 0
293+
else
294+
echo "$TESTNAME FAIL" > "$RES_FILE"
295+
log_fail "$TESTNAME FAIL"
296+
exit 1
297+
fi
298+
299+
# ---------- Artifacts ----------
300+
log_info "Artifacts under: $OUT_DIR/"
301+
for IDX in $INDICES; do
302+
CAM_DIR="${OUT_DIR%/}/cam${IDX}"
303+
log_info " - $CAM_DIR/"
304+
done

0 commit comments

Comments
 (0)