### GPIO Control using CdevPin Character Device Interface Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt This example demonstrates controlling GPIO pins using the CdevPin struct, which interfaces with the Linux character device driver for GPIO. It shows how to configure pins as input or output, set their state, and read input values. It also illustrates converting pins between input and output modes. ```rust use embedded_hal::digital::{InputPin, OutputPin, PinState}; use linux_embedded_hal::CdevPin; use gpio_cdev::{Chip, LineRequestFlags}; fn main() -> Result<(), Box> { // Open GPIO chip let mut chip = Chip::new("/dev/gpiochip0")?; // Request GPIO line 17 as output (e.g., for an LED) let led_line = chip.get_line(17)?; let led_handle = led_line.request(LineRequestFlags::OUTPUT, 0, "led")?; let mut led = CdevPin::new(led_handle)?; // Control the LED led.set_high()?; println!("LED is ON"); std::thread::sleep(std::time::Duration::from_secs(1)); led.set_low()?; println!("LED is OFF"); // Request GPIO line 27 as input (e.g., for a button) let button_line = chip.get_line(27)?; let button_handle = button_line.request(LineRequestFlags::INPUT, 0, "button")?; let mut button = CdevPin::new(button_handle)?; // Read button state if button.is_high()? { println!("Button is pressed"); } else { println!("Button is released"); } // Convert output pin to input and vice versa let gpio_line = chip.get_line(22)?; let gpio_handle = gpio_line.request(LineRequestFlags::OUTPUT, 0, "gpio")?; let gpio_out = CdevPin::new(gpio_handle)?; // Convert to input mode let mut gpio_in = gpio_out.into_input_pin()?; println!("GPIO 22 value: {}", gpio_in.is_high()?); // Convert back to output mode with initial state let mut gpio_out = gpio_in.into_output_pin(PinState::Low)?; gpio_out.set_high()?; Ok(()) } ``` -------------------------------- ### Linux Embedded HAL Feature Flags Configuration Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Illustrates how to configure the `linux-embedded-hal` crate using Cargo feature flags in `Cargo.toml`. This allows users to enable or disable specific peripheral support, minimizing dependencies based on hardware requirements. Examples show default, minimal, GPIO-specific, SPI/I2C, and async configurations. ```toml # Cargo.toml examples # Default: all features enabled [dependencies] linux-embedded-hal = "0.4" # Minimal: only what you need [dependencies] linux-embedded-hal = { version = "0.4", default-features = false, features = ["i2c"] } # GPIO with character device (modern, recommended) [dependencies] linux-embedded-hal = { version = "0.4", default-features = false, features = ["gpio_cdev"] } # GPIO with sysfs (legacy compatibility) [dependencies] linux-embedded-hal = { version = "0.4", default-features = false, features = ["gpio_sysfs"] } # SPI and I2C only [dependencies] linux-embedded-hal = { version = "0.4", default-features = false, features = ["spi", "i2c"] } # All peripherals with async support (requires tokio runtime) [dependencies] linux-embedded-hal = { version = "0.4", features = ["async-tokio"] } # Available features: # - gpio_cdev: Character device GPIO (Linux 4.4+) # - gpio_sysfs: Legacy sysfs GPIO # - i2c: I2C bus support # - spi: SPI bus support # - serial: UART/serial port support # - async-tokio: Async delay support using tokio ``` -------------------------------- ### Direct SPI Bus Access with Manual Chip Select using SpidevBus Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt This example demonstrates how to use SpidevBus for direct SPI communication. It shows manual control of chip select pins using GPIO and configuring SPI settings like speed and mode. This is useful when drivers require exclusive bus access or manual CS management. ```rust use embedded_hal::spi::SpiBus; use embedded_hal::digital::OutputPin; use linux_embedded_hal::{SpidevBus, CdevPin}; use gpio_cdev::{Chip, LineRequestFlags}; use spidev::{SpiModeFlags, SpidevOptions}; fn main() -> Result<(), Box> { // Open SPI bus (use a dummy device for bus access) let mut spi_bus = SpidevBus::open("/dev/spidev0.0")?; // Configure SPI settings let options = SpidevOptions::new() .bits_per_word(8) .max_speed_hz(2_000_000) .mode(SpiModeFlags::SPI_MODE_0 | SpiModeFlags::SPI_NO_CS) .build(); spi_bus.configure(&options)?; // Setup GPIO as manual chip select let mut chip = Chip::new("/dev/gpiochip0")?; let cs_line = chip.get_line(17)?; let cs_handle = cs_line.request(LineRequestFlags::OUTPUT, 1, "spi-cs")?; let mut cs_pin = CdevPin::new(cs_handle)?; // Manual transaction with GPIO CS control cs_pin.set_low()?; let tx_data = [0x01, 0x02, 0x03, 0x04]; spi_bus.write(&tx_data)?; let mut rx_data = [0u8; 4]; spi_bus.read(&mut rx_data)?; spi_bus.flush()?; cs_pin.set_high()?; println!("Received: {:?}", rx_data); // Transfer in place (TX and RX use same buffer) cs_pin.set_low()?; let mut transfer_buf = [0x9F, 0x00, 0x00, 0x00]; spi_bus.transfer_in_place(&mut transfer_buf)?; cs_pin.set_high()?; println!("JEDEC ID: {:02X} {:02X} {:02X}", transfer_buf[1], transfer_buf[2], transfer_buf[3]); Ok(()) } ``` -------------------------------- ### SysTimer: Countdown Timer Implementation in Rust Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Implements a periodic countdown timer using `std::time::Instant`, conforming to the `CountDown` trait. This allows for non-blocking timer operations essential for timing loops and periodic tasks. The example shows basic blocking waits and non-blocking checks for timer expiration. ```rust use std::time::Duration; use nb::block; use linux_embedded_hal::{CountDown, SysTimer, Periodic}; fn main() { let mut timer = SysTimer::new(); // Basic countdown timer usage timer.start(Duration::from_millis(100)).unwrap(); println!("Timer started for 100ms"); // Block until timer expires block!(timer.wait()).unwrap(); println!("Timer expired!"); // Non-blocking timer check (returns WouldBlock if not ready) timer.start(Duration::from_secs(1)).unwrap(); loop { match timer.wait() { Ok(()) => { println!("Timer done!"); break; } Err(nb::Error::WouldBlock) => { // Do other work while waiting println!("Still waiting..."); std::thread::sleep(Duration::from_millis(100)); } Err(nb::Error::Other(e)) => panic!("Timer error: {:?}", e), } } // Periodic timer example (SysTimer implements Periodic) fn periodic_task(timer: &mut T) where T::Time: From, { timer.start(Duration::from_millis(500)).unwrap(); for i in 0..5 { block!(timer.wait()).unwrap(); println!("Periodic tick {}", i); // Timer automatically restarts for next period } } periodic_task(&mut timer); } ``` -------------------------------- ### SPI Communication with SpidevDevice in Rust Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Illustrates SPI communication using the `SpidevDevice` struct from `linux-embedded-hal`. It covers device opening, configuration, simple read/write, simultaneous transfer, and complex transactions with multiple operations. Requires access to `/dev/spidev*.*` devices. ```rust use embedded_hal::spi::{SpiDevice, Operation as SpiOperation}; use linux_embedded_hal::SpidevDevice; use spidev::{SpiModeFlags, SpidevOptions}; fn main() -> Result<(), Box> { // Open SPI device (bus 0, chip select 0) let mut spi = SpidevDevice::open("/dev/spidev0.0")?; // Configure SPI settings let options = SpidevOptions::new() .bits_per_word(8) .max_speed_hz(1_000_000) .mode(SpiModeFlags::SPI_MODE_0) .build(); spi.configure(&options)?; // Simple write operation let tx_buf = [0x01, 0x02, 0x03]; spi.write(&tx_buf)?; // Simple read operation let mut rx_buf = [0u8; 4]; spi.read(&mut rx_buf)?; println!("Received: {:?}", rx_buf); // Simultaneous transfer (write and read) let mut read_data = [0u8; 3]; spi.transfer(&mut read_data, &tx_buf)?; println!("Transfer result: {:?}", read_data); // Complex transaction with multiple operations let mut response = [0u8; 2]; let mut ops = [ SpiOperation::Write(&[0x9F]), // Send command SpiOperation::Read(&mut response), // Read response SpiOperation::DelayNs(1000), // Delay 1 microsecond ]; spi.transaction(&mut ops)?; println!("Device ID: {:?}", response); Ok(()) } ``` -------------------------------- ### Enable gpio_sysfs Feature in Cargo.toml Source: https://github.com/rust-embedded/linux-embedded-hal/blob/master/README.md This snippet demonstrates how to include the `linux-embedded-hal` crate in your Cargo.toml and specifically enable the `gpio_sysfs` feature. This allows the usage of `SysfsPin` for interacting with sysfs GPIO, which is an alternative to the character device approach. ```toml linux-embedded-hal = { version = "0.4", features = ["gpio_sysfs"] } ``` -------------------------------- ### Serial Port Communication with linux-embedded-hal Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Demonstrates how to open, configure, read from, and write to serial ports (UART) using the `Serial` struct from `linux-embedded-hal`. It utilizes non-blocking I/O with the `nb` crate and supports configurable baud rates and advanced serial port settings via a builder pattern. ```rust use embedded_hal_nb::serial::{Read, Write}; use linux_embedded_hal::Serial; use serialport::{DataBits, FlowControl, Parity, StopBits}; use nb::block; fn main() -> Result<(), Box> { // Open serial port with path and baud rate let mut serial = Serial::open("/dev/ttyUSB0".to_string(), 115200)?; // Write a single byte block!(serial.write(0x55))?; println!("Sent: 0x55"); // Write multiple bytes let message = b"Hello, UART!\n"; for byte in message { block!(serial.write(*byte))?; } block!(serial.flush())?; // Read a single byte (non-blocking) match serial.read() { Ok(byte) => println!("Received: 0x{:02X}", byte), Err(nb::Error::WouldBlock) => println!("No data available"), Err(nb::Error::Other(e)) => println!("Error: {}", e), } // Blocking read let received = block!(serial.read())?; println!("Received byte: {}", received); // Open with advanced configuration using builder let builder = serialport::new("/dev/ttyAMA0", 9600) .data_bits(DataBits::Eight) .parity(Parity::None) .stop_bits(StopBits::One) .flow_control(FlowControl::None) .timeout(std::time::Duration::from_millis(100)); let mut serial2 = Serial::open_from_builder(builder)?; // Simple echo loop loop { match serial2.read() { Ok(byte) => { block!(serial2.write(byte))?; if byte == b'q' { break; } } Err(nb::Error::WouldBlock) => continue, Err(e) => return Err(e.into()), } } Ok(()) } ``` -------------------------------- ### Enable gpio_cdev Feature in Cargo.toml Source: https://github.com/rust-embedded/linux-embedded-hal/blob/master/README.md This snippet shows how to add the `linux-embedded-hal` crate to your Cargo.toml file and enable the `gpio_cdev` feature. This feature allows the use of `CdevPin` which wraps `LineHandle` from the `gpio-cdev` crate for interacting with Linux GPIO character devices. ```toml linux-embedded-hal = { version = "0.4", features = ["gpio_cdev"] } ``` -------------------------------- ### SysfsPin: GPIO Sysfs Interface (Legacy) in Rust Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Demonstrates how to use the SysfsPin struct for GPIO control via the legacy sysfs interface. It covers pin creation, export/unexport, setting pin direction (input/output), and reading/writing pin states. Note that this method is deprecated in favor of character device GPIO. ```rust use embedded_hal::digital::{InputPin, OutputPin, PinState}; use linux_embedded_hal::SysfsPin; use std::ops::Deref; fn main() -> Result<(), Box> { // Create GPIO pin by number let led_pin = SysfsPin::new(17); // Export the pin (make it available to userspace) led_pin.export()?; // Set as output with initial low state let mut led = led_pin.into_output_pin(PinState::Low)?; // Blink LED for _ in 0..5 { led.set_high()?; std::thread::sleep(std::time::Duration::from_millis(500)); led.set_low()?; std::thread::sleep(std::time::Duration::from_millis(500)); } // Create input pin for button let button_pin = SysfsPin::new(27); button_pin.export()?; let mut button = button_pin.into_input_pin()?; // Read button state let state = if button.is_high()? { "HIGH" } else { "LOW" }; println!("Button state: {}", state); // Create pin from sysfs path let gpio_from_path = SysfsPin::from_path("/sys/class/gpio/gpio22")?; // Access underlying sysfs_gpio::Pin for advanced features led.deref().set_active_low(true)?; // Unexport when done led.unexport()?; button.unexport()?; Ok(()) } ``` -------------------------------- ### Enable Specific Features in Cargo.toml Source: https://github.com/rust-embedded/linux-embedded-hal/blob/master/README.md This configuration shows how to disable default features for the `linux-embedded-hal` crate and selectively enable specific features like `gpio_cdev`, `gpio_sysfs`, `i2c`, and `spi`. This approach allows for a more tailored dependency, including only the necessary functionalities. ```toml [dependencies.linux-embedded-hal] version = "0.4" default-features = false features = [ "gpio_cdev", "gpio_sysfs", "i2c", "spi", ] ``` -------------------------------- ### I2C Communication with I2cdev in Rust Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Demonstrates I2C communication using the `I2cdev` struct from `linux-embedded-hal`. It covers basic read/write operations, write-read sequences, and complex transactions with multiple operations. Requires access to `/dev/i2c-*` devices. ```rust use embedded_hal::i2c::{I2c, Operation as I2cOperation}; use linux_embedded_hal::I2cdev; fn main() -> Result<(), Box> { // Open the I2C bus let mut i2c = I2cdev::new("/dev/i2c-1")?; // Simple write to device at address 0x50 let device_addr: u8 = 0x50; let write_data = [0x00, 0x42]; // Register address + data i2c.write(device_addr, &write_data)?; // Simple read from device let mut read_buffer = [0u8; 4]; i2c.read(device_addr, &mut read_buffer)?; println!("Read data: {:?}", read_buffer); // Write-then-read (common pattern for register reads) let register_addr = [0x00]; let mut value = [0u8; 2]; i2c.write_read(device_addr, ®ister_addr, &mut value)?; println!("Register value: {:?}", value); // Complex transaction with multiple operations let mut ops = [ I2cOperation::Write(&[0xAB]), // Write register address I2cOperation::Read(&mut read_buffer), // Read response ]; i2c.transaction(device_addr, &mut ops)?; println!("Transaction result: {:?}", read_buffer); Ok(()) } ``` -------------------------------- ### Delay: Blocking and Async Delay Implementations in Rust Source: https://context7.com/rust-embedded/linux-embedded-hal/llms.txt Provides blocking delay functionality using `std::thread::sleep` and implements the `DelayNs` trait for nanosecond, microsecond, and millisecond precision. With the `async-tokio` feature enabled, it also supports asynchronous delays. ```rust use embedded_hal::delay::DelayNs; use linux_embedded_hal::Delay; fn main() { let mut delay = Delay; println!("Starting delay sequence..."); // Delay in nanoseconds delay.delay_ns(1_000_000); // 1ms in nanoseconds println!("1ms nanosecond delay complete"); // Delay in microseconds delay.delay_us(500); // 500 microseconds println!("500us delay complete"); // Delay in milliseconds delay.delay_ms(1000); // 1 second println!("1 second delay complete"); // Using delay in a sensor read pattern fn read_sensor_with_delay(delay: &mut D) -> u16 { // Start measurement delay.delay_ms(10); // Wait for sensor to initialize // Read data delay.delay_us(100); // Wait between reads // Return simulated value 42 } let value = read_sensor_with_delay(&mut delay); println!("Sensor value: {}", value); } // Async delay example (requires `async-tokio` feature) #[cfg(feature = "async-tokio")] async fn async_delay_example() { use embedded_hal_async::delay::DelayNs; use linux_embedded_hal::Delay; let mut delay = Delay; // Async delays using tokio delay.delay_ms(100).await; println!("Async delay complete"); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.