1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
//! Rust Embedded HAL for Apache NuttX RTOS
#![no_std] // Use the Rust Core Library instead of the Rust Standard Library, which is not compatible with embedded systems
// Import NuttX Macros
#[macro_use]
mod macros;
// Import NuttX HAL
mod hal;
pub use hal::*;
// Import Libraries
use core::{ // Rust Core Library
fmt, // String Formatting
str::FromStr, // For converting `str` to `String`
};
/// Print a message to the serial console.
/// TODO: Auto-generate this wrapper with `bindgen` from the C declaration
pub fn puts(s: &str) -> i32 { // `&str` is a reference to a string slice, similar to `const char *` in C
extern "C" { // Import C Function
/// Print a message to the serial console (from C stdio library)
fn puts(s: *const u8) -> i32;
}
// Convert `str` to `String`, which similar to `char [64]` in C
// TODO: Increase the buffer size if we're sure we won't overflow the stack
let mut s_with_null = String::from_str(s) // `mut` because we will modify it
.expect("puts conversion failed"); // If it exceeds 64 chars, halt with an error
// Terminate the string with null, since we will be passing to C
s_with_null.push('\0')
.expect("puts overflow"); // If we exceed 64 chars, halt with an error
// Convert the null-terminated string to a pointer
let p = s_with_null.as_str().as_ptr();
// Call the C function
unsafe { // Flag this code as unsafe because we're calling a C function
puts(p)
}
// No semicolon `;` here, so the value returned by the C function will be passed to our caller
}
/// Print a formatted message to the serial console. Called by println! macro.
pub fn puts_format(args: fmt::Arguments<'_>) {
// Allocate a 64-byte buffer.
// TODO: Increase the buffer size if we're sure we won't overflow the stack
let mut buf = String::new();
// Format the message into the buffer
fmt::write(&mut buf, args)
.expect("puts_format overflow");
// Print the buffer
puts(&buf);
}
/// Limit Strings to 64 chars, similar to `char[64]` in C
pub type String = heapless::String::<64>;
extern "C" { // Import POSIX Functions. TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rusti2c/include/unistd.h
/// Open a file path
pub fn open(path: *const u8, oflag: i32, ...) -> i32;
/// Read from a file descriptor
pub fn read(fd: i32, buf: *mut u8, count: size_t) -> ssize_t;
/// Write to a file descriptor
pub fn write(fd: i32, buf: *const u8, count: size_t) -> ssize_t;
/// Close a file descriptor
pub fn close(fd: i32) -> i32;
/// Execute device commands
pub fn ioctl(fd: i32, request: i32, ...) -> i32; // On NuttX: request is i32, not u64 like Linux
/// Sleep for a number of seconds
pub fn sleep(secs: u32) -> u32;
/// Sleep for a number of microseconds
pub fn usleep(usec: u32) -> u32;
/// Exit the program
pub fn exit(status: u32) -> !;
}
// GPIO ioctl Commands. TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rust/include/nuttx/ioexpander/gpio.h
/// Set the value of an output GPIO
pub const GPIOC_WRITE: i32 = _GPIOBASE | 1; // _GPIOC(1)
/// Read the value of an input or output GPIO
pub const GPIOC_READ: i32 = _GPIOBASE | 2; // _GPIOC(2)
/// Return the GPIO pin type.
pub const GPIOC_PINTYPE: i32 = _GPIOBASE | 3; // _GPIOC(3)
/// Register to receive a signal whenever there an interrupt
/// is received on an input gpio pin. This feature, of course,
/// depends upon interrupt GPIO support from the platform.
pub const GPIOC_REGISTER: i32 = _GPIOBASE | 4; // _GPIOC(4)
/// Stop receiving signals for pin interrupts.
pub const GPIOC_UNREGISTER: i32 = _GPIOBASE | 5; // _GPIOC(5)
/// Set the GPIO pin type.
pub const GPIOC_SETPINTYPE: i32 = _GPIOBASE | 6; // _GPIOC(6)
// GPIO Constants. TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rust/include/fcntl.h
/// GPIO driver commands
pub const _GPIOBASE: i32 = 0x2300;
// #define _GPIOC(nr) _IOC(_GPIOBASE,nr)
// #define _IOC(type,nr) ((type)|(nr))
// I2C ioctl Commands. TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rusti2c/include/nuttx/i2c/i2c_master.h#L105-L129
/// Perform an I2C transfer
pub const I2CIOC_TRANSFER: i32 = _I2CBASE | 0x0001; // _I2CIOC(0x0001)
/// Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
pub const I2CIOC_RESET: i32 = _I2CBASE | 0x0002; // _I2CIOC(0x0002)
// #define _I2CIOC(nr) _IOC(_I2CBASE,nr)
// #define _IOC(type,nr) ((type)|(nr))
// I2C Constants. TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rusti2c/include/nuttx/i2c/i2c_master.h#L93-L96
/// Read data, from slave to master
pub const I2C_M_READ: u16 = 0x0001;
/// Ten bit address
pub const I2C_M_TEN: u16 = 0x0002;
/// Message should not end with a STOP
pub const I2C_M_NOSTOP: u16 = 0x0040;
/// Message should not begin with a START
pub const I2C_M_NOSTART: u16 = 0x0080;
/// I2C driver commands
pub const _I2CBASE: i32 = 0x2100;
/// I2C Message Struct: I2C transaction segment beginning with a START. A number of these can
/// be transferred together to form an arbitrary sequence of write/read
/// transfer to an I2C device.
/// TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rusti2c/include/nuttx/i2c/i2c_master.h#L208-L215
#[repr(C)]
pub struct i2c_msg_s {
/// I2C Frequency
pub frequency: u32,
/// I2C Address
pub addr: u16,
/// I2C Flags (I2C_M_*)
pub flags: u16,
/// Buffer to be transferred
pub buffer: *mut u8,
/// Length of the buffer in bytes
pub length: ssize_t,
}
/// I2C Transfer Struct: This structure is used to communicate with the I2C character driver in
/// order to perform IOCTL transfers.
/// TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rusti2c/include/nuttx/i2c/i2c_master.h#L231-L235
#[repr(C)]
pub struct i2c_transfer_s {
/// Array of I2C messages for the transfer
pub msgv: *const i2c_msg_s,
/// Number of messages in the array
pub msgc: size_t,
}
// Input / Output Constants. TODO: Import with bindgen from https://github.com/lupyuen/incubator-nuttx/blob/rust/include/fcntl.h
/// Open for read access (only)
pub const O_RDONLY: i32 = 1 << 0;
/// Read access is permitted (non-standard)
pub const O_RDOK: i32 = O_RDONLY;
/// Open for write access (only)
pub const O_WRONLY: i32 = 1 << 1;
/// Write access is permitted (non-standard)
pub const O_WROK: i32 = O_WRONLY;
/// Open for both read & write access
pub const O_RDWR: i32 = O_RDOK|O_WROK;
/// size_t for NuttX 32-bit. TODO: Support other architectures
#[allow(non_camel_case_types)]
pub type size_t = u32;
/// ssize_t for NuttX 32-bit. TODO: Support other architectures
#[allow(non_camel_case_types)]
pub type ssize_t = i32;