Skip to content

Commit

Permalink
Use mdBook anchors (#24)
Browse files Browse the repository at this point in the history
* feat: Use anchors

* docs: Document anchor comment
  • Loading branch information
SergioGasquez authored Nov 14, 2023
1 parent 8a2607a commit c766e86
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fn deadly_recursion(data: [u8; 2048]) {
deadly_recursion([0u8; 2048]);
}

// ANCHOR: debug_assists
static DA: Mutex<RefCell<Option<DebugAssist>>> = Mutex::new(RefCell::new(None));

fn install_stack_guard(mut da: DebugAssist<'static>, safe_area_size: u32) {
Expand All @@ -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);
Expand All @@ -92,3 +98,4 @@ fn ASSIST_DEBUG() {
}
});
}
// ANCHOR_END: handler
11 changes: 11 additions & 0 deletions book/src/02_0_preparations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
4 changes: 2 additions & 2 deletions book/src/03_4_interrupt.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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].
Expand Down
89 changes: 8 additions & 81 deletions book/src/03_5_http_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<AccessPointInfo, 10>, 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.
Expand All @@ -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
Expand Down
47 changes: 6 additions & 41 deletions book/src/04_1_stack_overflow_protection.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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<RefCell<Option<DebugAssist>>> = 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)`.
Expand All @@ -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.
Expand All @@ -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}}
```
5 changes: 4 additions & 1 deletion intro/button-interrupt/examples/button-interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
18 changes: 17 additions & 1 deletion intro/http-client/examples/http-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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());

Expand Down Expand Up @@ -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 {
Expand All @@ -99,6 +110,7 @@ fn main() -> ! {
break;
}
}
// ANCHOR_END: ip

println!("Start busy loop on main");

Expand All @@ -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];
Expand All @@ -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
}
}

0 comments on commit c766e86

Please sign in to comment.