Skip to content

Commit

Permalink
scmi: sensor axis extended attributes support
Browse files Browse the repository at this point in the history
For Android requirment, virtio-scmi axis descriptor should
support extended attributes. This patch does this things.

We get axis's resolution during reading "scale" and store.
When agent wants to get axis descriptions,
device will add resolution value to extend attribute field.
At the same time, max and min range also have been configured.

Signed-off-by: Junnan Wu <[email protected]>
  • Loading branch information
junnan01-wu authored and stefano-garzarella committed Jan 17, 2025
1 parent d19a265 commit 53ded3f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 6 deletions.
2 changes: 2 additions & 0 deletions vhost-device-scmi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

### Added

- [[#798]](https://github.com/rust-vmm/vhost-device/pull/798) scmi: extended sensor attributes support

### Changed

### Fixed
Expand Down
25 changes: 24 additions & 1 deletion vhost-device-scmi/src/devices/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ pub trait SensorT: Send {
0
}

/// Returns the resolution of the sensor scale.
fn resolution(&self) -> u32 {
0
}

/// Returns the prefix of axes names.
///
/// Usually no need to redefine this.
Expand All @@ -383,8 +388,10 @@ pub trait SensorT: Send {
/// Usually no need to redefine this.
fn axis_description(&self, axis: u32) -> Vec<MessageValue> {
let mut values = vec![];
let axis_exponent = self.unit_exponent(0);
let axis_resolution = self.resolution();
values.push(MessageValue::Unsigned(axis)); // axis id
values.push(MessageValue::Unsigned(0)); // attributes low
values.push(MessageValue::Unsigned(1 << 8)); // attributes low (Extended attributes support)
values.push(MessageValue::Unsigned(self.format_unit(axis))); // attributes high

// Name in the recommended format, 16 bytes:
Expand All @@ -394,6 +401,22 @@ pub trait SensorT: Send {
format!("{prefix}_{suffix}"),
MAX_SIMPLE_STRING_LENGTH,
));

// Extended attribute
values.push(MessageValue::Unsigned(
axis_resolution | ((axis_exponent as u32) << 27),
)); //resolution

// In SCMI spec, it specifies that if the sensor does not report the min and max range,
// the following field should be as as:
// axis_min_range_low 0x0
// axis_min_range_high 0x80000000
// axis_max_range_low 0xFFFFFFFF
// axis_max_range_high 0x7FFFFFFF
values.push(MessageValue::Signed(0)); // min_range_low
values.push(MessageValue::Signed(i32::MIN)); // min_range_high
values.push(MessageValue::Signed(-1i32)); // max_range_low
values.push(MessageValue::Signed(i32::MAX)); // max_range_high
values
}

Expand Down
32 changes: 28 additions & 4 deletions vhost-device-scmi/src/devices/iio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,18 @@ struct Axis {
/// sufficiently accurate SCMI value that is represented by an integer (not
/// a float) + decadic exponent.
custom_exponent: i8,
/// This is an extended attribute field. It reports the resolution of the sensor axis.
/// The representation is in [custom_resolution] x 10^[custom_exponent] format.
/// This field is present only if Bit[8] of axis_attributes_low is set to 1.
custom_resolution: u64,
/// Channel scan type, necessary if the sensor supports notifications.
/// The data from /dev/iio:deviceX will be formatted according to this.
/// The ChanScanType is parsed from "scan_elements/<channel>_type"
scan_type: Option<ChanScanType>,
}

impl Axis {
fn new(path: OsString, unit_exponent: i8, custom_exponent: i8) -> Axis {
fn new(path: OsString, unit_exponent: i8, custom_exponent: i8, custom_resolution: u64) -> Axis {
let scan_path = Path::new(&path).parent().unwrap().join("scan_elements");
let mut scan_name = path.clone();
scan_name.push("_type");
Expand All @@ -273,13 +277,15 @@ impl Axis {
path,
unit_exponent,
custom_exponent,
custom_resolution,
scan_type: ChanScanType::new(scan_type),
}
} else {
Axis {
path,
unit_exponent,
custom_exponent,
custom_resolution,
scan_type: None,
}
}
Expand Down Expand Up @@ -371,6 +377,13 @@ impl SensorT for IIOSensor {
axis.unit_exponent + axis.custom_exponent
}

fn resolution(&self) -> u32 {
// All the axes are supposed to have the same value for resolution.
// We are just using the values from the Axis 0 here.
let axis: &Axis = self.axes.first().unwrap();
axis.custom_resolution as u32
}

fn number_of_axes(&self) -> u32 {
if self.scalar {
0
Expand Down Expand Up @@ -579,14 +592,23 @@ impl IIOSensor {
}
}

fn custom_exponent(&self, path: &OsStr, unit_exponent: i8) -> i8 {
// This function gets both custom exponent and resolution by reading "scale"
// A scale value should be parsed as "[resolution]e[exponent]"
fn custom_exponent_and_resolution(&self, path: &OsStr, unit_exponent: i8) -> (i8, u64) {
let mut custom_exponent: i8 = 0;
let mut custom_resolution: u64 = 0;
if let Ok(Some(scale)) = self.read_axis_scale(path) {
// Crash completely OK if *this* doesn't fit:
custom_exponent = scale.log10() as i8;
if scale < 1.0 {
// The logarithm is truncated towards zero, we need floor
custom_exponent -= 1;
// Calculate the resolution of scale
custom_resolution =
(scale * 10i32.pow(-custom_exponent as u32) as f64).trunc() as u64;
} else {
custom_resolution =
(scale / 10i32.pow(custom_exponent as u32) as f64).trunc() as u64;
}
// The SCMI exponent (unit_exponent + custom_exponent) can have max. 5 bits:
custom_exponent = min(15 - unit_exponent, custom_exponent);
Expand All @@ -596,7 +618,7 @@ impl IIOSensor {
&path, custom_exponent
);
}
custom_exponent
(custom_exponent, custom_resolution)
}

fn add_axis(&mut self, axes: &mut Vec<Axis>, path: &OsStr) {
Expand All @@ -606,11 +628,13 @@ impl IIOSensor {
.map_or(0, |mapping| mapping.unit_exponent);
// To get meaningful integer values, we must adjust exponent to
// the provided scale if any.
let custom_exponent = self.custom_exponent(path, unit_exponent);
let (custom_exponent, custom_resolution) =
self.custom_exponent_and_resolution(path, unit_exponent);
axes.push(Axis::new(
OsString::from(path),
unit_exponent,
custom_exponent,
custom_resolution,
));
}

Expand Down
8 changes: 7 additions & 1 deletion vhost-device-scmi/src/scmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1384,9 +1384,15 @@ mod tests {
let name = format!("acc_{}", char::from_u32('X' as u32 + axis_index).unwrap()).to_string();
let mut description = vec![
MessageValue::Unsigned(axis_index),
MessageValue::Unsigned(0),
MessageValue::Unsigned(1 << 8),
MessageValue::Unsigned(u32::from(SENSOR_UNIT_METERS_PER_SECOND_SQUARED)),
MessageValue::String(name, MAX_SIMPLE_STRING_LENGTH),
// Add extended attributes
MessageValue::Unsigned(0),
MessageValue::Signed(0),
MessageValue::Signed(i32::MIN),
MessageValue::Signed(-1i32),
MessageValue::Signed(i32::MAX),
];
result.append(&mut description);
test_message(
Expand Down

0 comments on commit 53ded3f

Please sign in to comment.