Skip to content

Commit f4a42b0

Browse files
authored
Merge pull request #45 from Jim-Hodapp-Coaching/support_dns
Support DNS
2 parents 4c5bd70 + 19135b2 commit f4a42b0

File tree

8 files changed

+365
-27
lines changed

8 files changed

+365
-27
lines changed

cross/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
members = [
33
"get_fw_version",
44
"join",
5+
"dns"
56
]
67

78
[profile.dev]

cross/dns/Cargo.toml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[package]
2+
authors = [
3+
"Jim Hodapp",
4+
"Caleb Bourg",
5+
"Glyn Matthews"
6+
]
7+
edition = "2021"
8+
name = "dns"
9+
version = "0.1.0"
10+
description = "Example target application that demonstrates DNS functionality with the Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards."
11+
12+
# makes `cargo check --all-targets` work
13+
[[bin]]
14+
name = "dns"
15+
bench = false
16+
doctest = false
17+
test = false
18+
19+
[dependencies]
20+
defmt = "0.3.0"
21+
defmt-rtt = "0.3.0"
22+
cortex-m = "0.7"
23+
cortex-m-rt = "0.7"
24+
embedded-hal = { version = "0.2", features=["unproven"] }
25+
esp32-wroom-rp = { path = "../../esp32-wroom-rp" }
26+
panic-probe = { version = "0.3.0", features = ["print-rtt"] }
27+
28+
rp2040-hal = { version = "0.6", features=["rt", "eh1_0_alpha"] }
29+
rp2040-boot2 = { version = "0.2" }
30+
fugit = "0.3"
31+
32+
[features]
33+
default = ['defmt-default']
34+
# these features are required by defmt
35+
defmt-default = []
36+
defmt-trace = []
37+
defmt-debug = []
38+
defmt-info = []
39+
defmt-warn = []
40+
defmt-error = []

cross/dns/src/main.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//! # ESP32-WROOM-RP Pico Wireless Example
2+
//!
3+
//! This application demonstrates how to use the ESP32-WROOM-RP crate to perform
4+
//! a DNS hostname lookup after setting what DNS server to use.
5+
//!
6+
//! See the `Cargo.toml` file for Copyright and license details.
7+
8+
#![no_std]
9+
#![no_main]
10+
11+
extern crate esp32_wroom_rp;
12+
13+
include!("secrets/secrets.rs");
14+
15+
// The macro for our start-up function
16+
use cortex_m_rt::entry;
17+
18+
// Needed for debug output symbols to be linked in binary image
19+
use defmt_rtt as _;
20+
21+
use panic_probe as _;
22+
23+
// Alias for our HAL crate
24+
use rp2040_hal as hal;
25+
26+
use embedded_hal::spi::MODE_0;
27+
use fugit::RateExtU32;
28+
use hal::clocks::Clock;
29+
use hal::pac;
30+
31+
use esp32_wroom_rp::network::IpAddress;
32+
33+
/// The linker will place this boot block at the start of our program image. We
34+
/// need this to help the ROM bootloader get our code up and running.
35+
#[link_section = ".boot2"]
36+
#[used]
37+
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
38+
39+
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
40+
/// if your board has a different frequency
41+
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
42+
43+
/// Entry point to our bare-metal application.
44+
///
45+
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
46+
/// as soon as all global variables are initialized.
47+
#[entry]
48+
fn main() -> ! {
49+
// Grab our singleton objects
50+
let mut pac = pac::Peripherals::take().unwrap();
51+
let core = pac::CorePeripherals::take().unwrap();
52+
53+
// Set up the watchdog driver - needed by the clock setup code
54+
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
55+
56+
// Configure the clocks
57+
let clocks = hal::clocks::init_clocks_and_plls(
58+
XTAL_FREQ_HZ,
59+
pac.XOSC,
60+
pac.CLOCKS,
61+
pac.PLL_SYS,
62+
pac.PLL_USB,
63+
&mut pac.RESETS,
64+
&mut watchdog,
65+
)
66+
.ok()
67+
.unwrap();
68+
69+
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
70+
71+
// The single-cycle I/O block controls our GPIO pins
72+
let sio = hal::Sio::new(pac.SIO);
73+
74+
// Set the pins to their default state
75+
let pins = hal::gpio::Pins::new(
76+
pac.IO_BANK0,
77+
pac.PADS_BANK0,
78+
sio.gpio_bank0,
79+
&mut pac.RESETS,
80+
);
81+
82+
defmt::info!("ESP32-WROOM-RP DNS resolve example");
83+
84+
// These are implicitly used by the spi driver if they are in the correct mode
85+
let _spi_miso = pins.gpio16.into_mode::<hal::gpio::FunctionSpi>();
86+
let _spi_sclk = pins.gpio18.into_mode::<hal::gpio::FunctionSpi>();
87+
let _spi_mosi = pins.gpio19.into_mode::<hal::gpio::FunctionSpi>();
88+
89+
let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);
90+
91+
// Exchange the uninitialized SPI driver for an initialized one
92+
let mut spi = spi.init(
93+
&mut pac.RESETS,
94+
clocks.peripheral_clock.freq(),
95+
8.MHz(),
96+
&MODE_0,
97+
);
98+
99+
let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins {
100+
// CS on pin x (GPIO7)
101+
cs: pins.gpio7.into_mode::<hal::gpio::PushPullOutput>(),
102+
// GPIO0 on pin x (GPIO2)
103+
gpio0: pins.gpio2.into_mode::<hal::gpio::PushPullOutput>(),
104+
// RESETn on pin x (GPIO11)
105+
resetn: pins.gpio11.into_mode::<hal::gpio::PushPullOutput>(),
106+
// ACK on pin x (GPIO10)
107+
ack: pins.gpio10.into_mode::<hal::gpio::FloatingInput>(),
108+
};
109+
110+
let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap();
111+
112+
let result = wifi.join(SSID, PASSPHRASE);
113+
defmt::info!("Join Result: {:?}", result);
114+
115+
defmt::info!("Entering main loop");
116+
117+
loop {
118+
match wifi.get_connection_status() {
119+
Ok(byte) => {
120+
defmt::info!("Get Connection Result: {:?}", byte);
121+
let sleep: u32 = 1500;
122+
delay.delay_ms(sleep);
123+
124+
if byte == 3 {
125+
defmt::info!("Connected to Network: {:?}", SSID);
126+
127+
// The IPAddresses of two DNS servers to resolve hostnames with.
128+
// Note that failover from ip1 to ip2 is fully functional.
129+
let ip1: IpAddress = [9, 9, 9, 9];
130+
let ip2: IpAddress = [8, 8, 8, 8];
131+
let dns_result = wifi.set_dns(ip1, Some(ip2));
132+
133+
defmt::info!("set_dns result: {:?}", dns_result);
134+
135+
let hostname = "github.com";
136+
defmt::info!("Doing a DNS resolve for {}", hostname);
137+
138+
match wifi.resolve(hostname) {
139+
Ok(ip) => {
140+
defmt::info!("Server IP: {:?}", ip);
141+
}
142+
Err(e) => {
143+
defmt::error!("Failed to resolve hostname {}", hostname);
144+
defmt::error!("Err: {}", e);
145+
}
146+
}
147+
148+
wifi.leave().ok().unwrap();
149+
} else if byte == 6 {
150+
defmt::info!("Disconnected from Network: {:?}", SSID);
151+
}
152+
}
153+
Err(e) => {
154+
defmt::info!("Failed to Get Connection Result: {:?}", e);
155+
}
156+
}
157+
}
158+
}

cross/dns/src/secrets/secrets.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//
2+
// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across
3+
// all example applications
4+
//
5+
6+
const SSID: &str = "ssid";
7+
const PASSPHRASE: &str = "passphrase";

esp32-wroom-rp/src/lib.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,14 @@ pub mod gpio;
8888
/// Fundamental interface for controlling a connected ESP32-WROOM NINA firmware-based Wifi board.
8989
pub mod wifi;
9090

91+
/// Responsible for interactions over a WiFi network and also contains related types.
92+
pub mod network;
93+
/// Responsible for interactions with NINA firmware over a data bus.
9194
pub mod protocol;
95+
9296
mod spi;
9397

98+
use network::{IpAddress, NetworkError};
9499
use protocol::{ProtocolError, ProtocolInterface};
95100

96101
use defmt::{write, Format, Formatter};
@@ -105,6 +110,9 @@ pub enum Error {
105110
Bus,
106111
/// Protocol error in communicating with the ESP32 WiFi target
107112
Protocol(ProtocolError),
113+
114+
/// Network related error
115+
Network(NetworkError),
108116
}
109117

110118
impl Format for Error {
@@ -116,6 +124,7 @@ impl Format for Error {
116124
"Communication protocol error with ESP32 WiFi target: {}",
117125
e
118126
),
127+
Error::Network(e) => write!(fmt, "Network error: {}", e),
119128
}
120129
}
121130
}
@@ -126,6 +135,12 @@ impl From<protocol::ProtocolError> for Error {
126135
}
127136
}
128137

138+
impl From<network::NetworkError> for Error {
139+
fn from(err: network::NetworkError) -> Self {
140+
Error::Network(err)
141+
}
142+
}
143+
129144
/// A structured representation of a connected NINA firmware device's version number (e.g. 1.7.4).
130145
#[derive(Debug, Default, Eq, PartialEq)]
131146
pub struct FirmwareVersion {
@@ -184,19 +199,27 @@ where
184199
}
185200

186201
fn firmware_version(&mut self) -> Result<FirmwareVersion, Error> {
187-
Ok(self.protocol_handler.get_fw_version()?)
202+
self.protocol_handler.get_fw_version()
188203
}
189204

190205
fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> {
191-
Ok(self.protocol_handler.set_passphrase(ssid, passphrase)?)
206+
self.protocol_handler.set_passphrase(ssid, passphrase)
192207
}
193208

194209
fn leave(&mut self) -> Result<(), Error> {
195-
Ok(self.protocol_handler.disconnect()?)
210+
self.protocol_handler.disconnect()
196211
}
197212

198213
fn get_connection_status(&mut self) -> Result<u8, Error> {
199-
Ok(self.protocol_handler.get_conn_status()?)
214+
self.protocol_handler.get_conn_status()
215+
}
216+
217+
fn set_dns(&mut self, dns1: IpAddress, dns2: Option<IpAddress>) -> Result<(), Error> {
218+
self.protocol_handler.set_dns_config(dns1, dns2)
219+
}
220+
221+
fn resolve(&mut self, hostname: &str) -> Result<IpAddress, Error> {
222+
self.protocol_handler.resolve(hostname)
200223
}
201224
}
202225

esp32-wroom-rp/src/network.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use defmt::{write, Format, Formatter};
2+
3+
/// A four byte array type alias representing an IP address.
4+
pub type IpAddress = [u8; 4];
5+
6+
/// Errors that occur due to issues involving communication over
7+
/// WiFi network.
8+
#[derive(PartialEq, Eq, Debug)]
9+
pub enum NetworkError {
10+
/// Failed to resolve a hostname for the provided IP address.
11+
DnsResolveFailed,
12+
}
13+
14+
impl Format for NetworkError {
15+
fn format(&self, fmt: Formatter) {
16+
match self {
17+
NetworkError::DnsResolveFailed => {
18+
write!(fmt, "Failed to resolve a hostname for the provided IP address")
19+
}
20+
}
21+
}
22+
}

esp32-wroom-rp/src/protocol.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub(crate) enum NinaCommand {
1717
SetPassphrase = 0x11u8,
1818
GetConnStatus = 0x20u8,
1919
Disconnect = 0x30u8,
20+
SetDNSConfig = 0x15u8,
21+
ReqHostByName = 0x34u8,
22+
GetHostByName = 0x35u8,
2023
}
2124

2225
pub(crate) trait NinaParam {
@@ -225,10 +228,14 @@ impl NinaParam for NinaLargeArrayParam {
225228
pub(crate) trait ProtocolInterface {
226229
fn init(&mut self);
227230
fn reset<D: DelayMs<u16>>(&mut self, delay: &mut D);
228-
fn get_fw_version(&mut self) -> Result<FirmwareVersion, ProtocolError>;
229-
fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), ProtocolError>;
230-
fn disconnect(&mut self) -> Result<(), ProtocolError>;
231-
fn get_conn_status(&mut self) -> Result<u8, ProtocolError>;
231+
fn get_fw_version(&mut self) -> Result<FirmwareVersion, Error>;
232+
fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error>;
233+
fn disconnect(&mut self) -> Result<(), Error>;
234+
fn get_conn_status(&mut self) -> Result<u8, Error>;
235+
fn set_dns_config(&mut self, dns1: IpAddress, dns2: Option<IpAddress>) -> Result<(), Error>;
236+
fn req_host_by_name(&mut self, hostname: &str) -> Result<u8, Error>;
237+
fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>;
238+
fn resolve(&mut self, hostname: &str) -> Result<IpAddress, Error>;
232239
}
233240

234241
#[derive(Debug)]
@@ -241,12 +248,19 @@ pub(crate) struct NinaProtocolHandler<'a, B, C> {
241248

242249
// TODO: look at Nina Firmware code to understand conditions
243250
// that lead to NinaProtocolVersionMismatch
251+
/// Errors related to communication with NINA firmware
244252
#[derive(Debug, Eq, PartialEq)]
245253
pub enum ProtocolError {
254+
/// TODO: look at Nina Firmware code to understand conditions
255+
/// that lead to NinaProtocolVersionMismatch
246256
NinaProtocolVersionMismatch,
257+
/// A timeout occurred.
247258
CommunicationTimeout,
259+
/// An invalid NINA command has been sent over the data bus.
248260
InvalidCommand,
261+
/// An invalid number of parameters sent over the data bus.
249262
InvalidNumberOfParameters,
263+
/// Too many parameters sent over the data bus.
250264
TooManyParameters,
251265
}
252266

@@ -257,7 +271,7 @@ impl Format for ProtocolError {
257271
ProtocolError::CommunicationTimeout => write!(fmt, "Communication with ESP32 target timed out."),
258272
ProtocolError::InvalidCommand => write!(fmt, "Encountered an invalid command while communicating with ESP32 target."),
259273
ProtocolError::InvalidNumberOfParameters => write!(fmt, "Encountered an unexpected number of parameters for a NINA command while communicating with ESP32 target."),
260-
ProtocolError::TooManyParameters => write!(fmt, "Encountered too many parameters for a NINA command while communicating with ESP32 target."),
274+
ProtocolError::TooManyParameters => write!(fmt, "Encountered too many parameters for a NINA command while communicating with ESP32 target.")
261275
}
262276
}
263277
}

0 commit comments

Comments
 (0)