Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause-Clear
# Source init_env and functestlib.sh

# Robustly find and source init_env
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
INIT_ENV=""
SEARCH="$SCRIPT_DIR"
Expand All @@ -14,33 +14,36 @@ while [ "$SEARCH" != "/" ]; do
fi
SEARCH=$(dirname "$SEARCH")
done

if [ -z "$INIT_ENV" ]; then
echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2
exit 1
fi

# shellcheck disable=SC1090
. "$INIT_ENV"


if [ -z "$__INIT_ENV_LOADED" ]; then
# shellcheck disable=SC1090
. "$INIT_ENV"
fi
# shellcheck disable=SC1090,SC1091
. "$TOOLS/functestlib.sh"
TESTNAME="Bluetooth"

TESTNAME="BT_ON_FF"
test_path=$(find_test_case_by_name "$TESTNAME") || {
log_fail "$TESTNAME : Test directory not found."
echo "$TESTNAME FAIL" > "./$TESTNAME.res"
exit 1
}

cd "$test_path" || exit 1
res_file="./$TESTNAME.res"
rm -f "$res_file"
log_info "-----------------------------------------------------------------------------------------"
log_info "-------------------Starting $TESTNAME Testcase----------------------------"

log_info "------------------------------------------------------------"
log_info "Starting $TESTNAME Testcase"
log_info "Checking dependency: bluetoothctl"
check_dependencies bluetoothctl

# verify that all necessary dependencies
check_dependencies bluetoothctl pgrep

log_info "Checking if bluetoothd is running..."
MAX_RETRIES=3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@

# Bluetooth BT_SCAN_PAIR Test

This test automates Bluetooth scanning and pairing for embedded Linux devices using BlueZ and bluetoothctl. It is designed for use in the [qcom-linux-testkit](https://github.com/qualcomm-linux/qcom-linux-testkit) test suite.

## Features

- Scans for Bluetooth devices
- Optionally pairs with a device by name or MAC address
- Retries pairing on failure, including handling for busy/temporarily unavailable devices
- Cleans up previous pairings for repeatable CI runs
- Accepts device name/MAC as argument, environment variable, or in `bt_device_list.txt`
- Generates summary and detailed logs (`scan.log`, `pair.log`, `found_devices.log`)

## Usage

```sh
./run.sh [DEVICE_NAME_OR_MAC] [WHITELIST]
```
- `DEVICE_NAME_OR_MAC` – (optional) Device name or MAC address to pair.
- Can also be set as `BT_NAME_ENV` or in `bt_device_list.txt`
- `WHITELIST` – (optional) Comma-separated MACs/names allowed for pairing.
- Can also be set as `BT_WHITELIST_ENV`

If no device name is given, only scanning is performed and the test passes if devices are found.

## Examples

```sh
./run.sh [BT_NAME] [WHITELIST]
```

- `BT_NAME` - Optional. Bluetooth name or MAC to search for.
- `WHITELIST` - Optional. Comma-separated names/MACs allowed for pairing.

- Scan for any device (no pairing):

```
./run.sh
```

- Scan and pair with a device named "MySpeaker":

```
./run.sh MySpeaker
```

- Scan and pair only if device MAC is in whitelist:

```
./run.sh MySpeaker 00:11:22:33:44:55,AnotherSpeaker
```

- Use environment variables:

```
export BT_NAME_ENV="MySpeaker"
export BT_WHITELIST_ENV="00:11:22:33:44:55"
./run.sh
```

- Device list file (first line is used):

```
echo "MySpeaker" > bt_device_list.txt
./run.sh
```

## Whitelist Usage

To ensure only known devices are considered during scan:

```sh
./run.sh JBL_Speaker "JBL_Speaker,12:34:56:78:9A:BC"
```

## Arguments & Variables

- Argument 1: Device name or MAC address (takes precedence)
- `BT_NAME_ENV`: Device name or MAC from the environment
- `bt_device_list.txt`: Fallback if argument or env is not set

## Example Summary Output

```
[INFO] 2025-06-23 10:00:00 - Starting BT_SCAN_PAIR Testcase
[INFO] 2025-06-23 10:00:02 - Unblocking and powering on Bluetooth
[INFO] 2025-06-23 10:00:05 - Devices found during scan:
Device 12:34:56:78:9A:BC SomeBTHeadset
[INFO] 2025-06-23 10:00:06 - Expected device 'SomeBTHeadset' found in scan
[PASS] 2025-06-23 10:00:08 - Pairing successful with 12:34:56:78:9A:BC
```

## Result

- PASS: Device paired (or scan-only with no target)
- FAIL: Device not found, not in whitelist, or pairing failed
- All paired devices are removed after the test

## Files Generated

- `BT_SCAN_PAIR.res`: Test PASS/FAIL/SKIP result
- `scan.log`: Output of Bluetooth device scan
- `found_devices.log`: List of discovered device names/MACs
- `pair.log`: Detailed pairing output and errors

## Troubleshooting

- Ensure `bluetoothctl`, `rfkill`, `expect`, and `hciconfig` are available.
- For headless automation, the remote device must be in pairing/discoverable mode.
- The script retries pairing if "busy" or "temporarily unavailable" errors are seen.
- Check `pair.log` and `scan.log` for detailed debug info if a failure occurs.

## Helper Functions (in functestlib.sh)

- `bt_scan_devices` – Scans and logs found BT devices
- `bt_pair_with_mac` – Attempts pairing via expect with retries
- `bt_in_whitelist` – Checks if MAC/name is in whitelist
- `bt_cleanup_paired_device` – Removes paired device by MAC

## Customization

- **Whitelist**: You can restrict scan to a whitelist of MAC addresses or names using environment variables or script customization.
- **Retries/Timeouts**: Retry and timeout values can be set in the script for more robust pairing.

## Integration with LAVA

In your LAVA job:

```yaml
deploy:
to: tftp
images:
bt_device_list.txt:
image: path/to/bt_device_list.txt
compression: none
```

Injects a per-DUT Bluetooth configuration.

## Dependencies

- `bluetoothctl`, `expect`, `rfkill`, `hciconfig`
- BlueZ stack running on embedded Linux

## License

SPDX-License-Identifier: BSD-3-Clause-Clear
Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
Empty file.
180 changes: 180 additions & 0 deletions Runner/suites/Connectivity/Bluetooth/BT_SCAN_PAIR/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#!/bin/sh

# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause-Clear

# Robustly find and source init_env
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
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
exit 1
fi

if [ -z "$__INIT_ENV_LOADED" ]; then
# shellcheck disable=SC1090
. "$INIT_ENV"
fi

# shellcheck disable=SC1090,SC1091
. "$TOOLS/functestlib.sh"

TESTNAME="BT_SCAN_PAIR"
test_path=$(find_test_case_by_name "$TESTNAME") || {
log_fail "$TESTNAME : Test directory not found."
echo "$TESTNAME FAIL" > "./$TESTNAME.res"
exit 1
}
cd "$test_path" || exit 1
RES_FILE="./$TESTNAME.res"
rm -f "$RES_FILE"

log_info "------------------------------------------------------------"
log_info "Starting $TESTNAME Testcase"

BT_NAME=""
BT_MAC=""
WHITELIST=""
PAIR_RETRIES="${PAIR_RETRIES:-3}"
SCAN_ATTEMPTS="${SCAN_ATTEMPTS:-2}"

# Parse arguments
if [ -n "$1" ]; then
if echo "$1" | grep -Eq '^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$'; then
BT_MAC="$1"
else
BT_NAME="$1"
fi
fi

if [ -n "$2" ]; then
WHITELIST="$2"
if [ -z "$BT_MAC" ] && echo "$2" | grep -Eq '^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$'; then
BT_MAC="$2"
fi
fi

# Fallback to file
if [ -z "$BT_NAME" ] && [ -z "$BT_MAC" ] && [ -f "./bt_device_list.txt" ]; then
BT_NAME=$(awk '!/^#/ && NF {print $2}' ./bt_device_list.txt | head -n1)
BT_MAC=$(awk '!/^#/ && NF {print $1}' ./bt_device_list.txt | head -n1)
fi

check_dependencies bluetoothctl rfkill expect hciconfig || {
echo "$TESTNAME SKIP" > "$RES_FILE"
exit 0
}

cleanup_bt_test() {
[ -n "$BT_MAC" ] && bt_cleanup_paired_device "$BT_MAC"
killall -q bluetoothctl 2>/dev/null
}
trap cleanup_bt_test EXIT

rfkill unblock bluetooth
retry_command_bt "hciconfig hci0 up" "Bring up hci0" || {
log_fail "Failed to bring up hci0"
echo "$TESTNAME FAIL" > "$RES_FILE"
exit 1
}

bt_remove_all_paired_devices

MATCH_FOUND=0

for scan_try in $(seq 1 "$SCAN_ATTEMPTS"); do
log_info "Bluetooth scan attempt $scan_try..."
bt_scan_devices

LATEST_FOUND_LOG=$(find . -maxdepth 1 -name 'found_devices_*.log' -type f -print | sort -r | head -n1)
[ -z "$LATEST_FOUND_LOG" ] && continue

log_info "Devices found during scan:"
cat "$LATEST_FOUND_LOG"

if [ -z "$BT_NAME" ] && [ -z "$BT_MAC" ]; then
log_pass "No device specified. Scan-only mode."
echo "$TESTNAME PASS" > "$RES_FILE"
exit 0
fi

log_info "Matching against: BT_NAME='$BT_NAME', BT_MAC='$BT_MAC', WHITELIST='$WHITELIST'"
bt_remove_all_paired_devices
bluetoothctl --timeout 3 devices | awk '{print $2}' | while read -r addr; do
log_info "Forcing device removal: $addr"
bluetoothctl remove "$addr" >/dev/null 2>&1
done

# Clean and prepare whitelist
WHITELIST_CLEAN=$(echo "$WHITELIST" | tr -d '\r' | tr ',\n' ' ' | xargs)
MATCH_FOUND=0

while IFS= read -r line; do
mac=$(echo "$line" | awk '{print $1}')
name=$(echo "$line" | cut -d' ' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

log_info "Parsed: MAC='$mac' NAME='$name'"
log_info "Checking if MAC or NAME is in whitelist: '$WHITELIST_CLEAN'"

if [ -n "$BT_MAC" ] && [ "$mac" = "$BT_MAC" ]; then
log_info "MAC matched: $mac"
if [ -z "$WHITELIST_CLEAN" ] || echo "$WHITELIST_CLEAN" | grep -wq "$mac" || echo "$WHITELIST_CLEAN" | grep -wq "$name"; then
log_info "MAC allowed by whitelist: $mac ($name)"
MATCH_FOUND=1
break
else
log_info "MAC matched but not in whitelist: $name"
fi
elif [ -n "$BT_NAME" ] && [ "$name" = "$BT_NAME" ]; then
log_info "Name matched: $name"
if [ -z "$WHITELIST_CLEAN" ] || echo "$WHITELIST_CLEAN" | grep -wq "$mac" || echo "$WHITELIST_CLEAN" | grep -wq "$name"; then
log_info "Name allowed by whitelist: $name ($mac)"
BT_MAC="$mac"
MATCH_FOUND=1
break
else
log_info "Name matched but not in whitelist: $name"
fi
fi
done < "$LATEST_FOUND_LOG"

[ "$MATCH_FOUND" -eq 1 ] && break
sleep 2
done

if [ "$MATCH_FOUND" -ne 1 ]; then
log_fail "Expected device not found or not in whitelist"
echo "$TESTNAME FAIL" > "$RES_FILE"
exit 1
fi

log_info "Attempting to pair with $BT_NAME ($BT_MAC)"
if bt_pair_with_mac "$BT_MAC" "$PAIR_RETRIES"; then
log_info "Pairing successful. Attempting post-pair connection..."
if bt_post_pair_connect "$BT_MAC"; then
log_info "Post-pair connection successful, verifying with l2ping..."
if bt_l2ping_check "$BT_MAC" "$RES_FILE"; then
log_pass "Post-pair connection and l2ping verified"
echo "$TESTNAME PASS" > "$RES_FILE"
exit 0
else
log_warn "Post-pair successful but l2ping failed"
echo "$TESTNAME FAIL" > "$RES_FILE"
exit 1
fi
fi
else
log_fail "Pairing failed after $PAIR_RETRIES retries"
echo "$TESTNAME FAIL" > "$RES_FILE"
exit 1
fi
Loading
Loading