blob: 072e6b58375b7e6fc3d2c90f5963babf17cd8d29 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{format_err, Error};
use at::BluetoothHFIndicator;
use at_commands as at;
use core::fmt::Debug;
use tracing::warn;
/// This mode's behavior is to forward unsolicited result codes directly per
/// 3GPP TS 27.007 version 6.8.0, Section 8.10.
/// This is the only supported mode in the Event Reporting Enabling AT command (AT+CMER).
/// Defined in HFP v1.8 Section 4.34.2.
pub const INDICATOR_REPORTING_MODE: i64 = 3;
/// Assigned numbers to supported HF Indicators according to the
/// Bluetooth SIG.
/// Defined in HFP v1.8 Section 4.36.1.1
pub const ENHANCED_SAFETY: u16 = 0x0001;
pub const BATTERY_LEVEL: u16 = 0x0002;
// A single indicator status + value.
#[derive(Clone, Copy, Debug)]
pub struct Indicator<T: Clone + Copy + Debug> {
/// Whether this indicator is enabled or not.
pub enabled: bool,
/// The value of the indicator.
// TODO(https://fxbug.dev/332390332): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub value: Option<T>,
}
impl<T: Clone + Copy + Debug> Default for Indicator<T> {
fn default() -> Self {
Self { enabled: true, value: None }
}
}
/// The supported HF indicators and their enabled/disabled status & values.
/// The second bool determines whether the AG supports the indicator
/// Defined in HFP v1.8 Section 4.36
#[derive(Clone)]
pub struct HfIndicators {
/// The Enhanced Safety HF indicator. There are only two potential values (enabled, disabled).
pub enhanced_safety: (Indicator<bool>, bool),
/// The Battery Level HF indicator. Can be any integer value between [0, 5].
pub battery_level: (Indicator<u8>, bool),
}
impl Default for HfIndicators {
fn default() -> Self {
Self {
enhanced_safety: (Indicator { enabled: false, value: None }, false),
battery_level: (Indicator { enabled: false, value: None }, false),
}
}
}
impl HfIndicators {
/// Enables the ability to enable/disable the HF indicator if the AG supports it.
pub fn set_supported_indicators(&mut self, indicators: &Vec<BluetoothHFIndicator>) {
for indicator in indicators {
match indicator {
BluetoothHFIndicator::BatteryLevel => {
self.battery_level.1 = true;
}
BluetoothHFIndicator::EnhancedSafety => {
self.enhanced_safety.1 = true;
}
}
}
}
/// Checks to see if HF indicator is supported and then changes the state of it.
pub fn change_indicator_state(&mut self, response: &at::Success) -> Result<(), Error> {
match response {
at::Success::BindStatus { anum: BluetoothHFIndicator::BatteryLevel, state }
if self.battery_level.1 =>
{
self.battery_level.0.enabled = *state;
}
at::Success::BindStatus { anum: BluetoothHFIndicator::EnhancedSafety, state }
if self.battery_level.1 =>
{
self.enhanced_safety.0.enabled = *state;
}
at::Success::BindStatus { anum, state: _ } => {
warn!(
"Tried to enable unsupported HF Enhanced Safety indicator: {:?}, received {:?}",
anum, response
)
}
_ => {
return Err(format_err!(
"Received incorrect response. Recieved {:?} instead.",
response
));
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[fuchsia::test]
fn indicators_become_enabled() {
let supported_indicators =
vec![at::BluetoothHFIndicator::BatteryLevel, at::BluetoothHFIndicator::EnhancedSafety];
let mut hf_indicators = HfIndicators::default();
// Indicator should be in not supported state.
assert!(!hf_indicators.battery_level.1);
assert!(!hf_indicators.enhanced_safety.1);
hf_indicators.set_supported_indicators(&supported_indicators);
assert!(hf_indicators.battery_level.1);
assert!(hf_indicators.enhanced_safety.1);
}
#[fuchsia::test]
fn unsupported_indicators_do_not_get_enabled() {
let response1 =
at::Success::BindStatus { anum: at::BluetoothHFIndicator::BatteryLevel, state: true };
let response2 =
at::Success::BindStatus { anum: at::BluetoothHFIndicator::EnhancedSafety, state: true };
let mut hf_indicators = HfIndicators::default();
// Indicator should be in not supported state.
assert!(!hf_indicators.battery_level.1);
assert!(!hf_indicators.enhanced_safety.1);
// Indicators should default to disabled
assert!(!hf_indicators.battery_level.0.enabled);
assert!(!hf_indicators.enhanced_safety.0.enabled);
assert_matches!(hf_indicators.change_indicator_state(&response1), Ok(_));
assert_matches!(hf_indicators.change_indicator_state(&response2), Ok(_));
// Indicator should remain disabled
assert!(!hf_indicators.battery_level.0.enabled);
assert!(!hf_indicators.enhanced_safety.0.enabled);
}
#[fuchsia::test]
fn incorrect_response_returns_error_on_indicator_state() {
let wrong_response = at::Success::TestResponse {};
let mut hf_indicators = HfIndicators::default();
assert_matches!(hf_indicators.change_indicator_state(&wrong_response), Err(_));
}
}