use crate::error;
use crate::helpers::PointerToCStr;
use error::NegativeErrorExt;
pub mod registration;
pub struct RegistryEntry(*mut riot_sys::saul_reg);
pub type AllRegistryEntries = core::iter::MapWhile<
core::iter::Map<core::ops::RangeFrom<usize>, fn(usize) -> Option<RegistryEntry>>,
fn(Option<RegistryEntry>) -> Option<RegistryEntry>,
>;
impl RegistryEntry {
pub fn nth(pos: usize) -> Option<Self> {
(unsafe { riot_sys::saul_reg_find_nth(pos as _).as_mut() }).map(|r| RegistryEntry(r))
}
pub fn all() -> AllRegistryEntries {
(0..).map(Self::nth as _).map_while(|p| p)
}
pub fn type_(&self) -> Option<Class> {
let type_ = unsafe { (*(*self.0).driver).type_ };
Class::from_c(type_)
}
pub fn name(&self) -> Option<&'static str> {
unsafe { Some((*self.0).name.to_lifetimed_cstr()?.to_str().ok()?) }
}
pub fn read(&self) -> Result<Phydat, error::NumericError> {
let mut result: Phydat = Default::default();
let length = (unsafe { riot_sys::saul_reg_read(self.0 as *mut _, &mut result.values) })
.negative_to_error()?;
result.length = length as _;
Ok(result)
}
pub fn write(&self, value: Phydat) -> Result<(), error::NumericError> {
let length =
unsafe { riot_sys::saul_reg_write(self.0, &value.values as *const _ as *mut _) }
.negative_to_error()?;
if length != value.length.into() {
Err(error::NumericError::from_constant(riot_sys::EINVAL as _))
} else {
Ok(())
}
}
}
#[derive(Default, Copy, Clone)]
pub struct Phydat {
values: riot_sys::phydat_t,
length: u8,
}
impl Phydat {
pub fn new(data: &[i16], unit: Option<Unit>, scale: i8) -> Self {
let mut val = [0; riot_sys::PHYDAT_DIM as _];
val[..data.len()].copy_from_slice(data);
Phydat {
values: riot_sys::phydat_t {
val,
unit: Unit::to_c(unit),
scale: scale,
},
length: data.len() as _,
}
}
#[doc(alias = "phydat_fit")]
pub fn fit(data: &[i32], unit: Option<Unit>, scale: i8) -> Self {
let mut phydat = Phydat {
values: riot_sys::phydat_t {
val: Default::default(),
unit: Unit::to_c(unit),
scale: scale,
},
length: data.len() as _,
};
unsafe { riot_sys::phydat_fit(&mut phydat.values, data.as_ptr(), data.len() as _) };
phydat
}
pub fn value(&self) -> &[i16] {
&self.values.val[..self.length as _]
}
pub fn unit(&self) -> Option<Unit> {
Unit::from_c(self.values.unit)
}
pub fn scale(&self) -> i8 {
self.values.scale
}
}
impl core::fmt::Debug for Phydat {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
"Phydat {{ {:?} x 10^{} {:?} }}",
self.value(),
self.scale(),
self.unit()
)
}
}
impl core::fmt::Display for Phydat {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
if self.length == 1 {
write!(f, "{}", self.values.val[0])?;
} else {
write!(f, "{:?}", &self.values.val[..self.length as _])?;
}
if self.values.scale != 0 {
write!(f, "×10^{}", self.values.scale)?;
}
match Unit::from_c(self.values.unit).map(|u| (u, u.name_owned::<16>())) {
Some((_, Some(s))) => write!(f, " {}", s)?,
Some((u, _)) => write!(f, " in units of {:?}", u)?,
None => (),
}
Ok(())
}
}
#[derive(Copy, Clone, Debug)]
pub enum Class {
Actuator(Option<ActuatorClass>),
Sensor(Option<SensorClass>),
}
impl Class {
fn from_c(input: u8) -> Option<Class> {
use ActuatorClass::*;
use Class::*;
use SensorClass::*;
match input as _ {
riot_sys::SAUL_ACT_ANY => Some(Actuator(None)),
riot_sys::SAUL_ACT_LED_RGB => Some(Actuator(Some(LedRgb))),
riot_sys::SAUL_ACT_SERVO => Some(Actuator(Some(Servo))),
riot_sys::SAUL_ACT_MOTOR => Some(Actuator(Some(Motor))),
riot_sys::SAUL_ACT_SWITCH => Some(Actuator(Some(Switch))),
riot_sys::SAUL_ACT_DIMMER => Some(Actuator(Some(Dimmer))),
riot_sys::SAUL_SENSE_ANY => Some(Sensor(None)),
riot_sys::SAUL_SENSE_BTN => Some(Sensor(Some(Btn))),
riot_sys::SAUL_SENSE_TEMP => Some(Sensor(Some(Temp))),
riot_sys::SAUL_SENSE_HUM => Some(Sensor(Some(Hum))),
riot_sys::SAUL_SENSE_LIGHT => Some(Sensor(Some(Light))),
riot_sys::SAUL_SENSE_ACCEL => Some(Sensor(Some(Accel))),
riot_sys::SAUL_SENSE_MAG => Some(Sensor(Some(Mag))),
riot_sys::SAUL_SENSE_GYRO => Some(Sensor(Some(Gyro))),
riot_sys::SAUL_SENSE_COLOR => Some(Sensor(Some(Color))),
riot_sys::SAUL_SENSE_PRESS => Some(Sensor(Some(Press))),
riot_sys::SAUL_SENSE_ANALOG => Some(Sensor(Some(Analog))),
riot_sys::SAUL_SENSE_UV => Some(Sensor(Some(Uv))),
riot_sys::SAUL_SENSE_OBJTEMP => Some(Sensor(Some(Objtemp))),
riot_sys::SAUL_SENSE_COUNT => Some(Sensor(Some(Count))),
riot_sys::SAUL_SENSE_DISTANCE => Some(Sensor(Some(Distance))),
riot_sys::SAUL_SENSE_CO2 => Some(Sensor(Some(Co2))),
riot_sys::SAUL_SENSE_TVOC => Some(Sensor(Some(Tvoc))),
riot_sys::SAUL_SENSE_GAS => Some(Sensor(Some(Gas))),
riot_sys::SAUL_SENSE_OCCUP => Some(Sensor(Some(Occup))),
riot_sys::SAUL_SENSE_PROXIMITY => Some(Sensor(Some(Proximity))),
riot_sys::SAUL_SENSE_RSSI => Some(Sensor(Some(Rssi))),
riot_sys::SAUL_SENSE_CHARGE => Some(Sensor(Some(Charge))),
riot_sys::SAUL_SENSE_CURRENT => Some(Sensor(Some(Current))),
riot_sys::SAUL_SENSE_PM => Some(Sensor(Some(Pm))),
riot_sys::SAUL_SENSE_CAPACITANCE => Some(Sensor(Some(Capacitance))),
riot_sys::SAUL_SENSE_VOLTAGE => Some(Sensor(Some(Voltage))),
riot_sys::SAUL_SENSE_PH => Some(Sensor(Some(Ph))),
riot_sys::SAUL_SENSE_POWER => Some(Sensor(Some(Power))),
riot_sys::SAUL_SENSE_SIZE => Some(Sensor(Some(Size))),
x if x & riot_sys::SAUL_CAT_MASK == riot_sys::SAUL_CAT_ACT => Some(Actuator(None)),
x if x & riot_sys::SAUL_CAT_MASK == riot_sys::SAUL_CAT_SENSE => Some(Sensor(None)),
_ => None,
}
}
const fn to_c(self) -> u8 {
use ActuatorClass::*;
use Class::*;
use SensorClass::*;
(match self {
Actuator(None) => riot_sys::SAUL_ACT_ANY,
Actuator(Some(LedRgb)) => riot_sys::SAUL_ACT_LED_RGB,
Actuator(Some(Servo)) => riot_sys::SAUL_ACT_SERVO,
Actuator(Some(Motor)) => riot_sys::SAUL_ACT_MOTOR,
Actuator(Some(Switch)) => riot_sys::SAUL_ACT_SWITCH,
Actuator(Some(Dimmer)) => riot_sys::SAUL_ACT_DIMMER,
Sensor(None) => riot_sys::SAUL_SENSE_ANY,
Sensor(Some(Btn)) => riot_sys::SAUL_SENSE_BTN,
Sensor(Some(Temp)) => riot_sys::SAUL_SENSE_TEMP,
Sensor(Some(Hum)) => riot_sys::SAUL_SENSE_HUM,
Sensor(Some(Light)) => riot_sys::SAUL_SENSE_LIGHT,
Sensor(Some(Accel)) => riot_sys::SAUL_SENSE_ACCEL,
Sensor(Some(Mag)) => riot_sys::SAUL_SENSE_MAG,
Sensor(Some(Gyro)) => riot_sys::SAUL_SENSE_GYRO,
Sensor(Some(Color)) => riot_sys::SAUL_SENSE_COLOR,
Sensor(Some(Press)) => riot_sys::SAUL_SENSE_PRESS,
Sensor(Some(Analog)) => riot_sys::SAUL_SENSE_ANALOG,
Sensor(Some(Uv)) => riot_sys::SAUL_SENSE_UV,
Sensor(Some(Objtemp)) => riot_sys::SAUL_SENSE_OBJTEMP,
Sensor(Some(Count)) => riot_sys::SAUL_SENSE_COUNT,
Sensor(Some(Distance)) => riot_sys::SAUL_SENSE_DISTANCE,
Sensor(Some(Co2)) => riot_sys::SAUL_SENSE_CO2,
Sensor(Some(Tvoc)) => riot_sys::SAUL_SENSE_TVOC,
Sensor(Some(Gas)) => riot_sys::SAUL_SENSE_GAS,
Sensor(Some(Occup)) => riot_sys::SAUL_SENSE_OCCUP,
Sensor(Some(Proximity)) => riot_sys::SAUL_SENSE_PROXIMITY,
Sensor(Some(Rssi)) => riot_sys::SAUL_SENSE_RSSI,
Sensor(Some(Charge)) => riot_sys::SAUL_SENSE_CHARGE,
Sensor(Some(Current)) => riot_sys::SAUL_SENSE_CURRENT,
Sensor(Some(Pm)) => riot_sys::SAUL_SENSE_PM,
Sensor(Some(Capacitance)) => riot_sys::SAUL_SENSE_CAPACITANCE,
Sensor(Some(Voltage)) => riot_sys::SAUL_SENSE_VOLTAGE,
Sensor(Some(Ph)) => riot_sys::SAUL_SENSE_PH,
Sensor(Some(Power)) => riot_sys::SAUL_SENSE_POWER,
Sensor(Some(Size)) => riot_sys::SAUL_SENSE_SIZE,
}) as _
}
pub fn name(self) -> Option<&'static str> {
unsafe { riot_sys::saul_class_to_str(self.to_c()).to_lifetimed_cstr()? }
.to_str()
.ok()
}
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum ActuatorClass {
LedRgb,
Servo,
Motor,
Switch,
Dimmer,
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum SensorClass {
Btn,
Temp,
Hum,
Light,
Accel,
Mag,
Gyro,
Color,
Press,
Analog,
Uv,
Objtemp,
Count,
Distance,
Co2,
Tvoc,
Gas,
Occup,
Proximity,
Rssi,
Charge,
Current,
Pm,
Capacitance,
Voltage,
Ph,
Power,
Size,
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Unit {
None,
TempC,
TempF,
TempK,
Lux,
M,
M2,
M3,
GForce,
Dps,
Gram,
A,
V,
W,
Gauss,
T,
Dbm,
Coulomb,
F,
Ohm,
Ph,
Bar,
Pa,
Cd,
Bool,
Cts,
Percent,
Permill,
Ppm,
Ppb,
Time,
Date,
Gpm3,
Cpm3,
}
impl Unit {
fn from_c(input: u8) -> Option<Self> {
match input as _ {
riot_sys::UNIT_NONE => Some(Unit::None),
riot_sys::UNIT_TEMP_C => Some(Unit::TempC),
riot_sys::UNIT_TEMP_F => Some(Unit::TempF),
riot_sys::UNIT_TEMP_K => Some(Unit::TempK),
riot_sys::UNIT_LUX => Some(Unit::Lux),
riot_sys::UNIT_M => Some(Unit::M),
riot_sys::UNIT_M2 => Some(Unit::M2),
riot_sys::UNIT_M3 => Some(Unit::M3),
riot_sys::UNIT_G_FORCE => Some(Unit::GForce),
riot_sys::UNIT_DPS => Some(Unit::Dps),
riot_sys::UNIT_GRAM => Some(Unit::Gram),
riot_sys::UNIT_A => Some(Unit::A),
riot_sys::UNIT_V => Some(Unit::V),
riot_sys::UNIT_W => Some(Unit::W),
riot_sys::UNIT_GAUSS => Some(Unit::Gauss),
riot_sys::UNIT_T => Some(Unit::T),
riot_sys::UNIT_DBM => Some(Unit::Dbm),
riot_sys::UNIT_COULOMB => Some(Unit::Coulomb),
riot_sys::UNIT_F => Some(Unit::F),
riot_sys::UNIT_OHM => Some(Unit::Ohm),
riot_sys::UNIT_PH => Some(Unit::Ph),
riot_sys::UNIT_BAR => Some(Unit::Bar),
riot_sys::UNIT_PA => Some(Unit::Pa),
riot_sys::UNIT_CD => Some(Unit::Cd),
riot_sys::UNIT_BOOL => Some(Unit::Bool),
riot_sys::UNIT_CTS => Some(Unit::Cts),
riot_sys::UNIT_PERCENT => Some(Unit::Percent),
riot_sys::UNIT_PERMILL => Some(Unit::Permill),
riot_sys::UNIT_PPM => Some(Unit::Ppm),
riot_sys::UNIT_PPB => Some(Unit::Ppb),
riot_sys::UNIT_TIME => Some(Unit::Time),
riot_sys::UNIT_DATE => Some(Unit::Date),
riot_sys::UNIT_GPM3 => Some(Unit::Gpm3),
riot_sys::UNIT_CPM3 => Some(Unit::Cpm3),
_ => None,
}
}
fn to_c(input: Option<Self>) -> u8 {
(match input {
Some(Unit::None) => riot_sys::UNIT_NONE,
Some(Unit::TempC) => riot_sys::UNIT_TEMP_C,
Some(Unit::TempF) => riot_sys::UNIT_TEMP_F,
Some(Unit::TempK) => riot_sys::UNIT_TEMP_K,
Some(Unit::Lux) => riot_sys::UNIT_LUX,
Some(Unit::M) => riot_sys::UNIT_M,
Some(Unit::M2) => riot_sys::UNIT_M2,
Some(Unit::M3) => riot_sys::UNIT_M3,
Some(Unit::GForce) => riot_sys::UNIT_G_FORCE,
Some(Unit::Dps) => riot_sys::UNIT_DPS,
Some(Unit::Gram) => riot_sys::UNIT_GRAM,
Some(Unit::A) => riot_sys::UNIT_A,
Some(Unit::V) => riot_sys::UNIT_V,
Some(Unit::W) => riot_sys::UNIT_W,
Some(Unit::Gauss) => riot_sys::UNIT_GAUSS,
Some(Unit::T) => riot_sys::UNIT_T,
Some(Unit::Dbm) => riot_sys::UNIT_DBM,
Some(Unit::Coulomb) => riot_sys::UNIT_COULOMB,
Some(Unit::F) => riot_sys::UNIT_F,
Some(Unit::Ohm) => riot_sys::UNIT_OHM,
Some(Unit::Ph) => riot_sys::UNIT_PH,
Some(Unit::Bar) => riot_sys::UNIT_BAR,
Some(Unit::Pa) => riot_sys::UNIT_PA,
Some(Unit::Cd) => riot_sys::UNIT_CD,
Some(Unit::Bool) => riot_sys::UNIT_BOOL,
Some(Unit::Cts) => riot_sys::UNIT_CTS,
Some(Unit::Percent) => riot_sys::UNIT_PERCENT,
Some(Unit::Permill) => riot_sys::UNIT_PERMILL,
Some(Unit::Ppm) => riot_sys::UNIT_PPM,
Some(Unit::Ppb) => riot_sys::UNIT_PPB,
Some(Unit::Time) => riot_sys::UNIT_TIME,
Some(Unit::Date) => riot_sys::UNIT_DATE,
Some(Unit::Gpm3) => riot_sys::UNIT_GPM3,
Some(Unit::Cpm3) => riot_sys::UNIT_CPM3,
None => riot_sys::UNIT_UNDEF,
}) as _
}
#[doc(alias = "phydat_unit_write")]
pub fn name_owned<const S: usize>(self) -> Option<heapless::String<S>> {
let mut result = heapless::String::new();
let bytes = unsafe { result.as_mut_vec() };
let len = unsafe {
riot_sys::phydat_unit_write(
bytes.as_mut_ptr() as *mut _,
S as _,
Self::to_c(Some(self)),
)
}
.negative_to_error()
.ok()?;
unsafe { bytes.set_len(len as _) };
Some(result)
}
}