|
| 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 | +} |
0 commit comments