-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16833 from chrysn-pull-requests/rust-lib
Add some Rust library building infrastructure
- Loading branch information
Showing
40 changed files
with
1,288 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
include $(RIOTBOARD)/common/microbit/Makefile.dep | ||
include $(RIOTBOARD)/common/nrf52/Makefile.dep | ||
|
||
ifneq (,$(filter saul_default,$(USEMODULE))) | ||
USEMODULE += lsm303agr | ||
endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
const I2C_DEVICES: &[u8] = &[0]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "riot-module-lsm303agr" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
authors = ["Christian Amsüss <[email protected]>"] | ||
license = "LGPL-2.1-only" | ||
|
||
# Shipped with RIOT-OS; this has no external API that would make | ||
# sense to consume in any context than from within RIOT | ||
publish = false | ||
|
||
[dependencies] | ||
lsm303agr = "^0.2" | ||
riot-wrappers = "^0.7.17" | ||
# Whatever lsm uses | ||
nb = "*" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright (c) 2022 HAW Hamburg | ||
# | ||
# This file is subject to the terms and conditions of the GNU Lesser | ||
# General Public License v2.1. See the file LICENSE in the top level | ||
# directory for more details. | ||
# | ||
|
||
config MODULE_LSM303AGR | ||
bool | ||
prompt "LSM303AGR 3D accelerometer/magnetometer" if !(MODULE_SAUL_DEFAULT && HAVE_LSM303AGR) | ||
default y if (MODULE_SAUL_DEFAULT && HAVE_LSM303AGR) | ||
depends on HAS_PERIPH_I2C | ||
depends on TEST_KCONFIG | ||
select MODULE_RUST_RIOTMODULES | ||
select MODULE_PERIPH_I2C | ||
|
||
config HAVE_LSM303AGR | ||
bool | ||
help | ||
Indicates that a lsm303agr sensor is present. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
USEMODULE += rust_riotmodules | ||
|
||
FEATURES_REQUIRED += periph_i2c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
PSEUDOMODULES += lsm303agr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/** | ||
|
||
@defgroup drivers_lsm303agr LSM303AGR 3D accelerometer/magnetometer | ||
@ingroup drivers_sensors | ||
@ingroup drivers_saul | ||
@brief Device driver for the LSM303AGR 3D accelerometer/magnetometer | ||
|
||
This driver is written in Rust, | ||
and based on the externally maintained [lsm303agr] crate. | ||
|
||
This means that: | ||
|
||
- it is only available on platforms supported by Rust, | ||
- it needs Rust installed on the build machine as described in @ref using-rust, and | ||
- it downloads additional Rust code from crates.io (in versions pinned by RIOT) when first used. | ||
|
||
[lsm303agr]: https://crates.io/crates/lsm303agr | ||
|
||
## Usage | ||
|
||
When configured on a board, the devices are initialized at a fixed data acquisition rate and the chip's default range of +-2g. | ||
Data values are obtained on demand | ||
whenever queried through @ref drivers_saul. | ||
|
||
For each device, two SAUL entries are registered labelled "LSM303AGR accelerometer" and "LSM303AGR magnetometer", | ||
which produces 3-axis values in units of g and Tesla, respectively. | ||
Accelerometer values are always scaled to milli-g (they come that way and don't exceed the i16 range of SAUL phydats); | ||
magnetometer readings are dynamically downscaled from their original i32 Nanotesla readings to fit in a phydat. | ||
|
||
The driver is configured for a board by placing an `lsm303agr-config.rs` file | ||
in the board's include directory, which lists the I2C device(s) on which an accelerometer should be found: | ||
|
||
``` | ||
const I2C_DEVICES: &[u8] = &[0]; | ||
``` | ||
|
||
## Limitations | ||
|
||
- Advanced features of the sensor | ||
(adjusting acquisition rate or resolution, free-fall detection, interrupts etc.) | ||
are not exposed. | ||
|
||
- The driver accepts some memory overhead (roughly, two mutexes) to avoid unsafe code and enhance readability. | ||
The unsafe code would be sound based on the assertion that the initialization code is only called once | ||
(and in particular is not reentrant). | ||
|
||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#![no_std] | ||
|
||
use lsm303agr::{interface, mode, Lsm303agr, AccelOutputDataRate::Hz50}; | ||
|
||
use riot_wrappers::{saul, println, i2c, cstr::cstr, mutex::Mutex}; | ||
use saul::{Phydat, registration}; | ||
|
||
// FIXME: Is this the way we want to go? It's mimicking the C way, but we could just as well take | ||
// the board config from some YAML. | ||
include!(concat!(env!("BOARDDIR"), "/include/lsm303agr-config.rs")); | ||
|
||
const NDEVICES: usize = I2C_DEVICES.len(); | ||
|
||
static DRIVER: registration::Driver<SaulLSM> = registration::Driver::new(); | ||
static DRIVER_MAG: registration::Driver<SaulLSM, MagAspect> = registration::Driver::new(); | ||
|
||
// These two being in mutexes is somewhat unnecessary (the mutexes are locked at startup and then | ||
// never unlocked). The alternative is to unsafely access them (asserting that auto_init_lsm303agr | ||
// / init will only ever be called once), or hiding that assertion at some preprocessor level (like | ||
// cortex-m-rt's main does). | ||
// | ||
// Doing it at runtime comes at the cost of two global mutexes in memory, and some more startup | ||
// calls. | ||
// | ||
// Using an Option (with .insert) rather than MaybeUninit (with .write) is another step that | ||
// sacrifices minimal resources (could be none at all, didn't check) for readability. | ||
|
||
// This can't go into ROM because it has a .next pointer that is altered at runtime when some other | ||
// device is registered. (In an alternative implementation where all SAUL registries are managed by | ||
// XFA, this would be possible; finding the point in time when they are ready to be used would be | ||
// tricky, though.). | ||
static REG: Mutex<[Option<registration::Registration<SaulLSM>>; NDEVICES]> = Mutex::new([None; NDEVICES]); | ||
static REG_MAG: Mutex<[Option<registration::Registration<SaulLSM, MagAspect>>; NDEVICES]> = Mutex::new([None; NDEVICES]); | ||
// This can't go into ROM because it contains an inner Mutex (and possibly state data from the | ||
// Lsm303agr instance, didn't bother to check) | ||
static LSM: Mutex<[Option<SaulLSM>; NDEVICES]> = Mutex::new([None; NDEVICES]); | ||
|
||
#[no_mangle] | ||
pub extern "C" fn auto_init_lsm303agr() { | ||
if let Err(e) = init() { | ||
println!("LSM303AGR init error: {}", e); | ||
} | ||
} | ||
|
||
/// Initialize the configured LSM303AGR device, returning an error string for debug if anything | ||
/// goes wrong | ||
fn init() -> Result<(), &'static str> { | ||
let lsm = LSM | ||
.try_leak() | ||
.expect("LSM303AGR init is only called once"); | ||
|
||
let reg = REG | ||
.try_leak() | ||
.expect("LSM303AGR init is only called once"); | ||
let reg_mag = REG_MAG | ||
.try_leak() | ||
.expect("LSM303AGR init is only called once"); | ||
|
||
for (&i2cdev, (lsm, (reg, reg_mag))) in I2C_DEVICES.iter().zip(lsm.iter_mut().zip(reg.iter_mut().zip(reg_mag.iter_mut()))) { | ||
let mut device = Lsm303agr::new_with_i2c(i2c::I2CDevice::new(i2cdev)); | ||
|
||
device.init() | ||
.map_err(|_| "Device initialization failed")?; | ||
device.set_accel_odr(Hz50) | ||
.map_err(|_| "Device configuration failed")?; | ||
|
||
let lsm = lsm.insert(SaulLSM { device: Mutex::new(device) }); | ||
|
||
let reg = reg.insert(registration::Registration::new(&DRIVER, lsm, Some(cstr!("LSM303AGR accelerometer")))); | ||
let reg_mag = reg_mag.insert(registration::Registration::new(&DRIVER_MAG, lsm, Some(cstr!("LSM303AGR magnetometer")))); | ||
|
||
reg.register_static(); | ||
reg_mag.register_static(); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
struct SaulLSM { | ||
device: Mutex<Lsm303agr<interface::I2cInterface<i2c::I2CDevice>, mode::MagOneShot>>, | ||
} | ||
|
||
impl registration::Drivable for &SaulLSM { | ||
const CLASS: saul::Class = saul::Class::Sensor(Some(saul::SensorClass::Accel)); | ||
|
||
const HAS_READ: bool = true; | ||
|
||
fn read(self) -> Result<Phydat, registration::Error> { | ||
// SAUL doesn't guarantee exclusive access; different threads may read simultaneously. | ||
let mut device = self.device.try_lock() | ||
.ok_or(registration::Error)?; | ||
|
||
let data = device.accel_data() | ||
.map_err(|_| registration::Error)?; | ||
// Data is in the +-2g range by default, which doesn't overflow even the i16 SAUL uses | ||
Ok(Phydat::new(&[data.x as _, data.y as _, data.z as _], Some(saul::Unit::G), -3)) | ||
} | ||
} | ||
|
||
struct MagAspect(&'static SaulLSM); | ||
|
||
impl From<&'static SaulLSM> for MagAspect { | ||
fn from(input: &'static SaulLSM) -> Self { | ||
Self(input) | ||
} | ||
} | ||
|
||
impl registration::Drivable for MagAspect { | ||
const CLASS: saul::Class = saul::Class::Sensor(Some(saul::SensorClass::Mag)); | ||
|
||
const HAS_READ: bool = true; | ||
|
||
fn read(self) -> Result<Phydat, registration::Error> { | ||
// SAUL doesn't guarantee exclusive access; different threads may read simultaneously. | ||
let mut device = self.0.device.try_lock() | ||
.ok_or(registration::Error)?; | ||
|
||
let data = nb::block!(device.mag_data()) | ||
.map_err(|_| registration::Error)?; | ||
// Original data is in nanotesla | ||
return Ok(Phydat::fit(&[data.x, data.y, data.z], Some(saul::Unit::T), -9)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.