Skip to content

Commit e6f16d4

Browse files
committed
add serial shell example
1 parent a8debb9 commit e6f16d4

File tree

3 files changed

+178
-1
lines changed

3 files changed

+178
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ st7735-lcd = { version = "0.7", optional = true }
2020
riscv-rt = "0.8.0"
2121
panic-halt = "0.2.0"
2222
embedded-graphics = "0.6"
23+
ushell = "0.3.3"
2324

2425
[features]
2526
lcd = ["st7735-lcd"]

examples/led_shell.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use panic_halt as _;
5+
6+
use core::fmt::Write;
7+
use gd32vf103xx_hal::{
8+
pac::USART0,
9+
serial::{self, Config, Parity, Rx, StopBits, Tx},
10+
};
11+
use longan_nano::{
12+
hal::{pac, prelude::*},
13+
led::{rgb, Led, BLUE, GREEN, RED},
14+
};
15+
use riscv_rt::entry;
16+
use ushell::{autocomplete::*, history::*, *};
17+
18+
const MAX_COMMAND_LEN: usize = 16;
19+
const HISTORY_SIZE: usize = 4;
20+
const COMMANDS: usize = 5;
21+
22+
const SHELL_PROMPT: &str = "#> ";
23+
const CR: &str = "\r\n";
24+
const HELP: &str = "\r\n\
25+
\x1b[31mL\x1b[32mE\x1b[34mD\x1b[33m Shell\x1b[0m\r\n\r\n\
26+
USAGE:\r\n\
27+
\tcommand [arg]\r\n\r\n\
28+
COMMANDS:\r\n\
29+
\ton <ch> Switch led channel on [r,g,b,a]\r\n\
30+
\toff <ch> Switch led channel off [r,g,b,a]\r\n\
31+
\tstatus Get leds status\r\n\
32+
\tclear Clear screen\r\n\
33+
\thelp Print this message\r\n
34+
";
35+
36+
struct Context {
37+
red: RED,
38+
green: GREEN,
39+
blue: BLUE,
40+
shell: UShell<
41+
ushell::Serial<u8, Tx<USART0>, Rx<USART0>>,
42+
StaticAutocomplete<{ COMMANDS }>,
43+
LRUHistory<{ MAX_COMMAND_LEN }, { HISTORY_SIZE }>,
44+
{ MAX_COMMAND_LEN },
45+
>,
46+
}
47+
48+
#[entry]
49+
fn main() -> ! {
50+
let dp = pac::Peripherals::take().unwrap();
51+
52+
// Configure clocks
53+
let mut rcu = dp
54+
.RCU
55+
.configure()
56+
.ext_hf_clock(8.mhz())
57+
.sysclk(108.mhz())
58+
.freeze();
59+
60+
let mut afio = dp.AFIO.constrain(&mut rcu);
61+
62+
let gpioa = dp.GPIOA.split(&mut rcu);
63+
let gpioc = dp.GPIOC.split(&mut rcu);
64+
65+
let tx = gpioa.pa9.into_alternate_push_pull();
66+
let rx = gpioa.pa10.into_floating_input();
67+
68+
let config = Config {
69+
baudrate: 115_200.bps(),
70+
parity: Parity::ParityNone,
71+
stopbits: StopBits::STOP1,
72+
};
73+
let uart = serial::Serial::new(dp.USART0, (tx, rx), config, &mut afio, &mut rcu);
74+
let (tx, rx) = uart.split();
75+
76+
let autocomplete = StaticAutocomplete(["clear", "help", "status", "off ", "on "]);
77+
let history = LRUHistory::default();
78+
let shell = UShell::new(ushell::Serial::from_parts(tx, rx), autocomplete, history);
79+
80+
let (mut red, mut green, mut blue) = rgb(gpioc.pc13, gpioa.pa1, gpioa.pa2);
81+
red.off();
82+
green.off();
83+
blue.off();
84+
85+
let mut ctx = Context {
86+
shell,
87+
red,
88+
green,
89+
blue,
90+
};
91+
92+
loop {
93+
poll_serial(&mut ctx);
94+
}
95+
}
96+
97+
fn poll_serial(ctx: &mut Context) {
98+
match ctx.shell.poll() {
99+
Ok(Some(Input::Command((cmd, args)))) => {
100+
match cmd {
101+
"help" => {
102+
ctx.shell.write_str(HELP).ok();
103+
}
104+
"clear" => {
105+
ctx.shell.clear().ok();
106+
}
107+
"status" => {
108+
let red = if ctx.red.is_on() { "On" } else { "Off" };
109+
let green = if ctx.green.is_on() { "On" } else { "Off" };
110+
let blue = if ctx.blue.is_on() { "On" } else { "Off" };
111+
write!(
112+
ctx.shell,
113+
"{0:}Red: {1:}{0:}Green: {2:}{0:}Blue: {3:}{0:}",
114+
CR, red, green, blue,
115+
)
116+
.ok();
117+
}
118+
"on" => {
119+
match args {
120+
"r" | "red" => ctx.red.on(),
121+
"g" | "green" => ctx.green.on(),
122+
"b" | "blue" => ctx.blue.on(),
123+
"a" | "all" => {
124+
ctx.red.on();
125+
ctx.green.on();
126+
ctx.blue.on();
127+
}
128+
_ => {
129+
write!(ctx.shell, "{0:}unsupported color channel", CR).ok();
130+
}
131+
}
132+
ctx.shell.write_str(CR).ok();
133+
}
134+
"off" => {
135+
match args {
136+
"r" | "red" => ctx.red.off(),
137+
"g" | "green" => ctx.green.off(),
138+
"b" | "blue" => ctx.blue.off(),
139+
"a" | "all" => {
140+
ctx.red.off();
141+
ctx.green.off();
142+
ctx.blue.off();
143+
}
144+
_ => {
145+
write!(ctx.shell, "{0:}unsupported color channel", CR).ok();
146+
}
147+
}
148+
ctx.shell.write_str(CR).ok();
149+
}
150+
"" => {
151+
ctx.shell.write_str(CR).ok();
152+
}
153+
_ => {
154+
write!(ctx.shell, "{0:}unsupported command{0:}", CR).ok();
155+
}
156+
}
157+
ctx.shell.write_str(SHELL_PROMPT).ok();
158+
}
159+
_ => {}
160+
}
161+
}

src/led.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! - Red = PC13
44
//! - Green = PA1
55
//! - Blue = PA2
6-
use embedded_hal::digital::v2::OutputPin;
6+
use embedded_hal::digital::v2::{OutputPin, StatefulOutputPin};
77
use gd32vf103xx_hal::gpio::gpioc::PC13;
88
use gd32vf103xx_hal::gpio::gpioa::{PA1, PA2};
99
use gd32vf103xx_hal::gpio::{Output, PushPull, Active};
@@ -66,6 +66,9 @@ pub trait Led {
6666

6767
/// Turns the LED on
6868
fn on(&mut self);
69+
70+
/// Checks the LED status
71+
fn is_on(&mut self) -> bool;
6972
}
7073

7174
impl Led for RED {
@@ -76,6 +79,10 @@ impl Led for RED {
7679
fn on(&mut self) {
7780
self.port.set_low().unwrap();
7881
}
82+
83+
fn is_on(&mut self) -> bool {
84+
self.port.is_set_low().unwrap()
85+
}
7986
}
8087

8188
impl Led for GREEN {
@@ -86,6 +93,10 @@ impl Led for GREEN {
8693
fn on(&mut self) {
8794
self.port.set_low().unwrap();
8895
}
96+
97+
fn is_on(&mut self) -> bool {
98+
self.port.is_set_low().unwrap()
99+
}
89100
}
90101

91102
impl Led for BLUE {
@@ -96,4 +107,8 @@ impl Led for BLUE {
96107
fn on(&mut self) {
97108
self.port.set_low().unwrap();
98109
}
110+
111+
fn is_on(&mut self) -> bool {
112+
self.port.is_set_low().unwrap()
113+
}
99114
}

0 commit comments

Comments
 (0)