Skip to content

Commit 437c903

Browse files
rushabhvglupyuen
authored andcommitted
examples/leds_rust: Add Rust App for blinking the LED
- This PR adds `examples/leds_rust` to call NuttX POSIX APIs like `open()` and `ioctl()`, so that it blinks an LED - The `leds_rust` app is also used for testing the GPIO and LED Drivers for Ox64 BL808 SBC and QEMU RISC-V Emulator in Google Summer of Code - `leds_rust` be executed locally on Linux / macOS / Windows, by commenting out the first 2 lines of code - The code is based on `examples/leds` in C, and `examples/hello_rust` in Rust Co-Authored-By: Lup Yuen Lee <9960133+lupyuen@users.noreply.github.com>
1 parent b4999fa commit 437c903

File tree

5 files changed

+336
-0
lines changed

5 files changed

+336
-0
lines changed

examples/leds_rust/Kconfig

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#
2+
# For a description of the syntax of this configuration file,
3+
# see the file kconfig-language.txt in the NuttX tools repository.
4+
#
5+
6+
config EXAMPLES_LEDS_RUST
7+
tristate "\"LEDs Rust\" example"
8+
default n
9+
depends on USERLED
10+
---help---
11+
Enable the \"LEDs Rust\" example
12+
13+
if EXAMPLES_LEDS_RUST
14+
15+
config EXAMPLES_LEDS_RUST_PROGNAME
16+
string "Program name"
17+
default "leds_rust"
18+
---help---
19+
This is the name of the program that will be used when the
20+
program is installed.
21+
22+
config EXAMPLES_LEDS_RUST_PRIORITY
23+
int "LEDs Rust task priority"
24+
default 100
25+
26+
config EXAMPLES_LEDS_RUST_STACKSIZE
27+
int "LEDs Rust stack size"
28+
default DEFAULT_TASK_STACKSIZE
29+
30+
endif

examples/leds_rust/Make.defs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
############################################################################
2+
# apps/examples/leds_rust/Make.defs
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership. The
7+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance with the
9+
# License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
############################################################################
20+
21+
ifneq ($(CONFIG_EXAMPLES_LEDS_RUST),)
22+
CONFIGURED_APPS += $(APPDIR)/examples/leds_rust
23+
endif

examples/leds_rust/Makefile

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
############################################################################
2+
# apps/examples/leds_rust/Makefile
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership. The
7+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance with the
9+
# License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
############################################################################
20+
21+
include $(APPDIR)/Make.defs
22+
23+
# Hello, Rust! built-in application info
24+
25+
PROGNAME = $(CONFIG_EXAMPLES_LEDS_RUST_PROGNAME)
26+
PRIORITY = $(CONFIG_EXAMPLES_LEDS_RUST_PRIORITY)
27+
STACKSIZE = $(CONFIG_EXAMPLES_LEDS_RUST_STACKSIZE)
28+
MODULE = $(CONFIG_EXAMPLES_LEDS_RUST)
29+
30+
# Hello, Rust! Example
31+
32+
MAINSRC = leds_rust_main.rs
33+
34+
RUSTFLAGS += -C panic=abort -O
35+
36+
include $(APPDIR)/Application.mk

examples/leds_rust/leds_rust_main.rs

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/****************************************************************************
2+
* apps/examples/leds_rust/leds_rust_main.rs
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one or more
5+
* contributor license agreements. See the NOTICE file distributed with
6+
* this work for additional information regarding copyright ownership. The
7+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance with the
9+
* License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
* License for the specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
****************************************************************************/
20+
21+
/****************************************************************************
22+
* Attributes
23+
****************************************************************************/
24+
25+
/* Comment out these lines for testing with Rust Standard Library */
26+
27+
#![no_main]
28+
#![no_std]
29+
30+
/****************************************************************************
31+
* Uses
32+
****************************************************************************/
33+
34+
#[cfg(target_os = "none")]
35+
use core::{
36+
panic::PanicInfo,
37+
result::Result::{self, Err, Ok},
38+
};
39+
40+
/****************************************************************************
41+
* Modules
42+
****************************************************************************/
43+
44+
mod nuttx;
45+
46+
/****************************************************************************
47+
* Private Functions
48+
****************************************************************************/
49+
50+
/****************************************************************************
51+
* Panic Handler (needed for [no_std] compilation)
52+
****************************************************************************/
53+
54+
#[cfg(target_os = "none")] /* For NuttX */
55+
#[panic_handler]
56+
fn panic(_panic: &PanicInfo<'_>) -> ! {
57+
loop {}
58+
}
59+
60+
/****************************************************************************
61+
* rust_main
62+
****************************************************************************/
63+
64+
fn rust_main(_argc: i32, _argv: *const *const u8) -> Result<i32, i32> {
65+
/* "Hello, Rust!!" using puts() from libc */
66+
67+
nuttx::safe_puts("Hello, Rust!!");
68+
69+
/* Blink LED 1 using ioctl() from NuttX */
70+
71+
nuttx::safe_puts("Opening /dev/userleds");
72+
let fd = nuttx::safe_open("/dev/userleds", nuttx::O_WRONLY)?;
73+
nuttx::safe_puts("Set LED 1 to 1");
74+
75+
nuttx::safe_ioctl(fd, nuttx::ULEDIOC_SETALL, 1)?;
76+
nuttx::safe_puts("Sleeping...");
77+
unsafe {
78+
nuttx::usleep(500_000);
79+
}
80+
81+
nuttx::safe_puts("Set LED 1 to 0");
82+
nuttx::safe_ioctl(fd, nuttx::ULEDIOC_SETALL, 0)?;
83+
unsafe {
84+
nuttx::close(fd);
85+
}
86+
87+
/* Exit with status 0 */
88+
89+
Ok(0)
90+
}
91+
92+
/****************************************************************************
93+
* Public Functions
94+
****************************************************************************/
95+
96+
/****************************************************************************
97+
* leds_rust_main
98+
****************************************************************************/
99+
100+
#[no_mangle]
101+
pub extern "C" fn leds_rust_main(_argc: i32, _argv: *const *const u8) -> i32 {
102+
/* Call the program logic in Rust Main */
103+
104+
let res = rust_main(0, core::ptr::null());
105+
106+
/* If Rust Main returns an error, print it */
107+
108+
if let Err(e) = res {
109+
unsafe {
110+
nuttx::printf(
111+
b"ERROR: rust_main() failed with error %d\n\0" as *const u8,
112+
e,
113+
);
114+
}
115+
e
116+
} else {
117+
0
118+
}
119+
}
120+
121+
/****************************************************************************
122+
* main
123+
****************************************************************************/
124+
125+
#[cfg(not(target_os = "none"))] /* For Testing Locally */
126+
fn main() {
127+
leds_rust_main(0, core::ptr::null());
128+
}

examples/leds_rust/nuttx.rs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/****************************************************************************
2+
* apps/examples/leds_rust/nuttx.rs
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one or more
5+
* contributor license agreements. See the NOTICE file distributed with
6+
* this work for additional information regarding copyright ownership. The
7+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance with the
9+
* License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
* License for the specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
****************************************************************************/
20+
21+
/* NuttX Definitions for Rust Apps */
22+
23+
/****************************************************************************
24+
* Uses
25+
****************************************************************************/
26+
27+
use core::result::Result::{self, Err, Ok};
28+
29+
/****************************************************************************
30+
* Externs
31+
****************************************************************************/
32+
33+
extern "C" {
34+
pub fn printf(format: *const u8, ...) -> i32;
35+
pub fn open(path: *const u8, oflag: i32, ...) -> i32;
36+
pub fn close(fd: i32) -> i32;
37+
pub fn ioctl(fd: i32, request: i32, ...) -> i32;
38+
pub fn usleep(usec: u32) -> u32;
39+
pub fn puts(s: *const u8) -> i32;
40+
}
41+
42+
/****************************************************************************
43+
* Public Constants
44+
****************************************************************************/
45+
46+
pub const ENAMETOOLONG: i32 = 36;
47+
pub const O_WRONLY: i32 = 1 << 1;
48+
pub const PATH_MAX: usize = 256;
49+
pub const PUTS_MAX: usize = 256;
50+
pub const ULEDIOC_SETALL: i32 = 0x1d03;
51+
52+
/****************************************************************************
53+
* Private Functions
54+
****************************************************************************/
55+
56+
/* Copy the Rust Str to the Byte Buffer and terminate with null */
57+
58+
fn copy_to_buffer(s: &str, buffer: &mut [u8]) -> Result<(), ()> {
59+
let byte_str = s.as_bytes();
60+
let len = byte_str.len();
61+
if len >= buffer.len() {
62+
Err(())
63+
} else {
64+
buffer[..len].copy_from_slice(&byte_str[..len]);
65+
buffer[len] = 0;
66+
Ok(())
67+
}
68+
}
69+
70+
/****************************************************************************
71+
* Public Functions
72+
****************************************************************************/
73+
74+
/* Safe Version of open() */
75+
76+
pub fn safe_open(path: &str, oflag: i32) -> Result<i32, i32> {
77+
let mut buffer = [0u8; PATH_MAX];
78+
let res = copy_to_buffer(path, &mut buffer);
79+
if res.is_err() {
80+
unsafe {
81+
puts(b"ERROR: safe_open() path size exceeds PATH_MAX\0" as *const u8);
82+
}
83+
return Err(-ENAMETOOLONG);
84+
}
85+
86+
let fd = unsafe { open(buffer.as_ptr(), oflag) };
87+
if fd < 0 {
88+
Err(fd)
89+
} else {
90+
Ok(fd)
91+
}
92+
}
93+
94+
/* Safe Version of ioctl() */
95+
96+
pub fn safe_ioctl(fd: i32, request: i32, arg: i32) -> Result<i32, i32> {
97+
let ret = unsafe { ioctl(fd, request, arg) };
98+
if ret < 0 {
99+
Err(ret)
100+
} else {
101+
Ok(ret)
102+
}
103+
}
104+
105+
/* Safe Version of puts() */
106+
107+
pub fn safe_puts(s: &str) {
108+
let mut buffer = [0u8; PUTS_MAX];
109+
let res = copy_to_buffer(s, &mut buffer);
110+
if res.is_err() {
111+
unsafe {
112+
puts(b"ERROR: safe_puts() string size exceeds PUTS_MAX\0" as *const u8);
113+
}
114+
} else {
115+
unsafe {
116+
puts(buffer.as_ptr());
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)