Skip to content

Commit cc4c417

Browse files
committed
add avail_data_tcp implementation
1 parent 34aa554 commit cc4c417

File tree

6 files changed

+357
-3
lines changed

6 files changed

+357
-3
lines changed

cross/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ members = [
33
"dns",
44
"get_fw_version",
55
"join",
6-
"send_data_tcp"
6+
"send_data_tcp",
7+
"receive_data_tcp"
78
]
89

910
[profile.dev]

cross/receive_data_tcp/Cargo.toml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[package]
2+
authors = [
3+
"Jim Hodapp",
4+
"Caleb Bourg",
5+
"Glyn Matthews",
6+
"Dilyn Corner"
7+
]
8+
edition = "2021"
9+
name = "receive_data_tcp"
10+
version = "0.3.0"
11+
description = "Example RP2040 target application that demonstrates how to receive data from a remote server over TCP."
12+
13+
# makes `cargo check --all-targets` work
14+
[[bin]]
15+
name = "receive_data_tcp"
16+
bench = false
17+
doctest = false
18+
test = false
19+
20+
[dependencies]
21+
defmt = "0.3.0"
22+
defmt-rtt = "0.3.1"
23+
cortex-m = "0.7"
24+
cortex-m-rt = "0.7"
25+
embedded-hal = { version = "0.2", features=["unproven"] }
26+
esp32-wroom-rp = { path = "../../esp32-wroom-rp" }
27+
panic-probe = { version = "0.3.0", features = ["print-rtt"] }
28+
heapless = "0.7.16"
29+
30+
rp2040-hal = { version = "0.6", features=["rt", "eh1_0_alpha"] }
31+
rp2040-boot2 = { version = "0.2" }
32+
fugit = "0.3"
33+
34+
[features]
35+
default = ['defmt-default']
36+
# these features are required by defmt
37+
defmt-default = []
38+
defmt-trace = []
39+
defmt-debug = []
40+
defmt-info = []
41+
defmt-warn = []
42+
defmt-error = []

cross/receive_data_tcp/src/main.rs

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
//! # ESP32-WROOM-RP Pico Wireless Example
2+
//!
3+
//! This application demonstrates how to use the ESP32-WROOM-RP crate to
4+
//! send data to a remote server over TCP.
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+
28+
use core::fmt::Write;
29+
30+
use fugit::RateExtU32;
31+
use hal::gpio::{FloatingInput, PushPullOutput};
32+
use hal::{clocks::Clock, pac};
33+
34+
use heapless::String;
35+
36+
use esp32_wroom_rp::{
37+
gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode,
38+
tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi,
39+
};
40+
41+
const MAX_HTTP_DOC_LENGTH: usize = 4096 as usize;
42+
43+
/// The linker will place this boot block at the start of our program image. We
44+
/// need this to help the ROM bootloader get our code up and running.
45+
#[link_section = ".boot2"]
46+
#[used]
47+
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
48+
49+
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
50+
/// if your board has a different frequency
51+
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
52+
53+
/// Entry point to our bare-metal application.
54+
///
55+
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
56+
/// as soon as all global variables are initialized.
57+
#[entry]
58+
fn main() -> ! {
59+
// Grab our singleton objects
60+
let mut pac = pac::Peripherals::take().unwrap();
61+
let core = pac::CorePeripherals::take().unwrap();
62+
63+
// Set up the watchdog driver - needed by the clock setup code
64+
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
65+
66+
// Configure the clocks
67+
let clocks = hal::clocks::init_clocks_and_plls(
68+
XTAL_FREQ_HZ,
69+
pac.XOSC,
70+
pac.CLOCKS,
71+
pac.PLL_SYS,
72+
pac.PLL_USB,
73+
&mut pac.RESETS,
74+
&mut watchdog,
75+
)
76+
.ok()
77+
.unwrap();
78+
79+
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
80+
81+
// The single-cycle I/O block controls our GPIO pins
82+
let sio = hal::Sio::new(pac.SIO);
83+
84+
// Set the pins to their default state
85+
let pins = hal::gpio::Pins::new(
86+
pac.IO_BANK0,
87+
pac.PADS_BANK0,
88+
sio.gpio_bank0,
89+
&mut pac.RESETS,
90+
);
91+
92+
defmt::info!("ESP32-WROOM-RP example to send data over TCP socket");
93+
94+
// These are implicitly used by the spi driver if they are in the correct mode
95+
let _spi_miso = pins.gpio16.into_mode::<hal::gpio::FunctionSpi>();
96+
let _spi_sclk = pins.gpio18.into_mode::<hal::gpio::FunctionSpi>();
97+
let _spi_mosi = pins.gpio19.into_mode::<hal::gpio::FunctionSpi>();
98+
99+
let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);
100+
101+
// Exchange the uninitialized SPI driver for an initialized one
102+
let spi = spi.init(
103+
&mut pac.RESETS,
104+
clocks.peripheral_clock.freq(),
105+
8.MHz(),
106+
&MODE_0,
107+
);
108+
109+
let esp_pins = EspControlPins {
110+
// CS on pin x (GPIO7)
111+
cs: pins.gpio7.into_mode::<PushPullOutput>(),
112+
// GPIO0 on pin x (GPIO2)
113+
gpio0: pins.gpio2.into_mode::<PushPullOutput>(),
114+
// RESETn on pin x (GPIO11)
115+
resetn: pins.gpio11.into_mode::<PushPullOutput>(),
116+
// ACK on pin x (GPIO10)
117+
ack: pins.gpio10.into_mode::<FloatingInput>(),
118+
};
119+
120+
let mut wifi = Wifi::init(spi, esp_pins, &mut delay).unwrap();
121+
122+
let result = wifi.join(SSID, PASSPHRASE);
123+
defmt::info!("Join Result: {:?}", result);
124+
125+
defmt::info!("Entering main loop");
126+
127+
let mut sleep: u32 = 1500;
128+
loop {
129+
match wifi.get_connection_status() {
130+
Ok(status) => {
131+
defmt::info!("Connection status: {:?}", status);
132+
delay.delay_ms(sleep);
133+
134+
if status == ConnectionStatus::Connected {
135+
defmt::info!("Connected to network: {:?}", SSID);
136+
137+
// The IPAddresses of two DNS servers to resolve hostnames with.
138+
// Note that failover from ip1 to ip2 is fully functional.
139+
let ip1: IpAddress = [9, 9, 9, 9];
140+
let ip2: IpAddress = [8, 8, 8, 8];
141+
let dns_result = wifi.set_dns(ip1, Some(ip2));
142+
143+
defmt::info!("set_dns result: {:?}", dns_result);
144+
145+
let hostname = "github.com";
146+
// let ip_address: IpAddress = [140, 82, 114, 3]; // github.com
147+
148+
let port: Port = 80;
149+
let mode: TransportMode = TransportMode::Tcp;
150+
151+
let mut http_document: String<MAX_HTTP_DOC_LENGTH> = String::from("");
152+
// write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n",
153+
// ip_address[0],
154+
// ip_address[1],
155+
// ip_address[2],
156+
// ip_address[3],
157+
// port
158+
// ).ok().unwrap();
159+
160+
write!(
161+
http_document,
162+
"GET / HTTP/1.1\r\nHost: {}:{}\r\nAccept: */*\r\n\r\n",
163+
hostname, port
164+
)
165+
.ok()
166+
.unwrap();
167+
168+
if let Err(e) = TcpClient::build(&mut wifi).connect(
169+
hostname,
170+
port,
171+
mode,
172+
&mut delay,
173+
&mut |tcp_client| {
174+
defmt::info!("TCP connection to {:?}:{:?} successful", hostname, port);
175+
defmt::info!("Hostname: {:?}", tcp_client.server_hostname());
176+
defmt::info!("Sending HTTP Document: {:?}", http_document.as_str());
177+
match tcp_client.send_data(&http_document) {
178+
Ok(result) => {
179+
defmt::info!("Data sent successfully: {:?}", result);
180+
defmt::info!("Receiving Response");
181+
182+
match tcp_client.receive_data() {
183+
Ok(response) => { defmt::info!("Response: {:?}", response); }
184+
Err(e) => { defmt::info!("Error receiving data: {:?}", e); }
185+
}
186+
}
187+
Err(e) => {
188+
defmt::error!("Response error: {:?}", e)
189+
}
190+
}
191+
},
192+
) {
193+
defmt::error!(
194+
"TCP connection to {:?}:{:?} failed: {:?}",
195+
hostname,
196+
port,
197+
e
198+
);
199+
}
200+
201+
delay.delay_ms(100);
202+
203+
defmt::info!("Leaving network: {:?}", SSID);
204+
wifi.leave().ok();
205+
} else if status == ConnectionStatus::Disconnected {
206+
sleep = 20000; // No need to loop as often after disconnecting
207+
}
208+
}
209+
Err(e) => {
210+
defmt::error!("Failed to get connection result: {:?}", e);
211+
}
212+
}
213+
}
214+
}

esp32-wroom-rp/src/protocol.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub(crate) enum NinaCommand {
3636
SetPassphrase = 0x11u8,
3737
SetDNSConfig = 0x15u8,
3838
GetConnStatus = 0x20u8,
39+
AvailDataTcp = 0x2bu8,
3940
StartClientTcp = 0x2du8,
4041
StopClientTcp = 0x2eu8,
4142
GetClientStateTcp = 0x2fu8,
@@ -392,7 +393,7 @@ pub(crate) trait ProtocolInterface {
392393
fn get_conn_status(&mut self) -> Result<ConnectionStatus, Error>;
393394
fn set_dns_config(&mut self, dns1: IpAddress, dns2: Option<IpAddress>) -> Result<(), Error>;
394395
fn req_host_by_name(&mut self, hostname: &str) -> Result<u8, Error>;
395-
fn get_host_by_name(&mut self) -> Result<[u8; MAX_NINA_RESPONSE_LENGTH], Error>;
396+
fn get_host_by_name(&mut self) -> Result<NinaResponseBuffer, Error>;
396397
fn resolve(&mut self, hostname: &str) -> Result<IpAddress, Error>;
397398
fn get_socket(&mut self) -> Result<Socket, Error>;
398399
fn start_client_tcp(
@@ -405,6 +406,13 @@ pub(crate) trait ProtocolInterface {
405406
fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>;
406407
fn get_client_state_tcp(&mut self, socket: Socket) -> Result<ConnectionState, Error>;
407408
fn send_data(&mut self, data: &str, socket: Socket) -> Result<[u8; 1], Error>;
409+
fn receive_data(&mut self, socket: Socket) -> Result<NinaResponseBuffer, Error>;
410+
fn avail_data_tcp(&mut self, socket: Socket) -> Result<usize, Error>;
411+
fn get_data_buf_tcp(
412+
&mut self,
413+
socket: Socket,
414+
available_length: usize,
415+
) -> Result<NinaResponseBuffer, Error>;
408416
}
409417

410418
#[derive(Debug)]

0 commit comments

Comments
 (0)