diff --git a/.github/workflows/buildtest.yml b/.github/workflows/buildtest.yml index a8928c74..1a9fb92a 100644 --- a/.github/workflows/buildtest.yml +++ b/.github/workflows/buildtest.yml @@ -37,7 +37,7 @@ jobs: # update` is much faster the second time (so a parallel execution may # still be faster but uses 3x the resources) run: | - export BOARDS='native sltb001a samr21-xpro' + export BOARDS='native sltb001a samr21-xpro stk3700' DIRS='examples/rust-hello-world examples/rust-gcoap tests/rust_minimal' # It appears that there has to be output before :: commands really catch on echo "Building ${DIRS} on ${BOARDS}" @@ -56,7 +56,7 @@ jobs: echo "::echo ::off" - name: Build and run tests run: | - export BOARDS='native sltb001a samr21-xpro' + export BOARDS='native sltb001a samr21-xpro stk3700' DIRS=$(echo tests/*/) export RIOTBASE=$(pwd)/RIOT # It appears that there has to be output before :: commands really catch on diff --git a/src/auto_init.rs b/src/auto_init.rs index 31213848..40070013 100644 --- a/src/auto_init.rs +++ b/src/auto_init.rs @@ -1,6 +1,6 @@ //! Tools for declaring a function that is run during initialization //! -//! The [auto_init!] macro is this module's main product. +//! The [`auto_init!`](super::auto_init!) macro is this module's main product. /// Wrapper around [riot_sys::auto_init_module_t] /// @@ -13,7 +13,7 @@ impl AutoInitModule { /// Initializer for module auto-initialization /// /// Do not call this directly: Its result must be placed in a static in a special section in - /// memory, which is handled by the [`auto_init!`] macro. + /// memory, which is handled by the [`auto_init!`](super::auto_init!) macro. pub const fn new( init_function: extern "C" fn(), priority: u16, diff --git a/src/bluetil.rs b/src/bluetil.rs index 6ac771f0..36d4da15 100644 --- a/src/bluetil.rs +++ b/src/bluetil.rs @@ -31,7 +31,7 @@ pub enum Error { impl From for Error { fn from(e: crate::error::NumericError) -> Error { - match e.number as _ { + match e.number() as _ { riot_sys::BLUETIL_AD_NOTFOUND => Error::NotFound, riot_sys::BLUETIL_AD_NOMEM => Error::NoMem, _ => panic!("Invalid bluetil error"), diff --git a/src/dac.rs b/src/dac.rs new file mode 100644 index 00000000..651a232d --- /dev/null +++ b/src/dac.rs @@ -0,0 +1,65 @@ +use riot_sys::dac_t; + +#[derive(Debug)] +pub struct DACLine { + line: dac_t, +} + +#[derive(Debug)] +#[non_exhaustive] +pub enum DACError { + /// The given dac_t line did not exist + NoLine, + /// An unknown error did occur + Unknown, +} + +impl DACLine { + /// Creates and intializes a new [`DACLine`]. + /// + /// The `index` indicates which dac device from the current board should be used. + /// For information on how many such devices are available for this board please + /// refer to its RIOT documentation. + /// + /// Returns an Error if the given line does not exist + /// on the board. + pub fn new(index: usize) -> Result { + let line = unsafe { riot_sys::macro_DAC_LINE(index as u32) }; + let res = unsafe { riot_sys::dac_init(line) } as i32; + + const DAC_OK: i32 = riot_sys::DAC_OK as i32; + const DAC_NOLINE: i32 = riot_sys::DAC_NOLINE as i32; + + match res { + DAC_OK => Ok(DACLine { line }), + DAC_NOLINE => Err(DACError::NoLine), + _ => Err(DACError::Unknown), + } + } + + /// Builds a [`DACLine`] from an already initialized [`dac_t`]. + /// + /// Providing a not initialized [`dac_t`] results in undefined behavior. + pub unsafe fn new_without_init(line: dac_t) -> Self { + DACLine { line } + } + + /// Writes the given value to this [`DACLine`] + /// + /// The `value` is internally scaled to the underlying + /// dac device so that the maximum voltage output + /// is always equivalent to [`u16::MAX`] + pub fn set(&mut self, value: u16) { + unsafe { riot_sys::dac_set(self.line, value) } + } + + /// Turns the [`DACLine`] on after `DACLine::power_off` + pub fn power_on(&mut self) { + unsafe { riot_sys::dac_poweron(self.line) } + } + + /// Turns the [`DACLine`] off + pub fn power_off(&mut self) { + unsafe { riot_sys::dac_poweroff(self.line) } + } +} diff --git a/src/error.rs b/src/error.rs index f96b350c..96a60d2d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,11 @@ //! Common error handling components for the RIOT operating system +//! +//! ## Constants +//! +//! Several commonly used errors are provided as constants rather than requiring the use of +//! [NumericError::from_constant] for easier use. That list is not created comprehensively but +//! populated on demand. (Copying the full list would needlessly limit RIOT's ability to slim down +//! the list). use core::convert::TryInto; @@ -16,8 +23,9 @@ pub trait NegativeErrorExt { /// represent `Result` as just the isize it originally was. For the /// time being, this works well enough, and performance evaluation can later be done against a /// manually implemented newtype around isize that'd be used to represent the Result. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct NumericError { + #[deprecated(note = "Use the .number() method")] pub number: isize, } @@ -43,21 +51,28 @@ impl NumericError { /// ## Panics /// /// In debug mode, this ensures that the given error is greater than zero. - pub fn from_constant(name: isize) -> Self { + pub const fn from_constant(name: isize) -> Self { debug_assert!( name > 0, "Error names are expected to be positive for conversion into negative error numbers." ); + #[allow(deprecated)] // it's deprecated *pub* NumericError { number: -name } } + /// Numeric value of the error + pub const fn number(&self) -> isize { + #[allow(deprecated)] // it's deprecated *pub* + self.number + } + /// Convert the error into an [nb::Error] that is [nb::Error::WouldBlock] if the error is /// `-EAGAIN`, and an actual error otherwise. pub fn again_is_wouldblock(self) -> nb::Error { - match -self.number as u32 { - riot_sys::EAGAIN => nb::Error::WouldBlock, - _ => nb::Error::Other(self), + if self == Self::from_constant(riot_sys::EAGAIN as _) { + return nb::Error::WouldBlock; } + nb::Error::Other(self) } } @@ -65,7 +80,7 @@ impl NumericError { // // impl core::fmt::Display for NumericError { // fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { -// write!(f, "Error {} ({})", self.number, ...) +// write!(f, "Error {} ({})", self.number(), ...) // } // } @@ -79,9 +94,22 @@ where if self >= Self::zero() { Ok(self) } else { + #[allow(deprecated)] // it's deprecated *pub* Err(NumericError { number: self.try_into().unwrap_or(-(riot_sys::EOVERFLOW as isize)), }) } } } + +macro_rules! E { + ($e:ident) => { + #[doc = concat!("The predefined error ", stringify!($e))] + pub const $e: NumericError = NumericError::from_constant(riot_sys::$e as _); + }; +} + +// See module level comment +E!(EAGAIN); +E!(ENOMEM); +E!(EOVERFLOW); diff --git a/src/gcoap.rs b/src/gcoap.rs index 3450bee1..66188374 100644 --- a/src/gcoap.rs +++ b/src/gcoap.rs @@ -216,7 +216,7 @@ unsafe extern "C" fn link_encoder( let h: &H = unsafe { &*((*resource).context as *const _) }; let buf = buf as *mut u8; // cast away signedness of char - let mut buf = if buf.is_null() { + let buf = if buf.is_null() { None } else { Some(core::slice::from_raw_parts_mut(buf, buf_len as _)) @@ -259,7 +259,7 @@ impl<'a, H> SingleHandlerListener<'a, H> where H: 'a + Handler + WithLinkEncoder, { - /// Like [`new()`], but utilizing that the handler is also [WithLinkEncoder] and can thus influence + /// Like [`Self::new()`], but utilizing that the handler is also [WithLinkEncoder] and can thus influence /// what is reported when the default .well-known/core handler is queried. pub fn new_with_link_encoder( path: &'a core::ffi::CStr, @@ -344,7 +344,6 @@ pub trait WithLinkEncoder { } use riot_sys::{ - coap_get_total_hdr_len, coap_opt_add_opaque, coap_opt_add_uint, coap_opt_get_next, @@ -376,11 +375,6 @@ impl PacketBuffer { }) as u8 // odd return type in C } - /// Wrapper for coap_get_total_hdr_len - fn get_total_hdr_len(&self) -> usize { - (unsafe { coap_get_total_hdr_len(crate::inline_cast(self.pkt)) }) as usize - } - /// Wrapper for gcoap_resp_init /// /// As it is used and wrapped here, this makes GCOAP_RESP_OPTIONS_BUF bytes unusable, but diff --git a/src/gnrc.rs b/src/gnrc.rs index 5c0bca52..53839700 100644 --- a/src/gnrc.rs +++ b/src/gnrc.rs @@ -5,7 +5,8 @@ pub mod ipv6; pub mod netapi; pub mod netreg; -pub mod pktbuf; +#[deprecated(note = "moved to gnrc_pktbuf toplevel module")] +pub use crate::gnrc_pktbuf as pktbuf; use riot_sys::{gnrc_netif_iter, gnrc_netif_t}; diff --git a/src/gnrc/ipv6.rs b/src/gnrc/ipv6.rs index 70e812bc..d8d401ae 100644 --- a/src/gnrc/ipv6.rs +++ b/src/gnrc/ipv6.rs @@ -101,7 +101,7 @@ impl ::core::str::FromStr for Address { // When no_std_net / embedded_nal is present, it may be a good idea to run through there. impl ::core::fmt::Debug for Address { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - let as_u8 = unsafe { &self.inner.u8_ }; + let as_u8 = self.raw(); write!( f, "{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:\ @@ -180,7 +180,7 @@ impl From for Address { #[cfg(feature = "with_embedded_nal")] impl From
for embedded_nal::Ipv6Addr { fn from(addr: Address) -> Self { - Self::from(unsafe { addr.inner.u8_ }) + Self::from(*addr.raw()) } } diff --git a/src/gnrc/netreg.rs b/src/gnrc/netreg.rs index f294afd8..573bf1b2 100644 --- a/src/gnrc/netreg.rs +++ b/src/gnrc/netreg.rs @@ -1,7 +1,7 @@ +#[cfg(feature = "with_msg_v2")] use core::mem::MaybeUninit; -use riot_sys::{gnrc_netreg_entry_t, gnrc_netreg_register, gnrc_netreg_unregister, gnrc_nettype_t}; - +#[cfg(feature = "with_msg_v2")] use crate::error::NegativeErrorExt; // Transmuting the pointer into a Pktsnip does the right thing by treating it as a smart diff --git a/src/gnrc/pktbuf.rs b/src/gnrc_pktbuf.rs similarity index 94% rename from src/gnrc/pktbuf.rs rename to src/gnrc_pktbuf.rs index 153001bd..c67a8f7c 100644 --- a/src/gnrc/pktbuf.rs +++ b/src/gnrc_pktbuf.rs @@ -11,7 +11,6 @@ use riot_sys::{ gnrc_pktbuf_realloc_data, gnrc_pktbuf_release_error, gnrc_pktsnip_t, - gnrc_udp_hdr_build, GNRC_NETERR_SUCCESS, }; @@ -138,6 +137,8 @@ impl Pktsnip { src: core::num::NonZeroU16, dst: core::num::NonZeroU16, ) -> Result, NotEnoughSpace> { + use riot_sys::gnrc_udp_hdr_build; + let snip = unsafe { gnrc_udp_hdr_build(self.ptr, src.into(), dst.into()) }; if snip == 0 as *mut _ { // All other errors are caught by the signature @@ -253,13 +254,19 @@ impl<'a> Pktsnip { size: usize, nettype: gnrc_nettype_t, ) -> Result { - let next = next.map(|s| s.ptr).unwrap_or(0 as *mut _); - let snip = - unsafe { gnrc_pktbuf_add(next, data as *const _, size.try_into().unwrap(), nettype) }; + let next_ptr = next.as_ref().map(|s| s.ptr).unwrap_or(0 as *mut _); + forget(next); + let snip = unsafe { + gnrc_pktbuf_add( + next_ptr, + data as *const _, + size.try_into().unwrap(), + nettype, + ) + }; if snip == 0 as *mut _ { return Err(NotEnoughSpace); } - forget(next); Ok(unsafe { Pktsnip::::from_ptr(snip) }) } @@ -284,7 +291,13 @@ impl<'a> Pktsnip { impl ::core::fmt::Debug for Pktsnip { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + let mode = core::any::type_name::(); + let mode = mode + .rsplit("::") + .next() + .expect("Type name contains :: because it is part of a module"); f.debug_struct("Pktsnip") + .field("M", &mode) .field("length", &self.len()) .field("snips", &self.count()) .finish() diff --git a/src/interrupt.rs b/src/interrupt.rs index 642f684a..a458a232 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -5,7 +5,7 @@ //! * Utility functions can disable interrupts (creating critical sections), check whether //! interrupts are enabled or to determine whether code is executed in a thread or an ISR. //! -//! * Some functions (eg. [`ZTimer::set_ticks_during`](crate::ztimer::ZTimer::set_ticks_during)) +//! * Some functions (eg. [`ZTimer::set_ticks_during`](crate::ztimer::Clock::set_during)) //! take callbacks that will be called in an interrupt context. //! //! These are typechecked to be Send, as they are moved from the thread to the interrupt context. diff --git a/src/lib.rs b/src/lib.rs index bdbabc36..f7fc829d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,18 +40,25 @@ mod helpers; mod never; use never::Never; +/// The identifier of the RIOT board the program is being built for (`RIOT_BOARD` in C). +#[doc(alias = "RIOT_BOARD")] +pub const BOARD: &'static str = { + let b = riot_sys::RIOT_BOARD; + let Ok(b) = core::ffi::CStr::from_bytes_with_nul(b) else { + // Could be `.expect()`, but that's not const yet + // Workaround-For: https://github.com/rust-lang/rust/issues/67441 + panic!("Board names are null-terminated C strings"); + }; + let Ok(b) = b.to_str() else { + panic!("Board names should be ASCII") + }; + b +}; + /// Name of the RIOT board that is being used -/// -/// Development: -/// -/// Once this can be const, it'll be deprecated in favor of a pub const &'static str. That'll also -/// force the compiler to remove all the exceptions at build time (currently it does not, even with -/// aggressive optimization). -pub fn board() -> &'static str { - core::ffi::CStr::from_bytes_with_nul(riot_sys::RIOT_BOARD) - .expect("Board names are null-terminated C strings") - .to_str() - .expect("Board names should be ASCII") +#[deprecated(note = "Access BOARD instead")] +pub const fn board() -> &'static str { + BOARD } /// Cast pointers around before passing them in to functions; this is sometimes needed when a @@ -105,6 +112,9 @@ pub mod thread; pub mod gcoap; #[cfg(riot_module_gnrc)] pub mod gnrc; +// Note that this can also exist without gnrc +#[cfg(riot_module_gnrc_pktbuf)] +pub mod gnrc_pktbuf; #[cfg(riot_module_gnrc)] pub mod gnrc_util; #[cfg(riot_module_periph_i2c)] @@ -118,6 +128,9 @@ pub mod spi; #[cfg(riot_module_periph_adc)] pub mod adc; +#[cfg(riot_module_periph_dac)] +pub mod dac; + #[cfg(riot_module_ztimer)] pub mod ztimer; diff --git a/src/main_module.rs b/src/main_module.rs index 5e8c8e99..c0943517 100644 --- a/src/main_module.rs +++ b/src/main_module.rs @@ -1,6 +1,6 @@ //! Tools for providing a RIOT main function //! -//! The main contribution of this module is the [riot_main] macro. +//! The main contribution of this module is the [`riot_main!`](super::riot_main!) macro. //! //! The alternative to using that (other than doing it manually) is to have C code along with the //! Rust application that occupies the main function. @@ -10,6 +10,7 @@ //! C code. use crate::stdio::println; +use crate::thread::{EndToken, StartToken}; // General alternative to this module: Build the extern "C" main all the time and request that the // application implement a named function. I never got the main function to be carried to the @@ -55,9 +56,9 @@ impl T, T: Termination> UsableAsMain<[u8; 1]> for F { } } -impl crate::never::Never> Sealed<[u8; 2]> for F {} +impl crate::never::Never> Sealed<[u8; 2]> for F {} -impl crate::never::Never> UsableAsMain<[u8; 2]> for F { +impl crate::never::Never> UsableAsMain<[u8; 2]> for F { unsafe fn call_main(&self) -> i32 { // unsafe: By construction of the C main function this only happens at startup time // with a thread that hasn't done anything relevant before. @@ -67,11 +68,9 @@ impl crate::never::Never> UsableAsMain<[u8; } } -impl ((), crate::thread::EndToken)> Sealed<[u8; 3]> for F {} +impl ((), EndToken)> Sealed<[u8; 3]> for F {} -impl ((), crate::thread::EndToken)> UsableAsMain<[u8; 3]> - for F -{ +impl ((), EndToken)> UsableAsMain<[u8; 3]> for F { unsafe fn call_main(&self) -> i32 { // unsafe: By construction of the C main function this only happens at startup time // with a thread that hasn't done anything relevant before. diff --git a/src/msg.rs b/src/msg.rs index c14afdb8..e99044c1 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -28,7 +28,7 @@ pub enum MsgSender { impl MsgSender { fn from_pid(pid: kernel_pid_t) -> Self { - if pid == crate::thread::pid_converted::KERNEL_PID_ISR { + if pid == crate::thread::KERNEL_PID_ISR { MsgSender::ISR } else { KernelPID::new(pid) diff --git a/src/never.rs b/src/never.rs index 3c12f841..499a750b 100644 --- a/src/never.rs +++ b/src/never.rs @@ -3,6 +3,7 @@ /// /// From , adjusted for /// usability with pub interfaces by using a pub trait in a private module (sealing). +#[cfg(not(feature = "actual_never_type"))] use crate::helpers::*; #[cfg(not(feature = "actual_never_type"))] diff --git a/src/panic.rs b/src/panic.rs index f5cf78d9..41e33547 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -24,46 +24,45 @@ fn panic(info: &::core::panic::PanicInfo) -> ! { cstr::cstr!("RUST PANIC").as_ptr() as _, ) }; - unreachable!() - } - - // I *guess* it's OK for a panic to simply make a thread into a zombie -- this does allow other - // threads (including spawned Rust threads) to continue, but my layman's understanding of - // panicking is that that's OK because whatever we were just mutating can simply never be used - // by someone else ever again. + } else { + // I *guess* it's OK for a panic to simply make a thread into a zombie -- this does allow other + // threads (including spawned Rust threads) to continue, but my layman's understanding of + // panicking is that that's OK because whatever we were just mutating can simply never be used + // by someone else ever again. - let me = thread::get_pid(); + let me = thread::get_pid(); - if cfg!(feature = "panic_handler_format") { - use crate::stdio::println; + if cfg!(feature = "panic_handler_format") { + use crate::stdio::println; - println!( - "Error in thread {:?} ({}):", - me, - me.get_name().unwrap_or("unnamed") - ); - println!("{}", info); - } else { - let mut stdio = crate::stdio::Stdio {}; - use core::fmt::Write; - let _ = stdio.write_str("Panic in thread "); - let _ = stdio.write_str(me.get_name().unwrap_or("unnamed")); - let _ = stdio.write_str("!\n"); - } + println!( + "Error in thread {:?} ({}):", + me, + me.get_name().unwrap_or("unnamed") + ); + println!("{}", info); + } else { + let mut stdio = crate::stdio::Stdio {}; + use core::fmt::Write; + let _ = stdio.write_str("Panic in thread "); + let _ = stdio.write_str(me.get_name().unwrap_or("unnamed")); + let _ = stdio.write_str("!\n"); + } - if cfg!(feature = "panic_handler_crash") { - unsafe { - riot_sys::core_panic( - riot_sys::core_panic_t_PANIC_GENERAL_ERROR, - cstr::cstr!("RUST PANIC").as_ptr() as _, - ) + if cfg!(feature = "panic_handler_crash") { + unsafe { + riot_sys::core_panic( + riot_sys::core_panic_t_PANIC_GENERAL_ERROR, + cstr::cstr!("RUST PANIC").as_ptr() as _, + ) + } } - } - // Not trying any unwinding -- this thread is just dead, won't be re-claimed, any mutexes it - // holds are just held indefinitely rather than throwing poison errors. - loop { - thread::sleep(); + // Not trying any unwinding -- this thread is just dead, won't be re-claimed, any mutexes it + // holds are just held indefinitely rather than throwing poison errors. + loop { + thread::sleep(); + } } } diff --git a/src/saul.rs b/src/saul.rs index 1e071e8a..4a592421 100644 --- a/src/saul.rs +++ b/src/saul.rs @@ -17,12 +17,8 @@ //! //! [SAUL]: https://doc.riot-os.org/group__drivers__saul.html -use riot_sys as raw; -use riot_sys::libc; - use crate::error; use crate::helpers::PointerToCStr; -use crate::Never; use error::NegativeErrorExt; pub mod registration; @@ -95,10 +91,9 @@ impl RegistryEntry { unsafe { riot_sys::saul_reg_write(self.0, &value.values as *const _ as *mut _) } .negative_to_error()?; if length != value.length.into() { - // FIXME is this the best way to express the error? - Err(error::NumericError { - number: length as isize, - }) + // It's not pretty to synthesize an error here, but neither would be expressing the + // partial write in the context of lengthful phydat items. + Err(error::NumericError::from_constant(riot_sys::EINVAL as _)) } else { Ok(()) } @@ -370,13 +365,13 @@ pub enum Unit { M, M2, M3, - G, + GForce, Dps, - Gr, + Gram, A, V, W, - Gs, + Gauss, T, Dbm, Coulomb, @@ -399,6 +394,18 @@ pub enum Unit { } impl Unit { + // Note that on the C side the code still uses the aliases on the C side -- they're deprecated, + // but we'd need to introduce a marker, and given they'll stay deprecated on C for a release, + // we can just switch over before they go. + #[deprecated(note = "Use the GForce variant instead")] + pub const G: Self = Unit::GForce; + #[allow(non_upper_case_globals)] + #[deprecated(note = "Use the Gram variant instead")] + pub const Gr: Self = Unit::Gram; + #[allow(non_upper_case_globals)] + #[deprecated(note = "Use the Gauss variant instead")] + pub const Gs: Self = Unit::Gauss; + fn from_c(input: u8) -> Option { match input as _ { riot_sys::UNIT_NONE => Some(Unit::None), @@ -409,13 +416,13 @@ impl Unit { 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 => Some(Unit::G), + riot_sys::UNIT_G_FORCE => Some(Unit::GForce), riot_sys::UNIT_DPS => Some(Unit::Dps), - riot_sys::UNIT_GR => Some(Unit::Gr), + 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_GS => Some(Unit::Gs), + 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), @@ -449,13 +456,13 @@ impl Unit { Some(Unit::M) => riot_sys::UNIT_M, Some(Unit::M2) => riot_sys::UNIT_M2, Some(Unit::M3) => riot_sys::UNIT_M3, - Some(Unit::G) => riot_sys::UNIT_G, + Some(Unit::GForce) => riot_sys::UNIT_G_FORCE, Some(Unit::Dps) => riot_sys::UNIT_DPS, - Some(Unit::Gr) => riot_sys::UNIT_GR, + 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::Gs) => riot_sys::UNIT_GS, + 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, diff --git a/src/saul/registration.rs b/src/saul/registration.rs index 29739768..74c264cd 100644 --- a/src/saul/registration.rs +++ b/src/saul/registration.rs @@ -33,8 +33,9 @@ pub trait Drivable: Sized { /// Set to true if `read` is implemented. /// /// Doing this on the type level (rather than having read and write return a more - /// differentiated error) allows the driver to point to the shared [riot_sys::saul_notsup] - /// handler rather than to monomorphize a custom erring handler for each device. + /// differentiated error) allows the driver to point to the shared [riot_sys::saul_read_notsup] + /// / [riot_sys::saul_write_notsup] handler rather than to monomorphize a custom erring handler + /// for each device. const HAS_READ: bool = false; /// Set to true if `write` is implemented. const HAS_WRITE: bool = false; @@ -50,7 +51,7 @@ pub trait Drivable: Sized { /// Set the state of an actuator, or reconfigure a sensor /// /// A &self is passed in on write because there could be concurrent access from multiple SAUL - /// users. One option of handling this is to implement Drivable for Mutex. + /// users. One option of handling this is to implement Drivable for `Mutex`. /// /// Note that due to the way SAUL is structured, the drivable can not know the number of /// entries which the user intended to set. The Drivable trait always builds the Rust Phydat diff --git a/src/shell.rs b/src/shell.rs index f5d86203..06a25d34 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -2,8 +2,8 @@ //! //! This module can be used in two ways: //! -//! * Declare static commands using [static_command]; these only take a `fn` (not a closure) -//! because shell commands don't have an arg pointer. +//! * Declare static commands using [`static_command!`](crate::static_command!); these only take a +//! `fn` (not a closure) because shell commands don't have an arg pointer. //! //! This works even in RIOT modules that are included in a C application that starts a shell, and //! show up in shells created through Rust without explicit inclusion. @@ -20,8 +20,8 @@ //! argument. This does allow the Rust wrappers to "just so" use a closure as a command handler, //! but also needs a lot of code. //! -//! That complexity is not pulled in when only using [static_command] and running on an otherwise -//! empty command list. +//! That complexity is not pulled in when only using [`static_command!`](crate::static_command!) +//! and running on an otherwise empty command list. use crate::{mutex, stdio}; use core::ffi::CStr; @@ -108,11 +108,13 @@ pub unsafe trait CommandListInternals: Sized { let sleeve = lock .as_ref() .expect("Callback called while no shell set up as running"); - // unsafe: A suitable callback is always configured. We can make a &mut out of it for as - // long as we hold the lock. - let root = unsafe { &mut *(sleeve.0 as *mut Self) }; - let result = root.find_self_and_run(argc, argv, command_index); - drop(root); + let result; + { + // unsafe: A suitable callback is always configured. We can make a &mut out of it for as + // long as we hold the lock. + let root = unsafe { &mut *(sleeve.0 as *mut Self) }; + result = root.find_self_and_run(argc, argv, command_index); + } drop(lock); result } diff --git a/src/socket_embedded_nal_tcp.rs b/src/socket_embedded_nal_tcp.rs index 33f8c81c..3959c94a 100644 --- a/src/socket_embedded_nal_tcp.rs +++ b/src/socket_embedded_nal_tcp.rs @@ -1,8 +1,9 @@ //! An implementation of the [embedded_nal] (Network Abstradtion Layer) TCP traits based on RIOT //! sockets //! -//! This is vastly distinct from [socket_embedded_nal] as it requires vastly different workarounds -//! (and because it was implemented when embedded-nal had already switched over to &mut stack). +//! This is vastly distinct from [the UDP version](crate::socket_embedded_nal) as it requires +//! vastly different workarounds (and because it was implemented when embedded-nal had already +//! switched over to &mut stack). //! //! ## Warning //! @@ -107,8 +108,8 @@ impl<'a, const QUEUELEN: usize> TcpClientStack for Pin<&'a mut ListenStack Result<(), nb::Error> { panic!("A ListenStack can not connect out.") } @@ -116,7 +117,7 @@ impl<'a, const QUEUELEN: usize> TcpClientStack for Pin<&'a mut ListenStack true, + SocketImpl::Connection(_n) => true, _ => false, }) } @@ -206,13 +207,15 @@ impl<'a, const QUEUELEN: usize> TcpFullStack for Pin<&'a mut ListenStack Result<(), Self::Error> { + fn listen(&mut self, _sock: &mut Self::TcpSocket) -> Result<(), Self::Error> { // Done already in bind Ok(()) } fn accept( &mut self, - sock: &mut Self::TcpSocket, + // This is and can actually be ignored, because our stack object only serves a single + // listening socket. + _sock: &mut Self::TcpSocket, ) -> Result<(Self::TcpSocket, SocketAddr), nb::Error> { let mut sockptr = core::ptr::null_mut(); unsafe { diff --git a/src/thread.rs b/src/thread.rs index 075e1d20..aa9e964a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,11 +2,11 @@ //! //! ## Tokens //! -//! Some thread creation mechanisms (currently only [riot_main_with_tokens] and not those in here) -//! are "with tokens". With these, the zero-sized type [StartToken] is used to pass along the -//! information that the execution is currently happening in a thread, and more importantly that -//! some operations doable only once per thread (eg. setting up a message queue) have not yet -//! happed. +//! Some thread creation mechanisms (currently only +//! [`riot_main_with_tokens!`](crate::riot_main_with_tokens!) and not those in here) are "with +//! tokens". With these, the zero-sized type [StartToken] is used to pass along the information +//! that the execution is currently happening in a thread, and more importantly that some +//! operations doable only once per thread (eg. setting up a message queue) have not yet happed. //! //! When threads are created that way, they need to return an [EndToken] which ensures that //! no operations that preclude the termination of a thread have happened. @@ -23,6 +23,7 @@ pub use riot_c::*; mod tokenparts; #[cfg(doc)] pub use tokenparts::TokenParts; +#[allow(deprecated)] pub use tokenparts::{EndToken, InIsr, InThread, StartToken, TerminationToken, ValueInThread}; mod stack_stats; diff --git a/src/thread/riot_c.rs b/src/thread/riot_c.rs index 750936b0..4a93e5cb 100644 --- a/src/thread/riot_c.rs +++ b/src/thread/riot_c.rs @@ -14,41 +14,33 @@ pub use creation::{scope, spawn, CountedThread, CountingThreadScope}; #[derive(Debug, PartialEq, Copy, Clone)] pub struct KernelPID(pub(crate) raw::kernel_pid_t); -pub(crate) mod pid_converted { - //! Converting the raw constants into consistently typed ones - use riot_sys as raw; - - pub const KERNEL_PID_UNDEF: raw::kernel_pid_t = raw::KERNEL_PID_UNDEF as _; - pub const KERNEL_PID_FIRST: raw::kernel_pid_t = raw::KERNEL_PID_FIRST as _; - pub const KERNEL_PID_LAST: raw::kernel_pid_t = raw::KERNEL_PID_LAST as _; - pub const KERNEL_PID_ISR: raw::kernel_pid_t = raw::KERNEL_PID_ISR as _; -} - -mod status_converted { - //! Converting the raw constants into consistently typed ones for use in match branches. If - //! that becomes a pattern, it might make sense to introduce a macro that forces a bunch of - //! symbols (with different capitalizations) into a given type and makes an enum with a - //! from_int method out of it. - - use riot_sys as raw; - - // This is special because it is not part of the enum but a cast -1 - // unsafe: Side effect free C macros - pub const STATUS_NOT_FOUND: i32 = unsafe { raw::macro_STATUS_NOT_FOUND() as _ }; - - pub const STATUS_STOPPED: i32 = raw::thread_status_t_STATUS_STOPPED as i32; - pub const STATUS_SLEEPING: i32 = raw::thread_status_t_STATUS_SLEEPING as i32; - pub const STATUS_MUTEX_BLOCKED: i32 = raw::thread_status_t_STATUS_MUTEX_BLOCKED as i32; - pub const STATUS_RECEIVE_BLOCKED: i32 = raw::thread_status_t_STATUS_RECEIVE_BLOCKED as i32; - pub const STATUS_SEND_BLOCKED: i32 = raw::thread_status_t_STATUS_SEND_BLOCKED as i32; - pub const STATUS_REPLY_BLOCKED: i32 = raw::thread_status_t_STATUS_REPLY_BLOCKED as i32; - pub const STATUS_FLAG_BLOCKED_ANY: i32 = raw::thread_status_t_STATUS_FLAG_BLOCKED_ANY as i32; - pub const STATUS_FLAG_BLOCKED_ALL: i32 = raw::thread_status_t_STATUS_FLAG_BLOCKED_ALL as i32; - pub const STATUS_MBOX_BLOCKED: i32 = raw::thread_status_t_STATUS_MBOX_BLOCKED as i32; - pub const STATUS_RUNNING: i32 = raw::thread_status_t_STATUS_RUNNING as i32; - pub const STATUS_PENDING: i32 = raw::thread_status_t_STATUS_PENDING as i32; -} - +// Converting the raw constants into consistently typed ones + +// pub(crate) const KERNEL_PID_UNDEF: riot_sys::kernel_pid_t = riot_sys::KERNEL_PID_UNDEF as _; +const KERNEL_PID_FIRST: riot_sys::kernel_pid_t = riot_sys::KERNEL_PID_FIRST as _; +const KERNEL_PID_LAST: riot_sys::kernel_pid_t = riot_sys::KERNEL_PID_LAST as _; +pub(crate) const KERNEL_PID_ISR: riot_sys::kernel_pid_t = riot_sys::KERNEL_PID_ISR as _; + +// Converting the raw constants into consistently typed ones for use in match branches. If +// that becomes a pattern, it might make sense to introduce a macro that forces a bunch of +// symbols (with different capitalizations) into a given type and makes an enum with a +// from_int method out of it. + +// This is special because it is not part of the enum but a cast -1 +// unsafe: Side effect free C macros +const STATUS_NOT_FOUND: i32 = unsafe { riot_sys::macro_STATUS_NOT_FOUND() as _ }; + +const STATUS_STOPPED: i32 = riot_sys::thread_status_t_STATUS_STOPPED as i32; +const STATUS_SLEEPING: i32 = riot_sys::thread_status_t_STATUS_SLEEPING as i32; +const STATUS_MUTEX_BLOCKED: i32 = riot_sys::thread_status_t_STATUS_MUTEX_BLOCKED as i32; +const STATUS_RECEIVE_BLOCKED: i32 = riot_sys::thread_status_t_STATUS_RECEIVE_BLOCKED as i32; +const STATUS_SEND_BLOCKED: i32 = riot_sys::thread_status_t_STATUS_SEND_BLOCKED as i32; +const STATUS_REPLY_BLOCKED: i32 = riot_sys::thread_status_t_STATUS_REPLY_BLOCKED as i32; +const STATUS_FLAG_BLOCKED_ANY: i32 = riot_sys::thread_status_t_STATUS_FLAG_BLOCKED_ANY as i32; +const STATUS_FLAG_BLOCKED_ALL: i32 = riot_sys::thread_status_t_STATUS_FLAG_BLOCKED_ALL as i32; +const STATUS_MBOX_BLOCKED: i32 = riot_sys::thread_status_t_STATUS_MBOX_BLOCKED as i32; +const STATUS_RUNNING: i32 = riot_sys::thread_status_t_STATUS_RUNNING as i32; +const STATUS_PENDING: i32 = riot_sys::thread_status_t_STATUS_PENDING as i32; #[derive(Debug)] #[non_exhaustive] @@ -56,17 +48,17 @@ pub enum Status { // I would not rely on any properties of the assigned values, but it might make the conversion // points easier on the generated code if it can be reasoned down to a simple check of whether // it's in range. - Stopped = status_converted::STATUS_STOPPED as isize, - Sleeping = status_converted::STATUS_SLEEPING as isize, - MutexBlocked = status_converted::STATUS_MUTEX_BLOCKED as isize, - ReceiveBlocked = status_converted::STATUS_RECEIVE_BLOCKED as isize, - SendBlocked = status_converted::STATUS_SEND_BLOCKED as isize, - ReplyBlocked = status_converted::STATUS_REPLY_BLOCKED as isize, - FlagBlockedAny = status_converted::STATUS_FLAG_BLOCKED_ANY as isize, - FlagBlockedAll = status_converted::STATUS_FLAG_BLOCKED_ALL as isize, - MboxBlocked = status_converted::STATUS_MBOX_BLOCKED as isize, - Running = status_converted::STATUS_RUNNING as isize, - Pending = status_converted::STATUS_PENDING as isize, + Stopped = STATUS_STOPPED as isize, + Sleeping = STATUS_SLEEPING as isize, + MutexBlocked = STATUS_MUTEX_BLOCKED as isize, + ReceiveBlocked = STATUS_RECEIVE_BLOCKED as isize, + SendBlocked = STATUS_SEND_BLOCKED as isize, + ReplyBlocked = STATUS_REPLY_BLOCKED as isize, + FlagBlockedAny = STATUS_FLAG_BLOCKED_ANY as isize, + FlagBlockedAll = STATUS_FLAG_BLOCKED_ALL as isize, + MboxBlocked = STATUS_MBOX_BLOCKED as isize, + Running = STATUS_RUNNING as isize, + Pending = STATUS_PENDING as isize, /// A status value not known to riot-wrappers. Don't match for this explicitly: Other values /// may, at any minor riot-wrappers update, become actual process states again. @@ -78,17 +70,17 @@ pub enum Status { impl Status { fn from_int(status: i32) -> Self { match status { - status_converted::STATUS_STOPPED => Status::Stopped, - status_converted::STATUS_SLEEPING => Status::Sleeping, - status_converted::STATUS_MUTEX_BLOCKED => Status::MutexBlocked, - status_converted::STATUS_RECEIVE_BLOCKED => Status::ReceiveBlocked, - status_converted::STATUS_SEND_BLOCKED => Status::SendBlocked, - status_converted::STATUS_REPLY_BLOCKED => Status::ReplyBlocked, - status_converted::STATUS_FLAG_BLOCKED_ANY => Status::FlagBlockedAny, - status_converted::STATUS_FLAG_BLOCKED_ALL => Status::FlagBlockedAll, - status_converted::STATUS_MBOX_BLOCKED => Status::MboxBlocked, - status_converted::STATUS_RUNNING => Status::Running, - status_converted::STATUS_PENDING => Status::Pending, + STATUS_STOPPED => Status::Stopped, + STATUS_SLEEPING => Status::Sleeping, + STATUS_MUTEX_BLOCKED => Status::MutexBlocked, + STATUS_RECEIVE_BLOCKED => Status::ReceiveBlocked, + STATUS_SEND_BLOCKED => Status::SendBlocked, + STATUS_REPLY_BLOCKED => Status::ReplyBlocked, + STATUS_FLAG_BLOCKED_ANY => Status::FlagBlockedAny, + STATUS_FLAG_BLOCKED_ALL => Status::FlagBlockedAll, + STATUS_MBOX_BLOCKED => Status::MboxBlocked, + STATUS_RUNNING => Status::Running, + STATUS_PENDING => Status::Pending, _ => Status::Other, } } @@ -109,7 +101,7 @@ impl KernelPID { // and then this function *should* be reevaluated). As pid_is_valid is static inline, the // compiler should be able to see through the calls down to there that the bounds checked // for there are the very bounds used in the construction here. - (pid_converted::KERNEL_PID_FIRST..=pid_converted::KERNEL_PID_LAST) + (KERNEL_PID_FIRST..=KERNEL_PID_LAST) .map(|i| KernelPID::new(i).expect("Should be valid by construction")) } @@ -128,7 +120,7 @@ impl KernelPID { pub fn status(&self) -> Result { // unsafe: Side effect free, always-callable C function let status = unsafe { raw::thread_getstatus(self.0) } as _; - if status == status_converted::STATUS_NOT_FOUND { + if status == STATUS_NOT_FOUND { Err(NoSuchThread) } else { Ok(Status::from_int(status)) @@ -172,16 +164,19 @@ impl KernelPID { /// This is not backed by C functions (as most of the rest of this crate is), but rather a /// practical way to access struct members that may or may not be present in a build. pub fn stack_stats(&self) -> Result { - let thread = self.thread()?; #[cfg(riot_develhelp)] - return Ok(StackStats { - // This cast is relevant because different platforms (eg. native and arm) disagree on - // whether that's an i8 or u8 pointer. Could have made it c_char, but a) don't want to - // alter the signatures and b) it's easier to use on the Rust side with a clear type. - start: unsafe { (*thread).stack_start as _ }, - size: unsafe { (*thread).stack_size as _ }, - free: unsafe { riot_sys::thread_measure_stack_free((*thread).stack_start) } as usize, - }); + { + let thread = self.thread()?; + return Ok(StackStats { + // This cast is relevant because different platforms (eg. native and arm) disagree on + // whether that's an i8 or u8 pointer. Could have made it c_char, but a) don't want to + // alter the signatures and b) it's easier to use on the Rust side with a clear type. + start: unsafe { (*thread).stack_start as _ }, + size: unsafe { (*thread).stack_size as _ }, + free: unsafe { riot_sys::thread_measure_stack_free((*thread).stack_start) } + as usize, + }); + } #[cfg(not(riot_develhelp))] return Err(StackStatsError::InformationUnavailable); } diff --git a/src/thread/stack_stats.rs b/src/thread/stack_stats.rs index 65466e82..10fa655a 100644 --- a/src/thread/stack_stats.rs +++ b/src/thread/stack_stats.rs @@ -1,4 +1,4 @@ -/// Gathered information about a thread, returned by [KernelPID::stack_stats()]. +/// Gathered information about a thread, returned by [super::KernelPID::stack_stats()]. /// /// All accessors are unconditional, because the StackStats can't be obtained without develhelp in /// the first place. diff --git a/src/thread/tokenparts.rs b/src/thread/tokenparts.rs index 6dabf227..ccd4afc8 100644 --- a/src/thread/tokenparts.rs +++ b/src/thread/tokenparts.rs @@ -44,8 +44,9 @@ pub struct TokenParts { /// Claim that the current thread has not done anything yet that is covered by this type /// - /// Do not call yourself; this needs to be public because [riot_main_with_tokens] is a macro - /// and thus technically called from the main crate. + /// Do not call yourself; this needs to be public because + /// [`riot_main_with_tokens!`](crate::riot_main_with_tokens!) is a macro and thus technically + /// called from the main crate. pub unsafe fn new() -> Self { TokenParts { _not_send: PhantomData, @@ -228,7 +229,7 @@ impl InThread { pub fn promote(self, value: T) -> ValueInThread { ValueInThread { value, - in_thread: self, + _in_thread: self, } } } @@ -253,12 +254,14 @@ impl InIsr { /// /// This does barely implement anything on its own, but the module implementing `T` might provide /// extra methods. +/// +/// This makes the wrapped value not `Send`. // Making the type fundamental results in ValueInThread<&Mutex> being shown at Mutex's page. #[derive(Copy, Clone)] #[cfg_attr(feature = "nightly_docs", fundamental)] pub struct ValueInThread { value: T, - in_thread: InThread, + _in_thread: InThread, } impl ValueInThread { diff --git a/src/vfs.rs b/src/vfs.rs index 39f40fda..0450969f 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -43,7 +43,7 @@ impl Stat { /// Parameter for seeking in a file /// -/// It is analogous to [std::io::SeekFrom]. +/// It is analogous to [std::io::SeekFrom](https://doc.rust-lang.org/std/io/enum.SeekFrom.html). #[derive(Debug)] pub enum SeekFrom { /// Seek to the given position from the start of the file diff --git a/tests/dac/Cargo.toml b/tests/dac/Cargo.toml new file mode 100644 index 00000000..f4e0ef37 --- /dev/null +++ b/tests/dac/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "riot-wrappers-test-dac" +version = "0.1.0" +authors = ["Christian Amsüss "] +edition = "2021" +publish = false + +[lib] +crate-type = ["staticlib"] + +[profile.release] +panic = "abort" + +[dependencies] +riot-wrappers = { version = "*", features = [ "set_panic_handler" ] } +riot-sys = "*" + +[patch.crates-io] +riot-sys = { git = "https://github.com/RIOT-OS/rust-riot-sys" } diff --git a/tests/dac/Makefile b/tests/dac/Makefile new file mode 100644 index 00000000..3e39f4c3 --- /dev/null +++ b/tests/dac/Makefile @@ -0,0 +1,14 @@ +# name of your application +APPLICATION = riot-wrappers-test-dac +APPLICATION_RUST_MODULE = riot_wrappers_test_dac +BASELIBS += $(APPLICATION_RUST_MODULE).module +FEATURES_REQUIRED += rust_target +FEATURES_REQUIRED += periph_dac + +# Of these boards it is known that DAC0 may be driven arbitrarily because it's +# just a pin on the extension header. (It's probably true for most boards, but +# so far nobody guarantees that. Just add your board here if your DAC0 pin is +# good to use). +BOARD_WHITELIST = stk3700 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/dac/src/lib.rs b/tests/dac/src/lib.rs new file mode 100644 index 00000000..12c5247b --- /dev/null +++ b/tests/dac/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] + +use riot_wrappers::dac; +use riot_wrappers::riot_main; + +riot_main!(main); + +fn main() { + let mut dac = dac::DACLine::new(0).unwrap(); + dac.set(655); // 1% of maximum value +} diff --git a/tests/gnrc-pktbuf/Cargo.toml b/tests/gnrc-pktbuf/Cargo.toml new file mode 100644 index 00000000..b23236f4 --- /dev/null +++ b/tests/gnrc-pktbuf/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "riot-wrappers-test-gnrc-pktbuf" +version = "0.1.0" +authors = ["Christian Amsüss "] +edition = "2021" +publish = false + +[lib] +crate-type = ["staticlib"] + +[profile.release] +panic = "abort" + +[dependencies] +riot-wrappers = { version = "*", features = [ "set_panic_handler", "panic_handler_format" ] } +riot-sys = "*" + +[patch.crates-io] +riot-sys = { git = "https://github.com/RIOT-OS/rust-riot-sys" } diff --git a/tests/gnrc-pktbuf/Makefile b/tests/gnrc-pktbuf/Makefile new file mode 100644 index 00000000..36095a97 --- /dev/null +++ b/tests/gnrc-pktbuf/Makefile @@ -0,0 +1,12 @@ +# name of your application +APPLICATION = riot-wrappers-test-gnrc-pktbuf +APPLICATION_RUST_MODULE = riot_wrappers_test_gnrc_pktbuf +BASELIBS += $(APPLICATION_RUST_MODULE).module +FEATURES_REQUIRED += rust_target + +USEMODULE += gnrc_pktbuf + +# thus we get `gnrc_pktbuf_is_empty` and `_is_sane` +CFLAGS += -DTEST_SUITES + +include $(RIOTBASE)/Makefile.include diff --git a/tests/gnrc-pktbuf/src/lib.rs b/tests/gnrc-pktbuf/src/lib.rs new file mode 100644 index 00000000..64ad97b5 --- /dev/null +++ b/tests/gnrc-pktbuf/src/lib.rs @@ -0,0 +1,76 @@ +#![no_std] + +use riot_wrappers::println; +use riot_wrappers::riot_main; + +use riot_wrappers::gnrc_pktbuf::{Pktsnip, Shared}; + +riot_main!(main); + +#[track_caller] +fn check() { + assert!( + unsafe { riot_sys::gnrc_pktbuf_is_sane() }, + "GNRC packet buffer in unsound state" + ); +} + +#[track_caller] +fn check_empty() { + check(); + assert!( + unsafe { riot_sys::gnrc_pktbuf_is_empty() }, + "GNRC packet buffer should be empty at this point" + ); +} + +fn main() { + check_empty(); + + let snip1 = Pktsnip::allocate(128, riot_sys::gnrc_nettype_t_GNRC_NETTYPE_UNDEF).unwrap(); + println!("Allocated pktsnip {:?}", snip1); + + check(); + + let snip2 = + Pktsnip::allocate_from(&[1, 2, 3, 4], riot_sys::gnrc_nettype_t_GNRC_NETTYPE_UNDEF).unwrap(); + println!("Allocated another pktsnip {:?}", snip2); + let snip2 = snip2 + .add(10, riot_sys::gnrc_nettype_t_GNRC_NETTYPE_UNDEF) + .unwrap(); + println!("... and prefixed it with 10 bytes into {:?}", snip2); + + check(); + + let snip2a: Pktsnip = snip2.into(); + let snip2b = snip2a.clone(); + let snip2b = snip2b + .add(10, riot_sys::gnrc_nettype_t_GNRC_NETTYPE_UNDEF) + .unwrap(); + println!( + "We have two of them now, the second one with an extension: {:?}, {:?}", + snip2a, snip2b + ); + + println!( + "Making the second writable should not change anything about memory usage (not tested)..." + ); + let snip2b: Pktsnip = snip2b.into(); // and the method isn't even available unless we + // make it shared in the first place + let snip2b = snip2b.start_write().unwrap(); + println!("... whereas making the first writable entails copying"); + let snip2a = snip2a.start_write().unwrap(); + println!( + "In the end, they still look the same: {:?}, {:?}", + snip2a, snip2b + ); + + drop(snip1); + drop(snip2a); + drop(snip2b); + println!("Dropped it"); + + check_empty(); + + println!("Tests completed."); +} diff --git a/tests/gnrc-pktbuf/tests/01-run.py b/tests/gnrc-pktbuf/tests/01-run.py new file mode 100755 index 00000000..ac26a3bd --- /dev/null +++ b/tests/gnrc-pktbuf/tests/01-run.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +import sys +from testrunner import run + +def test(child): + child.expect_exact("Tests completed.") + +if __name__ == "__main__": + sys.exit(run(test)) diff --git a/tests/led/src/lib.rs b/tests/led/src/lib.rs index 73571e24..f0ca139c 100644 --- a/tests/led/src/lib.rs +++ b/tests/led/src/lib.rs @@ -1,28 +1,27 @@ #![no_std] -use riot_wrappers::led; +use riot_wrappers::led::LED; use riot_wrappers::riot_main; riot_main!(main); fn main() { - let mut led0 = riot_wrappers::led::LED::<0>::new(); - let mut led1 = riot_wrappers::led::LED::<1>::new(); - let mut led2 = riot_wrappers::led::LED::<2>::new(); - let mut led3 = riot_wrappers::led::LED::<3>::new(); - let mut led4 = riot_wrappers::led::LED::<4>::new(); - let mut led5 = riot_wrappers::led::LED::<5>::new(); - let mut led6 = riot_wrappers::led::LED::<6>::new(); - let mut led7 = riot_wrappers::led::LED::<7>::new(); + 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(); 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, ]; - use switch_hal::ToggleableOutputSwitch; loop { for i in 0..=255 { for j in 0..8 { if (i ^ (i - 1)) & (1 << j) != 0 { - leds[j].toggle(); + leds[j].toggle().unwrap(); } } } diff --git a/tests/mutex/src/lib.rs b/tests/mutex/src/lib.rs index 0bda93f4..926b1374 100644 --- a/tests/mutex/src/lib.rs +++ b/tests/mutex/src/lib.rs @@ -3,7 +3,7 @@ use riot_wrappers::mutex::Mutex; use riot_wrappers::println; use riot_wrappers::riot_main; -use riot_wrappers::thread::{InThread, ValueInThread}; +use riot_wrappers::thread::InThread; riot_main!(main);