diff --git a/Runner/suites/Multimedia/Sensors/README_Sensors.md b/Runner/suites/Multimedia/Sensors/README_Sensors.md new file mode 100644 index 00000000..800ebc01 --- /dev/null +++ b/Runner/suites/Multimedia/Sensors/README_Sensors.md @@ -0,0 +1,210 @@ +# Sensors (Dynamic, DT-free) + +This test validates Qualcomm SSC/ADSP sensor streaming **without relying on Device Tree**. It dynamically discovers available sensor **TYPEs** using `ssc_sensor_info` and validates selected sensors using: + +- `see_workhorse` (streaming sanity / event flow) +- `ssc_drva_test` (driver validation test; optional on minimal builds) + +> **Important (Overlay-only):** +> The required user-space apps (`ssc_sensor_info`, `see_workhorse`, `ssc_drva_test`) are **not** part of the base image in many builds. +> They are typically provided via a **proprietary / vendor overlay** (or equivalent overlay package). +> This testcase is **meant to be executed only when those overlay apps are present**. + +--- + +## Location + +- `Runner/suites/Multimedia/Sensors/run.sh` +- Helper library: `Runner/utils/lib_sensors.sh` (sourced via `$TOOLS/lib_sensors.sh`) + +--- + +## What it does + +1. **Gates on ADSP remoteproc** + - Confirms ADSP remoteproc is present and **running** + - If not running, checks whether firmware (default `adsp.mbn`) exists + - Uses helper functions already in `functestlib.sh`: + - `get_remoteproc_path_by_firmware()` + - `get_remoteproc_state()` + +2. **Discovers sensors dynamically** + - Runs `ssc_sensor_info` once and saves full output to: + - `./logs_Sensors/ssc_sensor_info.txt` (or custom `--out`) + - Parses **TYPE** entries where `AVAILABLE=true` (and prefers physical sensors where possible) + +3. **Auto-selects sensor set** + - Default: `--profile auto` + - If `mag` or `pressure` is present → **Vision-like** profile: `accel,gyro,mag,pressure` + - Else → **Core-like** profile: `accel,gyro` + +4. **Runs functional validation** + - For each selected sensor TYPE: + - runs `see_workhorse -sensor= ...` + - runs `ssc_drva_test -sensor= ...` (if tool exists; otherwise SKIP that part) + - Redirects huge tool output to per-sensor log files. + - Prints **small progress heartbeats** to stdout for CI visibility. + +5. **Writes a LAVA-friendly result file** + - Always exits `0` (LAVA-friendly) + - Writes `Sensors.res` with `PASS` / `FAIL` / `SKIP` + +--- + +## Prerequisites + +### Required commands (overlay apps) +- `ssc_sensor_info` +- `see_workhorse` + +### Optional command +- `ssc_drva_test` + If missing, test still runs using `see_workhorse` and treats `ssc_drva_test` as **SKIP**. + +### Common shell utilities +- `awk`, `sed`, `grep`, `sort`, `wc`, `tr` + +### Files / directories +- `/etc/sensors/config` **must exist** + If missing, the script will **SKIP** (typically indicates a non-prop / non-overlay build). + +--- + +## Usage + +### Show help +```sh +./run.sh --help +``` + +### List discovered sensor TYPEs and exit +```sh +./run.sh --list +``` + +### Run with auto-detection (default) +```sh +./run.sh +``` + +### Run a profile preset +```sh +./run.sh --profile basic +./run.sh --profile vision +./run.sh --profile core +./run.sh --profile all --strict 0 # debug / long run +``` + +Profiles: +- `basic` / `core`: `accel,gyro` +- `vision`: `accel,gyro,mag,pressure` +- `all`: all discovered types (debug) +- `auto` (default): picks core/vision based on presence of `mag`/`pressure` + +### Run an explicit list of sensors +```sh +./run.sh --sensors accel,gyro,tilt --strict 0 +``` + +### Control durations / progress heartbeat +```sh +./run.sh --see-duration 5 --drva-duration 10 --hb 5 +``` + +### Output directory +```sh +./run.sh --out ./logs_Sensors +``` + +--- + +## Parameters + +### CLI options (most common) +- `--list` + List discovered sensor TYPEs and exit 0 +- `--profile ` + Select preset sensors list +- `--sensors ` + Comma-separated list of sensor TYPEs to test +- `--see-duration ` + Duration for `see_workhorse` (default: `5`) +- `--drva-duration ` + Duration for `ssc_drva_test` (default: `10`) +- `--hb ` + Heartbeat interval printed to stdout (default: `5`) +- `--strict <0|1>` + Require `accel` and `gyro` to exist (default: `1`) + +### Environment overrides +- `OUT_DIR` (same as `--out`) +- `SEE_DURATION` +- `DRVA_DURATION` +- `HB_SECS` +- `STRICT_REQUIRED` +- `SENSORS_TIMEOUT_PAD_SECS` + Extra timeout pad added beyond duration (default is handled in lib; keep small for CI) +- `SENSORS_DISPLAY_EVENTS` + Passed to `see_workhorse -display_events=` (default: `1`) +- `SENSORS_DRVA_NUM_SAMPLES` + Extra knob for accel in `ssc_drva_test` (default set in run.sh to `325`) + +--- + +## Output / logs + +All heavy tool output is redirected to files under `--out` (default `./logs_Sensors`): + +- `ssc_sensor_info.txt` +- `see_workhorse_.log` (e.g. `see_workhorse_gyro.log`) +- `ssc_drva_test_.log` (e.g. `ssc_drva_test_accel.log`) + +The console shows: +- high-level progress +- periodic heartbeat lines like: + - `see_workhorse(accel) running... 5/5s (log: ...)` +- final summary: + - `Summary: pass=X fail=Y skip=Z (logs in ...)` + +Result file: +- `Sensors.res` in the testcase directory + - `Sensors PASS` + - `Sensors FAIL` + - `Sensors SKIP` + +--- + +## Result parsing behavior + +### `see_workhorse` +The script determines PASS/FAIL primarily from log markers: +- `PASS see_workhorse ...` +- `FAIL see_workhorse ...` + +The log may contain duplicate PASS lines; verdict is based on the **last PASS/FAIL marker**. + +### `ssc_drva_test` +- If `ssc_drva_test` binary is missing → treated as **SKIP** for that sensor. +- If the log begins with `FAIL` → treated as **FAIL** (defensive). +- Otherwise, return code `0` → PASS. + +--- + +## Troubleshooting + +### `1970-01-01` timestamps +If system time is not set (no RTC sync), logs may show epoch timestamps. This does not affect functional PASS/FAIL. + +### `diag: failed to connect to diag socket` +Some builds print diagnostic socket warnings in `see_workhorse` output. +This is captured in the log file. The test still passes as long as the final PASS marker is present. + +### `ssc_sensor_info` outputs nothing / parsing fails +This is treated as **SKIP** (no usable inventory → no further tests). + +Check: +- overlay apps installed and runnable +- `/etc/sensors/config` exists +- ADSP remoteproc is running (`/sys/class/remoteproc/.../state`) + +--- diff --git a/Runner/suites/Multimedia/Sensors/run.sh b/Runner/suites/Multimedia/Sensors/run.sh new file mode 100755 index 00000000..330084a9 --- /dev/null +++ b/Runner/suites/Multimedia/Sensors/run.sh @@ -0,0 +1,340 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# Dynamic Sensors validation (DT-free): discover via ssc_sensor_info and validate selected sensor types. + +TESTNAME="Sensors" + +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" + +# shellcheck disable=SC2034 +RES_FILE="$SCRIPT_DIR/${TESTNAME}.res" + +usage() { + cat < Comma-separated list of sensor TYPEs to test + Example: --sensors accel,gyro,mag + --profile Choose a preset list: + basic : accel,gyro + core : accel,gyro + vision: accel,gyro,mag,pressure + all : all discovered types (debug) + Default: auto (core/vision inferred by presence of mag/pressure) + +Durations / progress: + --out Output directory (default: ./logs_Sensors) + --see-duration see_workhorse duration (default: 5) + --drva-duration ssc_drva_test duration (default: 10) + --hb Heartbeat seconds (default: 5) + --strict <0|1> Require accel+gyro to exist (default: 1) + +Other: + --help Show this help + +Examples: + $0 --list + $0 --profile basic + $0 --profile vision + $0 --sensors accel,gyro,tilt --strict 0 + $0 --profile all --strict 0 + +Environment overrides: + OUT_DIR, SEE_DURATION, DRVA_DURATION, HB_SECS, STRICT_REQUIRED, + SENSORS_TIMEOUT_PAD_SECS, SENSORS_DISPLAY_EVENTS, SENSORS_DRVA_NUM_SAMPLES +EOF +} + +SENSORS_CSV="" +PROFILE="auto" +LIST_ONLY=0 + +while [ $# -gt 0 ]; do + case "$1" in + --out) OUT_DIR="$2"; shift 2 ;; + --see-duration) SEE_DURATION="$2"; shift 2 ;; + --drva-duration) DRVA_DURATION="$2"; shift 2 ;; + --hb) HB_SECS="$2"; shift 2 ;; + --strict) STRICT_REQUIRED="$2"; shift 2 ;; + --sensors) SENSORS_CSV="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --list) LIST_ONLY=1; shift 1 ;; + --help|-h) usage; exit 0 ;; + *) echo "[WARN] Unknown arg: $1" >&2; shift 1 ;; + esac +done + +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + echo "$TESTNAME SKIP" >"$RES_FILE" 2>/dev/null || true + exit 0 +fi + +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/lib_sensors.sh" + +# Resolve test path and cd (single SKIP/exit path) +SKIP_REASON="" +test_path=$(find_test_case_by_name "$TESTNAME") +if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then + SKIP_REASON="$TESTNAME SKIP - test path not found" +elif ! cd "$test_path"; then + SKIP_REASON="$TESTNAME SKIP - cannot cd into $test_path" +else + RES_FILE="$test_path/${TESTNAME}.res" +fi + +if [ -n "$SKIP_REASON" ]; then + log_skip "$SKIP_REASON" + echo "$TESTNAME SKIP" >"$RES_FILE" 2>/dev/null || true + exit 0 +fi + +OUT_DIR="${OUT_DIR:-./logs_Sensors}" +SEE_DURATION="${SEE_DURATION:-5}" +DRVA_DURATION="${DRVA_DURATION:-10}" +HB_SECS="${HB_SECS:-5}" +STRICT_REQUIRED="${STRICT_REQUIRED:-1}" +: "${SENSORS_DRVA_NUM_SAMPLES:=325}" + +mkdir -p "$OUT_DIR" 2>/dev/null || true + +# ---- clock sanity (fix 1970 timestamps) ---- +# If system time is too old, many logs become confusing. We don't FAIL for this. +now_epoch="$(date +%s 2>/dev/null || echo 0)" +# Jan 1, 2022 = 1640995200 (safe threshold) +if [ "$now_epoch" -lt 1640995200 ] 2>/dev/null; then + log_warn "System clock looks unset (epoch=$now_epoch). Logs may show 1970, consider enabling NTP or setting RTC." +fi + +log_info "------------------- Starting $TESTNAME testcase -------------------" +log_info "OUT_DIR=$OUT_DIR SEE_DURATION=$SEE_DURATION DRVA_DURATION=$DRVA_DURATION HB_SECS=$HB_SECS STRICT_REQUIRED=$STRICT_REQUIRED PROFILE=$PROFILE" +[ -n "$SENSORS_CSV" ] && log_info "Requested sensors (override): $SENSORS_CSV" + +deps="ssc_sensor_info see_workhorse awk sed grep sort wc tr" +if ! check_dependencies "$deps"; then + log_skip "$TESTNAME SKIP - missing dependencies: $deps" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +if [ ! -d /etc/sensors/config ]; then + log_skip "$TESTNAME SKIP - /etc/sensors/config not present (likely non-prop build)" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +# ADSP remoteproc gating +sensors_check_adsp_remoteproc "adsp.mbn" +adsp_rc=$? + +log_info "ADSP remoteproc:" +log_info " path=${SENSORS_ADSP_RPROC_PATH:-unknown} state=${SENSORS_ADSP_STATE:-unknown} firmware=${SENSORS_ADSP_FW:-unknown}" + +if [ "$adsp_rc" -eq 3 ]; then + log_skip "$TESTNAME SKIP - ADSP remoteproc not found" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +elif [ "$adsp_rc" -eq 2 ]; then + log_fail "$TESTNAME FAIL - ADSP not running and firmware missing: ${SENSORS_ADSP_FW:-adsp.mbn}" + echo "$TESTNAME FAIL" >"$RES_FILE" + exit 0 +elif [ "$adsp_rc" -eq 1 ]; then + log_fail "$TESTNAME FAIL - ADSP remoteproc state is not running: ${SENSORS_ADSP_STATE:-unknown}" + echo "$TESTNAME FAIL" >"$RES_FILE" + exit 0 +fi + +# Discover sensors +SSC_LOG="$OUT_DIR/ssc_sensor_info.txt" +log_info "Collecting sensor inventory -> $SSC_LOG" + +if ! sensors_dump_ssc_sensor_info "$SSC_LOG"; then + log_skip "$TESTNAME SKIP - ssc_sensor_info failed to run (see $SSC_LOG)" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +if [ ! -s "$SSC_LOG" ] || ! grep -q '^TYPE[[:space:]]*=' "$SSC_LOG" 2>/dev/null; then + log_skip "$TESTNAME SKIP - ssc_sensor_info produced no TYPE entries (see $SSC_LOG)" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +types_nl="$(sensors_types_from_ssc_file "$SSC_LOG" 2>/dev/null || true)" +if [ -z "$types_nl" ]; then + log_skip "$TESTNAME SKIP - no parsable sensor inventory from ssc_sensor_info (see $SSC_LOG)" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +log_info "Sensor TYPEs discovered:" +printf '%s\n' "$types_nl" | while IFS= read -r t; do + [ -n "$t" ] && log_info " - $t" +done + +# ---- list-only mode should be a clean PASS for LAVA ---- +if [ "$LIST_ONLY" -eq 1 ]; then + log_pass "$TESTNAME PASS - --list requested" + echo "$TESTNAME PASS" >"$RES_FILE" + exit 0 +fi + +# strict accel+gyro requirement +req_missing=0 +for r in accel gyro; do + if ! sensors_type_present "$types_nl" "$r"; then + log_warn "Missing required sensor type: $r" + req_missing=1 + fi +done +if [ "$STRICT_REQUIRED" = "1" ] && [ "$req_missing" -eq 1 ]; then + log_fail "$TESTNAME FAIL - required sensor types missing (need accel+gyro)" + echo "$TESTNAME FAIL" >"$RES_FILE" + exit 0 +fi + +# infer kit for auto profile +is_vision=0 +if sensors_type_present "$types_nl" "mag" || sensors_type_present "$types_nl" "pressure"; then + is_vision=1 + log_info "Kit guess (DT-free): Vision-like (mag/pressure present)" +else + log_info "Kit guess (DT-free): Core-like (mag/pressure not present)" +fi + +TARGET_NL="" + +# 1) explicit sensor list overrides everything +if [ -n "$SENSORS_CSV" ]; then + OLDIFS=$IFS + IFS=, + set -- "$SENSORS_CSV" + IFS=$OLDIFS + for s in "$@"; do + s="$(printf '%s' "$s" | tr -d '[:space:]')" + [ -z "$s" ] && continue + TARGET_NL="$(sensors_append_unique_line "$TARGET_NL" "$s")" + done +else + # 2) profile selection + case "$PROFILE" in + auto) + if [ "$is_vision" -eq 1 ]; then + PROFILE="vision" + else + PROFILE="core" + fi + ;; + esac + + case "$PROFILE" in + basic|core) + TARGET_NL="accel +gyro" + ;; + vision) + TARGET_NL="accel +gyro +mag +pressure" + ;; + all) + TARGET_NL="$types_nl" + ;; + *) + log_skip "$TESTNAME SKIP - unknown profile: $PROFILE" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 + ;; + esac +fi + +log_info "Sensors selected to test:" +printf '%s\n' "$TARGET_NL" | while IFS= read -r s; do + [ -n "$s" ] && log_info " - $s" +done + +TARGET_FILE="$OUT_DIR/targets.txt" +printf '%s\n' "$TARGET_NL" >"$TARGET_FILE" 2>/dev/null || true + +pass_count=0 +fail_count=0 +skip_count=0 + +while IFS= read -r s; do + [ -z "$s" ] && continue + + log_info "---- Sensor test: $s ----" + + if ! sensors_type_present "$types_nl" "$s"; then + log_info "Sensor $s: not present -> SKIP" + skip_count=$((skip_count + 1)) + continue + fi + + if sensors_run_see_workhorse "$s" "$SEE_DURATION" "$OUT_DIR" "$HB_SECS"; then + log_info "see_workhorse: PASS ($s) [log: $OUT_DIR/see_workhorse_${s}.log]" + else + log_error "see_workhorse: FAIL ($s) [log: $OUT_DIR/see_workhorse_${s}.log]" + fail_count=$((fail_count + 1)) + continue + fi + + sensors_run_ssc_drva_test "$s" "$DRVA_DURATION" "$OUT_DIR" "$HB_SECS" + rc=$? + if [ "$rc" -eq 0 ]; then + log_info "ssc_drva_test: PASS ($s) [log: $OUT_DIR/ssc_drva_test_${s}.log]" + pass_count=$((pass_count + 1)) + continue + fi + if [ "$rc" -eq 2 ]; then + log_info "ssc_drva_test: SKIP ($s) (tool not present)" + pass_count=$((pass_count + 1)) + continue + fi + + log_error "ssc_drva_test: FAIL ($s) [log: $OUT_DIR/ssc_drva_test_${s}.log]" + fail_count=$((fail_count + 1)) +done <"$TARGET_FILE" + +log_info "Summary: pass=$pass_count fail=$fail_count skip=$skip_count (logs in $OUT_DIR)" + +if [ "$fail_count" -gt 0 ]; then + log_fail "$TESTNAME FAIL - failures=$fail_count passes=$pass_count skips=$skip_count (logs in $OUT_DIR)" + echo "$TESTNAME FAIL" >"$RES_FILE" +else + if [ "$pass_count" -eq 0 ]; then + log_skip "$TESTNAME SKIP - no selected sensors were validated (all missing/unsupported)" + echo "$TESTNAME SKIP" >"$RES_FILE" + else + log_pass "$TESTNAME PASS - passes=$pass_count skips=$skip_count" + echo "$TESTNAME PASS" >"$RES_FILE" + fi +fi + +exit 0 diff --git a/Runner/suites/Multimedia/Sensors/sensors.yaml b/Runner/suites/Multimedia/Sensors/sensors.yaml new file mode 100755 index 00000000..2808c40a --- /dev/null +++ b/Runner/suites/Multimedia/Sensors/sensors.yaml @@ -0,0 +1,16 @@ +metadata: + name: Sensors + format: "Lava-Test Test Definition 1.0" + description: "Dynamic Sensors validation (DT-free): auto-detect sensors via ssc_sensor_info and validate using see_workhorse/ssc_drva_test." + os: + - linux + scope: + - functional + - multimedia + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/Sensors + - ./run.sh || true + - $REPO_PATH/Runner/utils/send-to-lava.sh Sensors.res || true diff --git a/Runner/utils/lib_sensors.sh b/Runner/utils/lib_sensors.sh new file mode 100755 index 00000000..a76ee0cc --- /dev/null +++ b/Runner/utils/lib_sensors.sh @@ -0,0 +1,254 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear +# Sensor helpers (DT-free): discovery via ssc_sensor_info, run see_workhorse/ssc_drva_test, parse PASS/FAIL. + +# Global outputs set by sensors_check_adsp_remoteproc() +SENSORS_ADSP_FW="" +SENSORS_ADSP_RPROC_PATH="" +SENSORS_ADSP_STATE="" + +sensors__trim_ws() { + # usage: sensors__trim_ws " abc " -> prints "abc" + # shellcheck disable=SC2001 + echo "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' +} + +# Append a line to a newline-separated list if it doesn't already exist. +# usage: new_list="$(sensors_append_unique_line "$list" "accel")" +sensors_append_unique_line() { + list="$1" + line="$2" + + [ -z "$line" ] && { printf '%s\n' "$list"; return 0; } + + if [ -z "$list" ]; then + printf '%s\n' "$line" + return 0 + fi + + printf '%s\n' "$list" | grep -Fxq "$line" 2>/dev/null && { + printf '%s\n' "$list" + return 0 + } + + printf '%s\n%s\n' "$list" "$line" +} + +sensors__firmware_exists_quick() { + fw="$1" + [ -z "$fw" ] && return 1 + # quick/cheap checks only (avoid heavy find): + [ -f "/lib/firmware/$fw" ] && return 0 + [ -f "/lib/firmware/qcom/$fw" ] && return 0 + [ -f "/lib/firmware/qcom/qcs6490/$fw" ] && return 0 + [ -f "/vendor/firmware/$fw" ] && return 0 + [ -f "/vendor/firmware_mnt/image/$fw" ] && return 0 + return 1 +} + +# Return codes: +# 0 = running +# 1 = remoteproc found but not running +# 2 = remoteproc not running and firmware missing +# 3 = remoteproc not found (by firmware mapping) +sensors_check_adsp_remoteproc() { + fw="${1:-adsp.mbn}" + + # NOTE: these are intentionally "output variables" for the caller (run.sh) + # shellcheck disable=SC2034 + SENSORS_ADSP_FW="$fw" + # shellcheck disable=SC2034 + SENSORS_ADSP_RPROC_PATH="" + SENSORS_ADSP_STATE="" + + if ! command -v get_remoteproc_path_by_firmware >/dev/null 2>&1; then + return 3 + fi + + rpath="$(get_remoteproc_path_by_firmware "$fw" 2>/dev/null || true)" + if [ -z "$rpath" ] || [ ! -d "$rpath" ]; then + return 3 + fi + + # shellcheck disable=SC2034 + SENSORS_ADSP_RPROC_PATH="$rpath" + + if command -v get_remoteproc_state >/dev/null 2>&1; then + SENSORS_ADSP_STATE="$(get_remoteproc_state "$rpath" 2>/dev/null || true)" + SENSORS_ADSP_STATE="$(sensors__trim_ws "$SENSORS_ADSP_STATE")" + else + if [ -r "$rpath/state" ]; then + SENSORS_ADSP_STATE="$(cat "$rpath/state" 2>/dev/null || true)" + SENSORS_ADSP_STATE="$(sensors__trim_ws "$SENSORS_ADSP_STATE")" + fi + fi + + [ "$SENSORS_ADSP_STATE" = "running" ] && return 0 + + if sensors__firmware_exists_quick "$fw"; then + return 1 + fi + return 2 +} + +sensors_dump_ssc_sensor_info() { + out_file="$1" + : >"$out_file" 2>/dev/null || true + ssc_sensor_info >"$out_file" 2>&1 + return $? +} + +sensors_types_from_ssc_file() { + f="$1" + [ -r "$f" ] || return 1 + + awk ' + function trim(s) { sub(/^[ \t\r\n]+/, "", s); sub(/[ \t\r\n]+$/, "", s); return s } + /^TYPE[[:space:]]*=/ { + type = $0 + sub(/^TYPE[[:space:]]*=[[:space:]]*/, "", type) + type = trim(type) + } + /^AVAILABLE[[:space:]]*=/ { + avail = $0 + sub(/^AVAILABLE[[:space:]]*=[[:space:]]*/, "", avail) + avail = trim(avail) + } + /^PHYSICAL_SENSOR[[:space:]]*=/ { + phys = $0 + sub(/^PHYSICAL_SENSOR[[:space:]]*=[[:space:]]*/, "", phys) + phys = trim(phys) + } + /^$/ { + if (type != "" && avail == "true") { + if (phys == "" || phys == "true") print type + } + type=""; avail=""; phys="" + } + END { + if (type != "" && avail == "true") { + if (phys == "" || phys == "true") print type + } + } + ' "$f" 2>/dev/null | sort -u +} + +sensors_type_present() { + types_nl="$1" + needle="$2" + printf '%s\n' "$types_nl" | grep -Fxq "$needle" 2>/dev/null +} + +# Run a command in background, redirect all output to logfile, and print a heartbeat. +# sensors_run_cmd_with_progress