diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7d6167..1001b6c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,6 +34,7 @@ jobs: with: repository: RIOT-OS/RIOT path: RIOT + # common steps end here - name: Patch .cargo/config.toml to use current checkout run: | set -x @@ -59,7 +60,6 @@ jobs: cargo tree --manifest-path $MANIF echo "::endgroup::" done - # common steps end here - name: Build the example run: | @@ -91,7 +91,7 @@ jobs: board: [native, sltb001a, samr21-xpro, stk3700] testdir: ${{ fromJSON(needs.enumerate-wrappers-tests.outputs.list) }} steps: - # common steps start here + # common steps start here (kept in sync even though we wouldn't need to patch RIOT's .cargo/config.toml) - name: Check out riot-wrappers uses: actions/checkout@v3 - name: Check out RIOT @@ -99,32 +99,14 @@ jobs: with: repository: RIOT-OS/RIOT path: RIOT - - name: Patch .cargo/config.toml to use current checkout + # common steps end here + + - name: Patch local .cargo/config.toml to use current checkout run: | - set -x - cd RIOT - rm -f .cargo/config.toml - mkdir -p .cargo # Keep working if RIOT ever decides it doesn't need overrides any more + mkdir .cargo echo '[patch.crates-io]' >> .cargo/config.toml - echo 'riot-wrappers = { path = "../", version = "*" }' >> .cargo/config.toml + echo 'riot-wrappers = { path = ".", version = "*" }' >> .cargo/config.toml echo 'riot-sys = { git = "https://github.com/RIOT-OS/rust-riot-sys" }' >> .cargo/config.toml - - name: Pull cargo updates - # No sense in running this in parallel -- this will download the index - # and all relevant crates once, and after that, just make some notes in Cargo.lock - run: | - set -x - # It is important to cd in early, for otherwise the patch.crates-io - # will not catch on during the update - cd RIOT - for MANIF in $(find -name Cargo.toml) - do - echo "::group::Updating ${MANIF}" - cargo update -p riot-sys -p riot-wrappers --aggressive --manifest-path $MANIF - cargo fetch --manifest-path $MANIF - cargo tree --manifest-path $MANIF - echo "::endgroup::" - done - # common steps end here - name: Build and run test run: | diff --git a/Cargo.toml b/Cargo.toml index 7d1edb6..3db923a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.4", features = ["u embedded-hal = "1" switch-hal = "0.4.0" nb = "0.1.1" -riot-sys = "0.7.10" +riot-sys = "0.7.13" num-traits = { version = "0.2", default-features = false } mutex-trait = "0.2" diff --git a/src/led.rs b/src/led.rs index c61cd1b..8e47161 100644 --- a/src/led.rs +++ b/src/led.rs @@ -7,13 +7,57 @@ use core::convert::Infallible; /// The preferred interface for turning a LED on and off is [switch_hal::OutputSwitch]. /// /// LEDs are accessible safely; any not implemented on a board are silently ignored. +#[derive(Debug)] pub struct LED(()); +/// The indicated LED is not present on the current board. +#[derive(Debug)] +pub struct LedNotPresent; + impl LED { + #[deprecated( + note = "Use new_unchecked() to retain the behavior this function has always had; future versions of `.new()` will panic when used with a board that does not have that LED.", + since = "0.9.1" + )] pub const fn new() -> Self { + Self::new_unchecked() + } + + /// Accesses the LED numbered `I`. + /// + /// It is not an error if this board does not have a LED with that number; the resulting struct + /// will be available but its methods have no effect. + pub const fn new_unchecked() -> Self { assert!(I < 8, "RIOT only defines LED0..7"); Self(()) } + + /// Accesses the LED numbered `I`. + /// + /// An LED is returned if present on the board, which is known at build time. + pub const fn new_checked() -> Result { + if Self::is_present() { + Ok(Self(())) + } else { + Err(LedNotPresent) + } + } + + const fn is_present() -> bool { + unsafe { + match I { + 0 => riot_sys::macro_LED0_IS_PRESENT() != -1, + 1 => riot_sys::macro_LED1_IS_PRESENT() != -1, + 2 => riot_sys::macro_LED2_IS_PRESENT() != -1, + 3 => riot_sys::macro_LED3_IS_PRESENT() != -1, + 4 => riot_sys::macro_LED4_IS_PRESENT() != -1, + 5 => riot_sys::macro_LED5_IS_PRESENT() != -1, + 6 => riot_sys::macro_LED6_IS_PRESENT() != -1, + 7 => riot_sys::macro_LED7_IS_PRESENT() != -1, + _ => panic!("RIOT only defines LED0..7"), + } + } + } } impl switch_hal::OutputSwitch for LED { diff --git a/tests/led/src/lib.rs b/tests/led/src/lib.rs index 6d1b906..792d50a 100644 --- a/tests/led/src/lib.rs +++ b/tests/led/src/lib.rs @@ -6,14 +6,17 @@ use riot_wrappers::riot_main; riot_main!(main); fn main() { - let mut led0 = LED::<0>::new(); - let mut led1 = LED::<1>::new(); - let mut led2 = LED::<2>::new(); - let mut led3 = LED::<3>::new(); - let mut led4 = LED::<4>::new(); - let mut led5 = LED::<5>::new(); - let mut led6 = LED::<6>::new(); - let mut led7 = LED::<7>::new(); + // Using the `unchecked` methods because the loop rotates the blinking speeds through all LEDs + // anyway -- so every speed will be on every LED, and that's easier to express if the number of + // considered LEDs is constant. + let mut led0 = LED::<0>::new_unchecked(); + let mut led1 = LED::<1>::new_unchecked(); + let mut led2 = LED::<2>::new_unchecked(); + let mut led3 = LED::<3>::new_unchecked(); + let mut led4 = LED::<4>::new_unchecked(); + let mut led5 = LED::<5>::new_unchecked(); + let mut led6 = LED::<6>::new_unchecked(); + let mut led7 = LED::<7>::new_unchecked(); let mut leds: [&mut dyn switch_hal::ToggleableOutputSwitch; 8] = [ &mut led0, &mut led1, &mut led2, &mut led3, &mut led4, &mut led5, &mut led6, &mut led7, ];