From c766e8690e37447983eb3b0daf916f9837dd86d7 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Tue, 14 Nov 2023 13:25:44 +0100 Subject: [PATCH] Use mdBook anchors (#24) * feat: Use anchors * docs: Document anchor comment --- .../examples/stack_overflow_protection.rs | 7 ++ book/src/02_0_preparations.md | 11 +++ book/src/03_4_interrupt.md | 4 +- book/src/03_5_http_client.md | 89 ++----------------- book/src/04_1_stack_overflow_protection.md | 47 ++-------- .../examples/button-interrupt.rs | 5 +- intro/http-client/examples/http-client.rs | 18 +++- 7 files changed, 55 insertions(+), 126 deletions(-) diff --git a/advanced/stack_overflow_detection/examples/stack_overflow_protection.rs b/advanced/stack_overflow_detection/examples/stack_overflow_protection.rs index 2921d33..f28ebd5 100644 --- a/advanced/stack_overflow_detection/examples/stack_overflow_protection.rs +++ b/advanced/stack_overflow_detection/examples/stack_overflow_protection.rs @@ -53,6 +53,7 @@ fn deadly_recursion(data: [u8; 2048]) { deadly_recursion([0u8; 2048]); } +// ANCHOR: debug_assists static DA: Mutex>> = Mutex::new(RefCell::new(None)); fn install_stack_guard(mut da: DebugAssist<'static>, safe_area_size: u32) { @@ -75,9 +76,14 @@ fn install_stack_guard(mut da: DebugAssist<'static>, safe_area_size: u32) { ) .unwrap(); } +// ANCHOR_END: debug_assists +// ANCHOR: interrupt +// ANCHOR: handler #[interrupt] fn ASSIST_DEBUG() { + // ANCHOR_END: interrupt + critical_section::with(|cs| { println!("\n\nPossible Stack Overflow Detected"); let mut da = DA.borrow_ref_mut(cs); @@ -92,3 +98,4 @@ fn ASSIST_DEBUG() { } }); } +// ANCHOR_END: handler diff --git a/book/src/02_0_preparations.md b/book/src/02_0_preparations.md index 39e5bf7..7339935 100644 --- a/book/src/02_0_preparations.md +++ b/book/src/02_0_preparations.md @@ -12,6 +12,17 @@ We use Icons to mark different kinds of information in the book: > Example note: Notes like this one contain helpful information +## Code annotations + +In some Rust files, you can find some anchor comments: +```rust,ignore +// ANCHOR: test +let foo = 1; +... +// ANCHOR_END: test +``` +Anchor comments can be ingored, they are only used to introduce those parts of code in this book. See [`mdBook` documentation](https://rust-lang.github.io/mdBook/format/mdbook.html#including-portions-of-a-file) + ## Required Hardware - [Rust ESP Board](https://github.com/esp-rs/esp-rust-board): available on Mouser, Aliexpress. [Full list of vendors](https://github.com/esp-rs/esp-rust-board#where-to-buy). diff --git a/book/src/03_4_interrupt.md b/book/src/03_4_interrupt.md index df6670b..e1368e6 100644 --- a/book/src/03_4_interrupt.md +++ b/book/src/03_4_interrupt.md @@ -36,7 +36,7 @@ We need the `Mutex` to make access to the button safe. ✅ Let's add a [`critical-section`], using the `with()` method and enable an interrupt: ```rust,ignore -critical_section::with(|cs| BUTTON.borrow_ref_mut(cs).replace(button)); +{{#include ../../intro/button-interrupt/examples/button-interrupt.rs:critical_section}} ``` In this line we move our button into the `static BUTTON` for the interrupt handler to get hold of it. @@ -46,7 +46,7 @@ The code running inside the `critical_section::with` closure runs within a criti ✅ Enable the interrupt: ```rust,ignore -interrupt::enable(peripherals::Interrupt::GPIO, interrupt::Priority::Priority3).unwrap(); +{{#include ../../intro/button-interrupt/examples/button-interrupt.rs:interrupt}} ``` First parameter here is the kind of interrupt we want. There are several [possible interrupts]. diff --git a/book/src/03_5_http_client.md b/book/src/03_5_http_client.md index 811decd..7530d03 100644 --- a/book/src/03_5_http_client.md +++ b/book/src/03_5_http_client.md @@ -46,82 +46,29 @@ cargo run --release --example http-client ✅ Create a [`timer`][timer] and initialize the Wi-Fi ```rust,ignore -let timer = SystemTimer::new(peripherals.SYSTIMER).alarm0; -let init = initialize( - EspWifiInitFor::Wifi, - timer, - Rng::new(peripherals.RNG), - system.radio_clock_control, - &clocks, -) -.unwrap(); +{{#include ../../intro/http-client/examples/http-client.rs:wifi_init}} ``` ✅ Configure Wi-Fi using Station Mode ```rust,ignore -let (wifi, _) = peripherals.RADIO.split(); -let mut socket_set_entries: [SocketStorage; 3] = Default::default(); -let (iface, device, mut controller, sockets) = - create_network_interface(&init, wifi, WifiMode::Sta, &mut socket_set_entries); -let wifi_stack = WifiStack::new(iface, device, sockets, current_millis); +{{#include ../../intro/http-client/examples/http-client.rs:wifi_config}} ``` ✅ Create a Client with your Wi-Fi credentials and default configuration. Look for a suitable constructor in the documentation. ```rust,ignore -let client_config = Configuration::Client( +{{#include ../../intro/http-client/examples/http-client.rs:client_config_start}} .... -); -let res = controller.set_configuration(&client_config); -println!("Wi-Fi set_configuration returned {:?}", res); +{{#include ../../intro/http-client/examples/http-client.rs:client_config_end}} ``` ✅ Start the Wi-Fi controller, scan the available networks, and try to connect to the one we set. ```rust,ignore -controller.start().unwrap(); -println!("Is wifi started: {:?}", controller.is_started()); - -println!("Start Wifi Scan"); -let res: Result<(heapless::Vec, usize), WifiError> = controller.scan_n(); -if let Ok((res, _count)) = res { - for ap in res { - println!("{:?}", ap); - } -} - -println!("{:?}", controller.get_capabilities()); -println!("Wi-Fi connect: {:?}", controller.connect()); - -// Wait to get connected -println!("Wait to get connected"); -loop { - let res = controller.is_connected(); - match res { - Ok(connected) => { - if connected { - break; - } - } - Err(err) => { - println!("{:?}", err); - loop {} - } - } -} -println!("{:?}", controller.is_connected()); +{{#include ../../intro/http-client/examples/http-client.rs:wifi_connect}} ``` ✅ Then we obtain the assigned IP ```rust,ignore -// Wait for getting an ip address -println!("Wait to get an ip address"); -loop { - wifi_stack.work(); - - if wifi_stack.is_iface_up() { - println!("got ip {:?}", wifi_stack.get_ip_info()); - break; - } -} +{{#include ../../intro/http-client/examples/http-client.rs:ip}} ``` If the connection succeeds, we proceed with the last part, making the HTTP request. @@ -136,32 +83,12 @@ To make an HTTP request, we first need to open a socket, and write to it the GET ✅ Then we wait for the response and read it out. ```rust,ignore -let wait_end = current_millis() + 20 * 1000; -loop { - let mut buffer = [0u8; 512]; - if let Ok(len) = socket.read(&mut buffer) { - let to_print = unsafe { core::str::from_utf8_unchecked(&buffer[..len]) }; - print!("{}", to_print); - } else { - break; - } - - if current_millis() > wait_end { - println!("Timeout"); - break; - } -} -println!(); +{{#include ../../intro/http-client/examples/http-client.rs:reponse}} ``` ✅ Finally, we will close the socket and wait ```rust,ignore -socket.disconnect(); - -let wait_end = current_millis() + 5 * 1000; -while current_millis() < wait_end { - socket.work(); -} +{{#include ../../intro/http-client/examples/http-client.rs:socket_close}} ``` [timer]: https://docs.rs/esp32c3-hal/latest/esp32c3_hal/systimer/index.html diff --git a/book/src/04_1_stack_overflow_protection.md b/book/src/04_1_stack_overflow_protection.md index 7743821..47ba6da 100644 --- a/book/src/04_1_stack_overflow_protection.md +++ b/book/src/04_1_stack_overflow_protection.md @@ -17,7 +17,7 @@ Some of our chips (including ESP32-C3) include the debug-assist peripheral. This peripheral can monitor the stack-pointer and detect read and/or write access to specified memory areas. -We could just use the stack-pointer monitoring which will work well as long as we don't use `esp-wifi`. +We could just use the stack-pointer monitoring which will work well as long as we don't use `esp-wifi`. The reason we cannot use that with `esp-wifi` is that it runs multiple tasks by quickly switching between them which includes switching stacks. In that case the stack bounds check will trigger as soon as we switch the running task for the first time. @@ -67,28 +67,10 @@ It should move the `DebugAssist` into a static variable. The resulting function should look like this ```rust,ignore -static DA: Mutex>> = Mutex::new(RefCell::new(None)); - -fn install_stack_guard(mut da: DebugAssist<'static>, safe_area_size: u32) { - extern "C" { - static mut _stack_end: u32; - static mut _stack_start: u32; - } - let stack_low = unsafe { (&mut _stack_end as *mut _ as *mut u32) as u32 }; - let stack_high = unsafe { (&mut _stack_start as *mut _ as *mut u32) as u32 }; - println!("Safe stack {} bytes", stack_high - stack_low - safe_area_size); - da.enable_region0_monitor(stack_low, stack_low + safe_area_size, true, true); - - critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da)); - interrupt::enable( - peripherals::Interrupt::ASSIST_DEBUG, - interrupt::Priority::Priority1, - ) - .unwrap(); -} +{{#include ../../advanced/stack_overflow_detection/examples/stack_overflow_protection.rs:debug_assists}} ``` -There is quite a lot going on here but most of this is setting up the interrupt. +There is quite a lot going on here but most of this is setting up the interrupt. You should recognize most of this from the interrupt exercise in the previous chapter. The most interesting part is probably `da.enable_region0_monitor(stack_low, stack_low + safe_area_size, true, true)`. @@ -102,10 +84,8 @@ As you probably remember from the introduction to interrupts we can define the i The name of the function needs to match the name of the interrupt. ```rust,ignore -#[interrupt] -fn ASSIST_DEBUG() { - ... -} +{{#include ../../advanced/stack_overflow_detection/examples/stack_overflow_protection.rs:interrupt}} +... ``` Next, we need to get access to the debug assist peripheral driver which we stored in the static variable. @@ -119,20 +99,5 @@ It is unfortunately not possible to generate a stack trace here since the stack The whole function should look like this ```rust,ignore -#[interrupt] -fn ASSIST_DEBUG() { - critical_section::with(|cs| { - println!("\n\nPossible Stack Overflow Detected"); - let mut da = DA.borrow_ref_mut(cs); - let da = da.as_mut().unwrap(); - - if da.is_region0_monitor_interrupt_set() { - let pc = da.get_region_monitor_pc(); - println!("PC = 0x{:x}", pc); - da.clear_region0_monitor_interrupt(); - da.disable_region0_monitor(); - loop {} - } - }); -} +{{#include ../../advanced/stack_overflow_detection/examples/stack_overflow_protection.rs:handler}} ``` diff --git a/intro/button-interrupt/examples/button-interrupt.rs b/intro/button-interrupt/examples/button-interrupt.rs index 1097321..2769bc3 100644 --- a/intro/button-interrupt/examples/button-interrupt.rs +++ b/intro/button-interrupt/examples/button-interrupt.rs @@ -32,9 +32,12 @@ fn main() -> ! { let mut button = io.pins.gpio9.into_pull_down_input(); button.listen(Event::FallingEdge); + // ANCHOR: critical_section critical_section::with(|cs| BUTTON.borrow_ref_mut(cs).replace(button)); - + // ANCHOR_END: critical_section + // ANCHOR: interrupt interrupt::enable(peripherals::Interrupt::GPIO, interrupt::Priority::Priority3).unwrap(); + // ANCHOR_END: interrupt unsafe { riscv::interrupt::enable(); diff --git a/intro/http-client/examples/http-client.rs b/intro/http-client/examples/http-client.rs index 3333042..957323f 100644 --- a/intro/http-client/examples/http-client.rs +++ b/intro/http-client/examples/http-client.rs @@ -33,6 +33,7 @@ fn main() -> ! { let clocks = ClockControl::max(system.clock_control).freeze(); // Initialize the timers used for Wifi + // ANCHOR: wifi_init let timer = SystemTimer::new(peripherals.SYSTIMER).alarm0; let init = initialize( EspWifiInitFor::Wifi, @@ -42,21 +43,29 @@ fn main() -> ! { &clocks, ) .unwrap(); + // ANCHOR_END: wifi_init // Configure Wifi + // ANCHOR: wifi_config let (wifi, _) = peripherals.RADIO.split(); let mut socket_set_entries: [SocketStorage; 3] = Default::default(); let (iface, device, mut controller, sockets) = create_network_interface(&init, wifi, WifiMode::Sta, &mut socket_set_entries).unwrap(); let wifi_stack = WifiStack::new(iface, device, sockets, current_millis); + // ANCHOR_END: wifi_config + // ANCHOR: client_config_start let client_config = Configuration::Client(ClientConfiguration { + // ANCHOR_END: client_config_start ssid: SSID.into(), password: PASSWORD.into(), - ..Default::default() + ..Default::default() // ANCHOR: client_config_end }); + let res = controller.set_configuration(&client_config); println!("Wi-Fi set_configuration returned {:?}", res); + // ANCHOR_END: client_config_end + // ANCHOR: wifi_connect controller.start().unwrap(); println!("Is wifi started: {:?}", controller.is_started()); @@ -88,7 +97,9 @@ fn main() -> ! { } } println!("{:?}", controller.is_connected()); + // ANCHOR_END: wifi_connect + // ANCHOR: ip // Wait for getting an ip address println!("Wait to get an ip address"); loop { @@ -99,6 +110,7 @@ fn main() -> ! { break; } } + // ANCHOR_END: ip println!("Start busy loop on main"); @@ -119,6 +131,7 @@ fn main() -> ! { .unwrap(); socket.flush().unwrap(); + // ANCHOR: reponse let wait_end = current_millis() + 20 * 1000; loop { let mut buffer = [0u8; 512]; @@ -135,12 +148,15 @@ fn main() -> ! { } } println!(); + // ANCHOR_END: reponse + // ANCHOR: socket_close socket.disconnect(); let wait_end = current_millis() + 5 * 1000; while current_millis() < wait_end { socket.work(); } + // ANCHOR_END: socket_close } }