diff --git a/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/README.md b/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/README.md new file mode 100644 index 00000000..2c7ebedc --- /dev/null +++ b/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/README.md @@ -0,0 +1,63 @@ +# Bluetooth power-cycle validation + +`BT_ON_OFF` verifies that a BlueZ controller can transition from powered on to +powered off and back on without changing the selected adapter. + +## Usage + +Run with automatic adapter discovery: + +```sh +./run.sh +``` + +Select an adapter and tune the retry delays: + +```sh +./run.sh \ + --adapter hci0 \ + --power-cycle-delay 10 \ + --power-on-attempts 2 \ + --power-on-retry-delay 10 \ + --restart-service-on-retry 1 +``` + +The command-line adapter overrides `BT_ADAPTER`. When neither is set, the +shared Bluetooth helper selects a usable runtime controller. + +## Validation contract + +The test uses the exact BlueZ `Powered: yes|no` property as its power-state +evidence. A transition passes only after two consecutive observations match the +requested state. This avoids accepting a transient or stale response while +BlueZ and the UART controller are settling. + +`PowerState` and `hciconfig` state are retained as diagnostics only. For +example, `PowerState: on` or `UP RUNNING` can be present while BlueZ reports +`Powered: no`, so neither is accepted as proof of a successful power-on. + +Expected success markers include: + +```text +Power OFF completed with consecutive Powered=no confirmations +Power ON completed with consecutive Powered=yes confirmations +``` + +The test fails when the requested stable state is not observed within the +bounded helper attempts. If a power-on attempt fails, the suite records +diagnostics and can perform the configured controlled recovery before retrying. + +## LAVA + +The packaged definition exposes these parameters: + +- `BT_ADAPTER` +- `BT_POWER_CYCLE_DELAY` +- `BT_POWER_ON_ATTEMPTS` +- `BT_POWER_ON_RETRY_DELAY` +- `BT_RESTART_SERVICE_ON_RETRY` +- `BT_RUNTIME_READY_WAIT` +- `BT_RUNTIME_RECOVERY_WAIT` +- `BT_RUNTIME_RECOVERY_ATTEMPTS` + +The result is written to `BT_ON_OFF.res` and sent to LAVA as `BT_ON_OFF`. diff --git a/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/run.sh b/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/run.sh index d1b80605..2b975d4e 100755 --- a/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/run.sh +++ b/Runner/suites/Connectivity/Bluetooth/BT_ON_OFF/run.sh @@ -2,7 +2,7 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause -# BT_ON_OFF - Basic Bluetooth power toggle validation (non-expect version) +# BT_ON_OFF - Basic Bluetooth power toggle validation # ---------- Repo env + helpers ---------- SCRIPT_DIR="$( @@ -241,18 +241,9 @@ log_info "Initial Powered = $initial_power" log_info "Powering OFF..." if ! btpower "$ADAPTER" off; then btloghcidiag "$ADAPTER" failure "$testpath" || true - test_result_finish "FAIL" "btpower($ADAPTER, off) failed at command level" -fi - -after_off="$(btgetpower "$ADAPTER" 2>/dev/null || true)" -[ -z "$after_off" ] && after_off="unknown" - -if [ "$after_off" = "no" ]; then - test_result_record "PASS" "Post-OFF verification reported Powered=no" -else - btloghcidiag "$ADAPTER" failure "$testpath" || true - test_result_finish "FAIL" "Post-OFF verification failed with Powered=$after_off" + test_result_finish "FAIL" "btpower($ADAPTER, off) did not confirm stable Powered=no" fi +test_result_record "PASS" "Power OFF completed with consecutive Powered=no confirmations" # ---- Power ON test ---- log_info "Waiting ${BT_POWER_CYCLE_DELAY}s before Powering ON..." @@ -266,15 +257,8 @@ while [ "$on_attempt" -le "$BT_POWER_ON_ATTEMPTS" ]; do log_info "Power ON attempt $on_attempt/$BT_POWER_ON_ATTEMPTS" if btpower "$ADAPTER" on; then - after_on="$(btgetpower "$ADAPTER" 2>/dev/null || true)" - [ -z "$after_on" ] && after_on="unknown" - - if [ "$after_on" = "yes" ]; then - on_success=1 - break - fi - - log_warn "Power ON command returned success, but post-check Powered=$after_on" + on_success=1 + break else log_warn "btpower($ADAPTER, on) failed on attempt $on_attempt" fi @@ -309,7 +293,7 @@ if [ "$on_success" -eq 1 ]; then btwarniflistempty "$ADAPTER" || true - test_result_record "PASS" "Post-ON verification reported Powered=yes" + test_result_record "PASS" "Power ON completed with consecutive Powered=yes confirmations" test_result_finish fi @@ -317,4 +301,4 @@ after_on="$(btgetpower "$ADAPTER" 2>/dev/null || true)" [ -z "$after_on" ] && after_on="unknown" btloghcidiag "$ADAPTER" failure "$testpath" || true -test_result_finish "FAIL" "Post-ON verification failed after $BT_POWER_ON_ATTEMPTS attempts with Powered=$after_on" +test_result_finish "FAIL" "Stable Powered=yes was not confirmed after $BT_POWER_ON_ATTEMPTS attempts, final observation=$after_on" diff --git a/Runner/utils/lib_bluetooth.sh b/Runner/utils/lib_bluetooth.sh index a80d6c58..4ecbb762 100755 --- a/Runner/utils/lib_bluetooth.sh +++ b/Runner/utils/lib_bluetooth.sh @@ -3036,17 +3036,23 @@ btgetpower() { return 2 } -# Usage: btpower hci0 on|off -# Returns: -# 0 = requested state achieved (including when already in that state) -# 1 = requested state not achieved -# 2 = no controller / state unknown +# btpower ADAPTER on|off +# Request a BlueZ controller power transition and require two consecutive exact +# Powered=yes/no observations before reporting success. +# Inputs: adapter identifier and target state. Output: diagnostic logs only. +# Returns: 0 when the requested state is stable, 1 when it is not achieved, and +# 2 when no controller state can be read. Side effects: may issue bounded +# bluetoothctl power requests and wait between verification samples. btpower() { dev="${1:-}" want="${2:-}" case "$want" in - on|off) + on) + target_state=yes + ;; + off) + target_state=no ;; *) log_warn "btpower: invalid target state '$want'" @@ -3056,15 +3062,16 @@ btpower() { cur_state="$(btgetpower "$dev" 2>/dev/null || true)" [ -z "$cur_state" ] && cur_state="unknown" - - if [ "$want" = "on" ] && [ "$cur_state" = "yes" ]; then - log_info "btpower: $dev already Powered=yes; skipping 'power on'." - return 0 - fi - - if [ "$want" = "off" ] && [ "$cur_state" = "no" ]; then - log_info "btpower: $dev already Powered=no; skipping 'power off'." - return 0 + + if [ "$cur_state" = "$target_state" ]; then + log_info "btpower: $dev already Powered=$target_state, confirming stable state." + sleep 1 + confirm_state="$(btgetpower "$dev" 2>/dev/null || true)" + if [ "$confirm_state" = "$target_state" ]; then + log_info "btpower: $dev Powered=$target_state confirmed stable without a new request." + return 0 + fi + log_warn "btpower: $dev initial Powered=$target_state observation was not stable, observed=${confirm_state:-unknown} on confirmation" fi log_info "btpower: requesting '$want' on $dev (current=$cur_state)" @@ -3072,6 +3079,7 @@ btpower() { request_attempts="${BT_POWER_REQUEST_ATTEMPTS:-3}" verify_attempts="${BT_POWER_VERIFY_ATTEMPTS:-10}" retry_delay="${BT_POWER_REQUEST_RETRY_DELAY:-2}" + required_confirmations=2 case "$request_attempts" in ""|*[!0-9]*) request_attempts=3 ;; @@ -3089,8 +3097,11 @@ btpower() { if [ "$verify_attempts" -lt 1 ] 2>/dev/null; then verify_attempts=1 fi + if [ "$verify_attempts" -lt "$required_confirmations" ] 2>/dev/null; then + verify_attempts="$required_confirmations" + fi - log_info "btpower: request attempts=$request_attempts verify attempts=$verify_attempts retry delay=${retry_delay}s" + log_info "btpower: request attempts=$request_attempts verify attempts=$verify_attempts stable confirmations=$required_confirmations retry delay=${retry_delay}s" if command -v expect >/dev/null 2>&1; then log_info "btpower: using an expect PTY for interactive bluetoothctl power requests" else @@ -3110,19 +3121,25 @@ btpower() { fi verify_attempt=1 + stable_confirmations=0 while [ "$verify_attempt" -le "$verify_attempts" ]; do state="$(btgetpower "$dev" 2>/dev/null || true)" - if [ "$want" = "on" ] && [ "$state" = "yes" ]; then - log_info "btpower: $dev Powered=yes after request attempt $request_attempt." - return 0 + if [ "$state" = "$target_state" ]; then + stable_confirmations=$((stable_confirmations + 1)) + else + stable_confirmations=0 fi - if [ "$want" = "off" ] && [ "$state" = "no" ]; then - log_info "btpower: $dev Powered=no after request attempt $request_attempt." + if [ "$stable_confirmations" -ge "$required_confirmations" ]; then + log_info "btpower: $dev Powered=$state confirmed stable after request attempt $request_attempt." return 0 fi + if [ "$stable_confirmations" -gt 0 ]; then + log_info "btpower: $dev Powered=$state confirmation $stable_confirmations/$required_confirmations" + fi + sleep 1 verify_attempt=$((verify_attempt + 1)) done