@@ -416,3 +416,223 @@ libcam_scan_errors() {
416416 rm -f " $tmpf "
417417 return 0
418418}
419+
420+ # Camera common helpers (Downstream CAMX/NHX)
421+ # Keep generic helpers only. Policy and gating belongs in run.sh.
422+
423+ # -----------------------------------------------------------------------------
424+ # SoC id helper
425+ # -----------------------------------------------------------------------------
426+ # Return SoC id token used in firmware paths
427+ # Prefer /sys/devices/soc0/soc_id. Normalize to lowercase and trim.
428+ camx_read_soc_id () {
429+ soc=" "
430+
431+ if [ -r /sys/devices/soc0/soc_id ]; then
432+ soc=" $( tr -d ' \r\n[:space:]' < /sys/devices/soc0/soc_id 2> /dev/null | tr ' [:upper:]' ' [:lower:]' ) "
433+ fi
434+
435+ [ -n " $soc " ] || return 1
436+ echo " $soc "
437+ return 0
438+ }
439+
440+ # -----------------------------------------------------------------------------
441+ # Firmware helpers
442+ # -----------------------------------------------------------------------------
443+ # Find ICP camera firmware ELF (CAMERA_ICP_*.elf)
444+ # Prints first match path on stdout.
445+ camx_find_icp_firmware () {
446+ soc=" $( camx_read_soc_id 2> /dev/null || true) "
447+
448+ # First try soc-specific canonical path
449+ for root in /usr/lib/firmware /lib/firmware; do
450+ if [ -n " $soc " ] && [ -d " $root /qcom/$soc " ]; then
451+ p=" $( find " $root /qcom/$soc " -maxdepth 1 -type f -name ' CAMERA_ICP_*.elf' 2> /dev/null | head -n 1) "
452+ [ -n " $p " ] && echo " $p " && return 0
453+ fi
454+ done
455+
456+ # Fallback bounded search
457+ for root in /usr/lib/firmware /lib/firmware; do
458+ if [ -d " $root /qcom" ]; then
459+ p=" $( find " $root /qcom" -maxdepth 2 -type f -name ' CAMERA_ICP_*.elf' 2> /dev/null | head -n 1) "
460+ [ -n " $p " ] && echo " $p " && return 0
461+ fi
462+ done
463+
464+ return 1
465+ }
466+
467+ # -----------------------------------------------------------------------------
468+ # Package helpers (Yocto/QLI proprietary builds)
469+ # -----------------------------------------------------------------------------
470+ camx_opkg_list_camx () {
471+ command -v opkg > /dev/null 2>&1 || return 1
472+ out=" $( opkg list-installed 2> /dev/null | grep -i ' ^camx' || true) "
473+ [ -n " $out " ] || return 1
474+ printf ' %s\n' " $out "
475+ return 0
476+ }
477+
478+ # -----------------------------------------------------------------------------
479+ # DT camera nodes sample using fdtdump
480+ # -----------------------------------------------------------------------------
481+ camx_fdtdump_has_cam_nodes () {
482+ command -v fdtdump > /dev/null 2>&1 || return 2
483+ [ -r /sys/firmware/fdt ] || return 1
484+
485+ out=" $( fdtdump /sys/firmware/fdt 2> /dev/null \
486+ | grep -i ' cam' \
487+ | grep -Ei ' qcom,cam|qcom,camera|camera@|cam-req|cam-cpas|cam-jpeg|cam-ife|cam-icp|cam-sensor|camera0-thermal' || true) "
488+
489+ [ -n " $out " ] || return 1
490+ printf ' %s\n' " $out " | head -n 20
491+ return 0
492+ }
493+
494+ # ---- NHX dump + checksum validation helpers (POSIX) ----
495+
496+ nhx_pick_cksum_tool () {
497+ if command -v sha256sum > /dev/null 2>&1 ; then
498+ echo " sha256sum"
499+ elif command -v md5sum > /dev/null 2>&1 ; then
500+ echo " md5sum"
501+ else
502+ echo " "
503+ fi
504+ }
505+
506+ nhx_collect_new_dumps () {
507+ # $1 = dump_dir, $2 = marker_file, $3 = output_list_file
508+ # Collect NHX yuvs created after marker. Fallback to any *.yuv if none match.
509+ ddir=" $1 "
510+ marker=" $2 "
511+ out=" $3 "
512+
513+ : > " $out "
514+
515+ # Prefer NHX-tagged files (matches your observed names)
516+ find " $ddir " -maxdepth 1 -type f \
517+ \( -name ' *NHX*.yuv' -o -name ' *NHX*.raw' -o -name ' *NHX*.bin' \) \
518+ -newer " $marker " 2> /dev/null | sort > " $out "
519+
520+ if [ ! -s " $out " ]; then
521+ # Fallback: any yuv created after marker
522+ find " $ddir " -maxdepth 1 -type f -name ' *.yuv' -newer " $marker " 2> /dev/null | sort > " $out "
523+ fi
524+ }
525+
526+ nhx_validate_dumps_and_checksums () {
527+ # $1 = dump_dir, $2 = marker_file, $3 = log_dir
528+ ddir=" $1 "
529+ marker=" $2 "
530+ ldir=" $3 "
531+
532+ list=" $ldir /nhx_dumps.list"
533+ sumfile=" $ldir /nhx_checksums.txt"
534+ prevsum=" $ldir /nhx_checksums.prev.txt"
535+ tool=" $( nhx_pick_cksum_tool) "
536+
537+ if [ ! -d " $ddir " ]; then
538+ log_fail " DUMP_DIR does not exist: $ddir "
539+ return 1
540+ fi
541+
542+ if [ -z " $tool " ]; then
543+ log_skip " No checksum tool found (sha256sum/md5sum). Skipping dump checksum validation."
544+ return 0
545+ fi
546+
547+ nhx_collect_new_dumps " $ddir " " $marker " " $list "
548+
549+ if [ ! -s " $list " ]; then
550+ log_fail " No NHX dump files found in $ddir (after marker). Dump/checksum validation not exercised."
551+ return 1
552+ fi
553+
554+ # Basic sanity: non-empty, not all identical checksum
555+ : > " $sumfile "
556+ first_sum=" "
557+ all_same=" 1"
558+ count=" 0"
559+
560+ while IFS= read -r f; do
561+ [ -n " $f " ] || continue
562+
563+ if [ ! -s " $f " ]; then
564+ log_fail " Dump file is empty: $f "
565+ return 1
566+ fi
567+
568+ # Produce "HASH FILE" lines, same as sha256sum/md5sum
569+ line=" $( $tool " $f " 2> /dev/null) "
570+ if [ -z " $line " ]; then
571+ log_fail " Checksum tool failed for: $f "
572+ return 1
573+ fi
574+ echo " $line " >> " $sumfile "
575+
576+ cur_sum=$( echo " $line " | awk ' {print $1}' )
577+ if [ -z " $first_sum " ]; then
578+ first_sum=" $cur_sum "
579+ else
580+ if [ " $cur_sum " != " $first_sum " ]; then
581+ all_same=" 0"
582+ fi
583+ fi
584+
585+ count=$(( count + 1 ))
586+ done < " $list "
587+
588+ log_info " Dump files detected: $count (list: $list )"
589+ log_info " Checksums written: $sumfile (tool=$tool )"
590+
591+ if [ " $count " -lt 1 ]; then
592+ log_fail " Internal error: dump count computed as 0"
593+ return 1
594+ fi
595+
596+ if [ " $all_same " = " 1" ] && [ " $count " -gt 1 ]; then
597+ log_fail " All dump checksums are identical across $count files (suspicious: repeated/blank frames)"
598+ return 1
599+ fi
600+
601+ # Optional drift check: compare against previous run (same log dir)
602+ if [ -f " $prevsum " ]; then
603+ if ! diff -q " $prevsum " " $sumfile " > /dev/null 2>&1 ; then
604+ log_warn " Dump checksums changed vs previous run ($prevsum ). This may be expected; keeping as WARN."
605+ else
606+ log_info " Dump checksums match previous run ($prevsum )"
607+ fi
608+ fi
609+
610+ # Save current as previous for next run
611+ cp -f " $sumfile " " $prevsum " 2> /dev/null || true
612+
613+ log_pass " NHX dump checksum validation exercised ($count files)"
614+ return 0
615+ }
616+
617+ # POSIX way to tee live output while preserving exit code
618+ run_cmd_live_to_log () {
619+ # $1 = logfile, $2... = command
620+ logf=" $1 "
621+ shift
622+
623+ fifo=" $logf .fifo.$$ "
624+ rm -f " $fifo "
625+ mkfifo " $fifo " || return 1
626+
627+ # tee runs in background, command writes into fifo
628+ tee -a " $logf " < " $fifo " &
629+ teepid=$!
630+
631+ " $@ " > " $fifo " 2>&1
632+ rc=$?
633+
634+ # close fifo and wait tee
635+ rm -f " $fifo "
636+ wait " $teepid " 2> /dev/null || true
637+ return " $rc "
638+ }
0 commit comments