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;