nuttx_embedded_hal/
lib.rs

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