### Configure and Use Deterministic Heap Allocator in Rust Source: https://context7.com/drone-os/drone-core/llms.txt This snippet illustrates how to set up a deterministic heap memory pool allocator using the `heap!` macro. It configures memory pools with fixed-size blocks based on `layout.toml` settings, enabling O(1) allocation and deallocation. The example shows how standard allocations (like `Box` and `vec!`) utilize this allocator and demonstrates manual allocation and deallocation using the `Allocator` trait. ```rust #![feature(allocator_api)] #![feature(slice_ptr_get)] use drone_core::heap; // Configuration in layout.toml: // [heap.main] // size = "10K" // pools = [ // { block = "4", count = "896" }, # 896 x 4-byte blocks = 3584 bytes // { block = "32", count = "80" }, # 80 x 32-byte blocks = 2560 bytes // { block = "256", count = "16" }, # 16 x 256-byte blocks = 4096 bytes // ] // Define heap from layout configuration heap! { // Reference to heap in layout.toml layout => main; /// Heap metadata type metadata => pub Heap; /// Global allocator instance #[global_allocator] instance => pub HEAP; // Optional: enable trace stream for profiling // enable_trace_stream => 31; } fn main() { // Standard allocations now use the pool allocator let boxed_value = Box::new(42u32); // Uses 4-byte pool let buffer = vec![0u8; 24]; // Uses 32-byte pool let large_buffer = vec![0u8; 200]; // Uses 256-byte pool // Allocations are deterministic O(1) // No fragmentation within size classes // Manual allocation with specific allocator use alloc::alloc::{Allocator, Layout}; let layout = Layout::from_size_align(16, 4).unwrap(); let ptr = HEAP.allocate(layout).expect("allocation failed"); // Deallocate unsafe { HEAP.deallocate(ptr.cast(), layout) }; } ``` -------------------------------- ### Token System for Resource Ownership and Initialization in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Explains the use of zero-sized tokens to enforce resource ownership and one-time initialization patterns at compile time. This system ensures safe access to hardware resources and mutable static variables. It utilizes macros like `simple_token!`, `unsafe_simple_tokens!`, and `unsafe_static_tokens!` from the drone_core::token module. ```rust use drone_core::token::{simple_token, unsafe_simple_tokens, Token}; use drone_core::token::{unsafe_static_tokens, StaticToken}; // Define individual tokens simple_token! { /// Token for UART initialization pub struct UartInitToken; } simple_token! { /// Token for SPI initialization pub struct SpiInitToken; } // Group tokens together unsafe_simple_tokens! { /// All peripheral initialization tokens pub struct PeripheralTokens { UartInitToken, SpiInitToken, } } // Static variable tokens for safe mutable access static mut SYSTEM_TICKS: u64 = 0; static mut ERROR_LOG: [u8; 256] = [0; 256]; unsafe_static_tokens! { /// Static variable access tokens pub struct StaticTokens { SYSTEM_TICKS: u64, ERROR_LOG: [u8; 256], } } // One-time initializers consume tokens fn init_uart(token: UartInitToken) { // Can only be called once - token is consumed configure_uart_peripheral(); } fn init_spi(token: SpiInitToken) { configure_spi_peripheral(); } fn main() { // Take all tokens (unsafe - must be called once) let periph = unsafe { PeripheralTokens::take() }; let mut statics = unsafe { StaticTokens::take() }; // Tokens are zero-sized assert_eq!(core::mem::size_of_val(&periph), 0); // Initialize peripherals (consumes tokens) init_uart(periph.uart_init); init_spi(periph.spi_init); // Cannot call again - tokens were consumed // init_uart(periph.uart_init); // Compile error! // Safe mutable access to statics *statics.system_ticks.get() += 1; statics.error_log.get()[0] = b'E'; // Convert to static reference (consumes token) let ticks: &'static mut u64 = statics.system_ticks.into_static(); *ticks += 1; } fn configure_uart_peripheral() {} fn configure_spi_peripheral() {} ``` -------------------------------- ### Configure Drone Core Thread Pool in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Illustrates the configuration of a thread pool using the `drone_core::thr::pool!` macro. This macro defines the thread structure, thread-local storage, and individual threads with priorities for an embedded application. ```rust use drone_core::thr; use drone_core::token::Token; thr::pool! { /// The main thread object with custom fields thread => pub Thr { // Custom fields accessible via to_thr() - must be Sync pub peripheral_ready: bool = false; pub error_count: u32 = 0; }; /// Thread-local storage (doesn't need to be Sync) local => pub ThrLocal { // Use special `index` variable for thread position pub thread_id: u16 = index; pub scratch_buffer: [u8; 64] = [0; 64]; }; /// Token set for accessing thread tokens index => pub Thrs; /// Thread definitions with priorities threads => { /// System tick interrupt handler pub sys_tick; /// UART receive interrupt pub uart_rx; /// DMA transfer complete pub dma_complete; /// Timer interrupt pub timer1; }; } fn main() { // Take thread tokens (unsafe - must be called once) let thr = unsafe { Thrs::take() }; // Access thread object via token let sys_tick_thread = thr.sys_tick.to_thr(); // Access thread-local storage let local = Thr::local(); println!("Thread ID: {}", local.thread_id); // Check if fiber chain is empty if thr.uart_rx.is_empty() { // Add work to the thread thr.uart_rx.add_once(|| { process_uart_data(); }); } } fn process_uart_data() {} ``` -------------------------------- ### Create and Attach Fibers (Stackless Coroutines) in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Demonstrates the creation of different types of fibers (generator-based, closure-based, one-shot) and their attachment to threads within the Drone Core framework. Fibers are stackless coroutines that enable cooperative multitasking. ```rust #![feature(generators)] use drone_core::fib; use drone_core::thr::prelude::*; // Create a generator-based fiber that yields values let fiber_gen = fib::new(|| { // Perform work and yield intermediate result yield 1; // Continue processing and yield yield 2; // Complete and return final value 3 }); // Create a closure-based fiber using FnMut let fiber_fn = fib::new_fn(|| { // Check condition and either yield or complete if should_continue() { fib::Yielded(()) } else { fib::Complete(()) } }); // Create a one-shot fiber that runs once let fiber_once = fib::new_once(|| { // Perform initialization and return immediately initialize_peripheral(); }); // Define a thread pool and attach fibers drone_core::thr::pool! { thread => Thr {}; local => ThrLocal {}; index => Thrs; threads => { sys_tick; timer; }; } fn main() { let thr = unsafe { Thrs::take() }; // Attach generator fiber to SysTick thread thr.sys_tick.add(|| { // Fiber yields on each SysTick interrupt yield; // Process data yield; // Complete }); // Add a future-returning fiber let result_future = thr.sys_tick.add_future(fib::new(|| { yield; yield; 42 // Returns 42 after 3 SysTick triggers })); // Add a stream-producing fiber with ring buffer let stream = thr.timer.add_saturating_stream::<_, 8>(fib::new(|| { loop { let value = read_sensor(); yield Some(value); } })); } fn should_continue() -> bool { true } fn initialize_peripheral() {} fn read_sensor() -> u32 { 0 } ``` -------------------------------- ### Inventory Pattern for Resource Tracking in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Implements a compile-time token counting pattern for tracking resource states (enabled/disabled) to ensure proper cleanup. It uses Rust's type system and generics to manage resource lifetimes and dependencies, preventing use-after-free errors. ```rust use drone_core::inventory::{self, Inventory, Item}; use typenum::{U0, U1}; use core::sync::atomic::{AtomicBool, Ordering}; // Simulated power control static DMA_ENABLED: AtomicBool = AtomicBool::new(false); // Driver for disabled DMA pub struct Dma(Inventory); // Driver for enabled DMA pub struct DmaEnabled { // Hardware token would go here } impl Item for DmaEnabled { fn teardown(&mut self, _token: &mut inventory::GuardToken) { // Called automatically when guard drops or explicitly via teardown DMA_ENABLED.store(false, Ordering::SeqCst); } } impl Dma { pub fn new() -> Self { Self(Inventory::new(DmaEnabled {})) } // Enable with scoped guard (auto-disables on drop) pub fn enable(&mut self) -> inventory::Guard<'_, DmaEnabled> { DMA_ENABLED.store(true, Ordering::SeqCst); Inventory::guard(&mut self.0) } // Enable permanently until explicitly disabled pub fn into_enabled(self) -> Inventory { DMA_ENABLED.store(true, Ordering::SeqCst); let (enabled, token) = self.0.share1(); drop(token); // Will be recreated in from_enabled enabled } pub fn from_enabled(enabled: Inventory) -> Self { let token = unsafe { inventory::Token::new() }; let mut inventory = enabled.merge1(token); Inventory::teardown(&mut inventory); Self(inventory) } } // DMA channel that requires DMA to be enabled pub struct DmaChannel { channel_id: u8, } impl DmaChannel { pub fn transfer<'a>( &'a mut self, _dma_token: &'a inventory::Token, src: &[u8], dst: &mut [u8], ) { // Safe to use DMA - token proves it's enabled // Lifetime ensures DMA stays enabled during transfer dst.copy_from_slice(src); } } fn main() { let mut dma = Dma::new(); let mut channel = DmaChannel { channel_id: 0 }; assert!(!DMA_ENABLED.load(Ordering::SeqCst)); { // Scoped enable let dma_guard = dma.enable(); assert!(DMA_ENABLED.load(Ordering::SeqCst)); // Can use channel while guard exists let mut buffer = [0u8; 4]; channel.transfer(dma_guard.inventory_token(), &[1, 2, 3, 4], &mut buffer); } // DMA automatically disabled when guard dropped assert!(!DMA_ENABLED.load(Ordering::SeqCst)); } ``` -------------------------------- ### Define Bitfields with Derive Macro in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Demonstrates how to use the `Bitfield` derive macro to define integer types with named bit fields. This is useful for representing hardware registers or protocol data structures. It supports read-only, write-only, and read-write fields with optional documentation. ```rust use drone_core::bitfield::Bitfield; #[derive(Clone, Copy, Bitfield)] #[bitfield( // Field syntax: name(mode, offset[, width[, doc]]) // Modes: r (read-only), rw (read-write), w (write-only) enabled(rw, 0, 1, "Enable bit"), mode(rw, 1, 3, "Operating mode (0-7)"), prescaler(rw, 4, 4, "Clock prescaler"), irq_enable(rw, 8, 1, "Interrupt enable"), status(r, 9, 2, "Status flags (read-only)"), reserved(r, 11, 5, "Reserved bits"), )] struct ControlRegister(u16); #[derive(Clone, Copy, Bitfield)] #[bitfield( r(rw, 0, 8, "Red component"), g(rw, 8, 8, "Green component"), b(rw, 16, 8, "Blue component"), a(rw, 24, 8, "Alpha component"), )] struct Color(u32); fn main() { // Create with raw value let mut ctrl = ControlRegister(0b0000_0001_0101_0011); // One-bit field methods: field(), set_field(), clear_field(), toggle_field() assert!(ctrl.enabled()); ctrl.clear_enabled(); assert!(!ctrl.enabled()); ctrl.set_enabled(); ctrl.toggle_enabled(); // Multi-bit field methods: field(), write_field(value) assert_eq!(ctrl.mode(), 0b001); ctrl.write_mode(0b111); assert_eq!(ctrl.mode(), 0b111); // Read-only fields only have getter let _status = ctrl.status(); // Use with colors let mut pixel = Color(0); pixel.write_r(255); pixel.write_g(128); pixel.write_b(64); pixel.write_a(255); // Raw access assert_eq!(pixel.0, 0xFF40_80FF); // Size is exactly the underlying integer assert_eq!(core::mem::size_of::(), 2); assert_eq!(core::mem::size_of::(), 4); } ``` -------------------------------- ### Define and Access Memory-Mapped Registers in Rust Source: https://context7.com/drone-os/drone-core/llms.txt This snippet demonstrates how to define memory-mapped registers with specific fields, addresses, sizes, and access permissions using the `reg!` macro. It also shows how to take register tokens, load current values, modify registers using closures, and perform atomic operations on register fields. This approach ensures type-level safety and zero-cost abstractions for peripheral access. ```rust use drone_core::reg; use drone_core::reg::prelude::*; use drone_core::token::Token; // Define a register with fields reg! { /// GPIO Port A Control Register Low pub GPIOA CRL => { address => 0x4001_0800; // Memory address size => 0x20; // 32-bit register reset => 0x4444_4444; // Reset value traits => { RReg WReg }; // Read-write register fields => { /// Mode bits for pin 0 MODE0 => { offset => 0; width => 2; traits => { RRRegField WWRegField }; }; /// Configuration bits for pin 0 CNF0 => { offset => 2; width => 2; traits => { RRRegField WWRegField }; }; /// Mode bits for pin 1 MODE1 => { offset => 4; width => 2; traits => { RRRegField WWRegField }; }; }; }; } // Define register token index reg::tokens! { /// Register tokens macro pub macro app_reg_tokens; crate; crate; /// GPIO registers pub mod GPIOA { CRL; } } // Create concrete register index app_reg_tokens! { /// All peripheral registers index => pub Regs; } fn main() { // Take register tokens (zero-sized) let reg = unsafe { Regs::take() }; assert_eq!(core::mem::size_of_val(®), 0); // Read current register value let current = reg.gpioa_crl.load(); let mode0_val = current.mode0(); // Modify register with closure (read-modify-write) reg.gpioa_crl.into_unsync().modify(|r| { r.write_mode0(0b01) // Output mode, 10 MHz .write_cnf0(0b00) // Push-pull output }); // Store with default reset value modified reg.gpioa_crl.into_unsync().store(|r| { r.write_mode0(0b10) .write_mode1(0b10) }); // Direct field access with atomic operations (Srt = synchronized) let sync_reg = reg.gpioa_crl.into_sync(); sync_reg.store(|r| r.write_mode0(0b11)); // Copyable register token (Crt) for sharing let copy_reg = reg.gpioa_crl.into_copy(); let copy_reg2 = copy_reg; // Can be copied } ``` -------------------------------- ### Enable Host Feature for Drone Core in Cargo.toml Source: https://github.com/drone-os/drone-core/blob/master/README.md This snippet demonstrates how to enable the 'host' feature for the drone-core crate within your Cargo.toml file. Features allow for conditional compilation of specific functionalities. This is typically used when building for a host environment. ```toml [features] host = ["drone-core/host"] ``` -------------------------------- ### Process Loop Interface for Async Command Handling in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Enables wrapping synchronous, stackful code into an asynchronous command loop pattern, facilitating the integration of blocking operations within an async environment. It defines command and request types, and a `ProcLoop` trait for implementing the command processing logic. ```rust use drone_core::proc_loop::{Context, In, Out, ProcLoop, Sess}; use drone_core::fib::{self, Fiber, FiberState}; use core::pin::Pin; // Define command types pub enum Cmd { ReadSensor(u8), WriteConfig(u8, u32), Reset, } pub union CmdRes { sensor_value: u32, write_ok: bool, unit: (), } pub enum Req { Delay(u32), WaitForInterrupt, } pub union ReqRes { unit: (), } // Process loop implementation pub struct MyProcLoop; impl ProcLoop for MyProcLoop { type Context = MyContext; type Cmd = Cmd; type CmdRes = CmdRes; type Req = Req; type ReqRes = ReqRes; const STACK_SIZE: usize = 1024; fn run_cmd(cmd: Cmd, ctx: MyContext) -> CmdRes { match cmd { Cmd::ReadSensor(id) => { // Can make async requests from sync code ctx.req(Req::Delay(10)); let value = read_sensor_blocking(id); CmdRes { sensor_value: value } } Cmd::WriteConfig(reg, val) => { write_register(reg, val); CmdRes { write_ok: true } } Cmd::Reset => { ctx.req(Req::WaitForInterrupt); perform_reset(); CmdRes { unit: () } } } } fn on_create() { // Called when process is created } fn on_enter() { // Called before command loop starts } fn on_drop() { // Called when process is destroyed } } #[derive(Clone, Copy)] pub struct MyContext; impl Context for MyContext { unsafe fn new() -> Self { MyContext } fn req(self, req: Req) -> ReqRes { // This would yield to the async runtime // Implementation depends on platform ReqRes { unit: () } } } fn read_sensor_blocking(_id: u8) -> u32 { 42 } fn write_register(_reg: u8, _val: u32) {} fn perform_reset() {} ``` -------------------------------- ### Add Drone Core Dependency to Cargo.toml Source: https://github.com/drone-os/drone-core/blob/master/README.md This snippet shows how to add the drone-core crate as a dependency in your project's Cargo.toml file. It specifies the version of the crate to be used. Ensure you have a Rust development environment set up. ```toml [dependencies] drone-core = { version = "0.15.0" } ``` -------------------------------- ### Lock-Free Singly-Linked List in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Presents the `LinkedList` from `drone_core::sync`, a lock-free singly-linked list suitable for concurrent scenarios like work queues. It provides thread-safe `push` and `pop` operations, along with methods for iteration and modification (`iter_mut`) and selective removal (`drain_filter`). ```rust use drone_core::sync::LinkedList; fn main() { let list: LinkedList = LinkedList::new(); // Push elements (thread-safe) list.push(Task { id: 1, priority: 3 }); list.push(Task { id: 2, priority: 1 }); list.push(Task { id: 3, priority: 2 }); // Pop from front (LIFO order) assert_eq!(list.pop().unwrap().id, 3); assert_eq!(list.pop().unwrap().id, 2); // Check if empty assert!(!list.is_empty()); // Iterate with mutable access let mut work_list: LinkedList = LinkedList::new(); work_list.extend(&[ WorkItem { done: false, data: 10 }, WorkItem { done: false, data: 20 }, WorkItem { done: true, data: 30 }, ]); for item in work_list.iter_mut() { item.data *= 2; } // Drain with filter - remove completed items let completed: Vec<_> = work_list .drain_filter(|item| item.done) .collect(); // Collect remaining let remaining: Vec<_> = work_list.into_iter().collect(); } #[derive(Debug, PartialEq)] struct Task { id: u32, priority: u8, } #[derive(Clone, Copy)] struct WorkItem { done: bool, data: i32, } ``` -------------------------------- ### Futures-Aware Mutex for Embedded Systems in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Introduces the `Mutex` primitive from the `drone_core::sync` module, designed for lock-free synchronization in embedded environments. It supports asynchronous locking with `lock().await` and non-blocking attempts with `try_lock()`. The mutex automatically releases the lock when the guard object is dropped. ```rust use drone_core::sync::Mutex; // Create a mutex protecting shared data static SHARED_DATA: Mutex = Mutex::new(SensorData { temperature: 0, humidity: 0, timestamp: 0, }); struct SensorData { temperature: i16, humidity: u16, timestamp: u32, } async fn sensor_task() { // Async lock - yields if mutex is held let mut guard = SHARED_DATA.lock().await; guard.temperature = read_temperature(); guard.humidity = read_humidity(); guard.timestamp = get_tick_count(); // Mutex automatically released when guard drops } fn interrupt_handler() { // Try to acquire without blocking if let Some(mut guard) = SHARED_DATA.try_lock() { guard.timestamp = get_tick_count(); } // If locked, skip update this cycle } fn main() { let mut local_mutex = Mutex::new(vec![1, 2, 3]); // Direct mutable access when you have &mut local_mutex.get_mut().push(4); // Extract inner value let data = local_mutex.into_inner(); assert_eq!(data, vec![1, 2, 3, 4]); } fn read_temperature() -> i16 { 25 } fn read_humidity() -> u16 { 60 } fn get_tick_count() -> u32 { 0 } ``` -------------------------------- ### SPSC Channels: Oneshot and Ring Buffer Communication in Rust Source: https://context7.com/drone-os/drone-core/llms.txt Demonstrates the usage of oneshot and ring buffer SPSC channels for asynchronous communication between tasks. Oneshot channels are used for sending a single value, while ring buffers facilitate streaming data. These channels are part of the drone_core::sync module and require async/await. ```rust use drone_core::sync::spsc::{oneshot, ring}; // Oneshot channel - send a single value async fn oneshot_example() { let (tx, rx) = oneshot::channel::>(); // Sender side (e.g., in interrupt handler) spawn(async move { let result = perform_operation().await; tx.send(result).ok(); }); // Receiver side - await the result match rx.await { Ok(value) => println!("Received: {}", value), Err(oneshot::Canceled) => println!("Sender dropped"), } } // Ring buffer channel - stream of values async fn ring_channel_example() { use futures::stream::StreamExt; use futures::sink::SinkExt; // Create bounded channel with capacity 16 let (mut tx, mut rx) = ring::channel::(16); // Producer task spawn(async move { loop { let reading = SensorReading { value: read_adc(), timestamp: get_time(), }; // Send with backpressure if tx.send(reading).await.is_err() { break; // Receiver closed } } }); // Consumer task - process stream while let Some(reading) = rx.next().await { match reading { Ok(data) => process_reading(data), Err(e) => handle_error(e), } } } // Non-blocking operations fn try_operations() { let (mut tx, mut rx) = ring::channel::(8); // Try send without blocking match tx.try_send(42) { Ok(()) => println!("Sent"), Err(ring::TrySendError::Full(val)) => println!("Buffer full, {} rejected", val), Err(ring::TrySendError::Closed(val)) => println!("Channel closed"), } // Try receive without blocking match rx.try_next() { Ok(Some(val)) => println!("Got {}", val), Ok(None) => println!("Channel closed"), Err(ring::TryNextError::Empty) => println!("No data available"), } } #[derive(Debug)] struct Error; struct SensorReading { value: u16, timestamp: u32 } async fn perform_operation() -> Result { Ok(42) } fn spawn(_f: F) {} fn read_adc() -> u16 { 0 } fn get_time() -> u32 { 0 } fn process_reading(_r: SensorReading) {} fn handle_error(_e: Error) {} ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.