From 6d0fe044c0edbe41b6df8a3df6ee88eac6c36202 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 18:01:00 -0800 Subject: [PATCH 001/106] move Wifi struct to wifi module --- esp32-wroom-rp/src/network.rs | 5 ++- esp32-wroom-rp/src/spi.rs | 70 +------------------------------- esp32-wroom-rp/src/wifi.rs | 76 ++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 71 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index bee39c4..d5bf2b7 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -15,7 +15,10 @@ impl Format for NetworkError { fn format(&self, fmt: Formatter) { match self { NetworkError::DnsResolveFailed => { - write!(fmt, "Failed to resolve a hostname for the provided IP address") + write!( + fmt, + "Failed to resolve a hostname for the provided IP address" + ) } } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index a67bfa9..c572c1f 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -9,7 +9,7 @@ use super::protocol::{ use super::network::NetworkError; use super::protocol::operation::Operation; use super::protocol::ProtocolError; -use super::{Error, FirmwareVersion, WifiCommon, ARRAY_LENGTH_PLACEHOLDER}; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use super::IpAddress; @@ -18,9 +18,6 @@ use embedded_hal::blocking::spi::Transfer; use core::convert::Infallible; -// FIXME: remove before commit -//use defmt_rtt as _; - // TODO: this should eventually move into NinaCommandHandler #[repr(u8)] #[derive(Debug)] @@ -32,71 +29,6 @@ enum ControlByte { Error = 0xEFu8, } -/// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. -#[derive(Debug)] -pub struct Wifi<'a, B, C> { - common: WifiCommon>, -} - -impl<'a, S, C> Wifi<'a, S, C> -where - S: Transfer, - C: EspControlInterface, -{ - /// Initializes the ESP32-WROOM Wifi device. - /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. - pub fn init>( - spi: &'a mut S, - esp32_control_pins: &'a mut C, - delay: &mut D, - ) -> Result, Error> { - let mut wifi = Wifi { - common: WifiCommon { - protocol_handler: NinaProtocolHandler { - bus: spi, - control_pins: esp32_control_pins, - }, - }, - }; - - wifi.common.init(delay); - Ok(wifi) - } - - /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). - pub fn firmware_version(&mut self) -> Result { - self.common.firmware_version() - } - - /// Joins a WiFi network given an SSID and a Passphrase. - pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.common.join(ssid, passphrase) - } - - /// Disconnects from a joined WiFi network. - pub fn leave(&mut self) -> Result<(), Error> { - self.common.leave() - } - - /// Retrieves the current WiFi network connection status. - /// - /// NOTE: A future version will provide a enumerated type instead of the raw integer values - /// from the NINA firmware. - pub fn get_connection_status(&mut self) -> Result { - self.common.get_connection_status() - } - - /// Sets 1 or 2 DNS servers that are used for network hostname resolution. - pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.common.set_dns(dns1, dns2) - } - - /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. - pub fn resolve(&mut self, hostname: &str) -> Result { - self.common.resolve(hostname) - } -} - // All SPI-specific aspects of the NinaProtocolHandler go here in this struct impl impl<'a, S, C> ProtocolInterface for NinaProtocolHandler<'a, S, C> where diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 19790de..6ab08a8 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -1 +1,75 @@ -pub use crate::spi::Wifi; +use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::blocking::spi::Transfer; + +use super::WifiCommon; +use super::{Error, FirmwareVersion}; + +use super::gpio::EspControlInterface; +use super::protocol::NinaProtocolHandler; + +use super::IpAddress; + +/// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. +#[derive(Debug)] +pub struct Wifi<'a, B, C> { + common: WifiCommon>, +} + +impl<'a, S, C> Wifi<'a, S, C> +where + S: Transfer, + C: EspControlInterface, +{ + /// Initializes the ESP32-WROOM Wifi device. + /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. + pub fn init>( + spi: &'a mut S, + esp32_control_pins: &'a mut C, + delay: &mut D, + ) -> Result, Error> { + let mut wifi = Wifi { + common: WifiCommon { + protocol_handler: NinaProtocolHandler { + bus: spi, + control_pins: esp32_control_pins, + }, + }, + }; + + wifi.common.init(delay); + Ok(wifi) + } + + /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). + pub fn firmware_version(&mut self) -> Result { + self.common.firmware_version() + } + + /// Joins a WiFi network given an SSID and a Passphrase. + pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { + self.common.join(ssid, passphrase) + } + + /// Disconnects from a joined WiFi network. + pub fn leave(&mut self) -> Result<(), Error> { + self.common.leave() + } + + /// Retrieves the current WiFi network connection status. + /// + /// NOTE: A future version will provide a enumerated type instead of the raw integer values + /// from the NINA firmware. + pub fn get_connection_status(&mut self) -> Result { + self.common.get_connection_status() + } + + /// Sets 1 or 2 DNS servers that are used for network hostname resolution. + pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { + self.common.set_dns(dns1, dns2) + } + + /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. + pub fn resolve(&mut self, hostname: &str) -> Result { + self.common.resolve(hostname) + } +} From d1dd6b80838dd45e991563235466ea43058b7fbb Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 18:08:08 -0800 Subject: [PATCH 002/106] move WifiCommon to wifi module --- esp32-wroom-rp/src/lib.rs | 47 +------------------------------- esp32-wroom-rp/src/tcp_client.rs | 0 esp32-wroom-rp/src/wifi.rs | 46 +++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 48 deletions(-) create mode 100644 esp32-wroom-rp/src/tcp_client.rs diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 8179355..68f5413 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -96,10 +96,9 @@ pub mod protocol; mod spi; use network::{IpAddress, NetworkError}; -use protocol::{ProtocolError, ProtocolInterface}; +use protocol::ProtocolError; use defmt::{write, Format, Formatter}; -use embedded_hal::blocking::delay::DelayMs; const ARRAY_LENGTH_PLACEHOLDER: usize = 8; @@ -179,50 +178,6 @@ impl Format for FirmwareVersion { ); } } - -#[derive(Debug)] -struct WifiCommon { - protocol_handler: PH, -} - -impl WifiCommon -where - PH: ProtocolInterface, -{ - fn init>(&mut self, delay: &mut D) { - self.protocol_handler.init(); - self.reset(delay); - } - - fn reset>(&mut self, delay: &mut D) { - self.protocol_handler.reset(delay) - } - - fn firmware_version(&mut self) -> Result { - self.protocol_handler.get_fw_version() - } - - fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.protocol_handler.set_passphrase(ssid, passphrase) - } - - fn leave(&mut self) -> Result<(), Error> { - self.protocol_handler.disconnect() - } - - fn get_connection_status(&mut self) -> Result { - self.protocol_handler.get_conn_status() - } - - fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.protocol_handler.set_dns_config(dns1, dns2) - } - - fn resolve(&mut self, hostname: &str) -> Result { - self.protocol_handler.resolve(hostname) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs new file mode 100644 index 0000000..e69de29 diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 6ab08a8..05f23a5 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -1,11 +1,10 @@ use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; -use super::WifiCommon; use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; -use super::protocol::NinaProtocolHandler; +use super::protocol::{NinaProtocolHandler, ProtocolInterface}; use super::IpAddress; @@ -73,3 +72,46 @@ where self.common.resolve(hostname) } } + +#[derive(Debug)] +struct WifiCommon { + protocol_handler: PH, +} + +impl WifiCommon +where + PH: ProtocolInterface, +{ + fn init>(&mut self, delay: &mut D) { + self.protocol_handler.init(); + self.reset(delay); + } + + fn reset>(&mut self, delay: &mut D) { + self.protocol_handler.reset(delay) + } + + fn firmware_version(&mut self) -> Result { + self.protocol_handler.get_fw_version() + } + + fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { + self.protocol_handler.set_passphrase(ssid, passphrase) + } + + fn leave(&mut self) -> Result<(), Error> { + self.protocol_handler.disconnect() + } + + fn get_connection_status(&mut self) -> Result { + self.protocol_handler.get_conn_status() + } + + fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { + self.protocol_handler.set_dns_config(dns1, dns2) + } + + fn resolve(&mut self, hostname: &str) -> Result { + self.protocol_handler.resolve(hostname) + } +} From 8dde60920688921516df7a702545486501f81fd4 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 19:04:57 -0800 Subject: [PATCH 003/106] add tcp module and TcpClient struct --- esp32-wroom-rp/src/lib.rs | 3 +++ esp32-wroom-rp/src/tcp_client.rs | 23 +++++++++++++++++++++++ esp32-wroom-rp/src/wifi.rs | 11 +++++++++++ 3 files changed, 37 insertions(+) diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 68f5413..3e1b744 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -84,6 +84,9 @@ #![warn(missing_docs)] #![cfg_attr(not(test), no_std)] +/// Fundamental interface for creating and send/receiving data to/from a TCP server. +pub mod tcp_client; + pub mod gpio; /// Fundamental interface for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. pub mod wifi; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index e69de29..64437f6 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -0,0 +1,23 @@ +use super::protocol::NinaProtocolHandler; + +use super::IpAddress; + +pub struct TcpClient<'a, 'b, B, C> { + pub(crate) common: TcpClientCommon<'a, NinaProtocolHandler<'a, B, C>>, + pub(crate) server_ip_address: Option, + pub(crate) server_hostname: Option<&'b str> +} + +pub(crate) struct TcpClientCommon<'a, PH> { + pub(crate) protocol_handler: &'a PH, +} + +impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> { + fn server_ip_address(&mut self, ip: IpAddress) { + self.server_ip_address = Some(ip); + } + + fn server_hostname(&mut self, hostname: &'b str) { + self.server_hostname = Some(hostname); + } +} diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 05f23a5..af9a4e6 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -5,6 +5,7 @@ use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; +use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; @@ -71,6 +72,16 @@ where pub fn resolve(&mut self, hostname: &str) -> Result { self.common.resolve(hostname) } + + pub fn build_tcp_client(&self) -> TcpClient { + TcpClient { + common: TcpClientCommon { + protocol_handler: &self.common.protocol_handler + }, + server_ip_address: None, + server_hostname: None + } + } } #[derive(Debug)] From e5cde278c3429e6b9ae694f6c5b0330a5ad9814b Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 18 Nov 2022 07:04:48 -0800 Subject: [PATCH 004/106] add get_socket method to TcpClient --- esp32-wroom-rp/src/network.rs | 2 ++ esp32-wroom-rp/src/protocol.rs | 7 ++-- esp32-wroom-rp/src/protocol/operation.rs | 2 +- esp32-wroom-rp/src/spi.rs | 15 +++++++-- esp32-wroom-rp/src/tcp_client.rs | 43 +++++++++++++++++++----- esp32-wroom-rp/src/wifi.rs | 6 ++-- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index d5bf2b7..a5b6373 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -3,6 +3,8 @@ use defmt::{write, Format, Formatter}; /// A four byte array type alias representing an IP address. pub type IpAddress = [u8; 4]; +pub type Socket = u8; + /// Errors that occur due to issues involving communication over /// WiFi network. #[derive(PartialEq, Eq, Debug)] diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 07f3c98..a863316 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -1,13 +1,14 @@ pub(crate) mod operation; -use super::*; - use embedded_hal::blocking::delay::DelayMs; use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; +use super::network::{IpAddress, Socket}; +use super::{Error, FirmwareVersion}; + pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; #[repr(u8)] @@ -20,6 +21,7 @@ pub(crate) enum NinaCommand { SetDNSConfig = 0x15u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, + GetSocket = 0x3fu8, } pub(crate) trait NinaParam { @@ -236,6 +238,7 @@ pub(crate) trait ProtocolInterface { fn req_host_by_name(&mut self, hostname: &str) -> Result; fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; fn resolve(&mut self, hostname: &str) -> Result; + fn get_socket(&mut self) -> Result; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 383076f..70f729d 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -1,4 +1,4 @@ -use super::protocol::NinaCommand; +use crate::protocol::NinaCommand; use heapless::Vec; const MAX_NUMBER_OF_PARAMS: usize = 4; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index c572c1f..2ed7d0a 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -6,13 +6,11 @@ use super::protocol::{ ProtocolInterface, }; -use super::network::NetworkError; +use super::network::{IpAddress, NetworkError, Socket}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; -use super::IpAddress; - use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; @@ -147,6 +145,17 @@ where Err(NetworkError::DnsResolveFailed.into()) } } + + fn get_socket(&mut self) -> Result { + let operation = + Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("")); + + self.execute(&operation)?; + + let result = self.receive(&operation)?; + + Ok(result[0]) + } } impl<'a, S, C> NinaProtocolHandler<'a, S, C> diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 64437f6..b3d0c1a 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,23 +1,48 @@ +use super::Error; + use super::protocol::NinaProtocolHandler; +use crate::gpio::EspControlInterface; +use crate::protocol::ProtocolInterface; + +use super::network::{IpAddress, Socket}; -use super::IpAddress; +use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, 'b, B, C> { pub(crate) common: TcpClientCommon<'a, NinaProtocolHandler<'a, B, C>>, pub(crate) server_ip_address: Option, - pub(crate) server_hostname: Option<&'b str> + pub(crate) server_hostname: Option<&'b str>, } -pub(crate) struct TcpClientCommon<'a, PH> { - pub(crate) protocol_handler: &'a PH, -} - -impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> { - fn server_ip_address(&mut self, ip: IpAddress) { +impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> +where + B: Transfer, + C: EspControlInterface, +{ + fn server_ip_address(mut self, ip: IpAddress) -> Self { self.server_ip_address = Some(ip); + self } - fn server_hostname(&mut self, hostname: &'b str) { + fn server_hostname(mut self, hostname: &'b str) -> Self { self.server_hostname = Some(hostname); + self + } + + fn get_socket(&mut self) -> Result { + self.common.get_socket() + } +} + +pub(crate) struct TcpClientCommon<'a, PH> { + pub(crate) protocol_handler: &'a mut PH, +} + +impl<'a, PH> TcpClientCommon<'a, PH> +where + PH: ProtocolInterface, +{ + fn get_socket(&mut self) -> Result { + self.protocol_handler.get_socket() } } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index af9a4e6..7b17cdc 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -73,13 +73,13 @@ where self.common.resolve(hostname) } - pub fn build_tcp_client(&self) -> TcpClient { + pub fn build_tcp_client(&'a mut self) -> TcpClient { TcpClient { common: TcpClientCommon { - protocol_handler: &self.common.protocol_handler + protocol_handler: &mut self.common.protocol_handler, }, server_ip_address: None, - server_hostname: None + server_hostname: None, } } } From 8571cf5e3c87364b6a7f1fc45aeeea5c8e133dff Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 20 Nov 2022 13:42:38 -0600 Subject: [PATCH 005/106] Add the beginnings of a new example to demonstrate sending data over a TCP socket --- cross/Cargo.toml | 3 +- cross/send_data_tcp/Cargo.toml | 41 ++++++ cross/send_data_tcp/src/main.rs | 164 +++++++++++++++++++++ cross/send_data_tcp/src/secrets/secrets.rs | 7 + 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 cross/send_data_tcp/Cargo.toml create mode 100644 cross/send_data_tcp/src/main.rs create mode 100644 cross/send_data_tcp/src/secrets/secrets.rs diff --git a/cross/Cargo.toml b/cross/Cargo.toml index 6d78c56..4d4e89a 100644 --- a/cross/Cargo.toml +++ b/cross/Cargo.toml @@ -1,8 +1,9 @@ [workspace] members = [ + "dns", "get_fw_version", "join", - "dns" + "send_data_tcp" ] [profile.dev] diff --git a/cross/send_data_tcp/Cargo.toml b/cross/send_data_tcp/Cargo.toml new file mode 100644 index 0000000..c359eeb --- /dev/null +++ b/cross/send_data_tcp/Cargo.toml @@ -0,0 +1,41 @@ +[package] +authors = [ + "Jim Hodapp", + "Caleb Bourg", + "Dilyn Corner", + "Glyn Matthews" +] +edition = "2021" +name = "send_data_tcp" +version = "0.1.0" +description = "Example RP2040 target application that demonstrates how to send data to a remote server over TCP." + +# makes `cargo check --all-targets` work +[[bin]] +name = "send_data_tcp" +bench = false +doctest = false +test = false + +[dependencies] +defmt = "0.3.0" +defmt-rtt = "0.3.0" +cortex-m = "0.7" +cortex-m-rt = "0.7" +embedded-hal = { version = "0.2", features=["unproven"] } +esp32-wroom-rp = { path = "../../esp32-wroom-rp" } +panic-probe = { version = "0.3.0", features = ["print-rtt"] } + +rp2040-hal = { version = "0.6", features=["rt", "eh1_0_alpha"] } +rp2040-boot2 = { version = "0.2" } +fugit = "0.3" + +[features] +default = ['defmt-default'] +# these features are required by defmt +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs new file mode 100644 index 0000000..9af2667 --- /dev/null +++ b/cross/send_data_tcp/src/main.rs @@ -0,0 +1,164 @@ +//! # ESP32-WROOM-RP Pico Wireless Example +//! +//! This application demonstrates how to use the ESP32-WROOM-RP crate to +//! send data to a remote server over TCP. +//! +//! See the `Cargo.toml` file for Copyright and license details. + +#![no_std] +#![no_main] + +extern crate esp32_wroom_rp; + +include!("secrets/secrets.rs"); + +// The macro for our start-up function +use cortex_m_rt::entry; + +// Needed for debug output symbols to be linked in binary image +use defmt_rtt as _; + +use panic_probe as _; + +// Alias for our HAL crate +use rp2040_hal as hal; + +use embedded_hal::spi::MODE_0; +use fugit::RateExtU32; +use hal::gpio::{ + bank0::Gpio10, bank0::Gpio11, bank0::Gpio2, bank0::Gpio7, FloatingInput, Pin, PushPullOutput, +}; +use hal::{clocks::Clock, pac, spi::Enabled}; + +use esp32_wroom_rp::{gpio::EspControlPins, network::IpAddress, wifi::Wifi, Error}; + +/// The linker will place this boot block at the start of our program image. We +/// need this to help the ROM bootloader get our code up and running. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; + +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +type Spi = hal::Spi; +type Pins = EspControlPins< + Pin, + Pin, + Pin, + Pin, +>; + +/// Entry point to our bare-metal application. +/// +/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function +/// as soon as all global variables are initialized. +#[entry] +fn main() -> ! { + // Grab our singleton objects + let mut pac = pac::Peripherals::take().unwrap(); + let core = pac::CorePeripherals::take().unwrap(); + + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); + + // The single-cycle I/O block controls our GPIO pins + let sio = hal::Sio::new(pac.SIO); + + // Set the pins to their default state + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + defmt::info!("ESP32-WROOM-RP example to send data over TCP socket"); + + // These are implicitly used by the spi driver if they are in the correct mode + let _spi_miso = pins.gpio16.into_mode::(); + let _spi_sclk = pins.gpio18.into_mode::(); + let _spi_mosi = pins.gpio19.into_mode::(); + + let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); + + // Exchange the uninitialized SPI driver for an initialized one + let mut spi = spi.init( + &mut pac.RESETS, + clocks.peripheral_clock.freq(), + 8.MHz(), + &MODE_0, + ); + + let mut esp_pins = EspControlPins { + // CS on pin x (GPIO7) + cs: pins.gpio7.into_mode::(), + // GPIO0 on pin x (GPIO2) + gpio0: pins.gpio2.into_mode::(), + // RESETn on pin x (GPIO11) + resetn: pins.gpio11.into_mode::(), + // ACK on pin x (GPIO10) + ack: pins.gpio10.into_mode::(), + }; + + let mut wifi = Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + + let result = wifi.join(SSID, PASSPHRASE); + defmt::info!("Join Result: {:?}", result); + + defmt::info!("Entering main loop"); + + let mut sleep: u32 = 1500; + loop { + match wifi.get_connection_status() { + Ok(byte) => { + defmt::info!("Get Connection Result: {:?}", byte); + delay.delay_ms(sleep); + + if byte == 3 { + defmt::info!("Connected to Network: {:?}", SSID); + + // The IPAddresses of two DNS servers to resolve hostnames with. + // Note that failover from ip1 to ip2 is fully functional. + let ip1: IpAddress = [9, 9, 9, 9]; + let ip2: IpAddress = [8, 8, 8, 8]; + let dns_result = wifi.set_dns(ip1, Some(ip2)); + + defmt::info!("set_dns result: {:?}", dns_result); + + let _hostname = "github.com"; + + let _result = send_http_get(&wifi); + + wifi.leave().ok(); + } else if byte == 6 { + defmt::info!("Disconnected from Network: {:?}", SSID); + sleep = 20000; // No need to loop as often after disconnecting + } + } + Err(e) => { + defmt::info!("Failed to Get Connection Result: {:?}", e); + } + } + } +} + +fn send_http_get(_wifi: &Wifi) -> Result<(), Error> { + Ok(()) +} diff --git a/cross/send_data_tcp/src/secrets/secrets.rs b/cross/send_data_tcp/src/secrets/secrets.rs new file mode 100644 index 0000000..d4bd861 --- /dev/null +++ b/cross/send_data_tcp/src/secrets/secrets.rs @@ -0,0 +1,7 @@ +// +// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across +// all example applications +// + +const SSID: &str = "ssid"; +const PASSPHRASE: &str = "passphrase"; From c931626ad63dd96f165d5bde5058da30c4a8e897 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 20 Nov 2022 13:43:24 -0600 Subject: [PATCH 006/106] Delay longer in the DNS/Join examples after disconnected from WiFi network --- cross/dns/src/main.rs | 3 ++- cross/join/src/main.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index ec05dda..89b1661 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -114,11 +114,11 @@ fn main() -> ! { defmt::info!("Entering main loop"); + let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(byte) => { defmt::info!("Get Connection Result: {:?}", byte); - let sleep: u32 = 1500; delay.delay_ms(sleep); if byte == 3 { @@ -148,6 +148,7 @@ fn main() -> ! { wifi.leave().ok().unwrap(); } else if byte == 6 { defmt::info!("Disconnected from Network: {:?}", SSID); + sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 3b78c43..037e37c 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -113,11 +113,11 @@ fn main() -> ! { defmt::info!("Entering main loop"); + let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(byte) => { defmt::info!("Get Connection Result: {:?}", byte); - let sleep: u32 = 1500; delay.delay_ms(sleep); if byte == 3 { @@ -129,6 +129,7 @@ fn main() -> ! { wifi.leave().ok().unwrap(); } else if byte == 6 { defmt::info!("Disconnected from Network: {:?}", SSID); + sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { From 578145b2993e5cf712b52d8b8f6cce777aff387c Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sat, 19 Nov 2022 13:40:19 -0600 Subject: [PATCH 007/106] Create a common secrets.rs file to share among all example application binaries --- cross/dns/src/main.rs | 2 +- cross/get_fw_version/src/secrets/secrets.rs | 7 ------- cross/join/src/main.rs | 2 +- cross/join/src/secrets/secrets.rs | 7 ------- cross/{dns/src => }/secrets/secrets.rs | 0 5 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 cross/get_fw_version/src/secrets/secrets.rs delete mode 100644 cross/join/src/secrets/secrets.rs rename cross/{dns/src => }/secrets/secrets.rs (100%) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 89b1661..eefcdf0 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -10,7 +10,7 @@ extern crate esp32_wroom_rp; -include!("secrets/secrets.rs"); +include!("../../secrets/secrets.rs"); // The macro for our start-up function use cortex_m_rt::entry; diff --git a/cross/get_fw_version/src/secrets/secrets.rs b/cross/get_fw_version/src/secrets/secrets.rs deleted file mode 100644 index d4bd861..0000000 --- a/cross/get_fw_version/src/secrets/secrets.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across -// all example applications -// - -const SSID: &str = "ssid"; -const PASSPHRASE: &str = "passphrase"; diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 037e37c..437bd14 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -11,7 +11,7 @@ extern crate esp32_wroom_rp; -include!("secrets/secrets.rs"); +include!("../../secrets/secrets.rs"); // The macro for our start-up function use cortex_m_rt::entry; diff --git a/cross/join/src/secrets/secrets.rs b/cross/join/src/secrets/secrets.rs deleted file mode 100644 index d4bd861..0000000 --- a/cross/join/src/secrets/secrets.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across -// all example applications -// - -const SSID: &str = "ssid"; -const PASSPHRASE: &str = "passphrase"; diff --git a/cross/dns/src/secrets/secrets.rs b/cross/secrets/secrets.rs similarity index 100% rename from cross/dns/src/secrets/secrets.rs rename to cross/secrets/secrets.rs From c55ce19ef1ef0a6986b9a5fb73eb179d218e51d7 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 21 Nov 2022 10:32:40 -0600 Subject: [PATCH 008/106] Update README.md Update the example code to make sure it reflects the latest/most mature use of the crate. --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ed792c0..6324add 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,18 @@ Future implementations will support the [ESP32-WROOM-DA](https://www.espressif.c ## Usage ```rust -use esp32_wroom_rp::wifi; +use rp2040_hal as hal; + +use esp32_wroom_rp::{wifi::Wifi, gpio::EspControlPins}; use embedded_hal::blocking::delay::DelayMs; -let spi_miso = pins.gpio16.into_mode::(); -let spi_sclk = pins.gpio18.into_mode::(); -let spi_mosi = pins.gpio19.into_mode::(); +use embedded_hal::spi::MODE_0; +use fugit::RateExtU32; +use hal::{clocks::Clock, pac}; + +let _spi_miso = pins.gpio16.into_mode::(); +let _spi_sclk = pins.gpio18.into_mode::(); +let _spi_mosi = pins.gpio19.into_mode::(); let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); @@ -27,7 +33,7 @@ let spi = spi.init( &MODE_0, ); -let esp_pins = esp32_wroom_rp::gpio::EspControlPins { +let esp_pins = EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -38,7 +44,7 @@ let esp_pins = esp32_wroom_rp::gpio::EspControlPins { ack: pins.gpio10.into_mode::(), }; -let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); +let wifi = Wifi::init(spi, esp_pins, &mut delay).unwrap(); let version = wifi.firmware_version(); ``` From 1e50557ce9af63ea3df172a20ec99e5677c2e4c7 Mon Sep 17 00:00:00 2001 From: Dilyn Corner Date: Mon, 21 Nov 2022 19:30:49 -0500 Subject: [PATCH 009/106] Create and use the ConnectionStatus enum --- .gitignore | 1 + cross/dns/src/main.rs | 9 +-- cross/join/src/main.rs | 11 ++-- esp32-wroom-rp/src/lib.rs | 3 + esp32-wroom-rp/src/protocol.rs | 5 +- esp32-wroom-rp/src/spi.rs | 8 ++- esp32-wroom-rp/src/wifi.rs | 109 ++++++++++++++++++++++++++++++++- 7 files changed, 131 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 76221b4..b2f967c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # will have compiled files and executables /target/ /cross/target/ +/esp32-wroom-rp/target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index eefcdf0..8a2504a 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -29,6 +29,7 @@ use hal::clocks::Clock; use hal::pac; use esp32_wroom_rp::network::IpAddress; +use esp32_wroom_rp::wifi::ConnectionStatus; /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. @@ -117,11 +118,11 @@ fn main() -> ! { let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { - Ok(byte) => { - defmt::info!("Get Connection Result: {:?}", byte); + Ok(status) => { + defmt::info!("Get Connection Result: {:?}", status); delay.delay_ms(sleep); - if byte == 3 { + if status == ConnectionStatus::Connected { defmt::info!("Connected to Network: {:?}", SSID); // The IPAddresses of two DNS servers to resolve hostnames with. @@ -146,7 +147,7 @@ fn main() -> ! { } wifi.leave().ok().unwrap(); - } else if byte == 6 { + } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting } diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 437bd14..b93045d 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -10,6 +10,7 @@ #![no_main] extern crate esp32_wroom_rp; +use esp32_wroom_rp::wifi::ConnectionStatus; include!("../../secrets/secrets.rs"); @@ -116,20 +117,22 @@ fn main() -> ! { let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { - Ok(byte) => { - defmt::info!("Get Connection Result: {:?}", byte); + Ok(status) => { + defmt::info!("Get Connection Result: {:?}", status); delay.delay_ms(sleep); - if byte == 3 { + if status == ConnectionStatus::Connected { defmt::info!("Connected to Network: {:?}", SSID); defmt::info!("Sleeping for 5 seconds before disconnecting..."); delay.delay_ms(5000); wifi.leave().ok().unwrap(); - } else if byte == 6 { + } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting + } else { + defmt::info!("Unhandled WiFi connection status: {:?}", status); } } Err(e) => { diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 3e1b744..5f8e34e 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -103,6 +103,8 @@ use protocol::ProtocolError; use defmt::{write, Format, Formatter}; +use self::wifi::ConnectionStatus; + const ARRAY_LENGTH_PLACEHOLDER: usize = 8; /// Highest level error types for this crate. @@ -181,6 +183,7 @@ impl Format for FirmwareVersion { ); } } + #[cfg(test)] mod tests { use super::*; diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index a863316..1a198e6 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,8 +6,9 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; -use super::network::{IpAddress, Socket}; use super::{Error, FirmwareVersion}; +use super::network::{IpAddress, Socket}; +use super::wifi::ConnectionStatus; pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; @@ -233,7 +234,7 @@ pub(crate) trait ProtocolInterface { fn get_fw_version(&mut self) -> Result; fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error>; fn disconnect(&mut self) -> Result<(), Error>; - fn get_conn_status(&mut self) -> Result; + fn get_conn_status(&mut self) -> Result; fn set_dns_config(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error>; fn req_host_by_name(&mut self, hostname: &str) -> Result; fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 2ed7d0a..11a2cd7 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -6,10 +6,11 @@ use super::protocol::{ ProtocolInterface, }; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use super::network::{IpAddress, NetworkError, Socket}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; -use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; +use super::wifi::ConnectionStatus; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; @@ -65,7 +66,7 @@ where Ok(()) } - fn get_conn_status(&mut self) -> Result { + fn get_conn_status(&mut self) -> Result { let operation = Operation::new(NinaCommand::GetConnStatus, 1).with_no_params(NinaNoParams::new("")); @@ -73,7 +74,8 @@ where let result = self.receive(&operation)?; - Ok(result[0]) + // TODO: + Ok(ConnectionStatus::Connected) } fn disconnect(&mut self) -> Result<(), Error> { diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 7b17cdc..485ebd3 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -1,6 +1,8 @@ use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; +use defmt::{write, Format, Formatter}; + use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; @@ -9,6 +11,109 @@ use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; +/// An enumerated type that represents the current WiFi network connection status. +#[repr(u8)] +#[derive(Eq, PartialEq, PartialOrd, Debug)] +pub enum ConnectionStatus { + /// No device is connected to hardware + NoEsp32 = 255, + /// Temporary status while attempting to connect to WiFi network + Idle = 0, + /// No SSID is available + NoActiveSsid, + /// WiFi network scan has finished + ScanCompleted, + /// Device is connected to WiFi network + Connected, + /// Device failed to connect to WiFi network + Failed, + /// Device lost connection to WiFi network + Lost, + /// Device disconnected from WiFi network + Disconnected, + /// Device is listening for connections in Access Point mode + ApListening, + /// Device is connected in Access Point mode + ApConnected, + /// Device failed to make connection in Access Point mode + ApFailed, + /// Unexpected value returned from device, reset may be required + Invalid, +} + +impl From for ConnectionStatus { + fn from(status: u8) -> ConnectionStatus { + match status { + 0 => ConnectionStatus::Idle, + 1 => ConnectionStatus::NoActiveSsid, + 2 => ConnectionStatus::ScanCompleted, + 3 => ConnectionStatus::Connected, + 4 => ConnectionStatus::Failed, + 5 => ConnectionStatus::Lost, + 6 => ConnectionStatus::Disconnected, + 7 => ConnectionStatus::ApListening, + 8 => ConnectionStatus::ApConnected, + 9 => ConnectionStatus::ApFailed, + 255 => ConnectionStatus::NoEsp32, + _ => ConnectionStatus::Invalid, + } + } +} + +impl Format for ConnectionStatus { + fn format(&self, fmt: Formatter) { + match self { + ConnectionStatus::NoEsp32 => write!( + fmt,"No device is connected to hardware" + ), + ConnectionStatus::Idle => write!( + fmt, + "Temporary status while attempting to connect to WiFi network" + ), + ConnectionStatus::NoActiveSsid => write!( + fmt, + "No SSID is available" + ), + ConnectionStatus::ScanCompleted => write!( + fmt, + "WiFi network scan has finished" + ), + ConnectionStatus::Connected => write!( + fmt, + "Device is connected to WiFi network" + ), + ConnectionStatus::Failed => write!( + fmt, + "Device failed to connect to WiFi network" + ), + ConnectionStatus::Lost => write!( + fmt, + "Device lost connection to WiFi network" + ), + ConnectionStatus::Disconnected => write!( + fmt, + "Device disconnected from WiFi network" + ), + ConnectionStatus::ApListening => write!( + fmt, + "Device is lstening for connections in Access Point mode" + ), + ConnectionStatus::ApConnected => write!( + fmt, + "Device is connected in Access Point mode" + ), + ConnectionStatus::ApFailed => write!( + fmt, + "Device failed to make connection in Access Point mode" + ), + ConnectionStatus::Invalid => write!( + fmt, + "Unexpected value returned from device, reset may be required" + ), + } + } +} + /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi<'a, B, C> { @@ -59,7 +164,7 @@ where /// /// NOTE: A future version will provide a enumerated type instead of the raw integer values /// from the NINA firmware. - pub fn get_connection_status(&mut self) -> Result { + pub fn get_connection_status(&mut self) -> Result { self.common.get_connection_status() } @@ -114,7 +219,7 @@ where self.protocol_handler.disconnect() } - fn get_connection_status(&mut self) -> Result { + fn get_connection_status(&mut self) -> Result { self.protocol_handler.get_conn_status() } From f7c94c368be6c65970d1c413e4898f1df68fac67 Mon Sep 17 00:00:00 2001 From: Dilyn Corner Date: Sat, 19 Nov 2022 18:03:52 -0500 Subject: [PATCH 010/106] Implement From trait for Connection Status --- esp32-wroom-rp/src/spi.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 11a2cd7..7658c92 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -74,8 +74,7 @@ where let result = self.receive(&operation)?; - // TODO: - Ok(ConnectionStatus::Connected) + Ok(ConnectionStatus::from(result[0])) } fn disconnect(&mut self) -> Result<(), Error> { From ed9d39d01e1372ab473cf290be6b327ac149db8e Mon Sep 17 00:00:00 2001 From: Dilyn Corner Date: Tue, 22 Nov 2022 15:29:08 -0500 Subject: [PATCH 011/106] Implement basic Format trait for ConnectionStatus --- esp32-wroom-rp/src/wifi.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 485ebd3..2133987 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -11,6 +11,8 @@ use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; +use defmt::{write, Format, Formatter}; + /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] #[derive(Eq, PartialEq, PartialOrd, Debug)] From 34dc478b229e0d8ac142a01d1656f9b6de417cbf Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 18:01:00 -0800 Subject: [PATCH 012/106] move Wifi struct to wifi module --- esp32-wroom-rp/src/wifi.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 2133987..485ebd3 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -11,8 +11,6 @@ use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; -use defmt::{write, Format, Formatter}; - /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] #[derive(Eq, PartialEq, PartialOrd, Debug)] From 13a2fb3d4df83f71ecd63b2e86e72f303675782e Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 20 Nov 2022 13:43:24 -0600 Subject: [PATCH 013/106] Delay longer in the DNS/Join examples after disconnected from WiFi network --- cross/join/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index b93045d..31cd53f 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -133,6 +133,7 @@ fn main() -> ! { sleep = 20000; // No need to loop as often after disconnecting } else { defmt::info!("Unhandled WiFi connection status: {:?}", status); + sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { From 0ea354f08eea1693d331371383e01f83b122d88c Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 28 Nov 2022 11:07:20 -0800 Subject: [PATCH 014/106] Rebased with main branch to get ConnectionStatus changes. --- cross/send_data_tcp/src/main.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 9af2667..5705777 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -30,7 +30,13 @@ use hal::gpio::{ }; use hal::{clocks::Clock, pac, spi::Enabled}; -use esp32_wroom_rp::{gpio::EspControlPins, network::IpAddress, wifi::Wifi, Error}; +use esp32_wroom_rp::{ + Error, + gpio::EspControlPins, + network::IpAddress, + wifi::ConnectionStatus, + wifi::Wifi +}; /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. @@ -127,11 +133,11 @@ fn main() -> ! { let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { - Ok(byte) => { - defmt::info!("Get Connection Result: {:?}", byte); + Ok(status) => { + defmt::info!("Get Connection Result: {:?}", status); delay.delay_ms(sleep); - if byte == 3 { + if status == ConnectionStatus::Connected { defmt::info!("Connected to Network: {:?}", SSID); // The IPAddresses of two DNS servers to resolve hostnames with. @@ -147,7 +153,7 @@ fn main() -> ! { let _result = send_http_get(&wifi); wifi.leave().ok(); - } else if byte == 6 { + } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting } From 6a31b499a6f4caafcde6224f7bb1d80a64998f9b Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 15:00:38 -0800 Subject: [PATCH 015/106] remove WifiCommon --- esp32-wroom-rp/src/protocol.rs | 2 +- esp32-wroom-rp/src/spi.rs | 2 +- esp32-wroom-rp/src/wifi.rs | 146 +++++++++------------------------ 3 files changed, 42 insertions(+), 108 deletions(-) diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 1a198e6..5b4b3f0 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,9 +6,9 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; -use super::{Error, FirmwareVersion}; use super::network::{IpAddress, Socket}; use super::wifi::ConnectionStatus; +use super::{Error, FirmwareVersion}; pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 7658c92..b4766ea 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -6,11 +6,11 @@ use super::protocol::{ ProtocolInterface, }; -use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use super::network::{IpAddress, NetworkError, Socket}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; use super::wifi::ConnectionStatus; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 485ebd3..a359616 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -44,18 +44,18 @@ pub enum ConnectionStatus { impl From for ConnectionStatus { fn from(status: u8) -> ConnectionStatus { match status { - 0 => ConnectionStatus::Idle, - 1 => ConnectionStatus::NoActiveSsid, - 2 => ConnectionStatus::ScanCompleted, - 3 => ConnectionStatus::Connected, - 4 => ConnectionStatus::Failed, - 5 => ConnectionStatus::Lost, - 6 => ConnectionStatus::Disconnected, - 7 => ConnectionStatus::ApListening, - 8 => ConnectionStatus::ApConnected, - 9 => ConnectionStatus::ApFailed, + 0 => ConnectionStatus::Idle, + 1 => ConnectionStatus::NoActiveSsid, + 2 => ConnectionStatus::ScanCompleted, + 3 => ConnectionStatus::Connected, + 4 => ConnectionStatus::Failed, + 5 => ConnectionStatus::Lost, + 6 => ConnectionStatus::Disconnected, + 7 => ConnectionStatus::ApListening, + 8 => ConnectionStatus::ApConnected, + 9 => ConnectionStatus::ApFailed, 255 => ConnectionStatus::NoEsp32, - _ => ConnectionStatus::Invalid, + _ => ConnectionStatus::Invalid, } } } @@ -63,53 +63,31 @@ impl From for ConnectionStatus { impl Format for ConnectionStatus { fn format(&self, fmt: Formatter) { match self { - ConnectionStatus::NoEsp32 => write!( - fmt,"No device is connected to hardware" - ), + ConnectionStatus::NoEsp32 => write!(fmt, "No device is connected to hardware"), ConnectionStatus::Idle => write!( fmt, "Temporary status while attempting to connect to WiFi network" - ), - ConnectionStatus::NoActiveSsid => write!( - fmt, - "No SSID is available" - ), - ConnectionStatus::ScanCompleted => write!( - fmt, - "WiFi network scan has finished" - ), - ConnectionStatus::Connected => write!( - fmt, - "Device is connected to WiFi network" - ), - ConnectionStatus::Failed => write!( - fmt, - "Device failed to connect to WiFi network" - ), - ConnectionStatus::Lost => write!( - fmt, - "Device lost connection to WiFi network" - ), - ConnectionStatus::Disconnected => write!( - fmt, - "Device disconnected from WiFi network" - ), + ), + ConnectionStatus::NoActiveSsid => write!(fmt, "No SSID is available"), + ConnectionStatus::ScanCompleted => write!(fmt, "WiFi network scan has finished"), + ConnectionStatus::Connected => write!(fmt, "Device is connected to WiFi network"), + ConnectionStatus::Failed => write!(fmt, "Device failed to connect to WiFi network"), + ConnectionStatus::Lost => write!(fmt, "Device lost connection to WiFi network"), + ConnectionStatus::Disconnected => write!(fmt, "Device disconnected from WiFi network"), ConnectionStatus::ApListening => write!( fmt, "Device is lstening for connections in Access Point mode" - ), - ConnectionStatus::ApConnected => write!( - fmt, - "Device is connected in Access Point mode" - ), - ConnectionStatus::ApFailed => write!( - fmt, - "Device failed to make connection in Access Point mode" - ), + ), + ConnectionStatus::ApConnected => { + write!(fmt, "Device is connected in Access Point mode") + } + ConnectionStatus::ApFailed => { + write!(fmt, "Device failed to make connection in Access Point mode") + } ConnectionStatus::Invalid => write!( fmt, "Unexpected value returned from device, reset may be required" - ), + ), } } } @@ -117,7 +95,7 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi<'a, B, C> { - common: WifiCommon>, + protocol_handler: NinaProtocolHandler<'a, B, C>, } impl<'a, S, C> Wifi<'a, S, C> @@ -133,31 +111,30 @@ where delay: &mut D, ) -> Result, Error> { let mut wifi = Wifi { - common: WifiCommon { - protocol_handler: NinaProtocolHandler { - bus: spi, - control_pins: esp32_control_pins, - }, + protocol_handler: NinaProtocolHandler { + bus: spi, + control_pins: esp32_control_pins, }, }; - wifi.common.init(delay); + wifi.protocol_handler.init(); + wifi.protocol_handler.reset(delay); Ok(wifi) } /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). pub fn firmware_version(&mut self) -> Result { - self.common.firmware_version() + self.protocol_handler.get_fw_version() } /// Joins a WiFi network given an SSID and a Passphrase. pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.common.join(ssid, passphrase) + self.protocol_handler.set_passphrase(ssid, passphrase) } /// Disconnects from a joined WiFi network. pub fn leave(&mut self) -> Result<(), Error> { - self.common.leave() + self.protocol_handler.disconnect() } /// Retrieves the current WiFi network connection status. @@ -165,69 +142,26 @@ where /// NOTE: A future version will provide a enumerated type instead of the raw integer values /// from the NINA firmware. pub fn get_connection_status(&mut self) -> Result { - self.common.get_connection_status() + self.protocol_handler.get_conn_status() } /// Sets 1 or 2 DNS servers that are used for network hostname resolution. pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.common.set_dns(dns1, dns2) + self.protocol_handler.set_dns_config(dns1, dns2) } /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. pub fn resolve(&mut self, hostname: &str) -> Result { - self.common.resolve(hostname) + self.protocol_handler.resolve(hostname) } pub fn build_tcp_client(&'a mut self) -> TcpClient { TcpClient { common: TcpClientCommon { - protocol_handler: &mut self.common.protocol_handler, + protocol_handler: &mut self.protocol_handler, }, server_ip_address: None, server_hostname: None, } } } - -#[derive(Debug)] -struct WifiCommon { - protocol_handler: PH, -} - -impl WifiCommon -where - PH: ProtocolInterface, -{ - fn init>(&mut self, delay: &mut D) { - self.protocol_handler.init(); - self.reset(delay); - } - - fn reset>(&mut self, delay: &mut D) { - self.protocol_handler.reset(delay) - } - - fn firmware_version(&mut self) -> Result { - self.protocol_handler.get_fw_version() - } - - fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.protocol_handler.set_passphrase(ssid, passphrase) - } - - fn leave(&mut self) -> Result<(), Error> { - self.protocol_handler.disconnect() - } - - fn get_connection_status(&mut self) -> Result { - self.protocol_handler.get_conn_status() - } - - fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.protocol_handler.set_dns_config(dns1, dns2) - } - - fn resolve(&mut self, hostname: &str) -> Result { - self.protocol_handler.resolve(hostname) - } -} From 0e7475bbdd51dcc81302f0bf4fa17c099481789f Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 15:37:37 -0800 Subject: [PATCH 016/106] move control pins wrap spi in RefCell --- cross/send_data_tcp/src/main.rs | 4 ++-- esp32-wroom-rp/src/protocol.rs | 6 ++++-- esp32-wroom-rp/src/spi.rs | 10 +++++----- esp32-wroom-rp/src/wifi.rs | 6 ++++-- host-tests/tests/spi.rs | 20 ++++++++++---------- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 5705777..a1b648d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -112,7 +112,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = EspControlPins { + let esp_pins = EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -123,7 +123,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 5b4b3f0..e8777ce 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -10,6 +10,8 @@ use super::network::{IpAddress, Socket}; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion}; +use core::cell::RefCell; + pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; #[repr(u8)] @@ -245,9 +247,9 @@ pub(crate) trait ProtocolInterface { #[derive(Debug)] pub(crate) struct NinaProtocolHandler<'a, B, C> { /// A Spi or I2c instance - pub bus: &'a mut B, + pub bus: RefCell<&'a mut B>, /// An EspControlPins instance - pub control_pins: &'a mut C, + pub control_pins: C, } // TODO: look at Nina Firmware code to understand conditions diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index b4766ea..c4cfb7e 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -217,7 +217,7 @@ where for byte in buf { let write_buf = &mut [byte]; - self.bus.transfer(write_buf).ok(); + self.bus.borrow_mut().transfer(write_buf).ok(); } if num_params == 0 { @@ -264,13 +264,13 @@ where fn send_end_cmd(&mut self) -> Result<(), Infallible> { let end_command: &mut [u8] = &mut [ControlByte::End as u8]; - self.bus.transfer(end_command).ok(); + self.bus.borrow_mut().transfer(end_command).ok(); Ok(()) } fn get_byte(&mut self) -> Result { let word_out = &mut [ControlByte::Dummy as u8]; - let word = self.bus.transfer(word_out).ok().unwrap(); + let word = self.bus.borrow_mut().transfer(word_out).ok().unwrap(); Ok(word[0] as u8) } @@ -301,14 +301,14 @@ where self.send_param_length(param)?; for byte in param.data().iter() { - self.bus.transfer(&mut [*byte]).ok(); + self.bus.borrow_mut().transfer(&mut [*byte]).ok(); } Ok(()) } fn send_param_length(&mut self, param: &P) -> Result<(), Infallible> { for byte in param.length_as_bytes().into_iter() { - self.bus.transfer(&mut [byte]).ok(); + self.bus.borrow_mut().transfer(&mut [byte]).ok(); } Ok(()) } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index a359616..3d17505 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -9,6 +9,8 @@ use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; use super::tcp_client::{TcpClient, TcpClientCommon}; +use core::cell::RefCell; + use super::IpAddress; /// An enumerated type that represents the current WiFi network connection status. @@ -107,12 +109,12 @@ where /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. pub fn init>( spi: &'a mut S, - esp32_control_pins: &'a mut C, + esp32_control_pins: C, delay: &mut D, ) -> Result, Error> { let mut wifi = Wifi { protocol_handler: NinaProtocolHandler { - bus: spi, + bus: RefCell::new(spi), control_pins: esp32_control_pins, }, }; diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 6beeddb..56a28c0 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -50,9 +50,9 @@ fn too_many_parameters_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -80,9 +80,9 @@ fn invalid_number_of_parameters_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -111,9 +111,9 @@ fn invalid_command_induces_invalid_command_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -143,9 +143,9 @@ fn timeout_induces_communication_timeout_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -173,9 +173,9 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( From 1d0270805f2a3e0413236c447ec7dfc12dccc244 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Tue, 6 Dec 2022 18:10:59 -0600 Subject: [PATCH 017/106] Ensure all cross examples compile and work correctly with Wifi struct interface change. --- cross/dns/src/main.rs | 4 ++-- cross/get_fw_version/src/main.rs | 4 ++-- cross/join/src/main.rs | 7 ++----- cross/send_data_tcp/src/main.rs | 2 +- cross/send_data_tcp/src/secrets/secrets.rs | 7 ------- 5 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 cross/send_data_tcp/src/secrets/secrets.rs diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 8a2504a..9346366 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -97,7 +97,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins { + let esp_pins = esp32_wroom_rp::gpio::EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -108,7 +108,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/cross/get_fw_version/src/main.rs b/cross/get_fw_version/src/main.rs index 5acc3e1..eda2975 100644 --- a/cross/get_fw_version/src/main.rs +++ b/cross/get_fw_version/src/main.rs @@ -92,7 +92,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins { + let esp_pins = esp32_wroom_rp::gpio::EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -102,7 +102,7 @@ fn main() -> ! { // ACK on pin x (GPIO10) ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let firmware_version = wifi.firmware_version(); defmt::info!("NINA firmware version: {:?}", firmware_version); diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 31cd53f..ff2f9b8 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -96,7 +96,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins { + let esp_pins = esp32_wroom_rp::gpio::EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -107,7 +107,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); @@ -131,9 +131,6 @@ fn main() -> ! { } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting - } else { - defmt::info!("Unhandled WiFi connection status: {:?}", status); - sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index a1b648d..4d8b15d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -10,7 +10,7 @@ extern crate esp32_wroom_rp; -include!("secrets/secrets.rs"); +include!("../../secrets/secrets.rs"); // The macro for our start-up function use cortex_m_rt::entry; diff --git a/cross/send_data_tcp/src/secrets/secrets.rs b/cross/send_data_tcp/src/secrets/secrets.rs deleted file mode 100644 index d4bd861..0000000 --- a/cross/send_data_tcp/src/secrets/secrets.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across -// all example applications -// - -const SSID: &str = "ssid"; -const PASSPHRASE: &str = "passphrase"; From f6a2a35abe87285da50af05d8634a52af5cc0221 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 19:24:09 -0800 Subject: [PATCH 018/106] remove TcpCommon --- esp32-wroom-rp/src/tcp_client.rs | 17 ++--------------- esp32-wroom-rp/src/wifi.rs | 6 ++---- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index b3d0c1a..fd11469 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -9,7 +9,7 @@ use super::network::{IpAddress, Socket}; use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, 'b, B, C> { - pub(crate) common: TcpClientCommon<'a, NinaProtocolHandler<'a, B, C>>, + pub(crate) protocol_handler: &'a mut NinaProtocolHandler<'a, B, C>, pub(crate) server_ip_address: Option, pub(crate) server_hostname: Option<&'b str>, } @@ -29,20 +29,7 @@ where self } - fn get_socket(&mut self) -> Result { - self.common.get_socket() - } -} - -pub(crate) struct TcpClientCommon<'a, PH> { - pub(crate) protocol_handler: &'a mut PH, -} - -impl<'a, PH> TcpClientCommon<'a, PH> -where - PH: ProtocolInterface, -{ - fn get_socket(&mut self) -> Result { + pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 3d17505..6115266 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -7,7 +7,7 @@ use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; -use super::tcp_client::{TcpClient, TcpClientCommon}; +use super::tcp_client::TcpClient; use core::cell::RefCell; @@ -159,9 +159,7 @@ where pub fn build_tcp_client(&'a mut self) -> TcpClient { TcpClient { - common: TcpClientCommon { - protocol_handler: &mut self.protocol_handler, - }, + protocol_handler: &mut self.protocol_handler, server_ip_address: None, server_hostname: None, } From fa834fb2101035e064ae7f10e45c9e505417a1e8 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 19:58:01 -0800 Subject: [PATCH 019/106] move spi into Wifi --- cross/dns/src/main.rs | 4 ++-- cross/get_fw_version/src/main.rs | 4 ++-- cross/join/src/main.rs | 4 ++-- cross/send_data_tcp/src/main.rs | 4 ++-- esp32-wroom-rp/src/protocol.rs | 4 ++-- esp32-wroom-rp/src/spi.rs | 4 ++-- esp32-wroom-rp/src/tcp_client.rs | 10 +++++----- esp32-wroom-rp/src/wifi.rs | 14 +++++++------- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 9346366..1f87d93 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -90,7 +90,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -108,7 +108,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/cross/get_fw_version/src/main.rs b/cross/get_fw_version/src/main.rs index eda2975..2967fb3 100644 --- a/cross/get_fw_version/src/main.rs +++ b/cross/get_fw_version/src/main.rs @@ -85,7 +85,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -102,7 +102,7 @@ fn main() -> ! { // ACK on pin x (GPIO10) ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); let firmware_version = wifi.firmware_version(); defmt::info!("NINA firmware version: {:?}", firmware_version); diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index ff2f9b8..452f1ff 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -89,7 +89,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -107,7 +107,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 4d8b15d..03afc14 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -105,7 +105,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -123,7 +123,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = Wifi::init(spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index e8777ce..16f73a6 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -245,9 +245,9 @@ pub(crate) trait ProtocolInterface { } #[derive(Debug)] -pub(crate) struct NinaProtocolHandler<'a, B, C> { +pub(crate) struct NinaProtocolHandler { /// A Spi or I2c instance - pub bus: RefCell<&'a mut B>, + pub bus: RefCell, /// An EspControlPins instance pub control_pins: C, } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index c4cfb7e..aa47ff8 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -29,7 +29,7 @@ enum ControlByte { } // All SPI-specific aspects of the NinaProtocolHandler go here in this struct impl -impl<'a, S, C> ProtocolInterface for NinaProtocolHandler<'a, S, C> +impl ProtocolInterface for NinaProtocolHandler where S: Transfer, C: EspControlInterface, @@ -159,7 +159,7 @@ where } } -impl<'a, S, C> NinaProtocolHandler<'a, S, C> +impl NinaProtocolHandler where S: Transfer, C: EspControlInterface, diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index fd11469..4530b46 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -8,13 +8,13 @@ use super::network::{IpAddress, Socket}; use embedded_hal::blocking::spi::Transfer; -pub struct TcpClient<'a, 'b, B, C> { - pub(crate) protocol_handler: &'a mut NinaProtocolHandler<'a, B, C>, +pub struct TcpClient<'a, B, C> { + pub(crate) protocol_handler: NinaProtocolHandler, pub(crate) server_ip_address: Option, - pub(crate) server_hostname: Option<&'b str>, + pub(crate) server_hostname: Option<&'a str>, } -impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> +impl<'a, B, C> TcpClient<'a, B, C> where B: Transfer, C: EspControlInterface, @@ -24,7 +24,7 @@ where self } - fn server_hostname(mut self, hostname: &'b str) -> Self { + fn server_hostname(mut self, hostname: &'a str) -> Self { self.server_hostname = Some(hostname); self } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 6115266..0c48528 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -96,11 +96,11 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] -pub struct Wifi<'a, B, C> { - protocol_handler: NinaProtocolHandler<'a, B, C>, +pub struct Wifi { + protocol_handler: NinaProtocolHandler, } -impl<'a, S, C> Wifi<'a, S, C> +impl<'a, S, C> Wifi where S: Transfer, C: EspControlInterface, @@ -108,10 +108,10 @@ where /// Initializes the ESP32-WROOM Wifi device. /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. pub fn init>( - spi: &'a mut S, + spi: S, esp32_control_pins: C, delay: &mut D, - ) -> Result, Error> { + ) -> Result, Error> { let mut wifi = Wifi { protocol_handler: NinaProtocolHandler { bus: RefCell::new(spi), @@ -157,9 +157,9 @@ where self.protocol_handler.resolve(hostname) } - pub fn build_tcp_client(&'a mut self) -> TcpClient { + pub fn build_tcp_client(mut self) -> TcpClient<'a, S, C> { TcpClient { - protocol_handler: &mut self.protocol_handler, + protocol_handler: self.protocol_handler, server_ip_address: None, server_hostname: None, } From a176340882cc5461ff8575e26086d8e78e98a940 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 20:24:59 -0800 Subject: [PATCH 020/106] send_data_tcp compiles --- cross/send_data_tcp/src/main.rs | 7 +++++-- esp32-wroom-rp/src/tcp_client.rs | 2 +- esp32-wroom-rp/src/wifi.rs | 32 ++++++++++++++++++-------------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 03afc14..e5e5adc 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -150,7 +150,7 @@ fn main() -> ! { let _hostname = "github.com"; - let _result = send_http_get(&wifi); + let _result = send_http_get(&mut wifi); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { @@ -165,6 +165,9 @@ fn main() -> ! { } } -fn send_http_get(_wifi: &Wifi) -> Result<(), Error> { +fn send_http_get(wifi: &mut Wifi) -> Result<(), Error> { + let mut client = wifi.build_tcp_client(); + let socket = client.get_socket(); + Ok(()) } diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 4530b46..cf84880 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -9,7 +9,7 @@ use super::network::{IpAddress, Socket}; use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, B, C> { - pub(crate) protocol_handler: NinaProtocolHandler, + pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) server_ip_address: Option, pub(crate) server_hostname: Option<&'a str>, } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 0c48528..e1d34ac 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -97,7 +97,7 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi { - protocol_handler: NinaProtocolHandler, + protocol_handler: RefCell>, } impl<'a, S, C> Wifi @@ -112,31 +112,33 @@ where esp32_control_pins: C, delay: &mut D, ) -> Result, Error> { - let mut wifi = Wifi { - protocol_handler: NinaProtocolHandler { + let wifi = Wifi { + protocol_handler: RefCell::new(NinaProtocolHandler { bus: RefCell::new(spi), control_pins: esp32_control_pins, - }, + }), }; - wifi.protocol_handler.init(); - wifi.protocol_handler.reset(delay); + wifi.protocol_handler.borrow_mut().init(); + wifi.protocol_handler.borrow_mut().reset(delay); Ok(wifi) } /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). pub fn firmware_version(&mut self) -> Result { - self.protocol_handler.get_fw_version() + self.protocol_handler.borrow_mut().get_fw_version() } /// Joins a WiFi network given an SSID and a Passphrase. pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.protocol_handler.set_passphrase(ssid, passphrase) + self.protocol_handler + .borrow_mut() + .set_passphrase(ssid, passphrase) } /// Disconnects from a joined WiFi network. pub fn leave(&mut self) -> Result<(), Error> { - self.protocol_handler.disconnect() + self.protocol_handler.borrow_mut().disconnect() } /// Retrieves the current WiFi network connection status. @@ -144,22 +146,24 @@ where /// NOTE: A future version will provide a enumerated type instead of the raw integer values /// from the NINA firmware. pub fn get_connection_status(&mut self) -> Result { - self.protocol_handler.get_conn_status() + self.protocol_handler.borrow_mut().get_conn_status() } /// Sets 1 or 2 DNS servers that are used for network hostname resolution. pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.protocol_handler.set_dns_config(dns1, dns2) + self.protocol_handler + .borrow_mut() + .set_dns_config(dns1, dns2) } /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. pub fn resolve(&mut self, hostname: &str) -> Result { - self.protocol_handler.resolve(hostname) + self.protocol_handler.borrow_mut().resolve(hostname) } - pub fn build_tcp_client(mut self) -> TcpClient<'a, S, C> { + pub fn build_tcp_client(&'a mut self) -> TcpClient<'a, S, C> { TcpClient { - protocol_handler: self.protocol_handler, + protocol_handler: self.protocol_handler.get_mut(), server_ip_address: None, server_hostname: None, } From 52bf5b7878af1f193024191f4fad0e41f8212fa7 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 7 Dec 2022 05:01:17 -0800 Subject: [PATCH 021/106] update send_data_tcp --- cross/send_data_tcp/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index e5e5adc..39908c1 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -167,7 +167,9 @@ fn main() -> ! { fn send_http_get(wifi: &mut Wifi) -> Result<(), Error> { let mut client = wifi.build_tcp_client(); + defmt::info!("Getting Socket"); let socket = client.get_socket(); + defmt::info!("Get Socket Result: {:?}", socket); Ok(()) } From d54216f1e2375436d18c0c9a08cfb52d0489ed68 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 7 Dec 2022 07:48:03 -0800 Subject: [PATCH 022/106] add spi_as_mut_ref --- esp32-wroom-rp/src/wifi.rs | 4 ++++ host-tests/tests/spi.rs | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index e1d34ac..125d98c 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -168,4 +168,8 @@ where server_hostname: None, } } + + pub fn spi_as_mut_ref(&'a mut self) -> &'a mut S { + self.protocol_handler.get_mut().bus.get_mut() + } } diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 56a28c0..808ba1c 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -46,13 +46,13 @@ fn too_many_parameters_error() { // as we understand more. spi::Transaction::transfer(vec![0xff], vec![0x9]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -60,7 +60,7 @@ fn too_many_parameters_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::TooManyParameters) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -76,13 +76,13 @@ fn invalid_number_of_parameters_error() { spi::Transaction::transfer(vec![0xff], vec![0xb7]), spi::Transaction::transfer(vec![0xff], vec![0x0]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -92,7 +92,7 @@ fn invalid_number_of_parameters_error() { ) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -107,13 +107,13 @@ fn invalid_command_induces_invalid_command_error() { spi::Transaction::transfer(vec![0xff], vec![0xe0]), spi::Transaction::transfer(vec![0xff], vec![0x0]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -121,7 +121,7 @@ fn invalid_command_induces_invalid_command_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::InvalidCommand) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -139,13 +139,13 @@ fn timeout_induces_communication_timeout_error() { spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x0])) } - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -155,7 +155,7 @@ fn timeout_induces_communication_timeout_error() { ) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -169,13 +169,13 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { // wait_response_cmd() spi::Transaction::transfer(vec![0xff], vec![0xef]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -185,5 +185,5 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { ) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } From 8bd2d0f31ff904553bda2953de0a64ea142d7895 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 8 Dec 2022 05:39:28 -0800 Subject: [PATCH 023/106] add wifi.destroy() --- esp32-wroom-rp/src/wifi.rs | 4 ++-- host-tests/tests/spi.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 125d98c..244765d 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -169,7 +169,7 @@ where } } - pub fn spi_as_mut_ref(&'a mut self) -> &'a mut S { - self.protocol_handler.get_mut().bus.get_mut() + pub fn destroy(self) -> S { + self.protocol_handler.into_inner().bus.into_inner() } } diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 808ba1c..ebfa1be 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -60,7 +60,7 @@ fn too_many_parameters_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::TooManyParameters) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -92,7 +92,7 @@ fn invalid_number_of_parameters_error() { ) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -121,7 +121,7 @@ fn invalid_command_induces_invalid_command_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::InvalidCommand) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -155,7 +155,7 @@ fn timeout_induces_communication_timeout_error() { ) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -185,5 +185,5 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { ) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } From 4ebc042827b137849340850a143a551488d40c64 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 8 Dec 2022 06:41:11 -0800 Subject: [PATCH 024/106] use closure for TcpClient operations --- cross/send_data_tcp/src/main.rs | 26 ++++++++++---------------- esp32-wroom-rp/src/tcp_client.rs | 10 ++++------ esp32-wroom-rp/src/wifi.rs | 25 ++++++++++++++++++------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 39908c1..6bc965c 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -31,11 +31,7 @@ use hal::gpio::{ use hal::{clocks::Clock, pac, spi::Enabled}; use esp32_wroom_rp::{ - Error, - gpio::EspControlPins, - network::IpAddress, - wifi::ConnectionStatus, - wifi::Wifi + gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, }; /// The linker will place this boot block at the start of our program image. We @@ -148,9 +144,16 @@ fn main() -> ! { defmt::info!("set_dns result: {:?}", dns_result); - let _hostname = "github.com"; + let hostname = "github.com"; + let ip_address: IpAddress = [18, 195, 85, 27]; - let _result = send_http_get(&mut wifi); + wifi.connect_tcp(ip_address, hostname, |tcp_client, socket| { + defmt::info!("Get Socket Result: {:?}", socket); + defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); + defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + + // this is where you could call something like tcp_client.connect() + }); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { @@ -164,12 +167,3 @@ fn main() -> ! { } } } - -fn send_http_get(wifi: &mut Wifi) -> Result<(), Error> { - let mut client = wifi.build_tcp_client(); - defmt::info!("Getting Socket"); - let socket = client.get_socket(); - defmt::info!("Get Socket Result: {:?}", socket); - - Ok(()) -} diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index cf84880..e7cc967 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -19,14 +19,12 @@ where B: Transfer, C: EspControlInterface, { - fn server_ip_address(mut self, ip: IpAddress) -> Self { - self.server_ip_address = Some(ip); - self + pub fn server_ip_address(&self) -> Option { + self.server_ip_address } - fn server_hostname(mut self, hostname: &'a str) -> Self { - self.server_hostname = Some(hostname); - self + pub fn server_hostname(&self) -> Option<&'a str> { + self.server_hostname } pub fn get_socket(&mut self) -> Result { diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 244765d..1f473ce 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -11,7 +11,7 @@ use super::tcp_client::TcpClient; use core::cell::RefCell; -use super::IpAddress; +use super::network::{IpAddress, Socket}; /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] @@ -161,15 +161,26 @@ where self.protocol_handler.borrow_mut().resolve(hostname) } - pub fn build_tcp_client(&'a mut self) -> TcpClient<'a, S, C> { - TcpClient { - protocol_handler: self.protocol_handler.get_mut(), - server_ip_address: None, - server_hostname: None, - } + pub fn connect_tcp(&'a mut self, ip: IpAddress, hostname: &'a str, f: F) + where + F: Fn(TcpClient<'a, S, C>, Socket), + { + let mut tcp_client = self.build_tcp_client(ip, hostname); + let socket = tcp_client.get_socket().unwrap(); + // invokes closure or function passing in tcp_client and socket + // as arguments + f(tcp_client, socket) } pub fn destroy(self) -> S { self.protocol_handler.into_inner().bus.into_inner() } + + fn build_tcp_client(&'a mut self, ip: IpAddress, hostname: &'a str) -> TcpClient<'a, S, C> { + TcpClient { + protocol_handler: self.protocol_handler.get_mut(), + server_ip_address: Some(ip), + server_hostname: Some(hostname), + } + } } From 7d82a4c381cff46cfb1c26fbd70465c6d7230dff Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 8 Dec 2022 21:45:55 -0500 Subject: [PATCH 025/106] add TcpClient build and connect functions --- cross/secrets/secrets.rs | 4 ++-- cross/send_data_tcp/src/main.rs | 15 ++++++++------- esp32-wroom-rp/src/tcp_client.rs | 26 ++++++++++++++++++++++++++ esp32-wroom-rp/src/wifi.rs | 24 ++---------------------- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index d4bd861..95f689f 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = "ssid"; -const PASSPHRASE: &str = "passphrase"; +const SSID: &str = "Calebphone"; +const PASSPHRASE: &str = ""; diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 6bc965c..f38623e 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -31,7 +31,7 @@ use hal::gpio::{ use hal::{clocks::Clock, pac, spi::Enabled}; use esp32_wroom_rp::{ - gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, + gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient }; /// The linker will place this boot block at the start of our program image. We @@ -147,13 +147,14 @@ fn main() -> ! { let hostname = "github.com"; let ip_address: IpAddress = [18, 195, 85, 27]; - wifi.connect_tcp(ip_address, hostname, |tcp_client, socket| { - defmt::info!("Get Socket Result: {:?}", socket); - defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); - defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + TcpClient::build(&mut wifi) + .connect(ip_address, |tcp_client| { + defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); + defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + defmt::info!("Socket: {:?}", tcp_client.socket()); - // this is where you could call something like tcp_client.connect() - }); + // this is where you send/receive with a connected TCP socket to a remote server + }); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index e7cc967..c311e84 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,4 +1,5 @@ use super::Error; +use crate::wifi::Wifi; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; @@ -10,6 +11,7 @@ use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, + pub(crate) socket: Option, pub(crate) server_ip_address: Option, pub(crate) server_hostname: Option<&'a str>, } @@ -19,6 +21,26 @@ where B: Transfer, C: EspControlInterface, { + pub fn build(wifi: &'a mut Wifi) -> Self { + Self { + protocol_handler: wifi.protocol_handler.get_mut(), + socket: None, + server_ip_address: None, + server_hostname: None, + } + } + + pub fn connect(mut self, ip: IpAddress, f: F) + where + F: Fn(TcpClient<'a, B, C>), + { + let socket = self.get_socket().unwrap(); + self.socket = Some(socket); + self.server_ip_address = Some(ip); + + f(self) + } + pub fn server_ip_address(&self) -> Option { self.server_ip_address } @@ -30,4 +52,8 @@ where pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } + + pub fn socket(self) -> Socket { + self.socket.unwrap() + } } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 1f473ce..93c84bf 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -7,11 +7,10 @@ use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; -use super::tcp_client::TcpClient; use core::cell::RefCell; -use super::network::{IpAddress, Socket}; +use super::network::IpAddress; /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] @@ -97,7 +96,7 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi { - protocol_handler: RefCell>, + pub(crate) protocol_handler: RefCell>, } impl<'a, S, C> Wifi @@ -161,26 +160,7 @@ where self.protocol_handler.borrow_mut().resolve(hostname) } - pub fn connect_tcp(&'a mut self, ip: IpAddress, hostname: &'a str, f: F) - where - F: Fn(TcpClient<'a, S, C>, Socket), - { - let mut tcp_client = self.build_tcp_client(ip, hostname); - let socket = tcp_client.get_socket().unwrap(); - // invokes closure or function passing in tcp_client and socket - // as arguments - f(tcp_client, socket) - } - pub fn destroy(self) -> S { self.protocol_handler.into_inner().bus.into_inner() } - - fn build_tcp_client(&'a mut self, ip: IpAddress, hostname: &'a str) -> TcpClient<'a, S, C> { - TcpClient { - protocol_handler: self.protocol_handler.get_mut(), - server_ip_address: Some(ip), - server_hostname: Some(hostname), - } - } } From 15e04a89e9e3945fb86781f46d4be3d6e8e4bade Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 9 Dec 2022 14:37:38 -0500 Subject: [PATCH 026/106] introduce NinaAbstractParam --- esp32-wroom-rp/src/protocol.rs | 104 +++++++++++++++++++++-- esp32-wroom-rp/src/protocol/operation.rs | 8 +- esp32-wroom-rp/src/spi.rs | 46 +++++----- 3 files changed, 126 insertions(+), 32 deletions(-) diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 16f73a6..f5bb7d5 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -27,7 +27,7 @@ pub(crate) enum NinaCommand { GetSocket = 0x3fu8, } -pub(crate) trait NinaParam { +pub(crate) trait NinaConcreteParam { // Length of parameter in bytes type LengthAsBytes: IntoIterator; @@ -47,7 +47,7 @@ pub(crate) struct NinaNoParams { _placeholder: u8, } -impl NinaParam for NinaNoParams { +impl NinaConcreteParam for NinaNoParams { type LengthAsBytes = [u8; 0]; fn new(_data: &str) -> Self { @@ -71,6 +71,13 @@ impl NinaParam for NinaNoParams { } } +pub(crate) trait NinaParam { + fn length_as_bytes(&self) -> [u8; 2]; + fn data(&self) -> &[u8]; + fn length(&self) -> u16; + fn length_size(&self) -> u8; +} + // Used for single byte params pub(crate) struct NinaByteParam { length: u8, @@ -95,7 +102,92 @@ pub(crate) struct NinaLargeArrayParam { data: Vec, } -impl NinaParam for NinaByteParam { +pub(crate) struct NinaAbstractParam { + // Byte representation of length of data + length_as_bytes: [u8; 2], + // Data to be transfered over SPI bus + data: Vec, + // Number of bytes in data + length: u16, + // The number of bytes needed to represent + // length_as_bytes + length_size: u8, +} + +impl NinaParam for NinaAbstractParam { + fn length_as_bytes(&self) -> [u8; 2] { + self.length_as_bytes + } + + fn data(&self) -> &[u8] { + self.data.as_slice() + } + + fn length(&self) -> u16 { + self.length as u16 + } + + fn length_size(&self) -> u8 { + self.length_size + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaNoParams) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [0, 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 0, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaByteParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [concrete_param.length_as_bytes()[0], 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 1, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaWordParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [concrete_param.length_as_bytes()[0], 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 1, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaSmallArrayParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [concrete_param.length_as_bytes()[0], 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 1, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaLargeArrayParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: concrete_param.length_as_bytes(), + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 2, + } + } +} + +impl NinaConcreteParam for NinaByteParam { type LengthAsBytes = [u8; 1]; fn new(data: &str) -> Self { @@ -128,7 +220,7 @@ impl NinaParam for NinaByteParam { } } -impl NinaParam for NinaWordParam { +impl NinaConcreteParam for NinaWordParam { type LengthAsBytes = [u8; 1]; fn new(data: &str) -> Self { @@ -161,7 +253,7 @@ impl NinaParam for NinaWordParam { } } -impl NinaParam for NinaSmallArrayParam { +impl NinaConcreteParam for NinaSmallArrayParam { type LengthAsBytes = [u8; 1]; fn new(data: &str) -> Self { @@ -194,7 +286,7 @@ impl NinaParam for NinaSmallArrayParam { } } -impl NinaParam for NinaLargeArrayParam { +impl NinaConcreteParam for NinaLargeArrayParam { type LengthAsBytes = [u8; 2]; fn new(data: &str) -> Self { diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 70f729d..42295fc 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -1,4 +1,4 @@ -use crate::protocol::NinaCommand; +use crate::protocol::{NinaAbstractParam, NinaCommand}; use heapless::Vec; const MAX_NUMBER_OF_PARAMS: usize = 4; @@ -13,7 +13,7 @@ pub(crate) struct Operation

{ pub number_of_params_to_receive: u8, } -impl

Operation

{ +impl Operation { // Initializes new Operation instance. // // `has_params` defaults to `true` @@ -29,7 +29,7 @@ impl

Operation

{ // Pushes a new param into the internal `params` Vector which // builds up an internal byte stream representing one Nina command // on the data bus. - pub fn param(mut self, param: P) -> Self { + pub fn param(mut self, param: NinaAbstractParam) -> Self { self.params.push(param).ok().unwrap(); self } @@ -37,7 +37,7 @@ impl

Operation

{ // Used for denoting an Operation where no params are provided. // // Sets `has_params` to `false` - pub fn with_no_params(mut self, no_param: P) -> Self { + pub fn with_no_params(mut self, no_param: NinaAbstractParam) -> Self { self.params.push(no_param).ok().unwrap(); self.has_params = false; self diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index aa47ff8..9ff0954 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -2,8 +2,8 @@ use super::gpio::EspControlInterface; use super::protocol::{ - NinaByteParam, NinaCommand, NinaNoParams, NinaParam, NinaProtocolHandler, NinaSmallArrayParam, - ProtocolInterface, + NinaByteParam, NinaCommand, NinaConcreteParam, NinaNoParams, NinaParam, NinaProtocolHandler, + NinaSmallArrayParam, ProtocolInterface, }; use super::network::{IpAddress, NetworkError, Socket}; @@ -45,8 +45,8 @@ where fn get_fw_version(&mut self) -> Result { // TODO: improve the ergonomics around with_no_params() - let operation = - Operation::new(NinaCommand::GetFwVersion, 1).with_no_params(NinaNoParams::new("")); + let operation = Operation::new(NinaCommand::GetFwVersion, 1) + .with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -57,8 +57,8 @@ where fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { let operation = Operation::new(NinaCommand::SetPassphrase, 1) - .param(NinaSmallArrayParam::new(ssid)) - .param(NinaSmallArrayParam::new(passphrase)); + .param(NinaSmallArrayParam::new(ssid).into()) + .param(NinaSmallArrayParam::new(passphrase).into()); self.execute(&operation)?; @@ -67,8 +67,8 @@ where } fn get_conn_status(&mut self) -> Result { - let operation = - Operation::new(NinaCommand::GetConnStatus, 1).with_no_params(NinaNoParams::new("")); + let operation = Operation::new(NinaCommand::GetConnStatus, 1) + .with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -79,7 +79,7 @@ where fn disconnect(&mut self) -> Result<(), Error> { let dummy_param = NinaByteParam::from_bytes(&[ControlByte::Dummy as u8]); - let operation = Operation::new(NinaCommand::Disconnect, 1).param(dummy_param); + let operation = Operation::new(NinaCommand::Disconnect, 1).param(dummy_param.into()); self.execute(&operation)?; @@ -92,9 +92,9 @@ where // FIXME: refactor Operation so it can take different NinaParam types let operation = Operation::new(NinaCommand::SetDNSConfig, 1) // FIXME: first param should be able to be a NinaByteParam: - .param(NinaSmallArrayParam::from_bytes(&[1])) - .param(NinaSmallArrayParam::from_bytes(&ip1)) - .param(NinaSmallArrayParam::from_bytes(&ip2.unwrap_or_default())); + .param(NinaByteParam::from_bytes(&[1]).into()) + .param(NinaSmallArrayParam::from_bytes(&ip1).into()) + .param(NinaSmallArrayParam::from_bytes(&ip2.unwrap_or_default()).into()); self.execute(&operation)?; @@ -104,8 +104,8 @@ where } fn req_host_by_name(&mut self, hostname: &str) -> Result { - let operation = - Operation::new(NinaCommand::ReqHostByName, 1).param(NinaSmallArrayParam::new(hostname)); + let operation = Operation::new(NinaCommand::ReqHostByName, 1) + .param(NinaSmallArrayParam::new(hostname).into()); self.execute(&operation)?; @@ -119,8 +119,8 @@ where } fn get_host_by_name(&mut self) -> Result<[u8; 8], Error> { - let operation = - Operation::new(NinaCommand::GetHostByName, 1).with_no_params(NinaNoParams::new("")); + let operation = Operation::new(NinaCommand::GetHostByName, 1) + .with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -149,7 +149,7 @@ where fn get_socket(&mut self) -> Result { let operation = - Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("")); + Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -299,16 +299,18 @@ where fn send_param(&mut self, param: &P) -> Result<(), Infallible> { self.send_param_length(param)?; - - for byte in param.data().iter() { - self.bus.borrow_mut().transfer(&mut [*byte]).ok(); + let data_length = param.length() as usize; + let bytes = param.data(); + for i in 0..data_length { + self.bus.borrow_mut().transfer(&mut [bytes[i]]).ok(); } Ok(()) } fn send_param_length(&mut self, param: &P) -> Result<(), Infallible> { - for byte in param.length_as_bytes().into_iter() { - self.bus.borrow_mut().transfer(&mut [byte]).ok(); + let bytes = param.length_as_bytes(); + for i in 0..param.length_size() as usize { + self.bus.borrow_mut().transfer(&mut [bytes[i]]).ok(); } Ok(()) } From 682b0d262ed54988f5c9dbb6a8036557438572bc Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 11 Dec 2022 15:20:35 -0600 Subject: [PATCH 027/106] Improves the ergonomics of sending a NinaParam with no params --- cross/secrets/secrets.rs | 2 +- esp32-wroom-rp/src/protocol/operation.rs | 12 ++---------- esp32-wroom-rp/src/spi.rs | 12 ++++-------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index 95f689f..e97157b 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = "Calebphone"; +const SSID: &str = ""; const PASSPHRASE: &str = ""; diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 42295fc..1629cf6 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -21,7 +21,7 @@ impl Operation { Self { params: Vec::new(), command: nina_command, - has_params: true, + has_params: false, number_of_params_to_receive: number_of_nina_params_to_receive, } } @@ -31,15 +31,7 @@ impl Operation { // on the data bus. pub fn param(mut self, param: NinaAbstractParam) -> Self { self.params.push(param).ok().unwrap(); - self - } - - // Used for denoting an Operation where no params are provided. - // - // Sets `has_params` to `false` - pub fn with_no_params(mut self, no_param: NinaAbstractParam) -> Self { - self.params.push(no_param).ok().unwrap(); - self.has_params = false; + self.has_params = true; self } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 9ff0954..671581a 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -44,9 +44,7 @@ where } fn get_fw_version(&mut self) -> Result { - // TODO: improve the ergonomics around with_no_params() - let operation = Operation::new(NinaCommand::GetFwVersion, 1) - .with_no_params(NinaNoParams::new("").into()); + let operation = Operation::new(NinaCommand::GetFwVersion, 1); self.execute(&operation)?; @@ -67,8 +65,7 @@ where } fn get_conn_status(&mut self) -> Result { - let operation = Operation::new(NinaCommand::GetConnStatus, 1) - .with_no_params(NinaNoParams::new("").into()); + let operation = Operation::new(NinaCommand::GetConnStatus, 1); self.execute(&operation)?; @@ -119,8 +116,7 @@ where } fn get_host_by_name(&mut self) -> Result<[u8; 8], Error> { - let operation = Operation::new(NinaCommand::GetHostByName, 1) - .with_no_params(NinaNoParams::new("").into()); + let operation = Operation::new(NinaCommand::GetHostByName, 1); self.execute(&operation)?; @@ -149,7 +145,7 @@ where fn get_socket(&mut self) -> Result { let operation = - Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("").into()); + Operation::new(NinaCommand::GetSocket, 1); self.execute(&operation)?; From a60c3c899c99a08d1ed961667ca8481c860c00b7 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 11 Dec 2022 17:01:49 -0600 Subject: [PATCH 028/106] Adds a start_client method that is part of the total TcpClient::connect() implementation. Also adds a Port and TransportMode parameter to TcpClient::connect()'s passed params --- cross/send_data_tcp/src/main.rs | 10 +++++++--- esp32-wroom-rp/src/network.rs | 25 +++++++++++++++++++++++- esp32-wroom-rp/src/protocol.rs | 8 +++++--- esp32-wroom-rp/src/protocol/operation.rs | 6 ++++-- esp32-wroom-rp/src/spi.rs | 25 ++++++++++++++++++++++-- esp32-wroom-rp/src/tcp_client.rs | 24 +++++++++++++++++++---- 6 files changed, 83 insertions(+), 15 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index f38623e..0b0ec9b 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -31,7 +31,8 @@ use hal::gpio::{ use hal::{clocks::Clock, pac, spi::Enabled}; use esp32_wroom_rp::{ - gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient + gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, + wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient }; /// The linker will place this boot block at the start of our program image. We @@ -144,11 +145,14 @@ fn main() -> ! { defmt::info!("set_dns result: {:?}", dns_result); - let hostname = "github.com"; + let _hostname = "github.com"; + let ip_address: IpAddress = [18, 195, 85, 27]; + let port: Port = 80; + let mode: TransportMode = TransportMode::Tcp; TcpClient::build(&mut wifi) - .connect(ip_address, |tcp_client| { + .connect(ip_address, port, mode, |tcp_client| { defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index a5b6373..f9502ca 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -3,7 +3,22 @@ use defmt::{write, Format, Formatter}; /// A four byte array type alias representing an IP address. pub type IpAddress = [u8; 4]; -pub type Socket = u8; +/// A TCP/UDP network port. +pub type Port = u16; + +pub(crate) type Socket = u8; + +/// Defines the mode types that the ESP32 firmware can be put into when starting +/// a new client or server instance +#[repr(u8)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum TransportMode { + Tcp = 0, + Udp = 1, + Tls = 2, + UdpMulticast = 3, + TlsBearSsl = 4, +} /// Errors that occur due to issues involving communication over /// WiFi network. @@ -11,6 +26,8 @@ pub type Socket = u8; pub enum NetworkError { /// Failed to resolve a hostname for the provided IP address. DnsResolveFailed, + /// Failed to start up a new TCP/UDP client instancwe. + StartClientFailed, } impl Format for NetworkError { @@ -22,6 +39,12 @@ impl Format for NetworkError { "Failed to resolve a hostname for the provided IP address" ) } + NetworkError::StartClientFailed => { + write!( + fmt, + "Failed to start up a new TCP/UDP client instance" + ) + } } } } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index f5bb7d5..032bc24 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,7 +6,7 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; -use super::network::{IpAddress, Socket}; +use super::network::{IpAddress, Port, Socket, TransportMode}; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion}; @@ -17,13 +17,14 @@ pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; #[repr(u8)] #[derive(Copy, Clone, Debug)] pub(crate) enum NinaCommand { - GetFwVersion = 0x37u8, SetPassphrase = 0x11u8, + SetDNSConfig = 0x15u8, GetConnStatus = 0x20u8, + StartClient = 0x2du8, Disconnect = 0x30u8, - SetDNSConfig = 0x15u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, + GetFwVersion = 0x37u8, GetSocket = 0x3fu8, } @@ -334,6 +335,7 @@ pub(crate) trait ProtocolInterface { fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; fn resolve(&mut self, hostname: &str) -> Result; fn get_socket(&mut self) -> Result; + fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 1629cf6..b9a82f4 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -14,9 +14,11 @@ pub(crate) struct Operation

{ } impl Operation { - // Initializes new Operation instance. + // Initializes a new Operation instance with a specified command. // - // `has_params` defaults to `true` + // `number_of_nina_params_to_receive` specifies how many return parameters to expect + // when the NINA firmware replies to the command specified in `NinaCommand`. + // `has_params` defaults to `false` which allows for a NINA command with no parameters pub fn new(nina_command: NinaCommand, number_of_nina_params_to_receive: u8) -> Self { Self { params: Vec::new(), diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 671581a..261db40 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,12 +1,14 @@ //! Serial Peripheral Interface (SPI) for Wifi +use crate::protocol::NinaWordParam; + use super::gpio::EspControlInterface; use super::protocol::{ - NinaByteParam, NinaCommand, NinaConcreteParam, NinaNoParams, NinaParam, NinaProtocolHandler, + NinaByteParam, NinaCommand, NinaConcreteParam, NinaParam, NinaProtocolHandler, NinaSmallArrayParam, ProtocolInterface, }; -use super::network::{IpAddress, NetworkError, Socket}; +use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; use super::wifi::ConnectionStatus; @@ -153,6 +155,25 @@ where Ok(result[0]) } + + fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { + let port_as_bytes = [((port & 0xff00) >> 8) as u8, + (port & 0xff) as u8]; + let operation = Operation::new(NinaCommand::StartClient, 1) + .param(NinaSmallArrayParam::from_bytes(&ip).into()) + .param(NinaWordParam::from_bytes(&port_as_bytes).into()) + .param(NinaByteParam::from_bytes(&[socket]).into()) + .param(NinaByteParam::from_bytes(&[*mode as u8]).into()); + + self.execute(&operation)?; + + let result = self.receive(&operation)?; + if result[0] == 1 { + Ok(()) + } else { + Err(NetworkError::StartClientFailed.into()) + } + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index c311e84..b4458ab 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,11 +1,11 @@ use super::Error; -use crate::wifi::Wifi; +use crate::{wifi::Wifi}; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{IpAddress, Socket}; +use super::network::{IpAddress, Port, Socket, TransportMode}; use embedded_hal::blocking::spi::Transfer; @@ -13,6 +13,8 @@ pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, pub(crate) server_ip_address: Option, + pub(crate) port: Port, + pub(crate) mode: TransportMode, pub(crate) server_hostname: Option<&'a str>, } @@ -26,17 +28,23 @@ where protocol_handler: wifi.protocol_handler.get_mut(), socket: None, server_ip_address: None, + port: 0, + mode: TransportMode::Tcp, server_hostname: None, } } - pub fn connect(mut self, ip: IpAddress, f: F) + pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) where F: Fn(TcpClient<'a, B, C>), { - let socket = self.get_socket().unwrap(); + let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); self.server_ip_address = Some(ip); + self.port = port; + self.mode = mode; + + self.protocol_handler.start_client(socket, ip, port, &mode); f(self) } @@ -49,6 +57,14 @@ where self.server_hostname } + pub fn port(&self) -> Port { + self.port + } + + pub fn mode(&self) -> TransportMode { + self.mode + } + pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } From 72696c63594992363a638b6a9661dbffb19c7268 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 11 Dec 2022 22:22:43 -0600 Subject: [PATCH 029/106] No more need for Operations::has_params, just use Vec::is_empty() instead --- esp32-wroom-rp/src/protocol/operation.rs | 5 +---- esp32-wroom-rp/src/spi.rs | 11 +++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index b9a82f4..c42811a 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -9,7 +9,6 @@ const MAX_NUMBER_OF_PARAMS: usize = 4; pub(crate) struct Operation

{ pub params: Vec, pub command: NinaCommand, - pub has_params: bool, pub number_of_params_to_receive: u8, } @@ -18,12 +17,10 @@ impl Operation { // // `number_of_nina_params_to_receive` specifies how many return parameters to expect // when the NINA firmware replies to the command specified in `NinaCommand`. - // `has_params` defaults to `false` which allows for a NINA command with no parameters pub fn new(nina_command: NinaCommand, number_of_nina_params_to_receive: u8) -> Self { Self { params: Vec::new(), command: nina_command, - has_params: false, number_of_params_to_receive: number_of_nina_params_to_receive, } } @@ -32,8 +29,8 @@ impl Operation { // builds up an internal byte stream representing one Nina command // on the data bus. pub fn param(mut self, param: NinaAbstractParam) -> Self { + // FIXME: Vec::push() will return T when it is full, handle this gracefully self.params.push(param).ok().unwrap(); - self.has_params = true; self } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 261db40..a99e24d 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,6 +1,6 @@ //! Serial Peripheral Interface (SPI) for Wifi -use crate::protocol::NinaWordParam; +use crate::protocol::{NinaWordParam, NinaAbstractParam}; use super::gpio::EspControlInterface; use super::protocol::{ @@ -8,9 +8,8 @@ use super::protocol::{ NinaSmallArrayParam, ProtocolInterface, }; -use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; -use super::protocol::operation::Operation; -use super::protocol::ProtocolError; +use super::network::{ IpAddress, NetworkError, Port, Socket, TransportMode }; +use super::protocol::{ operation::Operation, ProtocolError }; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -184,7 +183,7 @@ where fn execute(&mut self, operation: &Operation

) -> Result<(), Error> { let mut param_size: u16 = 0; self.control_pins.wait_for_esp_select(); - let number_of_params: u8 = if operation.has_params { + let number_of_params: u8 = if !operation.params.is_empty() { operation.params.len() as u8 } else { 0 @@ -192,7 +191,7 @@ where let result = self.send_cmd(&operation.command, number_of_params); // Only send params if they are present - if operation.has_params { + if !operation.params.is_empty() { operation.params.iter().for_each(|param| { self.send_param(param).ok(); param_size += param.length(); From bbf2194f0d56565336183072ad78f7f214a4a983 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 11:52:56 -0600 Subject: [PATCH 030/106] Implement a stop_client() method that disconnects/stops an existing TCP/UDP client instance --- cross/send_data_tcp/src/main.rs | 5 +++-- esp32-wroom-rp/src/network.rs | 10 +++++++++- esp32-wroom-rp/src/protocol.rs | 4 +++- esp32-wroom-rp/src/spi.rs | 21 ++++++++++++++++++--- esp32-wroom-rp/src/tcp_client.rs | 14 +++++++++----- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 0b0ec9b..a9d2273 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -147,8 +147,9 @@ fn main() -> ! { let _hostname = "github.com"; - let ip_address: IpAddress = [18, 195, 85, 27]; - let port: Port = 80; + //let ip_address: IpAddress = [18, 195, 85, 27]; + let ip_address: IpAddress = [10, 0, 1, 3]; + let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; TcpClient::build(&mut wifi) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index f9502ca..0fe7412 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -26,8 +26,10 @@ pub enum TransportMode { pub enum NetworkError { /// Failed to resolve a hostname for the provided IP address. DnsResolveFailed, - /// Failed to start up a new TCP/UDP client instancwe. + /// Failed to start up a new TCP/UDP client instance. StartClientFailed, + /// Failed to stop an existing TCP/UDP client instance + StopClientFailed, } impl Format for NetworkError { @@ -45,6 +47,12 @@ impl Format for NetworkError { "Failed to start up a new TCP/UDP client instance" ) } + NetworkError::StopClientFailed => { + write!( + fmt, + "Failed to stop an existing TCP/UDP client instance" + ) + } } } } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 032bc24..34f870a 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -20,7 +20,8 @@ pub(crate) enum NinaCommand { SetPassphrase = 0x11u8, SetDNSConfig = 0x15u8, GetConnStatus = 0x20u8, - StartClient = 0x2du8, + StartClientTcp = 0x2du8, + StopClientTcp = 0x2eu8, Disconnect = 0x30u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, @@ -336,6 +337,7 @@ pub(crate) trait ProtocolInterface { fn resolve(&mut self, hostname: &str) -> Result; fn get_socket(&mut self) -> Result; fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; + fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index a99e24d..6ab9377 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -156,9 +156,8 @@ where } fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { - let port_as_bytes = [((port & 0xff00) >> 8) as u8, - (port & 0xff) as u8]; - let operation = Operation::new(NinaCommand::StartClient, 1) + let port_as_bytes = [((port & 0xff00) >> 8) as u8, (port & 0xff) as u8]; + let operation = Operation::new(NinaCommand::StartClientTcp, 1) .param(NinaSmallArrayParam::from_bytes(&ip).into()) .param(NinaWordParam::from_bytes(&port_as_bytes).into()) .param(NinaByteParam::from_bytes(&[socket]).into()) @@ -173,6 +172,22 @@ where Err(NetworkError::StartClientFailed.into()) } } + + // TODO: passing in TransportMode but not using, for now. It will become a way + // of stopping the right kind of client (e.g. TCP, vs UDP) + fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { + let operation = Operation::new(NinaCommand::StopClientTcp, 1) + .param(NinaByteParam::from_bytes(&[socket]).into()); + + self.execute(&operation)?; + + let result = self.receive(&operation)?; + if result[0] == 1 { + Ok(()) + } else { + Err(NetworkError::StopClientFailed.into()) + } + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index b4458ab..ec3f9d5 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -34,9 +34,9 @@ where } } - pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) + pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) -> Self where - F: Fn(TcpClient<'a, B, C>), + F: Fn(&mut TcpClient<'a, B, C>) { let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); @@ -44,9 +44,13 @@ where self.port = port; self.mode = mode; - self.protocol_handler.start_client(socket, ip, port, &mode); + self.protocol_handler.start_client(socket, ip, port, &mode).ok().unwrap(); - f(self) + f(&mut self); + + self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); + + self } pub fn server_ip_address(&self) -> Option { @@ -69,7 +73,7 @@ where self.protocol_handler.get_socket() } - pub fn socket(self) -> Socket { + pub fn socket(&self) -> Socket { self.socket.unwrap() } } From 3175bb6b1c1f3817c964f666574fcfbc055e598b Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 14:54:06 -0600 Subject: [PATCH 031/106] Move where the expected number of params to receive are specified to what seems like a more logical place. --- esp32-wroom-rp/src/protocol/operation.rs | 7 +--- esp32-wroom-rp/src/spi.rs | 44 +++++++++++++----------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index c42811a..1ac3aae 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -9,19 +9,14 @@ const MAX_NUMBER_OF_PARAMS: usize = 4; pub(crate) struct Operation

{ pub params: Vec, pub command: NinaCommand, - pub number_of_params_to_receive: u8, } impl Operation { // Initializes a new Operation instance with a specified command. - // - // `number_of_nina_params_to_receive` specifies how many return parameters to expect - // when the NINA firmware replies to the command specified in `NinaCommand`. - pub fn new(nina_command: NinaCommand, number_of_nina_params_to_receive: u8) -> Self { + pub fn new(nina_command: NinaCommand) -> Self { Self { params: Vec::new(), command: nina_command, - number_of_params_to_receive: number_of_nina_params_to_receive, } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 6ab9377..046a793 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -45,50 +45,51 @@ where } fn get_fw_version(&mut self) -> Result { - let operation = Operation::new(NinaCommand::GetFwVersion, 1); + let operation = Operation::new(NinaCommand::GetFwVersion); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(FirmwareVersion::new(result)) // e.g. 1.7.4 } fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - let operation = Operation::new(NinaCommand::SetPassphrase, 1) + let operation = Operation::new(NinaCommand::SetPassphrase) .param(NinaSmallArrayParam::new(ssid).into()) .param(NinaSmallArrayParam::new(passphrase).into()); self.execute(&operation)?; - self.receive(&operation)?; + self.receive(&operation, 1)?; Ok(()) } fn get_conn_status(&mut self) -> Result { - let operation = Operation::new(NinaCommand::GetConnStatus, 1); + let operation = Operation::new(NinaCommand::GetConnStatus); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(ConnectionStatus::from(result[0])) } fn disconnect(&mut self) -> Result<(), Error> { let dummy_param = NinaByteParam::from_bytes(&[ControlByte::Dummy as u8]); - let operation = Operation::new(NinaCommand::Disconnect, 1).param(dummy_param.into()); + let operation = Operation::new(NinaCommand::Disconnect) + .param(dummy_param.into()); self.execute(&operation)?; - self.receive(&operation)?; + self.receive(&operation, 1)?; Ok(()) } fn set_dns_config(&mut self, ip1: IpAddress, ip2: Option) -> Result<(), Error> { // FIXME: refactor Operation so it can take different NinaParam types - let operation = Operation::new(NinaCommand::SetDNSConfig, 1) + let operation = Operation::new(NinaCommand::SetDNSConfig) // FIXME: first param should be able to be a NinaByteParam: .param(NinaByteParam::from_bytes(&[1]).into()) .param(NinaSmallArrayParam::from_bytes(&ip1).into()) @@ -96,18 +97,18 @@ where self.execute(&operation)?; - self.receive(&operation)?; + self.receive(&operation, 1)?; Ok(()) } fn req_host_by_name(&mut self, hostname: &str) -> Result { - let operation = Operation::new(NinaCommand::ReqHostByName, 1) + let operation = Operation::new(NinaCommand::ReqHostByName) .param(NinaSmallArrayParam::new(hostname).into()); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; if result[0] != 1u8 { return Err(NetworkError::DnsResolveFailed.into()); @@ -117,11 +118,11 @@ where } fn get_host_by_name(&mut self) -> Result<[u8; 8], Error> { - let operation = Operation::new(NinaCommand::GetHostByName, 1); + let operation = Operation::new(NinaCommand::GetHostByName); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(result) } @@ -146,18 +147,18 @@ where fn get_socket(&mut self) -> Result { let operation = - Operation::new(NinaCommand::GetSocket, 1); + Operation::new(NinaCommand::GetSocket); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(result[0]) } fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { let port_as_bytes = [((port & 0xff00) >> 8) as u8, (port & 0xff) as u8]; - let operation = Operation::new(NinaCommand::StartClientTcp, 1) + let operation = Operation::new(NinaCommand::StartClientTcp) .param(NinaSmallArrayParam::from_bytes(&ip).into()) .param(NinaWordParam::from_bytes(&port_as_bytes).into()) .param(NinaByteParam::from_bytes(&[socket]).into()) @@ -165,7 +166,7 @@ where self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; if result[0] == 1 { Ok(()) } else { @@ -176,12 +177,12 @@ where // TODO: passing in TransportMode but not using, for now. It will become a way // of stopping the right kind of client (e.g. TCP, vs UDP) fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { - let operation = Operation::new(NinaCommand::StopClientTcp, 1) + let operation = Operation::new(NinaCommand::StopClientTcp) .param(NinaByteParam::from_bytes(&[socket]).into()); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; if result[0] == 1 { Ok(()) } else { @@ -228,11 +229,12 @@ where fn receive( &mut self, operation: &Operation

, + expected_num_params: u8 ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.control_pins.wait_for_esp_select(); let result = - self.wait_response_cmd(&operation.command, operation.number_of_params_to_receive); + self.wait_response_cmd(&operation.command, expected_num_params); self.control_pins.esp_deselect(); From 4fd44c8d9e09f0443239418376d99122836640ff Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 14:54:32 -0600 Subject: [PATCH 032/106] Clean up the unused pieces in send_data_tcp example --- cross/send_data_tcp/src/main.rs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index a9d2273..0b17c1d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -25,14 +25,12 @@ use rp2040_hal as hal; use embedded_hal::spi::MODE_0; use fugit::RateExtU32; -use hal::gpio::{ - bank0::Gpio10, bank0::Gpio11, bank0::Gpio2, bank0::Gpio7, FloatingInput, Pin, PushPullOutput, -}; -use hal::{clocks::Clock, pac, spi::Enabled}; +use hal::gpio::{FloatingInput, PushPullOutput}; +use hal::{clocks::Clock, pac}; use esp32_wroom_rp::{ gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, - wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient + wifi::ConnectionStatus, wifi::Wifi, tcp_client::TcpClient }; /// The linker will place this boot block at the start of our program image. We @@ -45,14 +43,6 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; /// if your board has a different frequency const XTAL_FREQ_HZ: u32 = 12_000_000u32; -type Spi = hal::Spi; -type Pins = EspControlPins< - Pin, - Pin, - Pin, - Pin, ->; - /// Entry point to our bare-metal application. /// /// The `#[entry]` macro ensures the Cortex-M start-up code calls this function @@ -131,11 +121,11 @@ fn main() -> ! { loop { match wifi.get_connection_status() { Ok(status) => { - defmt::info!("Get Connection Result: {:?}", status); + defmt::info!("Connection status: {:?}", status); delay.delay_ms(sleep); if status == ConnectionStatus::Connected { - defmt::info!("Connected to Network: {:?}", SSID); + defmt::info!("Connected to network: {:?}", SSID); // The IPAddresses of two DNS servers to resolve hostnames with. // Note that failover from ip1 to ip2 is fully functional. @@ -161,9 +151,9 @@ fn main() -> ! { // this is where you send/receive with a connected TCP socket to a remote server }); + defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { - defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting } } From dedf4b262d605bc52e3f9162f9c53b62c0f75dc5 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 15:59:38 -0600 Subject: [PATCH 033/106] Add a get_state() method to retrieve the current TCP client state's connection status to a remote server --- esp32-wroom-rp/src/network.rs | 36 ++++++++++++++++++++++++++++++++ esp32-wroom-rp/src/protocol.rs | 4 +++- esp32-wroom-rp/src/spi.rs | 11 ++++++++++ esp32-wroom-rp/src/tcp_client.rs | 2 ++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 0fe7412..5018be9 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -20,6 +20,42 @@ pub enum TransportMode { TlsBearSsl = 4, } +/// Defines all possible TCP connection states for a client or server instance. +#[repr(u8)] +#[derive(PartialEq, PartialOrd, Debug)] +pub enum ConnectionState { + Closed = 0, + Listening = 1, + SynSent = 2, + SynReceived = 3, + Established = 4, + FinWait1 = 5, + FinWait2 = 6, + CloseWait = 7, + Closing = 8, + LastAck = 9, + TimeWait = 10, +} + +impl From for ConnectionState { + fn from(state: u8) -> ConnectionState { + match state { + 0 => ConnectionState::Closed, + 1 => ConnectionState::Listening, + 2 => ConnectionState::SynSent, + 3 => ConnectionState::SynReceived, + 4 => ConnectionState::Established, + 5 => ConnectionState::FinWait1, + 6 => ConnectionState::FinWait2, + 7 => ConnectionState::CloseWait, + 8 => ConnectionState::Closing, + 9 => ConnectionState::LastAck, + 10 => ConnectionState::TimeWait, + _ => ConnectionState::Closed + } + } +} + /// Errors that occur due to issues involving communication over /// WiFi network. #[derive(PartialEq, Eq, Debug)] diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 34f870a..b7857b8 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,7 +6,7 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; -use super::network::{IpAddress, Port, Socket, TransportMode}; +use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion}; @@ -22,6 +22,7 @@ pub(crate) enum NinaCommand { GetConnStatus = 0x20u8, StartClientTcp = 0x2du8, StopClientTcp = 0x2eu8, + GetClientStateTcp = 0x2fu8, Disconnect = 0x30u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, @@ -338,6 +339,7 @@ pub(crate) trait ProtocolInterface { fn get_socket(&mut self) -> Result; fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; + fn get_state(&mut self, socket: Socket) -> Result; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 046a793..efa4e0f 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,5 +1,6 @@ //! Serial Peripheral Interface (SPI) for Wifi +use crate::network::ConnectionState; use crate::protocol::{NinaWordParam, NinaAbstractParam}; use super::gpio::EspControlInterface; @@ -189,6 +190,16 @@ where Err(NetworkError::StopClientFailed.into()) } } + + fn get_state(&mut self, socket: Socket) -> Result { + let operation = Operation::new(NinaCommand::GetClientStateTcp); + + self.execute(&operation)?; + + let result = self.receive(&operation, 1)?; + + Ok(ConnectionState::from(result[0])) + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index ec3f9d5..d170f12 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -46,6 +46,8 @@ where self.protocol_handler.start_client(socket, ip, port, &mode).ok().unwrap(); + // TODO: utilize get_state() here to determine when we're connected to the remote TCP server + f(&mut self); self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); From d16e998a7ffe2e9e9f2f66ec3d5f4af73288ddc9 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 16:01:56 -0600 Subject: [PATCH 034/106] No need to pass tcp_client instance into closure as a mutable shared reference --- esp32-wroom-rp/src/tcp_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index d170f12..2c04ecd 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -36,7 +36,7 @@ where pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) -> Self where - F: Fn(&mut TcpClient<'a, B, C>) + F: Fn(&TcpClient<'a, B, C>) { let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); @@ -48,7 +48,7 @@ where // TODO: utilize get_state() here to determine when we're connected to the remote TCP server - f(&mut self); + f(&self); self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); From c19e2f776d249d66369874ec9972345063a5cd99 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 13 Dec 2022 09:17:57 -0500 Subject: [PATCH 035/106] check TCP connection --- cross/send_data_tcp/src/main.rs | 10 ++-- esp32-wroom-rp/src/lib.rs | 11 +++++ esp32-wroom-rp/src/network.rs | 30 +++++++---- esp32-wroom-rp/src/protocol.rs | 12 +++-- esp32-wroom-rp/src/spi.rs | 34 +++++++------ esp32-wroom-rp/src/tcp_client.rs | 85 +++++++++++++++++++++++++++----- 6 files changed, 140 insertions(+), 42 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 0b17c1d..558f1b1 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -142,14 +142,16 @@ fn main() -> ! { let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; - TcpClient::build(&mut wifi) - .connect(ip_address, port, mode, |tcp_client| { - defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); + if let Err(e) = TcpClient::build(&mut wifi) + .connect(ip_address, port, mode, &mut delay, |tcp_client| { + defmt::info!("TCP Connection to {:?}:{:?} successful", ip_address, port); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); // this is where you send/receive with a connected TCP socket to a remote server - }); + }) { + defmt::info!("TCP Connection to {:?}:{:?} Failed: {:?}", ip_address, port, e); + } defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 5f8e34e..7e99955 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -100,6 +100,7 @@ mod spi; use network::{IpAddress, NetworkError}; use protocol::ProtocolError; +use tcp_client::TcpError; use defmt::{write, Format, Formatter}; @@ -117,6 +118,9 @@ pub enum Error { /// Network related error Network(NetworkError), + + /// TCP related error + Tcp(TcpError), } impl Format for Error { @@ -129,6 +133,7 @@ impl Format for Error { e ), Error::Network(e) => write!(fmt, "Network error: {}", e), + Error::Tcp(e) => write!(fmt, "TCP error: {}", e), } } } @@ -145,6 +150,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: tcp_client::TcpError) -> Self { + Error::Tcp(err) + } +} + /// A structured representation of a connected NINA firmware device's version number (e.g. 1.7.4). #[derive(Debug, Default, Eq, PartialEq)] pub struct FirmwareVersion { diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 5018be9..a7e0d2f 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -51,7 +51,25 @@ impl From for ConnectionState { 8 => ConnectionState::Closing, 9 => ConnectionState::LastAck, 10 => ConnectionState::TimeWait, - _ => ConnectionState::Closed + _ => ConnectionState::Closed, + } + } +} + +impl Format for ConnectionState { + fn format(&self, fmt: Formatter) { + match self { + ConnectionState::Closed => write!(fmt, "Connection Closed"), + ConnectionState::Listening => write!(fmt, "Connection Listening"), + ConnectionState::SynSent => write!(fmt, "Connection SynSent"), + ConnectionState::SynReceived => write!(fmt, "Connection SynRecieved"), + ConnectionState::Established => write!(fmt, "Connection Established"), + ConnectionState::FinWait1 => write!(fmt, "Connection FinWait1"), + ConnectionState::FinWait2 => write!(fmt, "Connection FinWait2"), + ConnectionState::CloseWait => write!(fmt, "Connection CloseWait"), + ConnectionState::Closing => write!(fmt, "Connection Closing"), + ConnectionState::LastAck => write!(fmt, "Connection LastAck"), + ConnectionState::TimeWait => write!(fmt, "Connection TimeWait"), } } } @@ -78,16 +96,10 @@ impl Format for NetworkError { ) } NetworkError::StartClientFailed => { - write!( - fmt, - "Failed to start up a new TCP/UDP client instance" - ) + write!(fmt, "Failed to start up a new TCP/UDP client instance") } NetworkError::StopClientFailed => { - write!( - fmt, - "Failed to stop an existing TCP/UDP client instance" - ) + write!(fmt, "Failed to stop an existing TCP/UDP client instance") } } } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index b7857b8..771fc44 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -337,9 +337,15 @@ pub(crate) trait ProtocolInterface { fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; fn resolve(&mut self, hostname: &str) -> Result; fn get_socket(&mut self) -> Result; - fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; - fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; - fn get_state(&mut self, socket: Socket) -> Result; + fn start_client_tcp( + &mut self, + socket: Socket, + ip: IpAddress, + port: Port, + mode: &TransportMode, + ) -> Result<(), Error>; + fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; + fn get_client_state_tcp(&mut self, socket: Socket) -> Result; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index efa4e0f..3792b67 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,7 +1,7 @@ //! Serial Peripheral Interface (SPI) for Wifi use crate::network::ConnectionState; -use crate::protocol::{NinaWordParam, NinaAbstractParam}; +use crate::protocol::{NinaAbstractParam, NinaWordParam}; use super::gpio::EspControlInterface; use super::protocol::{ @@ -9,8 +9,8 @@ use super::protocol::{ NinaSmallArrayParam, ProtocolInterface, }; -use super::network::{ IpAddress, NetworkError, Port, Socket, TransportMode }; -use super::protocol::{ operation::Operation, ProtocolError }; +use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; +use super::protocol::{operation::Operation, ProtocolError}; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -78,8 +78,7 @@ where fn disconnect(&mut self) -> Result<(), Error> { let dummy_param = NinaByteParam::from_bytes(&[ControlByte::Dummy as u8]); - let operation = Operation::new(NinaCommand::Disconnect) - .param(dummy_param.into()); + let operation = Operation::new(NinaCommand::Disconnect).param(dummy_param.into()); self.execute(&operation)?; @@ -147,8 +146,7 @@ where } fn get_socket(&mut self) -> Result { - let operation = - Operation::new(NinaCommand::GetSocket); + let operation = Operation::new(NinaCommand::GetSocket); self.execute(&operation)?; @@ -157,14 +155,20 @@ where Ok(result[0]) } - fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { + fn start_client_tcp( + &mut self, + socket: Socket, + ip: IpAddress, + port: Port, + mode: &TransportMode, + ) -> Result<(), Error> { let port_as_bytes = [((port & 0xff00) >> 8) as u8, (port & 0xff) as u8]; let operation = Operation::new(NinaCommand::StartClientTcp) .param(NinaSmallArrayParam::from_bytes(&ip).into()) .param(NinaWordParam::from_bytes(&port_as_bytes).into()) .param(NinaByteParam::from_bytes(&[socket]).into()) .param(NinaByteParam::from_bytes(&[*mode as u8]).into()); - + self.execute(&operation)?; let result = self.receive(&operation, 1)?; @@ -177,7 +181,7 @@ where // TODO: passing in TransportMode but not using, for now. It will become a way // of stopping the right kind of client (e.g. TCP, vs UDP) - fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { + fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { let operation = Operation::new(NinaCommand::StopClientTcp) .param(NinaByteParam::from_bytes(&[socket]).into()); @@ -191,13 +195,14 @@ where } } - fn get_state(&mut self, socket: Socket) -> Result { + fn get_client_state_tcp(&mut self, socket: Socket) -> Result { let operation = Operation::new(NinaCommand::GetClientStateTcp); self.execute(&operation)?; let result = self.receive(&operation, 1)?; - + // TODO: Determine whether or not any ConnectionState variants should be considered + // an error. Ok(ConnectionState::from(result[0])) } } @@ -240,12 +245,11 @@ where fn receive( &mut self, operation: &Operation

, - expected_num_params: u8 + expected_num_params: u8, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.control_pins.wait_for_esp_select(); - let result = - self.wait_response_cmd(&operation.command, expected_num_params); + let result = self.wait_response_cmd(&operation.command, expected_num_params); self.control_pins.esp_deselect(); diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 2c04ecd..6eb0631 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,14 +1,30 @@ use super::Error; -use crate::{wifi::Wifi}; +use crate::wifi::Wifi; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{IpAddress, Port, Socket, TransportMode}; +use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; +use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; +use defmt::{write, Format, Formatter}; + +#[derive(Debug, Eq, PartialEq)] +pub enum TcpError { + Timeout, +} + +impl Format for TcpError { + fn format(&self, fmt: Formatter) { + match self { + TcpError::Timeout => write!(fmt, "Timeout Connecting to TCP Server"), + } + } +} + pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, @@ -34,9 +50,16 @@ where } } - pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) -> Self + pub fn connect>( + mut self, + ip: IpAddress, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error> where - F: Fn(&TcpClient<'a, B, C>) + F: Fn(&TcpClient<'a, B, C>), { let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); @@ -44,15 +67,55 @@ where self.port = port; self.mode = mode; - self.protocol_handler.start_client(socket, ip, port, &mode).ok().unwrap(); - - // TODO: utilize get_state() here to determine when we're connected to the remote TCP server - - f(&self); + self.protocol_handler + .start_client_tcp(socket, ip, port, &mode) + .ok() + .unwrap(); + + // FIXME: without this delay, we'll frequently see timing issues and receive + // a CmdResponseErr. We may not be handling busy/ack flag handling properly + // and needs further investigation. I suspect that the ESP32 isn't ready to + // receive another command yet. (copied this from POC) + delay.delay_ms(250); + + let mut retry_limit = 10_000; + + while retry_limit > 0 { + match self.protocol_handler.get_client_state_tcp(socket) { + Ok(ConnectionState::Established) => { + f(&self); + + self.protocol_handler + .stop_client_tcp(socket, &mode) + .ok() + .unwrap(); + return Ok(()); + } + Ok(status) => { + defmt::debug!("TCP Client Connection Status: {:?}", status); + } + Err(error) => { + // At this point any error will likely be a protocol level error. + // We do not currently consider any ConnectionState variants as errors. + defmt::debug!("TCP Client Connection Error: {:?}", error); + self.protocol_handler + .stop_client_tcp(socket, &mode) + .ok() + .unwrap(); + + return Err(error); + } + } + delay.delay_ms(100); + retry_limit -= 1; + } - self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); + self.protocol_handler + .stop_client_tcp(socket, &mode) + .ok() + .unwrap(); - self + Err(TcpError::Timeout.into()) } pub fn server_ip_address(&self) -> Option { From 97a77282a02925bed5f73118dc6cef0ec54788f8 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Tue, 13 Dec 2022 16:28:00 -0600 Subject: [PATCH 036/106] Convert error debug statements to use error macro, also make sure not to panic on TcpClient::connect() failure. --- cross/send_data_tcp/src/main.rs | 8 ++++---- esp32-wroom-rp/src/tcp_client.rs | 25 +++++++------------------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 558f1b1..3a142c7 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -138,19 +138,19 @@ fn main() -> ! { let _hostname = "github.com"; //let ip_address: IpAddress = [18, 195, 85, 27]; - let ip_address: IpAddress = [10, 0, 1, 3]; + let ip_address: IpAddress = [10, 0, 1, 4]; let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; if let Err(e) = TcpClient::build(&mut wifi) .connect(ip_address, port, mode, &mut delay, |tcp_client| { - defmt::info!("TCP Connection to {:?}:{:?} successful", ip_address, port); + defmt::info!("TCP connection to {:?}:{:?} successful", ip_address, port); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); // this is where you send/receive with a connected TCP socket to a remote server }) { - defmt::info!("TCP Connection to {:?}:{:?} Failed: {:?}", ip_address, port, e); + defmt::error!("TCP connection to {:?}:{:?} failed: {:?}", ip_address, port, e); } defmt::info!("Leaving network: {:?}", SSID); @@ -160,7 +160,7 @@ fn main() -> ! { } } Err(e) => { - defmt::info!("Failed to Get Connection Result: {:?}", e); + defmt::error!("Failed to get connection result: {:?}", e); } } } diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 6eb0631..583465b 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -67,10 +67,7 @@ where self.port = port; self.mode = mode; - self.protocol_handler - .start_client_tcp(socket, ip, port, &mode) - .ok() - .unwrap(); + self.protocol_handler.start_client_tcp(socket, ip, port, &mode)?; // FIXME: without this delay, we'll frequently see timing issues and receive // a CmdResponseErr. We may not be handling busy/ack flag handling properly @@ -85,23 +82,18 @@ where Ok(ConnectionState::Established) => { f(&self); - self.protocol_handler - .stop_client_tcp(socket, &mode) - .ok() - .unwrap(); + self.protocol_handler.stop_client_tcp(socket, &mode)?; + return Ok(()); } Ok(status) => { - defmt::debug!("TCP Client Connection Status: {:?}", status); + defmt::debug!("TCP client connection status: {:?}", status); } Err(error) => { // At this point any error will likely be a protocol level error. // We do not currently consider any ConnectionState variants as errors. - defmt::debug!("TCP Client Connection Error: {:?}", error); - self.protocol_handler - .stop_client_tcp(socket, &mode) - .ok() - .unwrap(); + defmt::error!("TCP client connection error: {:?}", error); + self.protocol_handler.stop_client_tcp(socket, &mode)?; return Err(error); } @@ -110,10 +102,7 @@ where retry_limit -= 1; } - self.protocol_handler - .stop_client_tcp(socket, &mode) - .ok() - .unwrap(); + self.protocol_handler.stop_client_tcp(socket, &mode)?; Err(TcpError::Timeout.into()) } From 5b8fe2bec713f2cb7eba09b6aac1f9ad4991612a Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 14 Dec 2022 08:20:04 -0500 Subject: [PATCH 037/106] add first pass at send_data --- esp32-wroom-rp/src/protocol.rs | 9 ++++++++- esp32-wroom-rp/src/spi.rs | 21 +++++++++++++++++++-- esp32-wroom-rp/src/tcp_client.rs | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 771fc44..c2ed0c6 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -7,8 +7,9 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; +use super::tcp_client::TcpData; use super::wifi::ConnectionStatus; -use super::{Error, FirmwareVersion}; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use core::cell::RefCell; @@ -28,6 +29,7 @@ pub(crate) enum NinaCommand { GetHostByName = 0x35u8, GetFwVersion = 0x37u8, GetSocket = 0x3fu8, + SendDataTcp = 0x44, } pub(crate) trait NinaConcreteParam { @@ -346,6 +348,11 @@ pub(crate) trait ProtocolInterface { ) -> Result<(), Error>; fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; fn get_client_state_tcp(&mut self, socket: Socket) -> Result; + fn send_data( + &mut self, + data: TcpData, + socket: Socket, + ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error>; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 3792b67..1edf25e 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -5,12 +5,13 @@ use crate::protocol::{NinaAbstractParam, NinaWordParam}; use super::gpio::EspControlInterface; use super::protocol::{ - NinaByteParam, NinaCommand, NinaConcreteParam, NinaParam, NinaProtocolHandler, - NinaSmallArrayParam, ProtocolInterface, + NinaByteParam, NinaCommand, NinaConcreteParam, NinaLargeArrayParam, NinaParam, + NinaProtocolHandler, NinaSmallArrayParam, ProtocolInterface, }; use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; use super::protocol::{operation::Operation, ProtocolError}; +use super::tcp_client::TcpData; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -205,6 +206,22 @@ where // an error. Ok(ConnectionState::from(result[0])) } + + fn send_data( + &mut self, + data: TcpData, + socket: Socket, + ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + let operation = Operation::new(NinaCommand::SendDataTcp) + .param(NinaWordParam::from_bytes(&[socket]).into()) + .param(NinaLargeArrayParam::new(&data).into()); + + self.execute(&operation)?; + + let result = self.receive(&operation, 1)?; + + Ok(result) + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 583465b..79a6d8c 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,4 +1,4 @@ -use super::Error; +use super::{Error, ARRAY_LENGTH_PLACEHOLDER}; use crate::wifi::Wifi; use super::protocol::NinaProtocolHandler; @@ -12,6 +12,13 @@ use embedded_hal::blocking::spi::Transfer; use defmt::{write, Format, Formatter}; +use heapless::String; + +// TODO: find a good max length +const MAX_DATA_LENGTH: usize = 512; + +pub type TcpData = String; + #[derive(Debug, Eq, PartialEq)] pub enum TcpError { Timeout, @@ -67,7 +74,8 @@ where self.port = port; self.mode = mode; - self.protocol_handler.start_client_tcp(socket, ip, port, &mode)?; + self.protocol_handler + .start_client_tcp(socket, ip, port, &mode)?; // FIXME: without this delay, we'll frequently see timing issues and receive // a CmdResponseErr. We may not be handling busy/ack flag handling properly @@ -107,6 +115,11 @@ where Err(TcpError::Timeout.into()) } + pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + self.protocol_handler + .send_data(data, self.socket.unwrap_or_default()) + } + pub fn server_ip_address(&self) -> Option { self.server_ip_address } From ca0f4684272a8fd4cf92212bd85a223904740f6d Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Thu, 15 Dec 2022 14:48:56 -0600 Subject: [PATCH 038/106] TcpClient::connect() can now take an IPAddress or a &str hostname to specify the server to connect to via TCP. Also, increase total number of Nina protocol params to 6 to match Arduino firmware. --- cross/send_data_tcp/src/main.rs | 30 +++-- esp32-wroom-rp/src/protocol/operation.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 142 ++++++++++++++++------- 3 files changed, 120 insertions(+), 54 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 3a142c7..457d704 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -30,7 +30,7 @@ use hal::{clocks::Clock, pac}; use esp32_wroom_rp::{ gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, - wifi::ConnectionStatus, wifi::Wifi, tcp_client::TcpClient + tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi, }; /// The linker will place this boot block at the start of our program image. We @@ -138,20 +138,34 @@ fn main() -> ! { let _hostname = "github.com"; //let ip_address: IpAddress = [18, 195, 85, 27]; - let ip_address: IpAddress = [10, 0, 1, 4]; + let ip_address: IpAddress = [10, 0, 1, 3]; let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; - if let Err(e) = TcpClient::build(&mut wifi) - .connect(ip_address, port, mode, &mut delay, |tcp_client| { - defmt::info!("TCP connection to {:?}:{:?} successful", ip_address, port); + if let Err(e) = TcpClient::build(&mut wifi).connect( + ip_address, + port, + mode, + &mut delay, + |tcp_client| { + defmt::info!( + "TCP connection to {:?}:{:?} successful", + ip_address, + port + ); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); // this is where you send/receive with a connected TCP socket to a remote server - }) { - defmt::error!("TCP connection to {:?}:{:?} failed: {:?}", ip_address, port, e); - } + }, + ) { + defmt::error!( + "TCP connection to {:?}:{:?} failed: {:?}", + ip_address, + port, + e + ); + } defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 1ac3aae..464b6e7 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -1,7 +1,7 @@ use crate::protocol::{NinaAbstractParam, NinaCommand}; use heapless::Vec; -const MAX_NUMBER_OF_PARAMS: usize = 4; +const MAX_NUMBER_OF_PARAMS: usize = 6; // Encapsulates all information needed to execute commands against Nina Firmware. // along with user supplied data. Ex. SSID, passphrase, etc. diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 79a6d8c..51fdb00 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -16,6 +16,7 @@ use heapless::String; // TODO: find a good max length const MAX_DATA_LENGTH: usize = 512; +const MAX_HOSTNAME_LENGTH: usize = 255; pub type TcpData = String; @@ -32,13 +33,71 @@ impl Format for TcpError { } } +pub trait Connect<'a, S, B, C> { + fn connect), D: DelayMs>( + &mut self, + server: S, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error>; +} + pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, pub(crate) server_ip_address: Option, pub(crate) port: Port, pub(crate) mode: TransportMode, - pub(crate) server_hostname: Option<&'a str>, + pub(crate) server_hostname: Option>, +} + +impl<'a, B, C> Connect<'a, IpAddress, B, C> for TcpClient<'a, B, C> +where + B: Transfer, + C: EspControlInterface, +{ + fn connect), D: DelayMs>( + &mut self, + ip: IpAddress, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error> { + let socket = self.get_socket().unwrap_or_default(); + self.socket = Some(socket); + self.server_ip_address = Some(ip); + self.server_hostname = Some(String::new()); + self.port = port; + self.mode = mode; + + self.connect_common(delay, f) + } +} + +impl<'a, B, C> Connect<'a, &str, B, C> for TcpClient<'a, B, C> +where + B: Transfer, + C: EspControlInterface, +{ + fn connect), D: DelayMs>( + &mut self, + server_hostname: &str, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error> { + let socket = self.get_socket().unwrap_or_default(); + self.socket = Some(socket); + self.server_hostname = Some(server_hostname.into()); // into() makes a copy of the &str slice + self.port = port; + self.mode = mode; + + self.connect_common(delay, f) + } } impl<'a, B, C> TcpClient<'a, B, C> @@ -53,26 +112,48 @@ where server_ip_address: None, port: 0, mode: TransportMode::Tcp, - server_hostname: None, + server_hostname: Some(String::new()), } } - pub fn connect>( - mut self, - ip: IpAddress, - port: Port, - mode: TransportMode, + pub fn server_ip_address(&self) -> Option { + self.server_ip_address + } + + pub fn server_hostname(&self) -> &str { + self.server_hostname.as_ref().unwrap().as_str() + } + + pub fn port(&self) -> Port { + self.port + } + + pub fn mode(&self) -> TransportMode { + self.mode + } + + pub fn get_socket(&mut self) -> Result { + self.protocol_handler.get_socket() + } + + pub fn socket(&self) -> Socket { + self.socket.unwrap() + } + + pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + self.protocol_handler + .send_data(data, self.socket.unwrap_or_default()) + } + + fn connect_common), D: DelayMs>( + &mut self, delay: &mut D, f: F, - ) -> Result<(), Error> - where - F: Fn(&TcpClient<'a, B, C>), - { - let socket = self.get_socket().unwrap_or_default(); - self.socket = Some(socket); - self.server_ip_address = Some(ip); - self.port = port; - self.mode = mode; + ) -> Result<(), Error> { + let socket = self.socket.unwrap_or_default(); + let mode = self.mode; + let ip = self.server_ip_address.unwrap_or_default(); + let port = self.port; self.protocol_handler .start_client_tcp(socket, ip, port, &mode)?; @@ -114,33 +195,4 @@ where Err(TcpError::Timeout.into()) } - - pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { - self.protocol_handler - .send_data(data, self.socket.unwrap_or_default()) - } - - pub fn server_ip_address(&self) -> Option { - self.server_ip_address - } - - pub fn server_hostname(&self) -> Option<&'a str> { - self.server_hostname - } - - pub fn port(&self) -> Port { - self.port - } - - pub fn mode(&self) -> TransportMode { - self.mode - } - - pub fn get_socket(&mut self) -> Result { - self.protocol_handler.get_socket() - } - - pub fn socket(&self) -> Socket { - self.socket.unwrap() - } } From 2d35c3a2d97ac350ca0b97bd50600c38e0236785 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 16 Dec 2022 10:47:29 -0600 Subject: [PATCH 039/106] Introduce type alias Hostname for a hostname string slice --- esp32-wroom-rp/src/network.rs | 3 +++ esp32-wroom-rp/src/tcp_client.rs | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index a7e0d2f..f8a6cb7 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -3,6 +3,9 @@ use defmt::{write, Format, Formatter}; /// A four byte array type alias representing an IP address. pub type IpAddress = [u8; 4]; +/// A named string slice type representing a network hostname. +pub type Hostname<'a> = &'static str; + /// A TCP/UDP network port. pub type Port = u16; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 51fdb00..6c45201 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -5,7 +5,14 @@ use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; +use super::network::{ + ConnectionState, + Hostname, + IpAddress, + Port, + Socket, + TransportMode +}; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; @@ -18,6 +25,7 @@ use heapless::String; const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; +// TODO: consider if we should move this type into network.rs pub type TcpData = String; #[derive(Debug, Eq, PartialEq)] @@ -77,14 +85,14 @@ where } } -impl<'a, B, C> Connect<'a, &str, B, C> for TcpClient<'a, B, C> +impl<'a, B, C> Connect<'a, Hostname<'_>, B, C> for TcpClient<'a, B, C> where B: Transfer, C: EspControlInterface, { fn connect), D: DelayMs>( &mut self, - server_hostname: &str, + server_hostname: Hostname, port: Port, mode: TransportMode, delay: &mut D, From 91c59434607bd2eb7ef4581a17d564bffe214621 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 16 Dec 2022 10:51:19 -0600 Subject: [PATCH 040/106] Use '?' after get_socket() instead of unwrap_or_default() --- esp32-wroom-rp/src/tcp_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 6c45201..aa32e98 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -74,7 +74,7 @@ where delay: &mut D, f: F, ) -> Result<(), Error> { - let socket = self.get_socket().unwrap_or_default(); + let socket = self.get_socket()?; self.socket = Some(socket); self.server_ip_address = Some(ip); self.server_hostname = Some(String::new()); @@ -98,7 +98,7 @@ where delay: &mut D, f: F, ) -> Result<(), Error> { - let socket = self.get_socket().unwrap_or_default(); + let socket = self.get_socket()?; self.socket = Some(socket); self.server_hostname = Some(server_hostname.into()); // into() makes a copy of the &str slice self.port = port; From f92fb20078cdf0982c947d4c4c1e37f2c8ccbcd1 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 16 Dec 2022 11:19:58 -0600 Subject: [PATCH 041/106] Change back to lifetime 'a instead of unintended static lifetime for Hostname --- esp32-wroom-rp/src/network.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index f8a6cb7..13c030f 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -4,7 +4,7 @@ use defmt::{write, Format, Formatter}; pub type IpAddress = [u8; 4]; /// A named string slice type representing a network hostname. -pub type Hostname<'a> = &'static str; +pub type Hostname<'a> = &'a str; /// A TCP/UDP network port. pub type Port = u16; From a141b0541a22d9ef743010bb696de8448dfb1419 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 16 Dec 2022 12:31:24 -0500 Subject: [PATCH 042/106] using send_data compiles --- cross/send_data_tcp/Cargo.toml | 1 + cross/send_data_tcp/src/main.rs | 25 ++++++++++++++++++++++--- esp32-wroom-rp/src/protocol.rs | 3 +-- esp32-wroom-rp/src/spi.rs | 5 ++--- esp32-wroom-rp/src/tcp_client.rs | 15 ++++++--------- 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/cross/send_data_tcp/Cargo.toml b/cross/send_data_tcp/Cargo.toml index c359eeb..b11500a 100644 --- a/cross/send_data_tcp/Cargo.toml +++ b/cross/send_data_tcp/Cargo.toml @@ -25,6 +25,7 @@ cortex-m-rt = "0.7" embedded-hal = { version = "0.2", features=["unproven"] } esp32-wroom-rp = { path = "../../esp32-wroom-rp" } panic-probe = { version = "0.3.0", features = ["print-rtt"] } +heapless = "0.7.16" rp2040-hal = { version = "0.6", features=["rt", "eh1_0_alpha"] } rp2040-boot2 = { version = "0.2" } diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 457d704..c6a049d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -24,15 +24,22 @@ use panic_probe as _; use rp2040_hal as hal; use embedded_hal::spi::MODE_0; + +use core::fmt::Write; + use fugit::RateExtU32; use hal::gpio::{FloatingInput, PushPullOutput}; use hal::{clocks::Clock, pac}; +use heapless::String; + use esp32_wroom_rp::{ gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi, }; +const MAX_HTTP_DOC_LENGTH: usize = u8::MAX as usize; + /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. #[link_section = ".boot2"] @@ -138,10 +145,21 @@ fn main() -> ! { let _hostname = "github.com"; //let ip_address: IpAddress = [18, 195, 85, 27]; - let ip_address: IpAddress = [10, 0, 1, 3]; - let port: Port = 4000; + // let ip_address: IpAddress = [10, 0, 1, 3]; + let ip_address: IpAddress = [140, 82, 114, 3]; // github.com + // let port: Port = 4000; + let port: Port = 443u16; // HTTPS let mode: TransportMode = TransportMode::Tcp; + let mut http_document: String = String::from(""); + write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n", + ip_address[0], + ip_address[1], + ip_address[2], + ip_address[3], + port + ); + if let Err(e) = TcpClient::build(&mut wifi).connect( ip_address, port, @@ -155,8 +173,9 @@ fn main() -> ! { ); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); + defmt::info!("Sending HTTP Document: {:?}", http_document.as_str()); + tcp_client.send_data(&http_document); - // this is where you send/receive with a connected TCP socket to a remote server }, ) { defmt::error!( diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index c2ed0c6..c20f883 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -7,7 +7,6 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; -use super::tcp_client::TcpData; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -350,7 +349,7 @@ pub(crate) trait ProtocolInterface { fn get_client_state_tcp(&mut self, socket: Socket) -> Result; fn send_data( &mut self, - data: TcpData, + data: &str, socket: Socket, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error>; } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 1edf25e..24c94fc 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -11,7 +11,6 @@ use super::protocol::{ use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; use super::protocol::{operation::Operation, ProtocolError}; -use super::tcp_client::TcpData; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -209,12 +208,12 @@ where fn send_data( &mut self, - data: TcpData, + data: &str, socket: Socket, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { let operation = Operation::new(NinaCommand::SendDataTcp) .param(NinaWordParam::from_bytes(&[socket]).into()) - .param(NinaLargeArrayParam::new(&data).into()); + .param(NinaLargeArrayParam::new(data).into()); self.execute(&operation)?; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index aa32e98..68f9f8a 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -25,9 +25,6 @@ use heapless::String; const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; -// TODO: consider if we should move this type into network.rs -pub type TcpData = String; - #[derive(Debug, Eq, PartialEq)] pub enum TcpError { Timeout, @@ -42,7 +39,7 @@ impl Format for TcpError { } pub trait Connect<'a, S, B, C> { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, server: S, port: Port, @@ -66,7 +63,7 @@ where B: Transfer, C: EspControlInterface, { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, ip: IpAddress, port: Port, @@ -90,7 +87,7 @@ where B: Transfer, C: EspControlInterface, { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, server_hostname: Hostname, port: Port, @@ -148,12 +145,12 @@ where self.socket.unwrap() } - pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + pub fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.protocol_handler .send_data(data, self.socket.unwrap_or_default()) } - fn connect_common), D: DelayMs>( + fn connect_common), D: DelayMs>( &mut self, delay: &mut D, f: F, @@ -177,7 +174,7 @@ where while retry_limit > 0 { match self.protocol_handler.get_client_state_tcp(socket) { Ok(ConnectionState::Established) => { - f(&self); + f(self); self.protocol_handler.stop_client_tcp(socket, &mode)?; From 68cc79cda8e7cb3f2f81a03fdc47e851be2b207e Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 16 Dec 2022 18:26:06 -0500 Subject: [PATCH 043/106] use length_size in padding calculation --- esp32-wroom-rp/src/spi.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 24c94fc..e64bb40 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -242,7 +242,7 @@ where if !operation.params.is_empty() { operation.params.iter().for_each(|param| { self.send_param(param).ok(); - param_size += param.length(); + param_size += param.length_size() as u16; }); self.send_end_cmd().ok(); diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 68f9f8a..c7bd77c 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -5,14 +5,7 @@ use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{ - ConnectionState, - Hostname, - IpAddress, - Port, - Socket, - TransportMode -}; +use super::network::{ConnectionState, Hostname, IpAddress, Port, Socket, TransportMode}; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; From fc697eccf7c525a522abb5bed5f5637ae491c60f Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Sat, 17 Dec 2022 09:03:42 -0500 Subject: [PATCH 044/106] modify padding calculation for send_data --- esp32-wroom-rp/src/spi.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index e64bb40..14b7941 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -212,7 +212,7 @@ where socket: Socket, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { let operation = Operation::new(NinaCommand::SendDataTcp) - .param(NinaWordParam::from_bytes(&[socket]).into()) + .param(NinaLargeArrayParam::from_bytes(&[socket]).into()) .param(NinaLargeArrayParam::new(data).into()); self.execute(&operation)?; @@ -229,7 +229,9 @@ where C: EspControlInterface, { fn execute(&mut self, operation: &Operation

) -> Result<(), Error> { - let mut param_size: u16 = 0; + let mut total_params_length: u16 = 0; + let mut total_params_length_size: u16 = 0; + self.control_pins.wait_for_esp_select(); let number_of_params: u8 = if !operation.params.is_empty() { operation.params.len() as u8 @@ -242,15 +244,19 @@ where if !operation.params.is_empty() { operation.params.iter().for_each(|param| { self.send_param(param).ok(); - param_size += param.length_size() as u16; + + total_params_length += param.length() as u16; + total_params_length_size += param.length_size() as u16; }); self.send_end_cmd().ok(); // This is to make sure we align correctly - // 4 (start byte, command byte, number of params, end byte) + 1 byte for each param + the sum of all param lengths + // 4 (start byte, command byte, number of params as byte, end byte) + // + the number of bytes to represent the param length (1 or 2) + // + the sum of all param lengths // See https://github.com/arduino/nina-fw/blob/master/main/CommandHandler.cpp#L2153 for the actual equation. - let command_size: u16 = 4u16 + number_of_params as u16 + param_size; + let command_size: u16 = 4u16 + total_params_length_size + total_params_length; self.pad_to_multiple_of_4(command_size); } self.control_pins.esp_deselect(); From 2d5dffff49976a6290c7755316164c9ac6020eee Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 18 Dec 2022 17:05:00 -0600 Subject: [PATCH 045/106] Can use either an ip_address or hostname to connect to remote TCP server and send_data() to it --- cross/send_data_tcp/src/main.rs | 89 +++++++++++++++++++++++++------- esp32-wroom-rp/src/protocol.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 8 ++- 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index c6a049d..dea2a57 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -38,7 +38,7 @@ use esp32_wroom_rp::{ tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi, }; -const MAX_HTTP_DOC_LENGTH: usize = u8::MAX as usize; +const MAX_HTTP_DOC_LENGTH: usize = 4096 as usize; /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. @@ -142,50 +142,103 @@ fn main() -> ! { defmt::info!("set_dns result: {:?}", dns_result); - let _hostname = "github.com"; + let hostname = "github.com"; + // let ip_address: IpAddress = [140, 82, 114, 3]; // github.com - //let ip_address: IpAddress = [18, 195, 85, 27]; - // let ip_address: IpAddress = [10, 0, 1, 3]; - let ip_address: IpAddress = [140, 82, 114, 3]; // github.com - // let port: Port = 4000; - let port: Port = 443u16; // HTTPS + let port: Port = 80; let mode: TransportMode = TransportMode::Tcp; let mut http_document: String = String::from(""); - write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n", - ip_address[0], - ip_address[1], - ip_address[2], - ip_address[3], + // write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n", + // ip_address[0], + // ip_address[1], + // ip_address[2], + // ip_address[3], + // port + // ).ok().unwrap(); + + write!(http_document, "GET / HTTP/1.1\r\nHost: {}:{}\r\nAccept: */*\r\n\r\n", + hostname, port - ); + ).ok().unwrap(); + + // let request_path: String = String::from("/api/readings/add"); + // let mut http_document: String = String::from("POST "); + // http_document.push_str(&request_path).ok().unwrap(); + // http_document + // .push_str(" HTTP/1.1\r\nHost: ") + // .ok() + // .unwrap(); + // let mut host_address_str: String = String::new(); + // write!( + // host_address_str, + // "{}.{}.{}.{}:{:?}\r\n", + // ip_address[0], + // ip_address[1], + // ip_address[2], + // ip_address[3], + // port + // ) + // .unwrap(); + // http_document.push_str(&host_address_str).ok().unwrap(); + // http_document + // .push_str("User-Agent: edge/0.0.1\r\n") + // .ok() + // .unwrap(); + // http_document.push_str("Accept: */*\r\n").ok().unwrap(); + // http_document + // .push_str("Content-Type: application/json\r\n") + // .ok() + // .unwrap(); + // let temperature = 22.0; + // let humidity = 35.0; + // let pressure = 9970.0; + // let mut json_str: String = String::new(); + // write!(json_str, + // "{{\"temperature\":\"{:.1?}\",\"humidity\":\"{:.1?}\",\"pressure\":\"{:.0?}\",\"dust_concentration\":\"200\",\"air_purity\":\"Low Pollution\"}}\r\n", + // temperature, humidity, pressure / 100.0 + // ).ok().unwrap(); + // let mut content_len_str: String = String::new(); + // write!(content_len_str, "{:?}\r\n", json_str.len()) + // .ok() + // .unwrap(); + // http_document.push_str("Content-Length: ").ok().unwrap(); + // http_document.push_str(&content_len_str).ok().unwrap(); + // http_document.push_str("\r\n").ok().unwrap(); + // http_document.push_str(&json_str).ok().unwrap(); + // http_document.push_str("\r\n").ok().unwrap(); if let Err(e) = TcpClient::build(&mut wifi).connect( - ip_address, + hostname, port, mode, &mut delay, |tcp_client| { defmt::info!( "TCP connection to {:?}:{:?} successful", - ip_address, + hostname, port ); - defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + defmt::info!("Hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); defmt::info!("Sending HTTP Document: {:?}", http_document.as_str()); - tcp_client.send_data(&http_document); + match tcp_client.send_data(&http_document) { + Ok(response) => { defmt::info!("Response: {:?}", response) } + Err(e) => { defmt::error!("Response error: {:?}", e) } + } }, ) { defmt::error!( "TCP connection to {:?}:{:?} failed: {:?}", - ip_address, + hostname, port, e ); } + delay.delay_ms(100); + defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index c20f883..244c0f7 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -12,7 +12,7 @@ use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use core::cell::RefCell; -pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; +pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 4096; #[repr(u8)] #[derive(Copy, Clone, Debug)] diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index c7bd77c..8b76061 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -150,9 +150,15 @@ where ) -> Result<(), Error> { let socket = self.socket.unwrap_or_default(); let mode = self.mode; - let ip = self.server_ip_address.unwrap_or_default(); + let mut ip = self.server_ip_address.unwrap_or_default(); + let hostname = self.server_hostname.as_ref().unwrap(); let port = self.port; + if !hostname.is_empty() { + ip = self.protocol_handler.resolve(hostname.as_str()).ok().unwrap_or_default(); + defmt::debug!("Resolved ip: {:?} for hostname: {:?}", ip, hostname.as_str()); + } + self.protocol_handler .start_client_tcp(socket, ip, port, &mode)?; From 0f40a396bd922f7f1efd7bc361995236b5f49eec Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 18 Dec 2022 17:05:43 -0600 Subject: [PATCH 046/106] Remove the unused HTTP POST doc from send_data_tcp example --- cross/send_data_tcp/src/main.rs | 46 --------------------------------- 1 file changed, 46 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index dea2a57..04ddd00 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -162,52 +162,6 @@ fn main() -> ! { port ).ok().unwrap(); - // let request_path: String = String::from("/api/readings/add"); - // let mut http_document: String = String::from("POST "); - // http_document.push_str(&request_path).ok().unwrap(); - // http_document - // .push_str(" HTTP/1.1\r\nHost: ") - // .ok() - // .unwrap(); - // let mut host_address_str: String = String::new(); - // write!( - // host_address_str, - // "{}.{}.{}.{}:{:?}\r\n", - // ip_address[0], - // ip_address[1], - // ip_address[2], - // ip_address[3], - // port - // ) - // .unwrap(); - // http_document.push_str(&host_address_str).ok().unwrap(); - // http_document - // .push_str("User-Agent: edge/0.0.1\r\n") - // .ok() - // .unwrap(); - // http_document.push_str("Accept: */*\r\n").ok().unwrap(); - // http_document - // .push_str("Content-Type: application/json\r\n") - // .ok() - // .unwrap(); - // let temperature = 22.0; - // let humidity = 35.0; - // let pressure = 9970.0; - // let mut json_str: String = String::new(); - // write!(json_str, - // "{{\"temperature\":\"{:.1?}\",\"humidity\":\"{:.1?}\",\"pressure\":\"{:.0?}\",\"dust_concentration\":\"200\",\"air_purity\":\"Low Pollution\"}}\r\n", - // temperature, humidity, pressure / 100.0 - // ).ok().unwrap(); - // let mut content_len_str: String = String::new(); - // write!(content_len_str, "{:?}\r\n", json_str.len()) - // .ok() - // .unwrap(); - // http_document.push_str("Content-Length: ").ok().unwrap(); - // http_document.push_str(&content_len_str).ok().unwrap(); - // http_document.push_str("\r\n").ok().unwrap(); - // http_document.push_str(&json_str).ok().unwrap(); - // http_document.push_str("\r\n").ok().unwrap(); - if let Err(e) = TcpClient::build(&mut wifi).connect( hostname, port, From ad4470c46ea5994bffed699bc58e6380559b0e7a Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 18 Dec 2022 18:12:27 -0600 Subject: [PATCH 047/106] Provide public trait/struct/method documentation for TcpClient and a few other missing areas. --- esp32-wroom-rp/src/lib.rs | 4 +--- esp32-wroom-rp/src/spi.rs | 6 +++--- esp32-wroom-rp/src/tcp_client.rs | 20 ++++++++++++++++++++ esp32-wroom-rp/src/wifi.rs | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 7e99955..bedda52 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -98,14 +98,12 @@ pub mod protocol; mod spi; -use network::{IpAddress, NetworkError}; +use network::NetworkError; use protocol::ProtocolError; use tcp_client::TcpError; use defmt::{write, Format, Formatter}; -use self::wifi::ConnectionStatus; - const ARRAY_LENGTH_PLACEHOLDER: usize = 8; /// Highest level error types for this crate. diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 14b7941..1412f2e 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,12 +1,11 @@ //! Serial Peripheral Interface (SPI) for Wifi use crate::network::ConnectionState; -use crate::protocol::{NinaAbstractParam, NinaWordParam}; use super::gpio::EspControlInterface; use super::protocol::{ NinaByteParam, NinaCommand, NinaConcreteParam, NinaLargeArrayParam, NinaParam, - NinaProtocolHandler, NinaSmallArrayParam, ProtocolInterface, + NinaProtocolHandler, NinaSmallArrayParam, NinaWordParam, ProtocolInterface, }; use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; @@ -196,7 +195,8 @@ where } fn get_client_state_tcp(&mut self, socket: Socket) -> Result { - let operation = Operation::new(NinaCommand::GetClientStateTcp); + let operation = Operation::new(NinaCommand::GetClientStateTcp) + .param(NinaByteParam::from_bytes(&[socket]).into()); self.execute(&operation)?; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 8b76061..6304495 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -31,7 +31,11 @@ impl Format for TcpError { } } +/// Connect trait that allows for a `TcpClient` instance to connect to a remote +/// server by providing either a `Hostname` or an `IpAddress`. This trait also +/// makes it possible to implement and support IPv6 addresses. pub trait Connect<'a, S, B, C> { + /// Connects to `server` on `port` using transport layer `mode`. fn connect), D: DelayMs>( &mut self, server: S, @@ -42,6 +46,8 @@ pub trait Connect<'a, S, B, C> { ) -> Result<(), Error>; } +/// A client that connects to and performs send/receive operations with a remote +/// server using the TCP protocol. pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, @@ -103,6 +109,7 @@ where B: Transfer, C: EspControlInterface, { + /// Builds a new instance of a `TcpClient` provided a `Wifi` instance. pub fn build(wifi: &'a mut Wifi) -> Self { Self { protocol_handler: wifi.protocol_handler.get_mut(), @@ -114,35 +121,48 @@ where } } + /// Returns `IpAddress` of the remote server to communicate with that is + /// set by calling `connect()`. pub fn server_ip_address(&self) -> Option { self.server_ip_address } + /// Returns `Hostname` of the remote server to communicate with that is + /// set by calling `connect()`. pub fn server_hostname(&self) -> &str { self.server_hostname.as_ref().unwrap().as_str() } + /// Returns `Port` of the remote server to communicate with that is + /// set by calling `connect()`. pub fn port(&self) -> Port { self.port } + /// Returns `TransportMode` used in communication with the remote server that is + /// set by calling `connect()`. pub fn mode(&self) -> TransportMode { self.mode } + // TODO: Make this non-public pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } + // TODO: Make this non-public pub fn socket(&self) -> Socket { self.socket.unwrap() } + /// Sends a string slice of data to a connected server. pub fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.protocol_handler .send_data(data, self.socket.unwrap_or_default()) } + // Provides the in-common connect() functionality used by the public interface's + // connect(ip_address) or connect(hostname) instances. fn connect_common), D: DelayMs>( &mut self, delay: &mut D, diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 93c84bf..82af832 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -160,6 +160,8 @@ where self.protocol_handler.borrow_mut().resolve(hostname) } + /// Provides a reference to the `Spi` bus instance typically used when cleaning up + /// an instance of `Wifi`. pub fn destroy(self) -> S { self.protocol_handler.into_inner().bus.into_inner() } From 21eb28ec53ef343821aa99ae966ee829ae8de04b Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 18:01:00 -0800 Subject: [PATCH 048/106] move Wifi struct to wifi module --- esp32-wroom-rp/src/network.rs | 5 ++- esp32-wroom-rp/src/spi.rs | 70 +------------------------------- esp32-wroom-rp/src/wifi.rs | 76 ++++++++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 72 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index bee39c4..d5bf2b7 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -15,7 +15,10 @@ impl Format for NetworkError { fn format(&self, fmt: Formatter) { match self { NetworkError::DnsResolveFailed => { - write!(fmt, "Failed to resolve a hostname for the provided IP address") + write!( + fmt, + "Failed to resolve a hostname for the provided IP address" + ) } } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 744fc33..50bf6a6 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -9,7 +9,7 @@ use super::protocol::{ use super::network::NetworkError; use super::protocol::operation::Operation; use super::protocol::ProtocolError; -use super::{Error, FirmwareVersion, WifiCommon, ARRAY_LENGTH_PLACEHOLDER}; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use super::IpAddress; @@ -20,9 +20,6 @@ use core::convert::Infallible; use super::wifi::ConnectionStatus; -// FIXME: remove before commit -//use defmt_rtt as _; - // TODO: this should eventually move into NinaCommandHandler #[repr(u8)] #[derive(Debug)] @@ -34,71 +31,6 @@ enum ControlByte { Error = 0xEFu8, } -/// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. -#[derive(Debug)] -pub struct Wifi<'a, B, C> { - common: WifiCommon>, -} - -impl<'a, S, C> Wifi<'a, S, C> -where - S: Transfer, - C: EspControlInterface, -{ - /// Initializes the ESP32-WROOM Wifi device. - /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. - pub fn init>( - spi: &'a mut S, - esp32_control_pins: &'a mut C, - delay: &mut D, - ) -> Result, Error> { - let mut wifi = Wifi { - common: WifiCommon { - protocol_handler: NinaProtocolHandler { - bus: spi, - control_pins: esp32_control_pins, - }, - }, - }; - - wifi.common.init(delay); - Ok(wifi) - } - - /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). - pub fn firmware_version(&mut self) -> Result { - self.common.firmware_version() - } - - /// Joins a WiFi network given an SSID and a Passphrase. - pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.common.join(ssid, passphrase) - } - - /// Disconnects from a joined WiFi network. - pub fn leave(&mut self) -> Result<(), Error> { - self.common.leave() - } - - /// Retrieves the current WiFi network connection status. - /// - /// NOTE: A future version will provide a enumerated type instead of the raw integer values - /// from the NINA firmware. - pub fn get_connection_status(&mut self) -> Result { - self.common.get_connection_status() - } - - /// Sets 1 or 2 DNS servers that are used for network hostname resolution. - pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.common.set_dns(dns1, dns2) - } - - /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. - pub fn resolve(&mut self, hostname: &str) -> Result { - self.common.resolve(hostname) - } -} - // All SPI-specific aspects of the NinaProtocolHandler go here in this struct impl impl<'a, S, C> ProtocolInterface for NinaProtocolHandler<'a, S, C> where diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 488e09c..18ebe4d 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -1,5 +1,3 @@ -pub use crate::spi::Wifi; - use defmt::{write, Format, Formatter}; /// An enumerated type that represents the current WiFi network connection status. @@ -102,5 +100,79 @@ impl Format for ConnectionStatus { "Unexpected value returned from device, reset may be required" ), } + +use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::blocking::spi::Transfer; + +use super::WifiCommon; +use super::{Error, FirmwareVersion}; + +use super::gpio::EspControlInterface; +use super::protocol::NinaProtocolHandler; + +use super::IpAddress; + +/// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. +#[derive(Debug)] +pub struct Wifi<'a, B, C> { + common: WifiCommon>, +} + +impl<'a, S, C> Wifi<'a, S, C> +where + S: Transfer, + C: EspControlInterface, +{ + /// Initializes the ESP32-WROOM Wifi device. + /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. + pub fn init>( + spi: &'a mut S, + esp32_control_pins: &'a mut C, + delay: &mut D, + ) -> Result, Error> { + let mut wifi = Wifi { + common: WifiCommon { + protocol_handler: NinaProtocolHandler { + bus: spi, + control_pins: esp32_control_pins, + }, + }, + }; + + wifi.common.init(delay); + Ok(wifi) + } + + /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). + pub fn firmware_version(&mut self) -> Result { + self.common.firmware_version() + } + + /// Joins a WiFi network given an SSID and a Passphrase. + pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { + self.common.join(ssid, passphrase) + } + + /// Disconnects from a joined WiFi network. + pub fn leave(&mut self) -> Result<(), Error> { + self.common.leave() + } + + /// Retrieves the current WiFi network connection status. + /// + /// NOTE: A future version will provide a enumerated type instead of the raw integer values + /// from the NINA firmware. + pub fn get_connection_status(&mut self) -> Result { + self.common.get_connection_status() + } + + /// Sets 1 or 2 DNS servers that are used for network hostname resolution. + pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { + self.common.set_dns(dns1, dns2) + } + + /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. + pub fn resolve(&mut self, hostname: &str) -> Result { + self.common.resolve(hostname) } } From 51fc7931a87c01b36923cf8c646a62dea2a80023 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 18:08:08 -0800 Subject: [PATCH 049/106] move WifiCommon to wifi module --- esp32-wroom-rp/src/lib.rs | 47 +------------------------------- esp32-wroom-rp/src/tcp_client.rs | 0 esp32-wroom-rp/src/wifi.rs | 46 +++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 48 deletions(-) create mode 100644 esp32-wroom-rp/src/tcp_client.rs diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 3d1f3a0..bc8fb4c 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -96,10 +96,9 @@ pub mod protocol; mod spi; use network::{IpAddress, NetworkError}; -use protocol::{ProtocolError, ProtocolInterface}; +use protocol::ProtocolError; use defmt::{write, Format, Formatter}; -use embedded_hal::blocking::delay::DelayMs; use self::wifi::ConnectionStatus; @@ -181,50 +180,6 @@ impl Format for FirmwareVersion { ); } } - -#[derive(Debug)] -struct WifiCommon { - protocol_handler: PH, -} - -impl WifiCommon -where - PH: ProtocolInterface, -{ - fn init>(&mut self, delay: &mut D) { - self.protocol_handler.init(); - self.reset(delay); - } - - fn reset>(&mut self, delay: &mut D) { - self.protocol_handler.reset(delay) - } - - fn firmware_version(&mut self) -> Result { - self.protocol_handler.get_fw_version() - } - - fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.protocol_handler.set_passphrase(ssid, passphrase) - } - - fn leave(&mut self) -> Result<(), Error> { - self.protocol_handler.disconnect() - } - - fn get_connection_status(&mut self) -> Result { - self.protocol_handler.get_conn_status() - } - - fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.protocol_handler.set_dns_config(dns1, dns2) - } - - fn resolve(&mut self, hostname: &str) -> Result { - self.protocol_handler.resolve(hostname) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs new file mode 100644 index 0000000..e69de29 diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 18ebe4d..1c22000 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -104,11 +104,10 @@ impl Format for ConnectionStatus { use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; -use super::WifiCommon; use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; -use super::protocol::NinaProtocolHandler; +use super::protocol::{NinaProtocolHandler, ProtocolInterface}; use super::IpAddress; @@ -176,3 +175,46 @@ where self.common.resolve(hostname) } } + +#[derive(Debug)] +struct WifiCommon { + protocol_handler: PH, +} + +impl WifiCommon +where + PH: ProtocolInterface, +{ + fn init>(&mut self, delay: &mut D) { + self.protocol_handler.init(); + self.reset(delay); + } + + fn reset>(&mut self, delay: &mut D) { + self.protocol_handler.reset(delay) + } + + fn firmware_version(&mut self) -> Result { + self.protocol_handler.get_fw_version() + } + + fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { + self.protocol_handler.set_passphrase(ssid, passphrase) + } + + fn leave(&mut self) -> Result<(), Error> { + self.protocol_handler.disconnect() + } + + fn get_connection_status(&mut self) -> Result { + self.protocol_handler.get_conn_status() + } + + fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { + self.protocol_handler.set_dns_config(dns1, dns2) + } + + fn resolve(&mut self, hostname: &str) -> Result { + self.protocol_handler.resolve(hostname) + } +} From 217b0bf83a04faa2e44951a335aaa3ae50ae21dc Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 19:04:57 -0800 Subject: [PATCH 050/106] add tcp module and TcpClient struct --- esp32-wroom-rp/src/lib.rs | 3 +++ esp32-wroom-rp/src/tcp_client.rs | 23 +++++++++++++++++++++++ esp32-wroom-rp/src/wifi.rs | 11 +++++++++++ 3 files changed, 37 insertions(+) diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index bc8fb4c..cb308ac 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -84,6 +84,9 @@ #![warn(missing_docs)] #![cfg_attr(not(test), no_std)] +/// Fundamental interface for creating and send/receiving data to/from a TCP server. +pub mod tcp_client; + pub mod gpio; /// Fundamental interface for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. pub mod wifi; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index e69de29..64437f6 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -0,0 +1,23 @@ +use super::protocol::NinaProtocolHandler; + +use super::IpAddress; + +pub struct TcpClient<'a, 'b, B, C> { + pub(crate) common: TcpClientCommon<'a, NinaProtocolHandler<'a, B, C>>, + pub(crate) server_ip_address: Option, + pub(crate) server_hostname: Option<&'b str> +} + +pub(crate) struct TcpClientCommon<'a, PH> { + pub(crate) protocol_handler: &'a PH, +} + +impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> { + fn server_ip_address(&mut self, ip: IpAddress) { + self.server_ip_address = Some(ip); + } + + fn server_hostname(&mut self, hostname: &'b str) { + self.server_hostname = Some(hostname); + } +} diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 1c22000..6c593e0 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -108,6 +108,7 @@ use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; +use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; @@ -174,6 +175,16 @@ where pub fn resolve(&mut self, hostname: &str) -> Result { self.common.resolve(hostname) } + + pub fn build_tcp_client(&self) -> TcpClient { + TcpClient { + common: TcpClientCommon { + protocol_handler: &self.common.protocol_handler + }, + server_ip_address: None, + server_hostname: None + } + } } #[derive(Debug)] From 638f60d6720518a4a735dfcca281f94518270f2c Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 18 Nov 2022 07:04:48 -0800 Subject: [PATCH 051/106] add get_socket method to TcpClient --- esp32-wroom-rp/src/network.rs | 2 ++ esp32-wroom-rp/src/protocol.rs | 8 +++-- esp32-wroom-rp/src/protocol/operation.rs | 2 +- esp32-wroom-rp/src/spi.rs | 15 +++++++-- esp32-wroom-rp/src/tcp_client.rs | 43 +++++++++++++++++++----- esp32-wroom-rp/src/wifi.rs | 6 ++-- 6 files changed, 58 insertions(+), 18 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index d5bf2b7..a5b6373 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -3,6 +3,8 @@ use defmt::{write, Format, Formatter}; /// A four byte array type alias representing an IP address. pub type IpAddress = [u8; 4]; +pub type Socket = u8; + /// Errors that occur due to issues involving communication over /// WiFi network. #[derive(PartialEq, Eq, Debug)] diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index c0e0a45..3e200b2 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -1,15 +1,17 @@ pub(crate) mod operation; -use super::*; - use embedded_hal::blocking::delay::DelayMs; use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; + use super::wifi::ConnectionStatus; +use super::network::{IpAddress, Socket}; +use super::{Error, FirmwareVersion}; + pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; #[repr(u8)] @@ -22,6 +24,7 @@ pub(crate) enum NinaCommand { SetDNSConfig = 0x15u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, + GetSocket = 0x3fu8, } pub(crate) trait NinaParam { @@ -238,6 +241,7 @@ pub(crate) trait ProtocolInterface { fn req_host_by_name(&mut self, hostname: &str) -> Result; fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; fn resolve(&mut self, hostname: &str) -> Result; + fn get_socket(&mut self) -> Result; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 383076f..70f729d 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -1,4 +1,4 @@ -use super::protocol::NinaCommand; +use crate::protocol::NinaCommand; use heapless::Vec; const MAX_NUMBER_OF_PARAMS: usize = 4; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 50bf6a6..abf7e31 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -6,13 +6,11 @@ use super::protocol::{ ProtocolInterface, }; -use super::network::NetworkError; +use super::network::{IpAddress, NetworkError, Socket}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; -use super::IpAddress; - use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; @@ -149,6 +147,17 @@ where Err(NetworkError::DnsResolveFailed.into()) } } + + fn get_socket(&mut self) -> Result { + let operation = + Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("")); + + self.execute(&operation)?; + + let result = self.receive(&operation)?; + + Ok(result[0]) + } } impl<'a, S, C> NinaProtocolHandler<'a, S, C> diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 64437f6..b3d0c1a 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,23 +1,48 @@ +use super::Error; + use super::protocol::NinaProtocolHandler; +use crate::gpio::EspControlInterface; +use crate::protocol::ProtocolInterface; + +use super::network::{IpAddress, Socket}; -use super::IpAddress; +use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, 'b, B, C> { pub(crate) common: TcpClientCommon<'a, NinaProtocolHandler<'a, B, C>>, pub(crate) server_ip_address: Option, - pub(crate) server_hostname: Option<&'b str> + pub(crate) server_hostname: Option<&'b str>, } -pub(crate) struct TcpClientCommon<'a, PH> { - pub(crate) protocol_handler: &'a PH, -} - -impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> { - fn server_ip_address(&mut self, ip: IpAddress) { +impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> +where + B: Transfer, + C: EspControlInterface, +{ + fn server_ip_address(mut self, ip: IpAddress) -> Self { self.server_ip_address = Some(ip); + self } - fn server_hostname(&mut self, hostname: &'b str) { + fn server_hostname(mut self, hostname: &'b str) -> Self { self.server_hostname = Some(hostname); + self + } + + fn get_socket(&mut self) -> Result { + self.common.get_socket() + } +} + +pub(crate) struct TcpClientCommon<'a, PH> { + pub(crate) protocol_handler: &'a mut PH, +} + +impl<'a, PH> TcpClientCommon<'a, PH> +where + PH: ProtocolInterface, +{ + fn get_socket(&mut self) -> Result { + self.protocol_handler.get_socket() } } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 6c593e0..45942ca 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -176,13 +176,13 @@ where self.common.resolve(hostname) } - pub fn build_tcp_client(&self) -> TcpClient { + pub fn build_tcp_client(&'a mut self) -> TcpClient { TcpClient { common: TcpClientCommon { - protocol_handler: &self.common.protocol_handler + protocol_handler: &mut self.common.protocol_handler, }, server_ip_address: None, - server_hostname: None + server_hostname: None, } } } From 1a89a5d82ac6ac935d55aee2f610cb9f62f2f740 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 20 Nov 2022 13:42:38 -0600 Subject: [PATCH 052/106] Add the beginnings of a new example to demonstrate sending data over a TCP socket --- cross/Cargo.toml | 3 +- cross/send_data_tcp/Cargo.toml | 41 ++++++ cross/send_data_tcp/src/main.rs | 164 +++++++++++++++++++++ cross/send_data_tcp/src/secrets/secrets.rs | 7 + 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 cross/send_data_tcp/Cargo.toml create mode 100644 cross/send_data_tcp/src/main.rs create mode 100644 cross/send_data_tcp/src/secrets/secrets.rs diff --git a/cross/Cargo.toml b/cross/Cargo.toml index 6d78c56..4d4e89a 100644 --- a/cross/Cargo.toml +++ b/cross/Cargo.toml @@ -1,8 +1,9 @@ [workspace] members = [ + "dns", "get_fw_version", "join", - "dns" + "send_data_tcp" ] [profile.dev] diff --git a/cross/send_data_tcp/Cargo.toml b/cross/send_data_tcp/Cargo.toml new file mode 100644 index 0000000..c359eeb --- /dev/null +++ b/cross/send_data_tcp/Cargo.toml @@ -0,0 +1,41 @@ +[package] +authors = [ + "Jim Hodapp", + "Caleb Bourg", + "Dilyn Corner", + "Glyn Matthews" +] +edition = "2021" +name = "send_data_tcp" +version = "0.1.0" +description = "Example RP2040 target application that demonstrates how to send data to a remote server over TCP." + +# makes `cargo check --all-targets` work +[[bin]] +name = "send_data_tcp" +bench = false +doctest = false +test = false + +[dependencies] +defmt = "0.3.0" +defmt-rtt = "0.3.0" +cortex-m = "0.7" +cortex-m-rt = "0.7" +embedded-hal = { version = "0.2", features=["unproven"] } +esp32-wroom-rp = { path = "../../esp32-wroom-rp" } +panic-probe = { version = "0.3.0", features = ["print-rtt"] } + +rp2040-hal = { version = "0.6", features=["rt", "eh1_0_alpha"] } +rp2040-boot2 = { version = "0.2" } +fugit = "0.3" + +[features] +default = ['defmt-default'] +# these features are required by defmt +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs new file mode 100644 index 0000000..9af2667 --- /dev/null +++ b/cross/send_data_tcp/src/main.rs @@ -0,0 +1,164 @@ +//! # ESP32-WROOM-RP Pico Wireless Example +//! +//! This application demonstrates how to use the ESP32-WROOM-RP crate to +//! send data to a remote server over TCP. +//! +//! See the `Cargo.toml` file for Copyright and license details. + +#![no_std] +#![no_main] + +extern crate esp32_wroom_rp; + +include!("secrets/secrets.rs"); + +// The macro for our start-up function +use cortex_m_rt::entry; + +// Needed for debug output symbols to be linked in binary image +use defmt_rtt as _; + +use panic_probe as _; + +// Alias for our HAL crate +use rp2040_hal as hal; + +use embedded_hal::spi::MODE_0; +use fugit::RateExtU32; +use hal::gpio::{ + bank0::Gpio10, bank0::Gpio11, bank0::Gpio2, bank0::Gpio7, FloatingInput, Pin, PushPullOutput, +}; +use hal::{clocks::Clock, pac, spi::Enabled}; + +use esp32_wroom_rp::{gpio::EspControlPins, network::IpAddress, wifi::Wifi, Error}; + +/// The linker will place this boot block at the start of our program image. We +/// need this to help the ROM bootloader get our code up and running. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; + +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +type Spi = hal::Spi; +type Pins = EspControlPins< + Pin, + Pin, + Pin, + Pin, +>; + +/// Entry point to our bare-metal application. +/// +/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function +/// as soon as all global variables are initialized. +#[entry] +fn main() -> ! { + // Grab our singleton objects + let mut pac = pac::Peripherals::take().unwrap(); + let core = pac::CorePeripherals::take().unwrap(); + + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); + + // The single-cycle I/O block controls our GPIO pins + let sio = hal::Sio::new(pac.SIO); + + // Set the pins to their default state + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + defmt::info!("ESP32-WROOM-RP example to send data over TCP socket"); + + // These are implicitly used by the spi driver if they are in the correct mode + let _spi_miso = pins.gpio16.into_mode::(); + let _spi_sclk = pins.gpio18.into_mode::(); + let _spi_mosi = pins.gpio19.into_mode::(); + + let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); + + // Exchange the uninitialized SPI driver for an initialized one + let mut spi = spi.init( + &mut pac.RESETS, + clocks.peripheral_clock.freq(), + 8.MHz(), + &MODE_0, + ); + + let mut esp_pins = EspControlPins { + // CS on pin x (GPIO7) + cs: pins.gpio7.into_mode::(), + // GPIO0 on pin x (GPIO2) + gpio0: pins.gpio2.into_mode::(), + // RESETn on pin x (GPIO11) + resetn: pins.gpio11.into_mode::(), + // ACK on pin x (GPIO10) + ack: pins.gpio10.into_mode::(), + }; + + let mut wifi = Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + + let result = wifi.join(SSID, PASSPHRASE); + defmt::info!("Join Result: {:?}", result); + + defmt::info!("Entering main loop"); + + let mut sleep: u32 = 1500; + loop { + match wifi.get_connection_status() { + Ok(byte) => { + defmt::info!("Get Connection Result: {:?}", byte); + delay.delay_ms(sleep); + + if byte == 3 { + defmt::info!("Connected to Network: {:?}", SSID); + + // The IPAddresses of two DNS servers to resolve hostnames with. + // Note that failover from ip1 to ip2 is fully functional. + let ip1: IpAddress = [9, 9, 9, 9]; + let ip2: IpAddress = [8, 8, 8, 8]; + let dns_result = wifi.set_dns(ip1, Some(ip2)); + + defmt::info!("set_dns result: {:?}", dns_result); + + let _hostname = "github.com"; + + let _result = send_http_get(&wifi); + + wifi.leave().ok(); + } else if byte == 6 { + defmt::info!("Disconnected from Network: {:?}", SSID); + sleep = 20000; // No need to loop as often after disconnecting + } + } + Err(e) => { + defmt::info!("Failed to Get Connection Result: {:?}", e); + } + } + } +} + +fn send_http_get(_wifi: &Wifi) -> Result<(), Error> { + Ok(()) +} diff --git a/cross/send_data_tcp/src/secrets/secrets.rs b/cross/send_data_tcp/src/secrets/secrets.rs new file mode 100644 index 0000000..d4bd861 --- /dev/null +++ b/cross/send_data_tcp/src/secrets/secrets.rs @@ -0,0 +1,7 @@ +// +// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across +// all example applications +// + +const SSID: &str = "ssid"; +const PASSPHRASE: &str = "passphrase"; From 351487aeb57f19dfa993b6e2a1cb5b71cb5c2322 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 20 Nov 2022 13:43:24 -0600 Subject: [PATCH 053/106] Delay longer in the DNS/Join examples after disconnected from WiFi network --- cross/dns/src/main.rs | 2 ++ cross/join/src/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 8246120..235beba 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -115,6 +115,7 @@ fn main() -> ! { defmt::info!("Entering main loop"); + let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(status) => { @@ -149,6 +150,7 @@ fn main() -> ! { wifi.leave().ok().unwrap(); } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); + sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 1c23f06..0a4a9d8 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -114,6 +114,7 @@ fn main() -> ! { defmt::info!("Entering main loop"); + let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(status) => { @@ -130,8 +131,7 @@ fn main() -> ! { wifi.leave().ok().unwrap(); } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); - } else { - defmt::info!("Unhandled WiFi connection status: {:?}", status); + sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { From 717a0aa9c0c4dbaee1f9d2a7247175c71a765829 Mon Sep 17 00:00:00 2001 From: Dilyn Corner Date: Mon, 21 Nov 2022 19:30:49 -0500 Subject: [PATCH 054/106] Create and use the ConnectionStatus enum --- .gitignore | 1 + cross/dns/src/main.rs | 1 + cross/join/src/main.rs | 3 + esp32-wroom-rp/src/lib.rs | 1 + esp32-wroom-rp/src/protocol.rs | 3 +- esp32-wroom-rp/src/spi.rs | 3 +- esp32-wroom-rp/src/wifi.rs | 107 ++++++++++++++++++++++++++++++++- 7 files changed, 116 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 76221b4..b2f967c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # will have compiled files and executables /target/ /cross/target/ +/esp32-wroom-rp/target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 235beba..362233e 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -120,6 +120,7 @@ fn main() -> ! { match wifi.get_connection_status() { Ok(status) => { defmt::info!("Get Connection Result: {:?}", status); + let sleep: u32 = 1500; delay.delay_ms(sleep); diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 0a4a9d8..6b6e991 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -119,6 +119,7 @@ fn main() -> ! { match wifi.get_connection_status() { Ok(status) => { defmt::info!("Get Connection Result: {:?}", status); + let sleep: u32 = 1500; delay.delay_ms(sleep); @@ -132,6 +133,8 @@ fn main() -> ! { } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting + } else { + defmt::info!("Unhandled WiFi connection status: {:?}", status); } } Err(e) => { diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index cb308ac..5f8e34e 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -183,6 +183,7 @@ impl Format for FirmwareVersion { ); } } + #[cfg(test)] mod tests { use super::*; diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 3e200b2..0c08054 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,11 +6,12 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; - use super::wifi::ConnectionStatus; use super::network::{IpAddress, Socket}; use super::{Error, FirmwareVersion}; +use super::network::{IpAddress, Socket}; +use super::wifi::ConnectionStatus; pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index abf7e31..868298c 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -6,10 +6,11 @@ use super::protocol::{ ProtocolInterface, }; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use super::network::{IpAddress, NetworkError, Socket}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; -use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; +use super::wifi::ConnectionStatus; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 45942ca..86fee7f 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -104,6 +104,8 @@ impl Format for ConnectionStatus { use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; +use defmt::{write, Format, Formatter}; + use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; @@ -112,6 +114,109 @@ use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; +/// An enumerated type that represents the current WiFi network connection status. +#[repr(u8)] +#[derive(Eq, PartialEq, PartialOrd, Debug)] +pub enum ConnectionStatus { + /// No device is connected to hardware + NoEsp32 = 255, + /// Temporary status while attempting to connect to WiFi network + Idle = 0, + /// No SSID is available + NoActiveSsid, + /// WiFi network scan has finished + ScanCompleted, + /// Device is connected to WiFi network + Connected, + /// Device failed to connect to WiFi network + Failed, + /// Device lost connection to WiFi network + Lost, + /// Device disconnected from WiFi network + Disconnected, + /// Device is listening for connections in Access Point mode + ApListening, + /// Device is connected in Access Point mode + ApConnected, + /// Device failed to make connection in Access Point mode + ApFailed, + /// Unexpected value returned from device, reset may be required + Invalid, +} + +impl From for ConnectionStatus { + fn from(status: u8) -> ConnectionStatus { + match status { + 0 => ConnectionStatus::Idle, + 1 => ConnectionStatus::NoActiveSsid, + 2 => ConnectionStatus::ScanCompleted, + 3 => ConnectionStatus::Connected, + 4 => ConnectionStatus::Failed, + 5 => ConnectionStatus::Lost, + 6 => ConnectionStatus::Disconnected, + 7 => ConnectionStatus::ApListening, + 8 => ConnectionStatus::ApConnected, + 9 => ConnectionStatus::ApFailed, + 255 => ConnectionStatus::NoEsp32, + _ => ConnectionStatus::Invalid, + } + } +} + +impl Format for ConnectionStatus { + fn format(&self, fmt: Formatter) { + match self { + ConnectionStatus::NoEsp32 => write!( + fmt,"No device is connected to hardware" + ), + ConnectionStatus::Idle => write!( + fmt, + "Temporary status while attempting to connect to WiFi network" + ), + ConnectionStatus::NoActiveSsid => write!( + fmt, + "No SSID is available" + ), + ConnectionStatus::ScanCompleted => write!( + fmt, + "WiFi network scan has finished" + ), + ConnectionStatus::Connected => write!( + fmt, + "Device is connected to WiFi network" + ), + ConnectionStatus::Failed => write!( + fmt, + "Device failed to connect to WiFi network" + ), + ConnectionStatus::Lost => write!( + fmt, + "Device lost connection to WiFi network" + ), + ConnectionStatus::Disconnected => write!( + fmt, + "Device disconnected from WiFi network" + ), + ConnectionStatus::ApListening => write!( + fmt, + "Device is lstening for connections in Access Point mode" + ), + ConnectionStatus::ApConnected => write!( + fmt, + "Device is connected in Access Point mode" + ), + ConnectionStatus::ApFailed => write!( + fmt, + "Device failed to make connection in Access Point mode" + ), + ConnectionStatus::Invalid => write!( + fmt, + "Unexpected value returned from device, reset may be required" + ), + } + } +} + /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi<'a, B, C> { @@ -217,7 +322,7 @@ where self.protocol_handler.disconnect() } - fn get_connection_status(&mut self) -> Result { + fn get_connection_status(&mut self) -> Result { self.protocol_handler.get_conn_status() } From a2cc61a77f80b0a06c93b1d0aea2066e1df3e1e4 Mon Sep 17 00:00:00 2001 From: Dilyn Corner Date: Tue, 22 Nov 2022 15:29:08 -0500 Subject: [PATCH 055/106] Implement basic Format trait for ConnectionStatus --- esp32-wroom-rp/src/wifi.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 86fee7f..5eec26f 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -114,6 +114,8 @@ use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; +use defmt::{write, Format, Formatter}; + /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] #[derive(Eq, PartialEq, PartialOrd, Debug)] From 761bdb64cf9cd18ec963f38b12418196c07fcbed Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 17 Nov 2022 18:01:00 -0800 Subject: [PATCH 056/106] move Wifi struct to wifi module --- esp32-wroom-rp/src/wifi.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 5eec26f..86fee7f 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -114,8 +114,6 @@ use super::tcp_client::{TcpClient, TcpClientCommon}; use super::IpAddress; -use defmt::{write, Format, Formatter}; - /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] #[derive(Eq, PartialEq, PartialOrd, Debug)] From 57d810f453624cd90fb8caf03a7983446fd2f5d5 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 20 Nov 2022 13:43:24 -0600 Subject: [PATCH 057/106] Delay longer in the DNS/Join examples after disconnected from WiFi network --- cross/join/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 6b6e991..7d3795b 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -135,6 +135,7 @@ fn main() -> ! { sleep = 20000; // No need to loop as often after disconnecting } else { defmt::info!("Unhandled WiFi connection status: {:?}", status); + sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { From b73f74a06b6e0221a20f26bf979ae875b0596875 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 28 Nov 2022 11:07:20 -0800 Subject: [PATCH 058/106] Rebased with main branch to get ConnectionStatus changes. --- cross/send_data_tcp/src/main.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 9af2667..5705777 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -30,7 +30,13 @@ use hal::gpio::{ }; use hal::{clocks::Clock, pac, spi::Enabled}; -use esp32_wroom_rp::{gpio::EspControlPins, network::IpAddress, wifi::Wifi, Error}; +use esp32_wroom_rp::{ + Error, + gpio::EspControlPins, + network::IpAddress, + wifi::ConnectionStatus, + wifi::Wifi +}; /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. @@ -127,11 +133,11 @@ fn main() -> ! { let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { - Ok(byte) => { - defmt::info!("Get Connection Result: {:?}", byte); + Ok(status) => { + defmt::info!("Get Connection Result: {:?}", status); delay.delay_ms(sleep); - if byte == 3 { + if status == ConnectionStatus::Connected { defmt::info!("Connected to Network: {:?}", SSID); // The IPAddresses of two DNS servers to resolve hostnames with. @@ -147,7 +153,7 @@ fn main() -> ! { let _result = send_http_get(&wifi); wifi.leave().ok(); - } else if byte == 6 { + } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting } From f59fd7932ead2e25ca5a21deffc3189319055329 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 15:00:38 -0800 Subject: [PATCH 059/106] remove WifiCommon --- esp32-wroom-rp/src/protocol.rs | 2 - esp32-wroom-rp/src/spi.rs | 2 +- esp32-wroom-rp/src/wifi.rs | 146 +++++++++------------------------ 3 files changed, 41 insertions(+), 109 deletions(-) diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 0c08054..ef6f1cb 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -10,8 +10,6 @@ use super::wifi::ConnectionStatus; use super::network::{IpAddress, Socket}; use super::{Error, FirmwareVersion}; -use super::network::{IpAddress, Socket}; -use super::wifi::ConnectionStatus; pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 868298c..60e408a 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -6,11 +6,11 @@ use super::protocol::{ ProtocolInterface, }; -use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use super::network::{IpAddress, NetworkError, Socket}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; use super::wifi::ConnectionStatus; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 86fee7f..bd7f678 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -147,18 +147,18 @@ pub enum ConnectionStatus { impl From for ConnectionStatus { fn from(status: u8) -> ConnectionStatus { match status { - 0 => ConnectionStatus::Idle, - 1 => ConnectionStatus::NoActiveSsid, - 2 => ConnectionStatus::ScanCompleted, - 3 => ConnectionStatus::Connected, - 4 => ConnectionStatus::Failed, - 5 => ConnectionStatus::Lost, - 6 => ConnectionStatus::Disconnected, - 7 => ConnectionStatus::ApListening, - 8 => ConnectionStatus::ApConnected, - 9 => ConnectionStatus::ApFailed, + 0 => ConnectionStatus::Idle, + 1 => ConnectionStatus::NoActiveSsid, + 2 => ConnectionStatus::ScanCompleted, + 3 => ConnectionStatus::Connected, + 4 => ConnectionStatus::Failed, + 5 => ConnectionStatus::Lost, + 6 => ConnectionStatus::Disconnected, + 7 => ConnectionStatus::ApListening, + 8 => ConnectionStatus::ApConnected, + 9 => ConnectionStatus::ApFailed, 255 => ConnectionStatus::NoEsp32, - _ => ConnectionStatus::Invalid, + _ => ConnectionStatus::Invalid, } } } @@ -166,53 +166,31 @@ impl From for ConnectionStatus { impl Format for ConnectionStatus { fn format(&self, fmt: Formatter) { match self { - ConnectionStatus::NoEsp32 => write!( - fmt,"No device is connected to hardware" - ), + ConnectionStatus::NoEsp32 => write!(fmt, "No device is connected to hardware"), ConnectionStatus::Idle => write!( fmt, "Temporary status while attempting to connect to WiFi network" - ), - ConnectionStatus::NoActiveSsid => write!( - fmt, - "No SSID is available" - ), - ConnectionStatus::ScanCompleted => write!( - fmt, - "WiFi network scan has finished" - ), - ConnectionStatus::Connected => write!( - fmt, - "Device is connected to WiFi network" - ), - ConnectionStatus::Failed => write!( - fmt, - "Device failed to connect to WiFi network" - ), - ConnectionStatus::Lost => write!( - fmt, - "Device lost connection to WiFi network" - ), - ConnectionStatus::Disconnected => write!( - fmt, - "Device disconnected from WiFi network" - ), + ), + ConnectionStatus::NoActiveSsid => write!(fmt, "No SSID is available"), + ConnectionStatus::ScanCompleted => write!(fmt, "WiFi network scan has finished"), + ConnectionStatus::Connected => write!(fmt, "Device is connected to WiFi network"), + ConnectionStatus::Failed => write!(fmt, "Device failed to connect to WiFi network"), + ConnectionStatus::Lost => write!(fmt, "Device lost connection to WiFi network"), + ConnectionStatus::Disconnected => write!(fmt, "Device disconnected from WiFi network"), ConnectionStatus::ApListening => write!( fmt, "Device is lstening for connections in Access Point mode" - ), - ConnectionStatus::ApConnected => write!( - fmt, - "Device is connected in Access Point mode" - ), - ConnectionStatus::ApFailed => write!( - fmt, - "Device failed to make connection in Access Point mode" - ), + ), + ConnectionStatus::ApConnected => { + write!(fmt, "Device is connected in Access Point mode") + } + ConnectionStatus::ApFailed => { + write!(fmt, "Device failed to make connection in Access Point mode") + } ConnectionStatus::Invalid => write!( fmt, "Unexpected value returned from device, reset may be required" - ), + ), } } } @@ -220,7 +198,7 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi<'a, B, C> { - common: WifiCommon>, + protocol_handler: NinaProtocolHandler<'a, B, C>, } impl<'a, S, C> Wifi<'a, S, C> @@ -236,31 +214,30 @@ where delay: &mut D, ) -> Result, Error> { let mut wifi = Wifi { - common: WifiCommon { - protocol_handler: NinaProtocolHandler { - bus: spi, - control_pins: esp32_control_pins, - }, + protocol_handler: NinaProtocolHandler { + bus: spi, + control_pins: esp32_control_pins, }, }; - wifi.common.init(delay); + wifi.protocol_handler.init(); + wifi.protocol_handler.reset(delay); Ok(wifi) } /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). pub fn firmware_version(&mut self) -> Result { - self.common.firmware_version() + self.protocol_handler.get_fw_version() } /// Joins a WiFi network given an SSID and a Passphrase. pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.common.join(ssid, passphrase) + self.protocol_handler.set_passphrase(ssid, passphrase) } /// Disconnects from a joined WiFi network. pub fn leave(&mut self) -> Result<(), Error> { - self.common.leave() + self.protocol_handler.disconnect() } /// Retrieves the current WiFi network connection status. @@ -268,69 +245,26 @@ where /// NOTE: A future version will provide a enumerated type instead of the raw integer values /// from the NINA firmware. pub fn get_connection_status(&mut self) -> Result { - self.common.get_connection_status() + self.protocol_handler.get_conn_status() } /// Sets 1 or 2 DNS servers that are used for network hostname resolution. pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.common.set_dns(dns1, dns2) + self.protocol_handler.set_dns_config(dns1, dns2) } /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. pub fn resolve(&mut self, hostname: &str) -> Result { - self.common.resolve(hostname) + self.protocol_handler.resolve(hostname) } pub fn build_tcp_client(&'a mut self) -> TcpClient { TcpClient { common: TcpClientCommon { - protocol_handler: &mut self.common.protocol_handler, + protocol_handler: &mut self.protocol_handler, }, server_ip_address: None, server_hostname: None, } } } - -#[derive(Debug)] -struct WifiCommon { - protocol_handler: PH, -} - -impl WifiCommon -where - PH: ProtocolInterface, -{ - fn init>(&mut self, delay: &mut D) { - self.protocol_handler.init(); - self.reset(delay); - } - - fn reset>(&mut self, delay: &mut D) { - self.protocol_handler.reset(delay) - } - - fn firmware_version(&mut self) -> Result { - self.protocol_handler.get_fw_version() - } - - fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.protocol_handler.set_passphrase(ssid, passphrase) - } - - fn leave(&mut self) -> Result<(), Error> { - self.protocol_handler.disconnect() - } - - fn get_connection_status(&mut self) -> Result { - self.protocol_handler.get_conn_status() - } - - fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.protocol_handler.set_dns_config(dns1, dns2) - } - - fn resolve(&mut self, hostname: &str) -> Result { - self.protocol_handler.resolve(hostname) - } -} From d6dfafe0f377513ca8ed0aff7ecca4ea6a31a6a8 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 15:37:37 -0800 Subject: [PATCH 060/106] move control pins wrap spi in RefCell --- cross/send_data_tcp/src/main.rs | 4 ++-- esp32-wroom-rp/src/protocol.rs | 6 ++++-- esp32-wroom-rp/src/spi.rs | 10 +++++----- esp32-wroom-rp/src/wifi.rs | 6 ++++-- host-tests/tests/spi.rs | 20 ++++++++++---------- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 5705777..a1b648d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -112,7 +112,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = EspControlPins { + let esp_pins = EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -123,7 +123,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index ef6f1cb..f7d8899 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -11,6 +11,8 @@ use super::wifi::ConnectionStatus; use super::network::{IpAddress, Socket}; use super::{Error, FirmwareVersion}; +use core::cell::RefCell; + pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; #[repr(u8)] @@ -246,9 +248,9 @@ pub(crate) trait ProtocolInterface { #[derive(Debug)] pub(crate) struct NinaProtocolHandler<'a, B, C> { /// A Spi or I2c instance - pub bus: &'a mut B, + pub bus: RefCell<&'a mut B>, /// An EspControlPins instance - pub control_pins: &'a mut C, + pub control_pins: C, } // TODO: look at Nina Firmware code to understand conditions diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 60e408a..4488213 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -219,7 +219,7 @@ where for byte in buf { let write_buf = &mut [byte]; - self.bus.transfer(write_buf).ok(); + self.bus.borrow_mut().transfer(write_buf).ok(); } if num_params == 0 { @@ -266,13 +266,13 @@ where fn send_end_cmd(&mut self) -> Result<(), Infallible> { let end_command: &mut [u8] = &mut [ControlByte::End as u8]; - self.bus.transfer(end_command).ok(); + self.bus.borrow_mut().transfer(end_command).ok(); Ok(()) } fn get_byte(&mut self) -> Result { let word_out = &mut [ControlByte::Dummy as u8]; - let word = self.bus.transfer(word_out).ok().unwrap(); + let word = self.bus.borrow_mut().transfer(word_out).ok().unwrap(); Ok(word[0] as u8) } @@ -303,14 +303,14 @@ where self.send_param_length(param)?; for byte in param.data().iter() { - self.bus.transfer(&mut [*byte]).ok(); + self.bus.borrow_mut().transfer(&mut [*byte]).ok(); } Ok(()) } fn send_param_length(&mut self, param: &P) -> Result<(), Infallible> { for byte in param.length_as_bytes().into_iter() { - self.bus.transfer(&mut [byte]).ok(); + self.bus.borrow_mut().transfer(&mut [byte]).ok(); } Ok(()) } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index bd7f678..218ac78 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -112,6 +112,8 @@ use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; use super::tcp_client::{TcpClient, TcpClientCommon}; +use core::cell::RefCell; + use super::IpAddress; /// An enumerated type that represents the current WiFi network connection status. @@ -210,12 +212,12 @@ where /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. pub fn init>( spi: &'a mut S, - esp32_control_pins: &'a mut C, + esp32_control_pins: C, delay: &mut D, ) -> Result, Error> { let mut wifi = Wifi { protocol_handler: NinaProtocolHandler { - bus: spi, + bus: RefCell::new(spi), control_pins: esp32_control_pins, }, }; diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 6beeddb..56a28c0 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -50,9 +50,9 @@ fn too_many_parameters_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -80,9 +80,9 @@ fn invalid_number_of_parameters_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -111,9 +111,9 @@ fn invalid_command_induces_invalid_command_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -143,9 +143,9 @@ fn timeout_induces_communication_timeout_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -173,9 +173,9 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { let mut delay = MockNoop::new(); - let mut pins = EspControlMock {}; + let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, &mut pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( From 76256398ca015a3ac3bd1b2033a303fa4b49c410 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Tue, 6 Dec 2022 18:10:59 -0600 Subject: [PATCH 061/106] Ensure all cross examples compile and work correctly with Wifi struct interface change. --- cross/dns/src/main.rs | 4 ++-- cross/get_fw_version/src/main.rs | 4 ++-- cross/join/src/main.rs | 7 ++----- cross/send_data_tcp/src/main.rs | 2 +- cross/send_data_tcp/src/secrets/secrets.rs | 7 ------- 5 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 cross/send_data_tcp/src/secrets/secrets.rs diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 362233e..ce8a5a9 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -97,7 +97,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins { + let esp_pins = esp32_wroom_rp::gpio::EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -108,7 +108,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/cross/get_fw_version/src/main.rs b/cross/get_fw_version/src/main.rs index 5acc3e1..eda2975 100644 --- a/cross/get_fw_version/src/main.rs +++ b/cross/get_fw_version/src/main.rs @@ -92,7 +92,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins { + let esp_pins = esp32_wroom_rp::gpio::EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -102,7 +102,7 @@ fn main() -> ! { // ACK on pin x (GPIO10) ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let firmware_version = wifi.firmware_version(); defmt::info!("NINA firmware version: {:?}", firmware_version); diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 7d3795b..1ad35a1 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -96,7 +96,7 @@ fn main() -> ! { &MODE_0, ); - let mut esp_pins = esp32_wroom_rp::gpio::EspControlPins { + let esp_pins = esp32_wroom_rp::gpio::EspControlPins { // CS on pin x (GPIO7) cs: pins.gpio7.into_mode::(), // GPIO0 on pin x (GPIO2) @@ -107,7 +107,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, &mut esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); @@ -133,9 +133,6 @@ fn main() -> ! { } else if status == ConnectionStatus::Disconnected { defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting - } else { - defmt::info!("Unhandled WiFi connection status: {:?}", status); - sleep = 20000; // No need to loop as often after disconnecting } } Err(e) => { diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index a1b648d..4d8b15d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -10,7 +10,7 @@ extern crate esp32_wroom_rp; -include!("secrets/secrets.rs"); +include!("../../secrets/secrets.rs"); // The macro for our start-up function use cortex_m_rt::entry; diff --git a/cross/send_data_tcp/src/secrets/secrets.rs b/cross/send_data_tcp/src/secrets/secrets.rs deleted file mode 100644 index d4bd861..0000000 --- a/cross/send_data_tcp/src/secrets/secrets.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -// secrets.rs - stores WiFi secrets like SSID, passphrase, etc shared across -// all example applications -// - -const SSID: &str = "ssid"; -const PASSPHRASE: &str = "passphrase"; From c1a517e9c354e5c6641b104c2bab885f1ca91853 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 19:24:09 -0800 Subject: [PATCH 062/106] remove TcpCommon --- esp32-wroom-rp/src/tcp_client.rs | 17 ++--------------- esp32-wroom-rp/src/wifi.rs | 6 ++---- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index b3d0c1a..fd11469 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -9,7 +9,7 @@ use super::network::{IpAddress, Socket}; use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, 'b, B, C> { - pub(crate) common: TcpClientCommon<'a, NinaProtocolHandler<'a, B, C>>, + pub(crate) protocol_handler: &'a mut NinaProtocolHandler<'a, B, C>, pub(crate) server_ip_address: Option, pub(crate) server_hostname: Option<&'b str>, } @@ -29,20 +29,7 @@ where self } - fn get_socket(&mut self) -> Result { - self.common.get_socket() - } -} - -pub(crate) struct TcpClientCommon<'a, PH> { - pub(crate) protocol_handler: &'a mut PH, -} - -impl<'a, PH> TcpClientCommon<'a, PH> -where - PH: ProtocolInterface, -{ - fn get_socket(&mut self) -> Result { + pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 218ac78..b2bc64b 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -110,7 +110,7 @@ use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; -use super::tcp_client::{TcpClient, TcpClientCommon}; +use super::tcp_client::TcpClient; use core::cell::RefCell; @@ -262,9 +262,7 @@ where pub fn build_tcp_client(&'a mut self) -> TcpClient { TcpClient { - common: TcpClientCommon { - protocol_handler: &mut self.protocol_handler, - }, + protocol_handler: &mut self.protocol_handler, server_ip_address: None, server_hostname: None, } From c4f19c12903fbe3370ba1da67bba4f17a5aa6eed Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 19:58:01 -0800 Subject: [PATCH 063/106] move spi into Wifi --- cross/dns/src/main.rs | 4 ++-- cross/get_fw_version/src/main.rs | 4 ++-- cross/join/src/main.rs | 4 ++-- cross/send_data_tcp/src/main.rs | 4 ++-- esp32-wroom-rp/src/protocol.rs | 4 ++-- esp32-wroom-rp/src/spi.rs | 4 ++-- esp32-wroom-rp/src/tcp_client.rs | 10 +++++----- esp32-wroom-rp/src/wifi.rs | 14 +++++++------- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index ce8a5a9..8d8f134 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -90,7 +90,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -108,7 +108,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/cross/get_fw_version/src/main.rs b/cross/get_fw_version/src/main.rs index eda2975..2967fb3 100644 --- a/cross/get_fw_version/src/main.rs +++ b/cross/get_fw_version/src/main.rs @@ -85,7 +85,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -102,7 +102,7 @@ fn main() -> ! { // ACK on pin x (GPIO10) ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); let firmware_version = wifi.firmware_version(); defmt::info!("NINA firmware version: {:?}", firmware_version); diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 1ad35a1..3025492 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -89,7 +89,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -107,7 +107,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = esp32_wroom_rp::wifi::Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 4d8b15d..03afc14 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -105,7 +105,7 @@ fn main() -> ! { let spi = hal::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialized SPI driver for an initialized one - let mut spi = spi.init( + let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 8.MHz(), @@ -123,7 +123,7 @@ fn main() -> ! { ack: pins.gpio10.into_mode::(), }; - let mut wifi = Wifi::init(&mut spi, esp_pins, &mut delay).unwrap(); + let mut wifi = Wifi::init(spi, esp_pins, &mut delay).unwrap(); let result = wifi.join(SSID, PASSPHRASE); defmt::info!("Join Result: {:?}", result); diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index f7d8899..ae73553 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -246,9 +246,9 @@ pub(crate) trait ProtocolInterface { } #[derive(Debug)] -pub(crate) struct NinaProtocolHandler<'a, B, C> { +pub(crate) struct NinaProtocolHandler { /// A Spi or I2c instance - pub bus: RefCell<&'a mut B>, + pub bus: RefCell, /// An EspControlPins instance pub control_pins: C, } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 4488213..7067026 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -31,7 +31,7 @@ enum ControlByte { } // All SPI-specific aspects of the NinaProtocolHandler go here in this struct impl -impl<'a, S, C> ProtocolInterface for NinaProtocolHandler<'a, S, C> +impl ProtocolInterface for NinaProtocolHandler where S: Transfer, C: EspControlInterface, @@ -161,7 +161,7 @@ where } } -impl<'a, S, C> NinaProtocolHandler<'a, S, C> +impl NinaProtocolHandler where S: Transfer, C: EspControlInterface, diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index fd11469..4530b46 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -8,13 +8,13 @@ use super::network::{IpAddress, Socket}; use embedded_hal::blocking::spi::Transfer; -pub struct TcpClient<'a, 'b, B, C> { - pub(crate) protocol_handler: &'a mut NinaProtocolHandler<'a, B, C>, +pub struct TcpClient<'a, B, C> { + pub(crate) protocol_handler: NinaProtocolHandler, pub(crate) server_ip_address: Option, - pub(crate) server_hostname: Option<&'b str>, + pub(crate) server_hostname: Option<&'a str>, } -impl<'a, 'b, B, C> TcpClient<'a, 'b, B, C> +impl<'a, B, C> TcpClient<'a, B, C> where B: Transfer, C: EspControlInterface, @@ -24,7 +24,7 @@ where self } - fn server_hostname(mut self, hostname: &'b str) -> Self { + fn server_hostname(mut self, hostname: &'a str) -> Self { self.server_hostname = Some(hostname); self } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index b2bc64b..52bed9e 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -199,11 +199,11 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] -pub struct Wifi<'a, B, C> { - protocol_handler: NinaProtocolHandler<'a, B, C>, +pub struct Wifi { + protocol_handler: NinaProtocolHandler, } -impl<'a, S, C> Wifi<'a, S, C> +impl<'a, S, C> Wifi where S: Transfer, C: EspControlInterface, @@ -211,10 +211,10 @@ where /// Initializes the ESP32-WROOM Wifi device. /// Calling this function puts the connected ESP32-WROOM device in a known good state to accept commands. pub fn init>( - spi: &'a mut S, + spi: S, esp32_control_pins: C, delay: &mut D, - ) -> Result, Error> { + ) -> Result, Error> { let mut wifi = Wifi { protocol_handler: NinaProtocolHandler { bus: RefCell::new(spi), @@ -260,9 +260,9 @@ where self.protocol_handler.resolve(hostname) } - pub fn build_tcp_client(&'a mut self) -> TcpClient { + pub fn build_tcp_client(mut self) -> TcpClient<'a, S, C> { TcpClient { - protocol_handler: &mut self.protocol_handler, + protocol_handler: self.protocol_handler, server_ip_address: None, server_hostname: None, } From 7a4af32d1f1c80de76631d7e3114fa39504c3e4c Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 6 Dec 2022 20:24:59 -0800 Subject: [PATCH 064/106] send_data_tcp compiles --- cross/send_data_tcp/src/main.rs | 7 +++++-- esp32-wroom-rp/src/tcp_client.rs | 2 +- esp32-wroom-rp/src/wifi.rs | 32 ++++++++++++++++++-------------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 03afc14..e5e5adc 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -150,7 +150,7 @@ fn main() -> ! { let _hostname = "github.com"; - let _result = send_http_get(&wifi); + let _result = send_http_get(&mut wifi); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { @@ -165,6 +165,9 @@ fn main() -> ! { } } -fn send_http_get(_wifi: &Wifi) -> Result<(), Error> { +fn send_http_get(wifi: &mut Wifi) -> Result<(), Error> { + let mut client = wifi.build_tcp_client(); + let socket = client.get_socket(); + Ok(()) } diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 4530b46..cf84880 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -9,7 +9,7 @@ use super::network::{IpAddress, Socket}; use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, B, C> { - pub(crate) protocol_handler: NinaProtocolHandler, + pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) server_ip_address: Option, pub(crate) server_hostname: Option<&'a str>, } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 52bed9e..264d460 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -200,7 +200,7 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi { - protocol_handler: NinaProtocolHandler, + protocol_handler: RefCell>, } impl<'a, S, C> Wifi @@ -215,31 +215,33 @@ where esp32_control_pins: C, delay: &mut D, ) -> Result, Error> { - let mut wifi = Wifi { - protocol_handler: NinaProtocolHandler { + let wifi = Wifi { + protocol_handler: RefCell::new(NinaProtocolHandler { bus: RefCell::new(spi), control_pins: esp32_control_pins, - }, + }), }; - wifi.protocol_handler.init(); - wifi.protocol_handler.reset(delay); + wifi.protocol_handler.borrow_mut().init(); + wifi.protocol_handler.borrow_mut().reset(delay); Ok(wifi) } /// Retrieves the NINA firmware version contained on the connected ESP32-WROOM device (e.g. 1.7.4). pub fn firmware_version(&mut self) -> Result { - self.protocol_handler.get_fw_version() + self.protocol_handler.borrow_mut().get_fw_version() } /// Joins a WiFi network given an SSID and a Passphrase. pub fn join(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.protocol_handler.set_passphrase(ssid, passphrase) + self.protocol_handler + .borrow_mut() + .set_passphrase(ssid, passphrase) } /// Disconnects from a joined WiFi network. pub fn leave(&mut self) -> Result<(), Error> { - self.protocol_handler.disconnect() + self.protocol_handler.borrow_mut().disconnect() } /// Retrieves the current WiFi network connection status. @@ -247,22 +249,24 @@ where /// NOTE: A future version will provide a enumerated type instead of the raw integer values /// from the NINA firmware. pub fn get_connection_status(&mut self) -> Result { - self.protocol_handler.get_conn_status() + self.protocol_handler.borrow_mut().get_conn_status() } /// Sets 1 or 2 DNS servers that are used for network hostname resolution. pub fn set_dns(&mut self, dns1: IpAddress, dns2: Option) -> Result<(), Error> { - self.protocol_handler.set_dns_config(dns1, dns2) + self.protocol_handler + .borrow_mut() + .set_dns_config(dns1, dns2) } /// Queries the DNS server(s) provided via [set_dns] for the associated IP address to the provided hostname. pub fn resolve(&mut self, hostname: &str) -> Result { - self.protocol_handler.resolve(hostname) + self.protocol_handler.borrow_mut().resolve(hostname) } - pub fn build_tcp_client(mut self) -> TcpClient<'a, S, C> { + pub fn build_tcp_client(&'a mut self) -> TcpClient<'a, S, C> { TcpClient { - protocol_handler: self.protocol_handler, + protocol_handler: self.protocol_handler.get_mut(), server_ip_address: None, server_hostname: None, } From 3e5e825f8f2124d513d964b4aabc3fc3710efde3 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 7 Dec 2022 05:01:17 -0800 Subject: [PATCH 065/106] update send_data_tcp --- cross/send_data_tcp/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index e5e5adc..39908c1 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -167,7 +167,9 @@ fn main() -> ! { fn send_http_get(wifi: &mut Wifi) -> Result<(), Error> { let mut client = wifi.build_tcp_client(); + defmt::info!("Getting Socket"); let socket = client.get_socket(); + defmt::info!("Get Socket Result: {:?}", socket); Ok(()) } From f60878051e665c155f13e056841c41e8ec673cad Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 7 Dec 2022 07:48:03 -0800 Subject: [PATCH 066/106] add spi_as_mut_ref --- esp32-wroom-rp/src/wifi.rs | 4 ++++ host-tests/tests/spi.rs | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 264d460..3b19606 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -271,4 +271,8 @@ where server_hostname: None, } } + + pub fn spi_as_mut_ref(&'a mut self) -> &'a mut S { + self.protocol_handler.get_mut().bus.get_mut() + } } diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 56a28c0..808ba1c 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -46,13 +46,13 @@ fn too_many_parameters_error() { // as we understand more. spi::Transaction::transfer(vec![0xff], vec![0x9]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -60,7 +60,7 @@ fn too_many_parameters_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::TooManyParameters) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -76,13 +76,13 @@ fn invalid_number_of_parameters_error() { spi::Transaction::transfer(vec![0xff], vec![0xb7]), spi::Transaction::transfer(vec![0xff], vec![0x0]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -92,7 +92,7 @@ fn invalid_number_of_parameters_error() { ) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -107,13 +107,13 @@ fn invalid_command_induces_invalid_command_error() { spi::Transaction::transfer(vec![0xff], vec![0xe0]), spi::Transaction::transfer(vec![0xff], vec![0x0]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -121,7 +121,7 @@ fn invalid_command_induces_invalid_command_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::InvalidCommand) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -139,13 +139,13 @@ fn timeout_induces_communication_timeout_error() { spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x0])) } - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -155,7 +155,7 @@ fn timeout_induces_communication_timeout_error() { ) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } #[test] @@ -169,13 +169,13 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { // wait_response_cmd() spi::Transaction::transfer(vec![0xff], vec![0xef]), ]; - let mut spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&spi_expectations); let mut delay = MockNoop::new(); let pins = EspControlMock {}; - let mut wifi = Wifi::init(&mut spi, pins, &mut delay).ok().unwrap(); + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); let f = wifi.firmware_version(); assert_eq!( @@ -185,5 +185,5 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { ) ); - spi.done(); + wifi.spi_as_mut_ref().done(); } From 3759a1929240370f3722dbebebead97c2d1b7e35 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 8 Dec 2022 05:39:28 -0800 Subject: [PATCH 067/106] add wifi.destroy() --- esp32-wroom-rp/src/wifi.rs | 4 ++-- host-tests/tests/spi.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 3b19606..fd722ae 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -272,7 +272,7 @@ where } } - pub fn spi_as_mut_ref(&'a mut self) -> &'a mut S { - self.protocol_handler.get_mut().bus.get_mut() + pub fn destroy(self) -> S { + self.protocol_handler.into_inner().bus.into_inner() } } diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 808ba1c..ebfa1be 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -60,7 +60,7 @@ fn too_many_parameters_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::TooManyParameters) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -92,7 +92,7 @@ fn invalid_number_of_parameters_error() { ) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -121,7 +121,7 @@ fn invalid_command_induces_invalid_command_error() { esp32_wroom_rp::Error::Protocol(esp32_wroom_rp::protocol::ProtocolError::InvalidCommand) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -155,7 +155,7 @@ fn timeout_induces_communication_timeout_error() { ) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } #[test] @@ -185,5 +185,5 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { ) ); - wifi.spi_as_mut_ref().done(); + wifi.destroy().done(); } From 3ba57b0242bbc12c89da102a54b022fc1889417c Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 8 Dec 2022 06:41:11 -0800 Subject: [PATCH 068/106] use closure for TcpClient operations --- cross/send_data_tcp/src/main.rs | 26 ++++++++++---------------- esp32-wroom-rp/src/tcp_client.rs | 10 ++++------ esp32-wroom-rp/src/wifi.rs | 25 ++++++++++++++++++------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 39908c1..6bc965c 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -31,11 +31,7 @@ use hal::gpio::{ use hal::{clocks::Clock, pac, spi::Enabled}; use esp32_wroom_rp::{ - Error, - gpio::EspControlPins, - network::IpAddress, - wifi::ConnectionStatus, - wifi::Wifi + gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, }; /// The linker will place this boot block at the start of our program image. We @@ -148,9 +144,16 @@ fn main() -> ! { defmt::info!("set_dns result: {:?}", dns_result); - let _hostname = "github.com"; + let hostname = "github.com"; + let ip_address: IpAddress = [18, 195, 85, 27]; - let _result = send_http_get(&mut wifi); + wifi.connect_tcp(ip_address, hostname, |tcp_client, socket| { + defmt::info!("Get Socket Result: {:?}", socket); + defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); + defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + + // this is where you could call something like tcp_client.connect() + }); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { @@ -164,12 +167,3 @@ fn main() -> ! { } } } - -fn send_http_get(wifi: &mut Wifi) -> Result<(), Error> { - let mut client = wifi.build_tcp_client(); - defmt::info!("Getting Socket"); - let socket = client.get_socket(); - defmt::info!("Get Socket Result: {:?}", socket); - - Ok(()) -} diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index cf84880..e7cc967 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -19,14 +19,12 @@ where B: Transfer, C: EspControlInterface, { - fn server_ip_address(mut self, ip: IpAddress) -> Self { - self.server_ip_address = Some(ip); - self + pub fn server_ip_address(&self) -> Option { + self.server_ip_address } - fn server_hostname(mut self, hostname: &'a str) -> Self { - self.server_hostname = Some(hostname); - self + pub fn server_hostname(&self) -> Option<&'a str> { + self.server_hostname } pub fn get_socket(&mut self) -> Result { diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index fd722ae..bab1d56 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -114,7 +114,7 @@ use super::tcp_client::TcpClient; use core::cell::RefCell; -use super::IpAddress; +use super::network::{IpAddress, Socket}; /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] @@ -264,15 +264,26 @@ where self.protocol_handler.borrow_mut().resolve(hostname) } - pub fn build_tcp_client(&'a mut self) -> TcpClient<'a, S, C> { - TcpClient { - protocol_handler: self.protocol_handler.get_mut(), - server_ip_address: None, - server_hostname: None, - } + pub fn connect_tcp(&'a mut self, ip: IpAddress, hostname: &'a str, f: F) + where + F: Fn(TcpClient<'a, S, C>, Socket), + { + let mut tcp_client = self.build_tcp_client(ip, hostname); + let socket = tcp_client.get_socket().unwrap(); + // invokes closure or function passing in tcp_client and socket + // as arguments + f(tcp_client, socket) } pub fn destroy(self) -> S { self.protocol_handler.into_inner().bus.into_inner() } + + fn build_tcp_client(&'a mut self, ip: IpAddress, hostname: &'a str) -> TcpClient<'a, S, C> { + TcpClient { + protocol_handler: self.protocol_handler.get_mut(), + server_ip_address: Some(ip), + server_hostname: Some(hostname), + } + } } From 48a514453553acacfc53decf10122e311666261f Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 8 Dec 2022 21:45:55 -0500 Subject: [PATCH 069/106] add TcpClient build and connect functions --- cross/secrets/secrets.rs | 4 ++-- cross/send_data_tcp/src/main.rs | 15 ++++++++------- esp32-wroom-rp/src/tcp_client.rs | 26 ++++++++++++++++++++++++++ esp32-wroom-rp/src/wifi.rs | 24 ++---------------------- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index d4bd861..95f689f 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = "ssid"; -const PASSPHRASE: &str = "passphrase"; +const SSID: &str = "Calebphone"; +const PASSPHRASE: &str = ""; diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 6bc965c..f38623e 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -31,7 +31,7 @@ use hal::gpio::{ use hal::{clocks::Clock, pac, spi::Enabled}; use esp32_wroom_rp::{ - gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, + gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient }; /// The linker will place this boot block at the start of our program image. We @@ -147,13 +147,14 @@ fn main() -> ! { let hostname = "github.com"; let ip_address: IpAddress = [18, 195, 85, 27]; - wifi.connect_tcp(ip_address, hostname, |tcp_client, socket| { - defmt::info!("Get Socket Result: {:?}", socket); - defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); - defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + TcpClient::build(&mut wifi) + .connect(ip_address, |tcp_client| { + defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); + defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + defmt::info!("Socket: {:?}", tcp_client.socket()); - // this is where you could call something like tcp_client.connect() - }); + // this is where you send/receive with a connected TCP socket to a remote server + }); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index e7cc967..c311e84 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,4 +1,5 @@ use super::Error; +use crate::wifi::Wifi; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; @@ -10,6 +11,7 @@ use embedded_hal::blocking::spi::Transfer; pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, + pub(crate) socket: Option, pub(crate) server_ip_address: Option, pub(crate) server_hostname: Option<&'a str>, } @@ -19,6 +21,26 @@ where B: Transfer, C: EspControlInterface, { + pub fn build(wifi: &'a mut Wifi) -> Self { + Self { + protocol_handler: wifi.protocol_handler.get_mut(), + socket: None, + server_ip_address: None, + server_hostname: None, + } + } + + pub fn connect(mut self, ip: IpAddress, f: F) + where + F: Fn(TcpClient<'a, B, C>), + { + let socket = self.get_socket().unwrap(); + self.socket = Some(socket); + self.server_ip_address = Some(ip); + + f(self) + } + pub fn server_ip_address(&self) -> Option { self.server_ip_address } @@ -30,4 +52,8 @@ where pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } + + pub fn socket(self) -> Socket { + self.socket.unwrap() + } } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index bab1d56..c692f3e 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -110,11 +110,10 @@ use super::{Error, FirmwareVersion}; use super::gpio::EspControlInterface; use super::protocol::{NinaProtocolHandler, ProtocolInterface}; -use super::tcp_client::TcpClient; use core::cell::RefCell; -use super::network::{IpAddress, Socket}; +use super::network::IpAddress; /// An enumerated type that represents the current WiFi network connection status. #[repr(u8)] @@ -200,7 +199,7 @@ impl Format for ConnectionStatus { /// Fundamental struct for controlling a connected ESP32-WROOM NINA firmware-based Wifi board. #[derive(Debug)] pub struct Wifi { - protocol_handler: RefCell>, + pub(crate) protocol_handler: RefCell>, } impl<'a, S, C> Wifi @@ -264,26 +263,7 @@ where self.protocol_handler.borrow_mut().resolve(hostname) } - pub fn connect_tcp(&'a mut self, ip: IpAddress, hostname: &'a str, f: F) - where - F: Fn(TcpClient<'a, S, C>, Socket), - { - let mut tcp_client = self.build_tcp_client(ip, hostname); - let socket = tcp_client.get_socket().unwrap(); - // invokes closure or function passing in tcp_client and socket - // as arguments - f(tcp_client, socket) - } - pub fn destroy(self) -> S { self.protocol_handler.into_inner().bus.into_inner() } - - fn build_tcp_client(&'a mut self, ip: IpAddress, hostname: &'a str) -> TcpClient<'a, S, C> { - TcpClient { - protocol_handler: self.protocol_handler.get_mut(), - server_ip_address: Some(ip), - server_hostname: Some(hostname), - } - } } From 27792b579b0776ad8eb7dffdd6f5925be938e8c9 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 9 Dec 2022 14:37:38 -0500 Subject: [PATCH 070/106] introduce NinaAbstractParam --- esp32-wroom-rp/src/protocol.rs | 104 +++++++++++++++++++++-- esp32-wroom-rp/src/protocol/operation.rs | 8 +- esp32-wroom-rp/src/spi.rs | 46 +++++----- 3 files changed, 126 insertions(+), 32 deletions(-) diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index ae73553..b229669 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -28,7 +28,7 @@ pub(crate) enum NinaCommand { GetSocket = 0x3fu8, } -pub(crate) trait NinaParam { +pub(crate) trait NinaConcreteParam { // Length of parameter in bytes type LengthAsBytes: IntoIterator; @@ -48,7 +48,7 @@ pub(crate) struct NinaNoParams { _placeholder: u8, } -impl NinaParam for NinaNoParams { +impl NinaConcreteParam for NinaNoParams { type LengthAsBytes = [u8; 0]; fn new(_data: &str) -> Self { @@ -72,6 +72,13 @@ impl NinaParam for NinaNoParams { } } +pub(crate) trait NinaParam { + fn length_as_bytes(&self) -> [u8; 2]; + fn data(&self) -> &[u8]; + fn length(&self) -> u16; + fn length_size(&self) -> u8; +} + // Used for single byte params pub(crate) struct NinaByteParam { length: u8, @@ -96,7 +103,92 @@ pub(crate) struct NinaLargeArrayParam { data: Vec, } -impl NinaParam for NinaByteParam { +pub(crate) struct NinaAbstractParam { + // Byte representation of length of data + length_as_bytes: [u8; 2], + // Data to be transfered over SPI bus + data: Vec, + // Number of bytes in data + length: u16, + // The number of bytes needed to represent + // length_as_bytes + length_size: u8, +} + +impl NinaParam for NinaAbstractParam { + fn length_as_bytes(&self) -> [u8; 2] { + self.length_as_bytes + } + + fn data(&self) -> &[u8] { + self.data.as_slice() + } + + fn length(&self) -> u16 { + self.length as u16 + } + + fn length_size(&self) -> u8 { + self.length_size + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaNoParams) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [0, 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 0, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaByteParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [concrete_param.length_as_bytes()[0], 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 1, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaWordParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [concrete_param.length_as_bytes()[0], 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 1, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaSmallArrayParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: [concrete_param.length_as_bytes()[0], 0], + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 1, + } + } +} + +impl From for NinaAbstractParam { + fn from(concrete_param: NinaLargeArrayParam) -> NinaAbstractParam { + NinaAbstractParam { + length_as_bytes: concrete_param.length_as_bytes(), + data: Vec::from_slice(concrete_param.data()).unwrap(), + length: concrete_param.length(), + length_size: 2, + } + } +} + +impl NinaConcreteParam for NinaByteParam { type LengthAsBytes = [u8; 1]; fn new(data: &str) -> Self { @@ -129,7 +221,7 @@ impl NinaParam for NinaByteParam { } } -impl NinaParam for NinaWordParam { +impl NinaConcreteParam for NinaWordParam { type LengthAsBytes = [u8; 1]; fn new(data: &str) -> Self { @@ -162,7 +254,7 @@ impl NinaParam for NinaWordParam { } } -impl NinaParam for NinaSmallArrayParam { +impl NinaConcreteParam for NinaSmallArrayParam { type LengthAsBytes = [u8; 1]; fn new(data: &str) -> Self { @@ -195,7 +287,7 @@ impl NinaParam for NinaSmallArrayParam { } } -impl NinaParam for NinaLargeArrayParam { +impl NinaConcreteParam for NinaLargeArrayParam { type LengthAsBytes = [u8; 2]; fn new(data: &str) -> Self { diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 70f729d..42295fc 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -1,4 +1,4 @@ -use crate::protocol::NinaCommand; +use crate::protocol::{NinaAbstractParam, NinaCommand}; use heapless::Vec; const MAX_NUMBER_OF_PARAMS: usize = 4; @@ -13,7 +13,7 @@ pub(crate) struct Operation

{ pub number_of_params_to_receive: u8, } -impl

Operation

{ +impl Operation { // Initializes new Operation instance. // // `has_params` defaults to `true` @@ -29,7 +29,7 @@ impl

Operation

{ // Pushes a new param into the internal `params` Vector which // builds up an internal byte stream representing one Nina command // on the data bus. - pub fn param(mut self, param: P) -> Self { + pub fn param(mut self, param: NinaAbstractParam) -> Self { self.params.push(param).ok().unwrap(); self } @@ -37,7 +37,7 @@ impl

Operation

{ // Used for denoting an Operation where no params are provided. // // Sets `has_params` to `false` - pub fn with_no_params(mut self, no_param: P) -> Self { + pub fn with_no_params(mut self, no_param: NinaAbstractParam) -> Self { self.params.push(no_param).ok().unwrap(); self.has_params = false; self diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 7067026..c52d13f 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -2,8 +2,8 @@ use super::gpio::EspControlInterface; use super::protocol::{ - NinaByteParam, NinaCommand, NinaNoParams, NinaParam, NinaProtocolHandler, NinaSmallArrayParam, - ProtocolInterface, + NinaByteParam, NinaCommand, NinaConcreteParam, NinaNoParams, NinaParam, NinaProtocolHandler, + NinaSmallArrayParam, ProtocolInterface, }; use super::network::{IpAddress, NetworkError, Socket}; @@ -47,8 +47,8 @@ where fn get_fw_version(&mut self) -> Result { // TODO: improve the ergonomics around with_no_params() - let operation = - Operation::new(NinaCommand::GetFwVersion, 1).with_no_params(NinaNoParams::new("")); + let operation = Operation::new(NinaCommand::GetFwVersion, 1) + .with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -59,8 +59,8 @@ where fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { let operation = Operation::new(NinaCommand::SetPassphrase, 1) - .param(NinaSmallArrayParam::new(ssid)) - .param(NinaSmallArrayParam::new(passphrase)); + .param(NinaSmallArrayParam::new(ssid).into()) + .param(NinaSmallArrayParam::new(passphrase).into()); self.execute(&operation)?; @@ -69,8 +69,8 @@ where } fn get_conn_status(&mut self) -> Result { - let operation = - Operation::new(NinaCommand::GetConnStatus, 1).with_no_params(NinaNoParams::new("")); + let operation = Operation::new(NinaCommand::GetConnStatus, 1) + .with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -81,7 +81,7 @@ where fn disconnect(&mut self) -> Result<(), Error> { let dummy_param = NinaByteParam::from_bytes(&[ControlByte::Dummy as u8]); - let operation = Operation::new(NinaCommand::Disconnect, 1).param(dummy_param); + let operation = Operation::new(NinaCommand::Disconnect, 1).param(dummy_param.into()); self.execute(&operation)?; @@ -94,9 +94,9 @@ where // FIXME: refactor Operation so it can take different NinaParam types let operation = Operation::new(NinaCommand::SetDNSConfig, 1) // FIXME: first param should be able to be a NinaByteParam: - .param(NinaSmallArrayParam::from_bytes(&[1])) - .param(NinaSmallArrayParam::from_bytes(&ip1)) - .param(NinaSmallArrayParam::from_bytes(&ip2.unwrap_or_default())); + .param(NinaByteParam::from_bytes(&[1]).into()) + .param(NinaSmallArrayParam::from_bytes(&ip1).into()) + .param(NinaSmallArrayParam::from_bytes(&ip2.unwrap_or_default()).into()); self.execute(&operation)?; @@ -106,8 +106,8 @@ where } fn req_host_by_name(&mut self, hostname: &str) -> Result { - let operation = - Operation::new(NinaCommand::ReqHostByName, 1).param(NinaSmallArrayParam::new(hostname)); + let operation = Operation::new(NinaCommand::ReqHostByName, 1) + .param(NinaSmallArrayParam::new(hostname).into()); self.execute(&operation)?; @@ -121,8 +121,8 @@ where } fn get_host_by_name(&mut self) -> Result<[u8; 8], Error> { - let operation = - Operation::new(NinaCommand::GetHostByName, 1).with_no_params(NinaNoParams::new("")); + let operation = Operation::new(NinaCommand::GetHostByName, 1) + .with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -151,7 +151,7 @@ where fn get_socket(&mut self) -> Result { let operation = - Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("")); + Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("").into()); self.execute(&operation)?; @@ -301,16 +301,18 @@ where fn send_param(&mut self, param: &P) -> Result<(), Infallible> { self.send_param_length(param)?; - - for byte in param.data().iter() { - self.bus.borrow_mut().transfer(&mut [*byte]).ok(); + let data_length = param.length() as usize; + let bytes = param.data(); + for i in 0..data_length { + self.bus.borrow_mut().transfer(&mut [bytes[i]]).ok(); } Ok(()) } fn send_param_length(&mut self, param: &P) -> Result<(), Infallible> { - for byte in param.length_as_bytes().into_iter() { - self.bus.borrow_mut().transfer(&mut [byte]).ok(); + let bytes = param.length_as_bytes(); + for i in 0..param.length_size() as usize { + self.bus.borrow_mut().transfer(&mut [bytes[i]]).ok(); } Ok(()) } From 0a99f8469984f27efc2f8d085fefa364ad2b1e70 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 11 Dec 2022 15:20:35 -0600 Subject: [PATCH 071/106] Improves the ergonomics of sending a NinaParam with no params --- cross/secrets/secrets.rs | 2 +- esp32-wroom-rp/src/protocol/operation.rs | 12 ++---------- esp32-wroom-rp/src/spi.rs | 12 ++++-------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index 95f689f..e97157b 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = "Calebphone"; +const SSID: &str = ""; const PASSPHRASE: &str = ""; diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 42295fc..1629cf6 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -21,7 +21,7 @@ impl Operation { Self { params: Vec::new(), command: nina_command, - has_params: true, + has_params: false, number_of_params_to_receive: number_of_nina_params_to_receive, } } @@ -31,15 +31,7 @@ impl Operation { // on the data bus. pub fn param(mut self, param: NinaAbstractParam) -> Self { self.params.push(param).ok().unwrap(); - self - } - - // Used for denoting an Operation where no params are provided. - // - // Sets `has_params` to `false` - pub fn with_no_params(mut self, no_param: NinaAbstractParam) -> Self { - self.params.push(no_param).ok().unwrap(); - self.has_params = false; + self.has_params = true; self } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index c52d13f..bacaef2 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -46,9 +46,7 @@ where } fn get_fw_version(&mut self) -> Result { - // TODO: improve the ergonomics around with_no_params() - let operation = Operation::new(NinaCommand::GetFwVersion, 1) - .with_no_params(NinaNoParams::new("").into()); + let operation = Operation::new(NinaCommand::GetFwVersion, 1); self.execute(&operation)?; @@ -69,8 +67,7 @@ where } fn get_conn_status(&mut self) -> Result { - let operation = Operation::new(NinaCommand::GetConnStatus, 1) - .with_no_params(NinaNoParams::new("").into()); + let operation = Operation::new(NinaCommand::GetConnStatus, 1); self.execute(&operation)?; @@ -121,8 +118,7 @@ where } fn get_host_by_name(&mut self) -> Result<[u8; 8], Error> { - let operation = Operation::new(NinaCommand::GetHostByName, 1) - .with_no_params(NinaNoParams::new("").into()); + let operation = Operation::new(NinaCommand::GetHostByName, 1); self.execute(&operation)?; @@ -151,7 +147,7 @@ where fn get_socket(&mut self) -> Result { let operation = - Operation::new(NinaCommand::GetSocket, 1).with_no_params(NinaNoParams::new("").into()); + Operation::new(NinaCommand::GetSocket, 1); self.execute(&operation)?; From 462ecb94e57b60dc421bf62e804a0af38bf84613 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 11 Dec 2022 17:01:49 -0600 Subject: [PATCH 072/106] Adds a start_client method that is part of the total TcpClient::connect() implementation. Also adds a Port and TransportMode parameter to TcpClient::connect()'s passed params --- cross/send_data_tcp/src/main.rs | 10 +++++++--- esp32-wroom-rp/src/network.rs | 25 +++++++++++++++++++++++- esp32-wroom-rp/src/protocol.rs | 8 ++++++-- esp32-wroom-rp/src/protocol/operation.rs | 6 ++++-- esp32-wroom-rp/src/spi.rs | 25 ++++++++++++++++++++++-- esp32-wroom-rp/src/tcp_client.rs | 24 +++++++++++++++++++---- 6 files changed, 84 insertions(+), 14 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index f38623e..0b0ec9b 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -31,7 +31,8 @@ use hal::gpio::{ use hal::{clocks::Clock, pac, spi::Enabled}; use esp32_wroom_rp::{ - gpio::EspControlPins, network::IpAddress, wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient + gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, + wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient }; /// The linker will place this boot block at the start of our program image. We @@ -144,11 +145,14 @@ fn main() -> ! { defmt::info!("set_dns result: {:?}", dns_result); - let hostname = "github.com"; + let _hostname = "github.com"; + let ip_address: IpAddress = [18, 195, 85, 27]; + let port: Port = 80; + let mode: TransportMode = TransportMode::Tcp; TcpClient::build(&mut wifi) - .connect(ip_address, |tcp_client| { + .connect(ip_address, port, mode, |tcp_client| { defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index a5b6373..f9502ca 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -3,7 +3,22 @@ use defmt::{write, Format, Formatter}; /// A four byte array type alias representing an IP address. pub type IpAddress = [u8; 4]; -pub type Socket = u8; +/// A TCP/UDP network port. +pub type Port = u16; + +pub(crate) type Socket = u8; + +/// Defines the mode types that the ESP32 firmware can be put into when starting +/// a new client or server instance +#[repr(u8)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum TransportMode { + Tcp = 0, + Udp = 1, + Tls = 2, + UdpMulticast = 3, + TlsBearSsl = 4, +} /// Errors that occur due to issues involving communication over /// WiFi network. @@ -11,6 +26,8 @@ pub type Socket = u8; pub enum NetworkError { /// Failed to resolve a hostname for the provided IP address. DnsResolveFailed, + /// Failed to start up a new TCP/UDP client instancwe. + StartClientFailed, } impl Format for NetworkError { @@ -22,6 +39,12 @@ impl Format for NetworkError { "Failed to resolve a hostname for the provided IP address" ) } + NetworkError::StartClientFailed => { + write!( + fmt, + "Failed to start up a new TCP/UDP client instance" + ) + } } } } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index b229669..7d0b3a4 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,6 +6,8 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; +use super::network::{IpAddress, Port, Socket, TransportMode}; + use super::wifi::ConnectionStatus; use super::network::{IpAddress, Socket}; @@ -18,13 +20,14 @@ pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; #[repr(u8)] #[derive(Copy, Clone, Debug)] pub(crate) enum NinaCommand { - GetFwVersion = 0x37u8, SetPassphrase = 0x11u8, + SetDNSConfig = 0x15u8, GetConnStatus = 0x20u8, + StartClient = 0x2du8, Disconnect = 0x30u8, - SetDNSConfig = 0x15u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, + GetFwVersion = 0x37u8, GetSocket = 0x3fu8, } @@ -335,6 +338,7 @@ pub(crate) trait ProtocolInterface { fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; fn resolve(&mut self, hostname: &str) -> Result; fn get_socket(&mut self) -> Result; + fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 1629cf6..b9a82f4 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -14,9 +14,11 @@ pub(crate) struct Operation

{ } impl Operation { - // Initializes new Operation instance. + // Initializes a new Operation instance with a specified command. // - // `has_params` defaults to `true` + // `number_of_nina_params_to_receive` specifies how many return parameters to expect + // when the NINA firmware replies to the command specified in `NinaCommand`. + // `has_params` defaults to `false` which allows for a NINA command with no parameters pub fn new(nina_command: NinaCommand, number_of_nina_params_to_receive: u8) -> Self { Self { params: Vec::new(), diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index bacaef2..af6a022 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,12 +1,14 @@ //! Serial Peripheral Interface (SPI) for Wifi +use crate::protocol::NinaWordParam; + use super::gpio::EspControlInterface; use super::protocol::{ - NinaByteParam, NinaCommand, NinaConcreteParam, NinaNoParams, NinaParam, NinaProtocolHandler, + NinaByteParam, NinaCommand, NinaConcreteParam, NinaParam, NinaProtocolHandler, NinaSmallArrayParam, ProtocolInterface, }; -use super::network::{IpAddress, NetworkError, Socket}; +use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; use super::protocol::operation::Operation; use super::protocol::ProtocolError; use super::wifi::ConnectionStatus; @@ -155,6 +157,25 @@ where Ok(result[0]) } + + fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { + let port_as_bytes = [((port & 0xff00) >> 8) as u8, + (port & 0xff) as u8]; + let operation = Operation::new(NinaCommand::StartClient, 1) + .param(NinaSmallArrayParam::from_bytes(&ip).into()) + .param(NinaWordParam::from_bytes(&port_as_bytes).into()) + .param(NinaByteParam::from_bytes(&[socket]).into()) + .param(NinaByteParam::from_bytes(&[*mode as u8]).into()); + + self.execute(&operation)?; + + let result = self.receive(&operation)?; + if result[0] == 1 { + Ok(()) + } else { + Err(NetworkError::StartClientFailed.into()) + } + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index c311e84..b4458ab 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,11 +1,11 @@ use super::Error; -use crate::wifi::Wifi; +use crate::{wifi::Wifi}; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{IpAddress, Socket}; +use super::network::{IpAddress, Port, Socket, TransportMode}; use embedded_hal::blocking::spi::Transfer; @@ -13,6 +13,8 @@ pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, pub(crate) server_ip_address: Option, + pub(crate) port: Port, + pub(crate) mode: TransportMode, pub(crate) server_hostname: Option<&'a str>, } @@ -26,17 +28,23 @@ where protocol_handler: wifi.protocol_handler.get_mut(), socket: None, server_ip_address: None, + port: 0, + mode: TransportMode::Tcp, server_hostname: None, } } - pub fn connect(mut self, ip: IpAddress, f: F) + pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) where F: Fn(TcpClient<'a, B, C>), { - let socket = self.get_socket().unwrap(); + let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); self.server_ip_address = Some(ip); + self.port = port; + self.mode = mode; + + self.protocol_handler.start_client(socket, ip, port, &mode); f(self) } @@ -49,6 +57,14 @@ where self.server_hostname } + pub fn port(&self) -> Port { + self.port + } + + pub fn mode(&self) -> TransportMode { + self.mode + } + pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } From 369a0aa721cc14f74b5081dc571a2300404b28b5 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 11 Dec 2022 22:22:43 -0600 Subject: [PATCH 073/106] No more need for Operations::has_params, just use Vec::is_empty() instead --- esp32-wroom-rp/src/protocol/operation.rs | 5 +---- esp32-wroom-rp/src/spi.rs | 11 +++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index b9a82f4..c42811a 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -9,7 +9,6 @@ const MAX_NUMBER_OF_PARAMS: usize = 4; pub(crate) struct Operation

{ pub params: Vec, pub command: NinaCommand, - pub has_params: bool, pub number_of_params_to_receive: u8, } @@ -18,12 +17,10 @@ impl Operation { // // `number_of_nina_params_to_receive` specifies how many return parameters to expect // when the NINA firmware replies to the command specified in `NinaCommand`. - // `has_params` defaults to `false` which allows for a NINA command with no parameters pub fn new(nina_command: NinaCommand, number_of_nina_params_to_receive: u8) -> Self { Self { params: Vec::new(), command: nina_command, - has_params: false, number_of_params_to_receive: number_of_nina_params_to_receive, } } @@ -32,8 +29,8 @@ impl Operation { // builds up an internal byte stream representing one Nina command // on the data bus. pub fn param(mut self, param: NinaAbstractParam) -> Self { + // FIXME: Vec::push() will return T when it is full, handle this gracefully self.params.push(param).ok().unwrap(); - self.has_params = true; self } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index af6a022..97d880c 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,6 +1,6 @@ //! Serial Peripheral Interface (SPI) for Wifi -use crate::protocol::NinaWordParam; +use crate::protocol::{NinaWordParam, NinaAbstractParam}; use super::gpio::EspControlInterface; use super::protocol::{ @@ -8,9 +8,8 @@ use super::protocol::{ NinaSmallArrayParam, ProtocolInterface, }; -use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; -use super::protocol::operation::Operation; -use super::protocol::ProtocolError; +use super::network::{ IpAddress, NetworkError, Port, Socket, TransportMode }; +use super::protocol::{ operation::Operation, ProtocolError }; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -186,7 +185,7 @@ where fn execute(&mut self, operation: &Operation

) -> Result<(), Error> { let mut param_size: u16 = 0; self.control_pins.wait_for_esp_select(); - let number_of_params: u8 = if operation.has_params { + let number_of_params: u8 = if !operation.params.is_empty() { operation.params.len() as u8 } else { 0 @@ -194,7 +193,7 @@ where let result = self.send_cmd(&operation.command, number_of_params); // Only send params if they are present - if operation.has_params { + if !operation.params.is_empty() { operation.params.iter().for_each(|param| { self.send_param(param).ok(); param_size += param.length(); From 2f39de239075cd05a494840c4bf4fa674a179563 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 11:52:56 -0600 Subject: [PATCH 074/106] Implement a stop_client() method that disconnects/stops an existing TCP/UDP client instance --- cross/send_data_tcp/src/main.rs | 5 +++-- esp32-wroom-rp/src/network.rs | 10 +++++++++- esp32-wroom-rp/src/protocol.rs | 4 +++- esp32-wroom-rp/src/spi.rs | 21 ++++++++++++++++++--- esp32-wroom-rp/src/tcp_client.rs | 14 +++++++++----- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 0b0ec9b..a9d2273 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -147,8 +147,9 @@ fn main() -> ! { let _hostname = "github.com"; - let ip_address: IpAddress = [18, 195, 85, 27]; - let port: Port = 80; + //let ip_address: IpAddress = [18, 195, 85, 27]; + let ip_address: IpAddress = [10, 0, 1, 3]; + let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; TcpClient::build(&mut wifi) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index f9502ca..0fe7412 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -26,8 +26,10 @@ pub enum TransportMode { pub enum NetworkError { /// Failed to resolve a hostname for the provided IP address. DnsResolveFailed, - /// Failed to start up a new TCP/UDP client instancwe. + /// Failed to start up a new TCP/UDP client instance. StartClientFailed, + /// Failed to stop an existing TCP/UDP client instance + StopClientFailed, } impl Format for NetworkError { @@ -45,6 +47,12 @@ impl Format for NetworkError { "Failed to start up a new TCP/UDP client instance" ) } + NetworkError::StopClientFailed => { + write!( + fmt, + "Failed to stop an existing TCP/UDP client instance" + ) + } } } } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 7d0b3a4..bd0ee90 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -23,7 +23,8 @@ pub(crate) enum NinaCommand { SetPassphrase = 0x11u8, SetDNSConfig = 0x15u8, GetConnStatus = 0x20u8, - StartClient = 0x2du8, + StartClientTcp = 0x2du8, + StopClientTcp = 0x2eu8, Disconnect = 0x30u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, @@ -339,6 +340,7 @@ pub(crate) trait ProtocolInterface { fn resolve(&mut self, hostname: &str) -> Result; fn get_socket(&mut self) -> Result; fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; + fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 97d880c..dc832b8 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -158,9 +158,8 @@ where } fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { - let port_as_bytes = [((port & 0xff00) >> 8) as u8, - (port & 0xff) as u8]; - let operation = Operation::new(NinaCommand::StartClient, 1) + let port_as_bytes = [((port & 0xff00) >> 8) as u8, (port & 0xff) as u8]; + let operation = Operation::new(NinaCommand::StartClientTcp, 1) .param(NinaSmallArrayParam::from_bytes(&ip).into()) .param(NinaWordParam::from_bytes(&port_as_bytes).into()) .param(NinaByteParam::from_bytes(&[socket]).into()) @@ -175,6 +174,22 @@ where Err(NetworkError::StartClientFailed.into()) } } + + // TODO: passing in TransportMode but not using, for now. It will become a way + // of stopping the right kind of client (e.g. TCP, vs UDP) + fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { + let operation = Operation::new(NinaCommand::StopClientTcp, 1) + .param(NinaByteParam::from_bytes(&[socket]).into()); + + self.execute(&operation)?; + + let result = self.receive(&operation)?; + if result[0] == 1 { + Ok(()) + } else { + Err(NetworkError::StopClientFailed.into()) + } + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index b4458ab..ec3f9d5 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -34,9 +34,9 @@ where } } - pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) + pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) -> Self where - F: Fn(TcpClient<'a, B, C>), + F: Fn(&mut TcpClient<'a, B, C>) { let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); @@ -44,9 +44,13 @@ where self.port = port; self.mode = mode; - self.protocol_handler.start_client(socket, ip, port, &mode); + self.protocol_handler.start_client(socket, ip, port, &mode).ok().unwrap(); - f(self) + f(&mut self); + + self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); + + self } pub fn server_ip_address(&self) -> Option { @@ -69,7 +73,7 @@ where self.protocol_handler.get_socket() } - pub fn socket(self) -> Socket { + pub fn socket(&self) -> Socket { self.socket.unwrap() } } From 6f414a19b44e106b5188d177089ce7fe57a7bdc5 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 14:54:06 -0600 Subject: [PATCH 075/106] Move where the expected number of params to receive are specified to what seems like a more logical place. --- esp32-wroom-rp/src/protocol/operation.rs | 7 +--- esp32-wroom-rp/src/spi.rs | 44 +++++++++++++----------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index c42811a..1ac3aae 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -9,19 +9,14 @@ const MAX_NUMBER_OF_PARAMS: usize = 4; pub(crate) struct Operation

{ pub params: Vec, pub command: NinaCommand, - pub number_of_params_to_receive: u8, } impl Operation { // Initializes a new Operation instance with a specified command. - // - // `number_of_nina_params_to_receive` specifies how many return parameters to expect - // when the NINA firmware replies to the command specified in `NinaCommand`. - pub fn new(nina_command: NinaCommand, number_of_nina_params_to_receive: u8) -> Self { + pub fn new(nina_command: NinaCommand) -> Self { Self { params: Vec::new(), command: nina_command, - number_of_params_to_receive: number_of_nina_params_to_receive, } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index dc832b8..88aa6d8 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -47,50 +47,51 @@ where } fn get_fw_version(&mut self) -> Result { - let operation = Operation::new(NinaCommand::GetFwVersion, 1); + let operation = Operation::new(NinaCommand::GetFwVersion); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(FirmwareVersion::new(result)) // e.g. 1.7.4 } fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - let operation = Operation::new(NinaCommand::SetPassphrase, 1) + let operation = Operation::new(NinaCommand::SetPassphrase) .param(NinaSmallArrayParam::new(ssid).into()) .param(NinaSmallArrayParam::new(passphrase).into()); self.execute(&operation)?; - self.receive(&operation)?; + self.receive(&operation, 1)?; Ok(()) } fn get_conn_status(&mut self) -> Result { - let operation = Operation::new(NinaCommand::GetConnStatus, 1); + let operation = Operation::new(NinaCommand::GetConnStatus); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(ConnectionStatus::from(result[0])) } fn disconnect(&mut self) -> Result<(), Error> { let dummy_param = NinaByteParam::from_bytes(&[ControlByte::Dummy as u8]); - let operation = Operation::new(NinaCommand::Disconnect, 1).param(dummy_param.into()); + let operation = Operation::new(NinaCommand::Disconnect) + .param(dummy_param.into()); self.execute(&operation)?; - self.receive(&operation)?; + self.receive(&operation, 1)?; Ok(()) } fn set_dns_config(&mut self, ip1: IpAddress, ip2: Option) -> Result<(), Error> { // FIXME: refactor Operation so it can take different NinaParam types - let operation = Operation::new(NinaCommand::SetDNSConfig, 1) + let operation = Operation::new(NinaCommand::SetDNSConfig) // FIXME: first param should be able to be a NinaByteParam: .param(NinaByteParam::from_bytes(&[1]).into()) .param(NinaSmallArrayParam::from_bytes(&ip1).into()) @@ -98,18 +99,18 @@ where self.execute(&operation)?; - self.receive(&operation)?; + self.receive(&operation, 1)?; Ok(()) } fn req_host_by_name(&mut self, hostname: &str) -> Result { - let operation = Operation::new(NinaCommand::ReqHostByName, 1) + let operation = Operation::new(NinaCommand::ReqHostByName) .param(NinaSmallArrayParam::new(hostname).into()); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; if result[0] != 1u8 { return Err(NetworkError::DnsResolveFailed.into()); @@ -119,11 +120,11 @@ where } fn get_host_by_name(&mut self) -> Result<[u8; 8], Error> { - let operation = Operation::new(NinaCommand::GetHostByName, 1); + let operation = Operation::new(NinaCommand::GetHostByName); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(result) } @@ -148,18 +149,18 @@ where fn get_socket(&mut self) -> Result { let operation = - Operation::new(NinaCommand::GetSocket, 1); + Operation::new(NinaCommand::GetSocket); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; Ok(result[0]) } fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { let port_as_bytes = [((port & 0xff00) >> 8) as u8, (port & 0xff) as u8]; - let operation = Operation::new(NinaCommand::StartClientTcp, 1) + let operation = Operation::new(NinaCommand::StartClientTcp) .param(NinaSmallArrayParam::from_bytes(&ip).into()) .param(NinaWordParam::from_bytes(&port_as_bytes).into()) .param(NinaByteParam::from_bytes(&[socket]).into()) @@ -167,7 +168,7 @@ where self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; if result[0] == 1 { Ok(()) } else { @@ -178,12 +179,12 @@ where // TODO: passing in TransportMode but not using, for now. It will become a way // of stopping the right kind of client (e.g. TCP, vs UDP) fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { - let operation = Operation::new(NinaCommand::StopClientTcp, 1) + let operation = Operation::new(NinaCommand::StopClientTcp) .param(NinaByteParam::from_bytes(&[socket]).into()); self.execute(&operation)?; - let result = self.receive(&operation)?; + let result = self.receive(&operation, 1)?; if result[0] == 1 { Ok(()) } else { @@ -230,11 +231,12 @@ where fn receive( &mut self, operation: &Operation

, + expected_num_params: u8 ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.control_pins.wait_for_esp_select(); let result = - self.wait_response_cmd(&operation.command, operation.number_of_params_to_receive); + self.wait_response_cmd(&operation.command, expected_num_params); self.control_pins.esp_deselect(); From 59308562a53281b0ea7a55e6208eb3b93a47ae45 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 14:54:32 -0600 Subject: [PATCH 076/106] Clean up the unused pieces in send_data_tcp example --- cross/send_data_tcp/src/main.rs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index a9d2273..0b17c1d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -25,14 +25,12 @@ use rp2040_hal as hal; use embedded_hal::spi::MODE_0; use fugit::RateExtU32; -use hal::gpio::{ - bank0::Gpio10, bank0::Gpio11, bank0::Gpio2, bank0::Gpio7, FloatingInput, Pin, PushPullOutput, -}; -use hal::{clocks::Clock, pac, spi::Enabled}; +use hal::gpio::{FloatingInput, PushPullOutput}; +use hal::{clocks::Clock, pac}; use esp32_wroom_rp::{ gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, - wifi::ConnectionStatus, wifi::Wifi, Error, tcp_client::TcpClient + wifi::ConnectionStatus, wifi::Wifi, tcp_client::TcpClient }; /// The linker will place this boot block at the start of our program image. We @@ -45,14 +43,6 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; /// if your board has a different frequency const XTAL_FREQ_HZ: u32 = 12_000_000u32; -type Spi = hal::Spi; -type Pins = EspControlPins< - Pin, - Pin, - Pin, - Pin, ->; - /// Entry point to our bare-metal application. /// /// The `#[entry]` macro ensures the Cortex-M start-up code calls this function @@ -131,11 +121,11 @@ fn main() -> ! { loop { match wifi.get_connection_status() { Ok(status) => { - defmt::info!("Get Connection Result: {:?}", status); + defmt::info!("Connection status: {:?}", status); delay.delay_ms(sleep); if status == ConnectionStatus::Connected { - defmt::info!("Connected to Network: {:?}", SSID); + defmt::info!("Connected to network: {:?}", SSID); // The IPAddresses of two DNS servers to resolve hostnames with. // Note that failover from ip1 to ip2 is fully functional. @@ -161,9 +151,9 @@ fn main() -> ! { // this is where you send/receive with a connected TCP socket to a remote server }); + defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { - defmt::info!("Disconnected from Network: {:?}", SSID); sleep = 20000; // No need to loop as often after disconnecting } } From 5873cc8620d2305983d23e29238c2b3645656b9f Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 15:59:38 -0600 Subject: [PATCH 077/106] Add a get_state() method to retrieve the current TCP client state's connection status to a remote server --- esp32-wroom-rp/src/network.rs | 36 ++++++++++++++++++++++++++++++++ esp32-wroom-rp/src/protocol.rs | 3 ++- esp32-wroom-rp/src/spi.rs | 11 ++++++++++ esp32-wroom-rp/src/tcp_client.rs | 2 ++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 0fe7412..5018be9 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -20,6 +20,42 @@ pub enum TransportMode { TlsBearSsl = 4, } +/// Defines all possible TCP connection states for a client or server instance. +#[repr(u8)] +#[derive(PartialEq, PartialOrd, Debug)] +pub enum ConnectionState { + Closed = 0, + Listening = 1, + SynSent = 2, + SynReceived = 3, + Established = 4, + FinWait1 = 5, + FinWait2 = 6, + CloseWait = 7, + Closing = 8, + LastAck = 9, + TimeWait = 10, +} + +impl From for ConnectionState { + fn from(state: u8) -> ConnectionState { + match state { + 0 => ConnectionState::Closed, + 1 => ConnectionState::Listening, + 2 => ConnectionState::SynSent, + 3 => ConnectionState::SynReceived, + 4 => ConnectionState::Established, + 5 => ConnectionState::FinWait1, + 6 => ConnectionState::FinWait2, + 7 => ConnectionState::CloseWait, + 8 => ConnectionState::Closing, + 9 => ConnectionState::LastAck, + 10 => ConnectionState::TimeWait, + _ => ConnectionState::Closed + } + } +} + /// Errors that occur due to issues involving communication over /// WiFi network. #[derive(PartialEq, Eq, Debug)] diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index bd0ee90..0daff34 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -10,7 +10,6 @@ use super::network::{IpAddress, Port, Socket, TransportMode}; use super::wifi::ConnectionStatus; -use super::network::{IpAddress, Socket}; use super::{Error, FirmwareVersion}; use core::cell::RefCell; @@ -25,6 +24,7 @@ pub(crate) enum NinaCommand { GetConnStatus = 0x20u8, StartClientTcp = 0x2du8, StopClientTcp = 0x2eu8, + GetClientStateTcp = 0x2fu8, Disconnect = 0x30u8, ReqHostByName = 0x34u8, GetHostByName = 0x35u8, @@ -341,6 +341,7 @@ pub(crate) trait ProtocolInterface { fn get_socket(&mut self) -> Result; fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; + fn get_state(&mut self, socket: Socket) -> Result; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 88aa6d8..922e444 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,5 +1,6 @@ //! Serial Peripheral Interface (SPI) for Wifi +use crate::network::ConnectionState; use crate::protocol::{NinaWordParam, NinaAbstractParam}; use super::gpio::EspControlInterface; @@ -191,6 +192,16 @@ where Err(NetworkError::StopClientFailed.into()) } } + + fn get_state(&mut self, socket: Socket) -> Result { + let operation = Operation::new(NinaCommand::GetClientStateTcp); + + self.execute(&operation)?; + + let result = self.receive(&operation, 1)?; + + Ok(ConnectionState::from(result[0])) + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index ec3f9d5..d170f12 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -46,6 +46,8 @@ where self.protocol_handler.start_client(socket, ip, port, &mode).ok().unwrap(); + // TODO: utilize get_state() here to determine when we're connected to the remote TCP server + f(&mut self); self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); From 0b614837acf6c94578036ab581db1e0024e9f939 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Mon, 12 Dec 2022 16:01:56 -0600 Subject: [PATCH 078/106] No need to pass tcp_client instance into closure as a mutable shared reference --- esp32-wroom-rp/src/tcp_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index d170f12..2c04ecd 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -36,7 +36,7 @@ where pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) -> Self where - F: Fn(&mut TcpClient<'a, B, C>) + F: Fn(&TcpClient<'a, B, C>) { let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); @@ -48,7 +48,7 @@ where // TODO: utilize get_state() here to determine when we're connected to the remote TCP server - f(&mut self); + f(&self); self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); From 45025b039a63ee7ec7ea718f9fc66ea468a75857 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 13 Dec 2022 09:17:57 -0500 Subject: [PATCH 079/106] check TCP connection --- cross/send_data_tcp/src/main.rs | 10 ++-- esp32-wroom-rp/src/lib.rs | 11 +++++ esp32-wroom-rp/src/network.rs | 30 +++++++---- esp32-wroom-rp/src/protocol.rs | 12 +++-- esp32-wroom-rp/src/spi.rs | 34 +++++++------ esp32-wroom-rp/src/tcp_client.rs | 85 +++++++++++++++++++++++++++----- 6 files changed, 140 insertions(+), 42 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 0b17c1d..558f1b1 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -142,14 +142,16 @@ fn main() -> ! { let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; - TcpClient::build(&mut wifi) - .connect(ip_address, port, mode, |tcp_client| { - defmt::info!("server_ip_address: {:?}", tcp_client.server_ip_address()); + if let Err(e) = TcpClient::build(&mut wifi) + .connect(ip_address, port, mode, &mut delay, |tcp_client| { + defmt::info!("TCP Connection to {:?}:{:?} successful", ip_address, port); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); // this is where you send/receive with a connected TCP socket to a remote server - }); + }) { + defmt::info!("TCP Connection to {:?}:{:?} Failed: {:?}", ip_address, port, e); + } defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 5f8e34e..7e99955 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -100,6 +100,7 @@ mod spi; use network::{IpAddress, NetworkError}; use protocol::ProtocolError; +use tcp_client::TcpError; use defmt::{write, Format, Formatter}; @@ -117,6 +118,9 @@ pub enum Error { /// Network related error Network(NetworkError), + + /// TCP related error + Tcp(TcpError), } impl Format for Error { @@ -129,6 +133,7 @@ impl Format for Error { e ), Error::Network(e) => write!(fmt, "Network error: {}", e), + Error::Tcp(e) => write!(fmt, "TCP error: {}", e), } } } @@ -145,6 +150,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: tcp_client::TcpError) -> Self { + Error::Tcp(err) + } +} + /// A structured representation of a connected NINA firmware device's version number (e.g. 1.7.4). #[derive(Debug, Default, Eq, PartialEq)] pub struct FirmwareVersion { diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 5018be9..a7e0d2f 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -51,7 +51,25 @@ impl From for ConnectionState { 8 => ConnectionState::Closing, 9 => ConnectionState::LastAck, 10 => ConnectionState::TimeWait, - _ => ConnectionState::Closed + _ => ConnectionState::Closed, + } + } +} + +impl Format for ConnectionState { + fn format(&self, fmt: Formatter) { + match self { + ConnectionState::Closed => write!(fmt, "Connection Closed"), + ConnectionState::Listening => write!(fmt, "Connection Listening"), + ConnectionState::SynSent => write!(fmt, "Connection SynSent"), + ConnectionState::SynReceived => write!(fmt, "Connection SynRecieved"), + ConnectionState::Established => write!(fmt, "Connection Established"), + ConnectionState::FinWait1 => write!(fmt, "Connection FinWait1"), + ConnectionState::FinWait2 => write!(fmt, "Connection FinWait2"), + ConnectionState::CloseWait => write!(fmt, "Connection CloseWait"), + ConnectionState::Closing => write!(fmt, "Connection Closing"), + ConnectionState::LastAck => write!(fmt, "Connection LastAck"), + ConnectionState::TimeWait => write!(fmt, "Connection TimeWait"), } } } @@ -78,16 +96,10 @@ impl Format for NetworkError { ) } NetworkError::StartClientFailed => { - write!( - fmt, - "Failed to start up a new TCP/UDP client instance" - ) + write!(fmt, "Failed to start up a new TCP/UDP client instance") } NetworkError::StopClientFailed => { - write!( - fmt, - "Failed to stop an existing TCP/UDP client instance" - ) + write!(fmt, "Failed to stop an existing TCP/UDP client instance") } } } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 0daff34..0fa6ae0 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -339,9 +339,15 @@ pub(crate) trait ProtocolInterface { fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>; fn resolve(&mut self, hostname: &str) -> Result; fn get_socket(&mut self) -> Result; - fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error>; - fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; - fn get_state(&mut self, socket: Socket) -> Result; + fn start_client_tcp( + &mut self, + socket: Socket, + ip: IpAddress, + port: Port, + mode: &TransportMode, + ) -> Result<(), Error>; + fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; + fn get_client_state_tcp(&mut self, socket: Socket) -> Result; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 922e444..d8e8fe4 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,7 +1,7 @@ //! Serial Peripheral Interface (SPI) for Wifi use crate::network::ConnectionState; -use crate::protocol::{NinaWordParam, NinaAbstractParam}; +use crate::protocol::{NinaAbstractParam, NinaWordParam}; use super::gpio::EspControlInterface; use super::protocol::{ @@ -9,8 +9,8 @@ use super::protocol::{ NinaSmallArrayParam, ProtocolInterface, }; -use super::network::{ IpAddress, NetworkError, Port, Socket, TransportMode }; -use super::protocol::{ operation::Operation, ProtocolError }; +use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; +use super::protocol::{operation::Operation, ProtocolError}; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -80,8 +80,7 @@ where fn disconnect(&mut self) -> Result<(), Error> { let dummy_param = NinaByteParam::from_bytes(&[ControlByte::Dummy as u8]); - let operation = Operation::new(NinaCommand::Disconnect) - .param(dummy_param.into()); + let operation = Operation::new(NinaCommand::Disconnect).param(dummy_param.into()); self.execute(&operation)?; @@ -149,8 +148,7 @@ where } fn get_socket(&mut self) -> Result { - let operation = - Operation::new(NinaCommand::GetSocket); + let operation = Operation::new(NinaCommand::GetSocket); self.execute(&operation)?; @@ -159,14 +157,20 @@ where Ok(result[0]) } - fn start_client(&mut self, socket: Socket, ip: IpAddress, port: Port, mode: &TransportMode) -> Result<(), Error> { + fn start_client_tcp( + &mut self, + socket: Socket, + ip: IpAddress, + port: Port, + mode: &TransportMode, + ) -> Result<(), Error> { let port_as_bytes = [((port & 0xff00) >> 8) as u8, (port & 0xff) as u8]; let operation = Operation::new(NinaCommand::StartClientTcp) .param(NinaSmallArrayParam::from_bytes(&ip).into()) .param(NinaWordParam::from_bytes(&port_as_bytes).into()) .param(NinaByteParam::from_bytes(&[socket]).into()) .param(NinaByteParam::from_bytes(&[*mode as u8]).into()); - + self.execute(&operation)?; let result = self.receive(&operation, 1)?; @@ -179,7 +183,7 @@ where // TODO: passing in TransportMode but not using, for now. It will become a way // of stopping the right kind of client (e.g. TCP, vs UDP) - fn stop_client(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { + fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error> { let operation = Operation::new(NinaCommand::StopClientTcp) .param(NinaByteParam::from_bytes(&[socket]).into()); @@ -193,13 +197,14 @@ where } } - fn get_state(&mut self, socket: Socket) -> Result { + fn get_client_state_tcp(&mut self, socket: Socket) -> Result { let operation = Operation::new(NinaCommand::GetClientStateTcp); self.execute(&operation)?; let result = self.receive(&operation, 1)?; - + // TODO: Determine whether or not any ConnectionState variants should be considered + // an error. Ok(ConnectionState::from(result[0])) } } @@ -242,12 +247,11 @@ where fn receive( &mut self, operation: &Operation

, - expected_num_params: u8 + expected_num_params: u8, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.control_pins.wait_for_esp_select(); - let result = - self.wait_response_cmd(&operation.command, expected_num_params); + let result = self.wait_response_cmd(&operation.command, expected_num_params); self.control_pins.esp_deselect(); diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 2c04ecd..6eb0631 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,14 +1,30 @@ use super::Error; -use crate::{wifi::Wifi}; +use crate::wifi::Wifi; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{IpAddress, Port, Socket, TransportMode}; +use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; +use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; +use defmt::{write, Format, Formatter}; + +#[derive(Debug, Eq, PartialEq)] +pub enum TcpError { + Timeout, +} + +impl Format for TcpError { + fn format(&self, fmt: Formatter) { + match self { + TcpError::Timeout => write!(fmt, "Timeout Connecting to TCP Server"), + } + } +} + pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, @@ -34,9 +50,16 @@ where } } - pub fn connect(mut self, ip: IpAddress, port: Port, mode: TransportMode, f: F) -> Self + pub fn connect>( + mut self, + ip: IpAddress, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error> where - F: Fn(&TcpClient<'a, B, C>) + F: Fn(&TcpClient<'a, B, C>), { let socket = self.get_socket().unwrap_or_default(); self.socket = Some(socket); @@ -44,15 +67,55 @@ where self.port = port; self.mode = mode; - self.protocol_handler.start_client(socket, ip, port, &mode).ok().unwrap(); - - // TODO: utilize get_state() here to determine when we're connected to the remote TCP server - - f(&self); + self.protocol_handler + .start_client_tcp(socket, ip, port, &mode) + .ok() + .unwrap(); + + // FIXME: without this delay, we'll frequently see timing issues and receive + // a CmdResponseErr. We may not be handling busy/ack flag handling properly + // and needs further investigation. I suspect that the ESP32 isn't ready to + // receive another command yet. (copied this from POC) + delay.delay_ms(250); + + let mut retry_limit = 10_000; + + while retry_limit > 0 { + match self.protocol_handler.get_client_state_tcp(socket) { + Ok(ConnectionState::Established) => { + f(&self); + + self.protocol_handler + .stop_client_tcp(socket, &mode) + .ok() + .unwrap(); + return Ok(()); + } + Ok(status) => { + defmt::debug!("TCP Client Connection Status: {:?}", status); + } + Err(error) => { + // At this point any error will likely be a protocol level error. + // We do not currently consider any ConnectionState variants as errors. + defmt::debug!("TCP Client Connection Error: {:?}", error); + self.protocol_handler + .stop_client_tcp(socket, &mode) + .ok() + .unwrap(); + + return Err(error); + } + } + delay.delay_ms(100); + retry_limit -= 1; + } - self.protocol_handler.stop_client(socket, &mode).ok().unwrap(); + self.protocol_handler + .stop_client_tcp(socket, &mode) + .ok() + .unwrap(); - self + Err(TcpError::Timeout.into()) } pub fn server_ip_address(&self) -> Option { From 177f57bd8ad5c0b190172ab1144edde0709421bf Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Tue, 13 Dec 2022 16:28:00 -0600 Subject: [PATCH 080/106] Convert error debug statements to use error macro, also make sure not to panic on TcpClient::connect() failure. --- cross/send_data_tcp/src/main.rs | 8 ++++---- esp32-wroom-rp/src/tcp_client.rs | 25 +++++++------------------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 558f1b1..3a142c7 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -138,19 +138,19 @@ fn main() -> ! { let _hostname = "github.com"; //let ip_address: IpAddress = [18, 195, 85, 27]; - let ip_address: IpAddress = [10, 0, 1, 3]; + let ip_address: IpAddress = [10, 0, 1, 4]; let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; if let Err(e) = TcpClient::build(&mut wifi) .connect(ip_address, port, mode, &mut delay, |tcp_client| { - defmt::info!("TCP Connection to {:?}:{:?} successful", ip_address, port); + defmt::info!("TCP connection to {:?}:{:?} successful", ip_address, port); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); // this is where you send/receive with a connected TCP socket to a remote server }) { - defmt::info!("TCP Connection to {:?}:{:?} Failed: {:?}", ip_address, port, e); + defmt::error!("TCP connection to {:?}:{:?} failed: {:?}", ip_address, port, e); } defmt::info!("Leaving network: {:?}", SSID); @@ -160,7 +160,7 @@ fn main() -> ! { } } Err(e) => { - defmt::info!("Failed to Get Connection Result: {:?}", e); + defmt::error!("Failed to get connection result: {:?}", e); } } } diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 6eb0631..583465b 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -67,10 +67,7 @@ where self.port = port; self.mode = mode; - self.protocol_handler - .start_client_tcp(socket, ip, port, &mode) - .ok() - .unwrap(); + self.protocol_handler.start_client_tcp(socket, ip, port, &mode)?; // FIXME: without this delay, we'll frequently see timing issues and receive // a CmdResponseErr. We may not be handling busy/ack flag handling properly @@ -85,23 +82,18 @@ where Ok(ConnectionState::Established) => { f(&self); - self.protocol_handler - .stop_client_tcp(socket, &mode) - .ok() - .unwrap(); + self.protocol_handler.stop_client_tcp(socket, &mode)?; + return Ok(()); } Ok(status) => { - defmt::debug!("TCP Client Connection Status: {:?}", status); + defmt::debug!("TCP client connection status: {:?}", status); } Err(error) => { // At this point any error will likely be a protocol level error. // We do not currently consider any ConnectionState variants as errors. - defmt::debug!("TCP Client Connection Error: {:?}", error); - self.protocol_handler - .stop_client_tcp(socket, &mode) - .ok() - .unwrap(); + defmt::error!("TCP client connection error: {:?}", error); + self.protocol_handler.stop_client_tcp(socket, &mode)?; return Err(error); } @@ -110,10 +102,7 @@ where retry_limit -= 1; } - self.protocol_handler - .stop_client_tcp(socket, &mode) - .ok() - .unwrap(); + self.protocol_handler.stop_client_tcp(socket, &mode)?; Err(TcpError::Timeout.into()) } From 600c0b5715ae4956a14886408b0e484d9d2586eb Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 14 Dec 2022 08:20:04 -0500 Subject: [PATCH 081/106] add first pass at send_data --- esp32-wroom-rp/src/protocol.rs | 6 ++++++ esp32-wroom-rp/src/spi.rs | 21 +++++++++++++++++++-- esp32-wroom-rp/src/tcp_client.rs | 17 +++++++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 0fa6ae0..5213e39 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -30,6 +30,7 @@ pub(crate) enum NinaCommand { GetHostByName = 0x35u8, GetFwVersion = 0x37u8, GetSocket = 0x3fu8, + SendDataTcp = 0x44, } pub(crate) trait NinaConcreteParam { @@ -348,6 +349,11 @@ pub(crate) trait ProtocolInterface { ) -> Result<(), Error>; fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>; fn get_client_state_tcp(&mut self, socket: Socket) -> Result; + fn send_data( + &mut self, + data: TcpData, + socket: Socket, + ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error>; } #[derive(Debug)] diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index d8e8fe4..121703d 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -5,12 +5,13 @@ use crate::protocol::{NinaAbstractParam, NinaWordParam}; use super::gpio::EspControlInterface; use super::protocol::{ - NinaByteParam, NinaCommand, NinaConcreteParam, NinaParam, NinaProtocolHandler, - NinaSmallArrayParam, ProtocolInterface, + NinaByteParam, NinaCommand, NinaConcreteParam, NinaLargeArrayParam, NinaParam, + NinaProtocolHandler, NinaSmallArrayParam, ProtocolInterface, }; use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; use super::protocol::{operation::Operation, ProtocolError}; +use super::tcp_client::TcpData; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -207,6 +208,22 @@ where // an error. Ok(ConnectionState::from(result[0])) } + + fn send_data( + &mut self, + data: TcpData, + socket: Socket, + ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + let operation = Operation::new(NinaCommand::SendDataTcp) + .param(NinaWordParam::from_bytes(&[socket]).into()) + .param(NinaLargeArrayParam::new(&data).into()); + + self.execute(&operation)?; + + let result = self.receive(&operation, 1)?; + + Ok(result) + } } impl NinaProtocolHandler diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 583465b..79a6d8c 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,4 +1,4 @@ -use super::Error; +use super::{Error, ARRAY_LENGTH_PLACEHOLDER}; use crate::wifi::Wifi; use super::protocol::NinaProtocolHandler; @@ -12,6 +12,13 @@ use embedded_hal::blocking::spi::Transfer; use defmt::{write, Format, Formatter}; +use heapless::String; + +// TODO: find a good max length +const MAX_DATA_LENGTH: usize = 512; + +pub type TcpData = String; + #[derive(Debug, Eq, PartialEq)] pub enum TcpError { Timeout, @@ -67,7 +74,8 @@ where self.port = port; self.mode = mode; - self.protocol_handler.start_client_tcp(socket, ip, port, &mode)?; + self.protocol_handler + .start_client_tcp(socket, ip, port, &mode)?; // FIXME: without this delay, we'll frequently see timing issues and receive // a CmdResponseErr. We may not be handling busy/ack flag handling properly @@ -107,6 +115,11 @@ where Err(TcpError::Timeout.into()) } + pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + self.protocol_handler + .send_data(data, self.socket.unwrap_or_default()) + } + pub fn server_ip_address(&self) -> Option { self.server_ip_address } From 6fac6384ee692979edd476aa364bb41c1a63a27d Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Thu, 15 Dec 2022 14:48:56 -0600 Subject: [PATCH 082/106] TcpClient::connect() can now take an IPAddress or a &str hostname to specify the server to connect to via TCP. Also, increase total number of Nina protocol params to 6 to match Arduino firmware. --- cross/send_data_tcp/src/main.rs | 30 +++-- esp32-wroom-rp/src/protocol/operation.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 142 ++++++++++++++++------- 3 files changed, 120 insertions(+), 54 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 3a142c7..457d704 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -30,7 +30,7 @@ use hal::{clocks::Clock, pac}; use esp32_wroom_rp::{ gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, - wifi::ConnectionStatus, wifi::Wifi, tcp_client::TcpClient + tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi, }; /// The linker will place this boot block at the start of our program image. We @@ -138,20 +138,34 @@ fn main() -> ! { let _hostname = "github.com"; //let ip_address: IpAddress = [18, 195, 85, 27]; - let ip_address: IpAddress = [10, 0, 1, 4]; + let ip_address: IpAddress = [10, 0, 1, 3]; let port: Port = 4000; let mode: TransportMode = TransportMode::Tcp; - if let Err(e) = TcpClient::build(&mut wifi) - .connect(ip_address, port, mode, &mut delay, |tcp_client| { - defmt::info!("TCP connection to {:?}:{:?} successful", ip_address, port); + if let Err(e) = TcpClient::build(&mut wifi).connect( + ip_address, + port, + mode, + &mut delay, + |tcp_client| { + defmt::info!( + "TCP connection to {:?}:{:?} successful", + ip_address, + port + ); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); // this is where you send/receive with a connected TCP socket to a remote server - }) { - defmt::error!("TCP connection to {:?}:{:?} failed: {:?}", ip_address, port, e); - } + }, + ) { + defmt::error!( + "TCP connection to {:?}:{:?} failed: {:?}", + ip_address, + port, + e + ); + } defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); diff --git a/esp32-wroom-rp/src/protocol/operation.rs b/esp32-wroom-rp/src/protocol/operation.rs index 1ac3aae..464b6e7 100644 --- a/esp32-wroom-rp/src/protocol/operation.rs +++ b/esp32-wroom-rp/src/protocol/operation.rs @@ -1,7 +1,7 @@ use crate::protocol::{NinaAbstractParam, NinaCommand}; use heapless::Vec; -const MAX_NUMBER_OF_PARAMS: usize = 4; +const MAX_NUMBER_OF_PARAMS: usize = 6; // Encapsulates all information needed to execute commands against Nina Firmware. // along with user supplied data. Ex. SSID, passphrase, etc. diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 79a6d8c..51fdb00 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -16,6 +16,7 @@ use heapless::String; // TODO: find a good max length const MAX_DATA_LENGTH: usize = 512; +const MAX_HOSTNAME_LENGTH: usize = 255; pub type TcpData = String; @@ -32,13 +33,71 @@ impl Format for TcpError { } } +pub trait Connect<'a, S, B, C> { + fn connect), D: DelayMs>( + &mut self, + server: S, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error>; +} + pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, pub(crate) server_ip_address: Option, pub(crate) port: Port, pub(crate) mode: TransportMode, - pub(crate) server_hostname: Option<&'a str>, + pub(crate) server_hostname: Option>, +} + +impl<'a, B, C> Connect<'a, IpAddress, B, C> for TcpClient<'a, B, C> +where + B: Transfer, + C: EspControlInterface, +{ + fn connect), D: DelayMs>( + &mut self, + ip: IpAddress, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error> { + let socket = self.get_socket().unwrap_or_default(); + self.socket = Some(socket); + self.server_ip_address = Some(ip); + self.server_hostname = Some(String::new()); + self.port = port; + self.mode = mode; + + self.connect_common(delay, f) + } +} + +impl<'a, B, C> Connect<'a, &str, B, C> for TcpClient<'a, B, C> +where + B: Transfer, + C: EspControlInterface, +{ + fn connect), D: DelayMs>( + &mut self, + server_hostname: &str, + port: Port, + mode: TransportMode, + delay: &mut D, + f: F, + ) -> Result<(), Error> { + let socket = self.get_socket().unwrap_or_default(); + self.socket = Some(socket); + self.server_hostname = Some(server_hostname.into()); // into() makes a copy of the &str slice + self.port = port; + self.mode = mode; + + self.connect_common(delay, f) + } } impl<'a, B, C> TcpClient<'a, B, C> @@ -53,26 +112,48 @@ where server_ip_address: None, port: 0, mode: TransportMode::Tcp, - server_hostname: None, + server_hostname: Some(String::new()), } } - pub fn connect>( - mut self, - ip: IpAddress, - port: Port, - mode: TransportMode, + pub fn server_ip_address(&self) -> Option { + self.server_ip_address + } + + pub fn server_hostname(&self) -> &str { + self.server_hostname.as_ref().unwrap().as_str() + } + + pub fn port(&self) -> Port { + self.port + } + + pub fn mode(&self) -> TransportMode { + self.mode + } + + pub fn get_socket(&mut self) -> Result { + self.protocol_handler.get_socket() + } + + pub fn socket(&self) -> Socket { + self.socket.unwrap() + } + + pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + self.protocol_handler + .send_data(data, self.socket.unwrap_or_default()) + } + + fn connect_common), D: DelayMs>( + &mut self, delay: &mut D, f: F, - ) -> Result<(), Error> - where - F: Fn(&TcpClient<'a, B, C>), - { - let socket = self.get_socket().unwrap_or_default(); - self.socket = Some(socket); - self.server_ip_address = Some(ip); - self.port = port; - self.mode = mode; + ) -> Result<(), Error> { + let socket = self.socket.unwrap_or_default(); + let mode = self.mode; + let ip = self.server_ip_address.unwrap_or_default(); + let port = self.port; self.protocol_handler .start_client_tcp(socket, ip, port, &mode)?; @@ -114,33 +195,4 @@ where Err(TcpError::Timeout.into()) } - - pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { - self.protocol_handler - .send_data(data, self.socket.unwrap_or_default()) - } - - pub fn server_ip_address(&self) -> Option { - self.server_ip_address - } - - pub fn server_hostname(&self) -> Option<&'a str> { - self.server_hostname - } - - pub fn port(&self) -> Port { - self.port - } - - pub fn mode(&self) -> TransportMode { - self.mode - } - - pub fn get_socket(&mut self) -> Result { - self.protocol_handler.get_socket() - } - - pub fn socket(&self) -> Socket { - self.socket.unwrap() - } } From 4b78c250ca9679c28976b0caf684ef429f66a621 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 16 Dec 2022 10:47:29 -0600 Subject: [PATCH 083/106] Introduce type alias Hostname for a hostname string slice --- esp32-wroom-rp/src/network.rs | 3 +++ esp32-wroom-rp/src/tcp_client.rs | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index a7e0d2f..f8a6cb7 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -3,6 +3,9 @@ use defmt::{write, Format, Formatter}; /// A four byte array type alias representing an IP address. pub type IpAddress = [u8; 4]; +/// A named string slice type representing a network hostname. +pub type Hostname<'a> = &'static str; + /// A TCP/UDP network port. pub type Port = u16; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 51fdb00..6c45201 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -5,7 +5,14 @@ use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; +use super::network::{ + ConnectionState, + Hostname, + IpAddress, + Port, + Socket, + TransportMode +}; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; @@ -18,6 +25,7 @@ use heapless::String; const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; +// TODO: consider if we should move this type into network.rs pub type TcpData = String; #[derive(Debug, Eq, PartialEq)] @@ -77,14 +85,14 @@ where } } -impl<'a, B, C> Connect<'a, &str, B, C> for TcpClient<'a, B, C> +impl<'a, B, C> Connect<'a, Hostname<'_>, B, C> for TcpClient<'a, B, C> where B: Transfer, C: EspControlInterface, { fn connect), D: DelayMs>( &mut self, - server_hostname: &str, + server_hostname: Hostname, port: Port, mode: TransportMode, delay: &mut D, From bc4a5b1339a3d605f8d7e203084c9874ea2bff4e Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 16 Dec 2022 10:51:19 -0600 Subject: [PATCH 084/106] Use '?' after get_socket() instead of unwrap_or_default() --- esp32-wroom-rp/src/tcp_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 6c45201..aa32e98 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -74,7 +74,7 @@ where delay: &mut D, f: F, ) -> Result<(), Error> { - let socket = self.get_socket().unwrap_or_default(); + let socket = self.get_socket()?; self.socket = Some(socket); self.server_ip_address = Some(ip); self.server_hostname = Some(String::new()); @@ -98,7 +98,7 @@ where delay: &mut D, f: F, ) -> Result<(), Error> { - let socket = self.get_socket().unwrap_or_default(); + let socket = self.get_socket()?; self.socket = Some(socket); self.server_hostname = Some(server_hostname.into()); // into() makes a copy of the &str slice self.port = port; From 500047f4b0f40df9f643eb40d58a2bc80244aadc Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 16 Dec 2022 11:19:58 -0600 Subject: [PATCH 085/106] Change back to lifetime 'a instead of unintended static lifetime for Hostname --- esp32-wroom-rp/src/network.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index f8a6cb7..13c030f 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -4,7 +4,7 @@ use defmt::{write, Format, Formatter}; pub type IpAddress = [u8; 4]; /// A named string slice type representing a network hostname. -pub type Hostname<'a> = &'static str; +pub type Hostname<'a> = &'a str; /// A TCP/UDP network port. pub type Port = u16; From 48dab2e83a69c79c01a1c607486036bf1785f672 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 16 Dec 2022 12:31:24 -0500 Subject: [PATCH 086/106] using send_data compiles --- cross/send_data_tcp/Cargo.toml | 1 + cross/send_data_tcp/src/main.rs | 25 ++++++++++++++++++++++--- esp32-wroom-rp/src/protocol.rs | 2 +- esp32-wroom-rp/src/spi.rs | 5 ++--- esp32-wroom-rp/src/tcp_client.rs | 15 ++++++--------- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/cross/send_data_tcp/Cargo.toml b/cross/send_data_tcp/Cargo.toml index c359eeb..b11500a 100644 --- a/cross/send_data_tcp/Cargo.toml +++ b/cross/send_data_tcp/Cargo.toml @@ -25,6 +25,7 @@ cortex-m-rt = "0.7" embedded-hal = { version = "0.2", features=["unproven"] } esp32-wroom-rp = { path = "../../esp32-wroom-rp" } panic-probe = { version = "0.3.0", features = ["print-rtt"] } +heapless = "0.7.16" rp2040-hal = { version = "0.6", features=["rt", "eh1_0_alpha"] } rp2040-boot2 = { version = "0.2" } diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 457d704..c6a049d 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -24,15 +24,22 @@ use panic_probe as _; use rp2040_hal as hal; use embedded_hal::spi::MODE_0; + +use core::fmt::Write; + use fugit::RateExtU32; use hal::gpio::{FloatingInput, PushPullOutput}; use hal::{clocks::Clock, pac}; +use heapless::String; + use esp32_wroom_rp::{ gpio::EspControlPins, network::IpAddress, network::Port, network::TransportMode, tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi, }; +const MAX_HTTP_DOC_LENGTH: usize = u8::MAX as usize; + /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. #[link_section = ".boot2"] @@ -138,10 +145,21 @@ fn main() -> ! { let _hostname = "github.com"; //let ip_address: IpAddress = [18, 195, 85, 27]; - let ip_address: IpAddress = [10, 0, 1, 3]; - let port: Port = 4000; + // let ip_address: IpAddress = [10, 0, 1, 3]; + let ip_address: IpAddress = [140, 82, 114, 3]; // github.com + // let port: Port = 4000; + let port: Port = 443u16; // HTTPS let mode: TransportMode = TransportMode::Tcp; + let mut http_document: String = String::from(""); + write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n", + ip_address[0], + ip_address[1], + ip_address[2], + ip_address[3], + port + ); + if let Err(e) = TcpClient::build(&mut wifi).connect( ip_address, port, @@ -155,8 +173,9 @@ fn main() -> ! { ); defmt::info!("hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); + defmt::info!("Sending HTTP Document: {:?}", http_document.as_str()); + tcp_client.send_data(&http_document); - // this is where you send/receive with a connected TCP socket to a remote server }, ) { defmt::error!( diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 5213e39..49e6976 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -351,7 +351,7 @@ pub(crate) trait ProtocolInterface { fn get_client_state_tcp(&mut self, socket: Socket) -> Result; fn send_data( &mut self, - data: TcpData, + data: &str, socket: Socket, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error>; } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 121703d..df71e40 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -11,7 +11,6 @@ use super::protocol::{ use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; use super::protocol::{operation::Operation, ProtocolError}; -use super::tcp_client::TcpData; use super::wifi::ConnectionStatus; use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; @@ -211,12 +210,12 @@ where fn send_data( &mut self, - data: TcpData, + data: &str, socket: Socket, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { let operation = Operation::new(NinaCommand::SendDataTcp) .param(NinaWordParam::from_bytes(&[socket]).into()) - .param(NinaLargeArrayParam::new(&data).into()); + .param(NinaLargeArrayParam::new(data).into()); self.execute(&operation)?; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index aa32e98..68f9f8a 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -25,9 +25,6 @@ use heapless::String; const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; -// TODO: consider if we should move this type into network.rs -pub type TcpData = String; - #[derive(Debug, Eq, PartialEq)] pub enum TcpError { Timeout, @@ -42,7 +39,7 @@ impl Format for TcpError { } pub trait Connect<'a, S, B, C> { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, server: S, port: Port, @@ -66,7 +63,7 @@ where B: Transfer, C: EspControlInterface, { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, ip: IpAddress, port: Port, @@ -90,7 +87,7 @@ where B: Transfer, C: EspControlInterface, { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, server_hostname: Hostname, port: Port, @@ -148,12 +145,12 @@ where self.socket.unwrap() } - pub fn send_data(mut self, data: TcpData) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + pub fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.protocol_handler .send_data(data, self.socket.unwrap_or_default()) } - fn connect_common), D: DelayMs>( + fn connect_common), D: DelayMs>( &mut self, delay: &mut D, f: F, @@ -177,7 +174,7 @@ where while retry_limit > 0 { match self.protocol_handler.get_client_state_tcp(socket) { Ok(ConnectionState::Established) => { - f(&self); + f(self); self.protocol_handler.stop_client_tcp(socket, &mode)?; From 75cde228fc616276afc4ddcc3656ac9994e7aeba Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Fri, 16 Dec 2022 18:26:06 -0500 Subject: [PATCH 087/106] use length_size in padding calculation --- esp32-wroom-rp/src/spi.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index df71e40..0ad6ec1 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -244,7 +244,7 @@ where if !operation.params.is_empty() { operation.params.iter().for_each(|param| { self.send_param(param).ok(); - param_size += param.length(); + param_size += param.length_size() as u16; }); self.send_end_cmd().ok(); diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 68f9f8a..c7bd77c 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -5,14 +5,7 @@ use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; use crate::protocol::ProtocolInterface; -use super::network::{ - ConnectionState, - Hostname, - IpAddress, - Port, - Socket, - TransportMode -}; +use super::network::{ConnectionState, Hostname, IpAddress, Port, Socket, TransportMode}; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; From df463df94138130138a1b30a08790be2ff86fad0 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Sat, 17 Dec 2022 09:03:42 -0500 Subject: [PATCH 088/106] modify padding calculation for send_data --- esp32-wroom-rp/src/spi.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 0ad6ec1..25af95e 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -214,7 +214,7 @@ where socket: Socket, ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { let operation = Operation::new(NinaCommand::SendDataTcp) - .param(NinaWordParam::from_bytes(&[socket]).into()) + .param(NinaLargeArrayParam::from_bytes(&[socket]).into()) .param(NinaLargeArrayParam::new(data).into()); self.execute(&operation)?; @@ -231,7 +231,9 @@ where C: EspControlInterface, { fn execute(&mut self, operation: &Operation

) -> Result<(), Error> { - let mut param_size: u16 = 0; + let mut total_params_length: u16 = 0; + let mut total_params_length_size: u16 = 0; + self.control_pins.wait_for_esp_select(); let number_of_params: u8 = if !operation.params.is_empty() { operation.params.len() as u8 @@ -244,15 +246,19 @@ where if !operation.params.is_empty() { operation.params.iter().for_each(|param| { self.send_param(param).ok(); - param_size += param.length_size() as u16; + + total_params_length += param.length() as u16; + total_params_length_size += param.length_size() as u16; }); self.send_end_cmd().ok(); // This is to make sure we align correctly - // 4 (start byte, command byte, number of params, end byte) + 1 byte for each param + the sum of all param lengths + // 4 (start byte, command byte, number of params as byte, end byte) + // + the number of bytes to represent the param length (1 or 2) + // + the sum of all param lengths // See https://github.com/arduino/nina-fw/blob/master/main/CommandHandler.cpp#L2153 for the actual equation. - let command_size: u16 = 4u16 + number_of_params as u16 + param_size; + let command_size: u16 = 4u16 + total_params_length_size + total_params_length; self.pad_to_multiple_of_4(command_size); } self.control_pins.esp_deselect(); From b713085427d4ebaab7df758ec18ef87025aa2078 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 18 Dec 2022 17:05:00 -0600 Subject: [PATCH 089/106] Can use either an ip_address or hostname to connect to remote TCP server and send_data() to it --- cross/send_data_tcp/src/main.rs | 89 +++++++++++++++++++++++++------- esp32-wroom-rp/src/protocol.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 8 ++- 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index c6a049d..dea2a57 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -38,7 +38,7 @@ use esp32_wroom_rp::{ tcp_client::Connect, tcp_client::TcpClient, wifi::ConnectionStatus, wifi::Wifi, }; -const MAX_HTTP_DOC_LENGTH: usize = u8::MAX as usize; +const MAX_HTTP_DOC_LENGTH: usize = 4096 as usize; /// The linker will place this boot block at the start of our program image. We /// need this to help the ROM bootloader get our code up and running. @@ -142,50 +142,103 @@ fn main() -> ! { defmt::info!("set_dns result: {:?}", dns_result); - let _hostname = "github.com"; + let hostname = "github.com"; + // let ip_address: IpAddress = [140, 82, 114, 3]; // github.com - //let ip_address: IpAddress = [18, 195, 85, 27]; - // let ip_address: IpAddress = [10, 0, 1, 3]; - let ip_address: IpAddress = [140, 82, 114, 3]; // github.com - // let port: Port = 4000; - let port: Port = 443u16; // HTTPS + let port: Port = 80; let mode: TransportMode = TransportMode::Tcp; let mut http_document: String = String::from(""); - write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n", - ip_address[0], - ip_address[1], - ip_address[2], - ip_address[3], + // write!(http_document, "GET / HTTP/1.1\r\nHost: {}.{}.{}.{}:{}\r\nAccept: */*\r\n\r\n", + // ip_address[0], + // ip_address[1], + // ip_address[2], + // ip_address[3], + // port + // ).ok().unwrap(); + + write!(http_document, "GET / HTTP/1.1\r\nHost: {}:{}\r\nAccept: */*\r\n\r\n", + hostname, port - ); + ).ok().unwrap(); + + // let request_path: String = String::from("/api/readings/add"); + // let mut http_document: String = String::from("POST "); + // http_document.push_str(&request_path).ok().unwrap(); + // http_document + // .push_str(" HTTP/1.1\r\nHost: ") + // .ok() + // .unwrap(); + // let mut host_address_str: String = String::new(); + // write!( + // host_address_str, + // "{}.{}.{}.{}:{:?}\r\n", + // ip_address[0], + // ip_address[1], + // ip_address[2], + // ip_address[3], + // port + // ) + // .unwrap(); + // http_document.push_str(&host_address_str).ok().unwrap(); + // http_document + // .push_str("User-Agent: edge/0.0.1\r\n") + // .ok() + // .unwrap(); + // http_document.push_str("Accept: */*\r\n").ok().unwrap(); + // http_document + // .push_str("Content-Type: application/json\r\n") + // .ok() + // .unwrap(); + // let temperature = 22.0; + // let humidity = 35.0; + // let pressure = 9970.0; + // let mut json_str: String = String::new(); + // write!(json_str, + // "{{\"temperature\":\"{:.1?}\",\"humidity\":\"{:.1?}\",\"pressure\":\"{:.0?}\",\"dust_concentration\":\"200\",\"air_purity\":\"Low Pollution\"}}\r\n", + // temperature, humidity, pressure / 100.0 + // ).ok().unwrap(); + // let mut content_len_str: String = String::new(); + // write!(content_len_str, "{:?}\r\n", json_str.len()) + // .ok() + // .unwrap(); + // http_document.push_str("Content-Length: ").ok().unwrap(); + // http_document.push_str(&content_len_str).ok().unwrap(); + // http_document.push_str("\r\n").ok().unwrap(); + // http_document.push_str(&json_str).ok().unwrap(); + // http_document.push_str("\r\n").ok().unwrap(); if let Err(e) = TcpClient::build(&mut wifi).connect( - ip_address, + hostname, port, mode, &mut delay, |tcp_client| { defmt::info!( "TCP connection to {:?}:{:?} successful", - ip_address, + hostname, port ); - defmt::info!("hostname: {:?}", tcp_client.server_hostname()); + defmt::info!("Hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); defmt::info!("Sending HTTP Document: {:?}", http_document.as_str()); - tcp_client.send_data(&http_document); + match tcp_client.send_data(&http_document) { + Ok(response) => { defmt::info!("Response: {:?}", response) } + Err(e) => { defmt::error!("Response error: {:?}", e) } + } }, ) { defmt::error!( "TCP connection to {:?}:{:?} failed: {:?}", - ip_address, + hostname, port, e ); } + delay.delay_ms(100); + defmt::info!("Leaving network: {:?}", SSID); wifi.leave().ok(); } else if status == ConnectionStatus::Disconnected { diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 49e6976..4036dfd 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -14,7 +14,7 @@ use super::{Error, FirmwareVersion}; use core::cell::RefCell; -pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 255; +pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 4096; #[repr(u8)] #[derive(Copy, Clone, Debug)] diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index c7bd77c..8b76061 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -150,9 +150,15 @@ where ) -> Result<(), Error> { let socket = self.socket.unwrap_or_default(); let mode = self.mode; - let ip = self.server_ip_address.unwrap_or_default(); + let mut ip = self.server_ip_address.unwrap_or_default(); + let hostname = self.server_hostname.as_ref().unwrap(); let port = self.port; + if !hostname.is_empty() { + ip = self.protocol_handler.resolve(hostname.as_str()).ok().unwrap_or_default(); + defmt::debug!("Resolved ip: {:?} for hostname: {:?}", ip, hostname.as_str()); + } + self.protocol_handler .start_client_tcp(socket, ip, port, &mode)?; From 321170a05313a897014ff99b143ec88e7c1d8c9e Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 18 Dec 2022 17:05:43 -0600 Subject: [PATCH 090/106] Remove the unused HTTP POST doc from send_data_tcp example --- cross/send_data_tcp/src/main.rs | 46 --------------------------------- 1 file changed, 46 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index dea2a57..04ddd00 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -162,52 +162,6 @@ fn main() -> ! { port ).ok().unwrap(); - // let request_path: String = String::from("/api/readings/add"); - // let mut http_document: String = String::from("POST "); - // http_document.push_str(&request_path).ok().unwrap(); - // http_document - // .push_str(" HTTP/1.1\r\nHost: ") - // .ok() - // .unwrap(); - // let mut host_address_str: String = String::new(); - // write!( - // host_address_str, - // "{}.{}.{}.{}:{:?}\r\n", - // ip_address[0], - // ip_address[1], - // ip_address[2], - // ip_address[3], - // port - // ) - // .unwrap(); - // http_document.push_str(&host_address_str).ok().unwrap(); - // http_document - // .push_str("User-Agent: edge/0.0.1\r\n") - // .ok() - // .unwrap(); - // http_document.push_str("Accept: */*\r\n").ok().unwrap(); - // http_document - // .push_str("Content-Type: application/json\r\n") - // .ok() - // .unwrap(); - // let temperature = 22.0; - // let humidity = 35.0; - // let pressure = 9970.0; - // let mut json_str: String = String::new(); - // write!(json_str, - // "{{\"temperature\":\"{:.1?}\",\"humidity\":\"{:.1?}\",\"pressure\":\"{:.0?}\",\"dust_concentration\":\"200\",\"air_purity\":\"Low Pollution\"}}\r\n", - // temperature, humidity, pressure / 100.0 - // ).ok().unwrap(); - // let mut content_len_str: String = String::new(); - // write!(content_len_str, "{:?}\r\n", json_str.len()) - // .ok() - // .unwrap(); - // http_document.push_str("Content-Length: ").ok().unwrap(); - // http_document.push_str(&content_len_str).ok().unwrap(); - // http_document.push_str("\r\n").ok().unwrap(); - // http_document.push_str(&json_str).ok().unwrap(); - // http_document.push_str("\r\n").ok().unwrap(); - if let Err(e) = TcpClient::build(&mut wifi).connect( hostname, port, From 8622ecb738dfec8961a40a72c02b52b3d0e9d66d Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 18 Dec 2022 18:12:27 -0600 Subject: [PATCH 091/106] Provide public trait/struct/method documentation for TcpClient and a few other missing areas. --- esp32-wroom-rp/src/lib.rs | 4 +--- esp32-wroom-rp/src/spi.rs | 6 +++--- esp32-wroom-rp/src/tcp_client.rs | 20 ++++++++++++++++++++ esp32-wroom-rp/src/wifi.rs | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index 7e99955..bedda52 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -98,14 +98,12 @@ pub mod protocol; mod spi; -use network::{IpAddress, NetworkError}; +use network::NetworkError; use protocol::ProtocolError; use tcp_client::TcpError; use defmt::{write, Format, Formatter}; -use self::wifi::ConnectionStatus; - const ARRAY_LENGTH_PLACEHOLDER: usize = 8; /// Highest level error types for this crate. diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 25af95e..def890e 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -1,12 +1,11 @@ //! Serial Peripheral Interface (SPI) for Wifi use crate::network::ConnectionState; -use crate::protocol::{NinaAbstractParam, NinaWordParam}; use super::gpio::EspControlInterface; use super::protocol::{ NinaByteParam, NinaCommand, NinaConcreteParam, NinaLargeArrayParam, NinaParam, - NinaProtocolHandler, NinaSmallArrayParam, ProtocolInterface, + NinaProtocolHandler, NinaSmallArrayParam, NinaWordParam, ProtocolInterface, }; use super::network::{IpAddress, NetworkError, Port, Socket, TransportMode}; @@ -198,7 +197,8 @@ where } fn get_client_state_tcp(&mut self, socket: Socket) -> Result { - let operation = Operation::new(NinaCommand::GetClientStateTcp); + let operation = Operation::new(NinaCommand::GetClientStateTcp) + .param(NinaByteParam::from_bytes(&[socket]).into()); self.execute(&operation)?; diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 8b76061..6304495 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -31,7 +31,11 @@ impl Format for TcpError { } } +/// Connect trait that allows for a `TcpClient` instance to connect to a remote +/// server by providing either a `Hostname` or an `IpAddress`. This trait also +/// makes it possible to implement and support IPv6 addresses. pub trait Connect<'a, S, B, C> { + /// Connects to `server` on `port` using transport layer `mode`. fn connect), D: DelayMs>( &mut self, server: S, @@ -42,6 +46,8 @@ pub trait Connect<'a, S, B, C> { ) -> Result<(), Error>; } +/// A client that connects to and performs send/receive operations with a remote +/// server using the TCP protocol. pub struct TcpClient<'a, B, C> { pub(crate) protocol_handler: &'a mut NinaProtocolHandler, pub(crate) socket: Option, @@ -103,6 +109,7 @@ where B: Transfer, C: EspControlInterface, { + /// Builds a new instance of a `TcpClient` provided a `Wifi` instance. pub fn build(wifi: &'a mut Wifi) -> Self { Self { protocol_handler: wifi.protocol_handler.get_mut(), @@ -114,35 +121,48 @@ where } } + /// Returns `IpAddress` of the remote server to communicate with that is + /// set by calling `connect()`. pub fn server_ip_address(&self) -> Option { self.server_ip_address } + /// Returns `Hostname` of the remote server to communicate with that is + /// set by calling `connect()`. pub fn server_hostname(&self) -> &str { self.server_hostname.as_ref().unwrap().as_str() } + /// Returns `Port` of the remote server to communicate with that is + /// set by calling `connect()`. pub fn port(&self) -> Port { self.port } + /// Returns `TransportMode` used in communication with the remote server that is + /// set by calling `connect()`. pub fn mode(&self) -> TransportMode { self.mode } + // TODO: Make this non-public pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } + // TODO: Make this non-public pub fn socket(&self) -> Socket { self.socket.unwrap() } + /// Sends a string slice of data to a connected server. pub fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.protocol_handler .send_data(data, self.socket.unwrap_or_default()) } + // Provides the in-common connect() functionality used by the public interface's + // connect(ip_address) or connect(hostname) instances. fn connect_common), D: DelayMs>( &mut self, delay: &mut D, diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index c692f3e..baf73e8 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -263,6 +263,8 @@ where self.protocol_handler.borrow_mut().resolve(hostname) } + /// Provides a reference to the `Spi` bus instance typically used when cleaning up + /// an instance of `Wifi`. pub fn destroy(self) -> S { self.protocol_handler.into_inner().bus.into_inner() } From da65c38b18f9c99405795eab10f4dd34195f5ad9 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 20 Dec 2022 07:43:45 -0500 Subject: [PATCH 092/106] make sure things work after large rebase --- cross/dns/src/main.rs | 2 +- cross/join/src/main.rs | 4 +- cross/secrets/secrets.rs | 2 +- cross/send_data_tcp/src/main.rs | 26 ++++---- esp32-wroom-rp/src/protocol.rs | 4 +- esp32-wroom-rp/src/spi.rs | 2 - esp32-wroom-rp/src/tcp_client.rs | 12 +++- esp32-wroom-rp/src/wifi.rs | 103 ------------------------------- 8 files changed, 30 insertions(+), 125 deletions(-) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 8d8f134..88a7968 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -121,7 +121,7 @@ fn main() -> ! { Ok(status) => { defmt::info!("Get Connection Result: {:?}", status); - let sleep: u32 = 1500; + let mut sleep: u32 = 1500; delay.delay_ms(sleep); if status == ConnectionStatus::Connected { diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 3025492..76a65f5 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -114,13 +114,13 @@ fn main() -> ! { defmt::info!("Entering main loop"); - let mut sleep: u32 = 1500; + let sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(status) => { defmt::info!("Get Connection Result: {:?}", status); - let sleep: u32 = 1500; + let mut sleep: u32 = 1500; delay.delay_ms(sleep); if status == ConnectionStatus::Connected { diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index e97157b..95f689f 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = ""; +const SSID: &str = "Calebphone"; const PASSPHRASE: &str = ""; diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 04ddd00..1b61e78 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -157,10 +157,13 @@ fn main() -> ! { // port // ).ok().unwrap(); - write!(http_document, "GET / HTTP/1.1\r\nHost: {}:{}\r\nAccept: */*\r\n\r\n", - hostname, - port - ).ok().unwrap(); + write!( + http_document, + "GET / HTTP/1.1\r\nHost: {}:{}\r\nAccept: */*\r\n\r\n", + hostname, port + ) + .ok() + .unwrap(); if let Err(e) = TcpClient::build(&mut wifi).connect( hostname, @@ -168,19 +171,18 @@ fn main() -> ! { mode, &mut delay, |tcp_client| { - defmt::info!( - "TCP connection to {:?}:{:?} successful", - hostname, - port - ); + defmt::info!("TCP connection to {:?}:{:?} successful", hostname, port); defmt::info!("Hostname: {:?}", tcp_client.server_hostname()); defmt::info!("Socket: {:?}", tcp_client.socket()); defmt::info!("Sending HTTP Document: {:?}", http_document.as_str()); match tcp_client.send_data(&http_document) { - Ok(response) => { defmt::info!("Response: {:?}", response) } - Err(e) => { defmt::error!("Response error: {:?}", e) } + Ok(response) => { + defmt::info!("Response: {:?}", response) + } + Err(e) => { + defmt::error!("Response error: {:?}", e) + } } - }, ) { defmt::error!( diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 4036dfd..eada4f4 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -6,11 +6,11 @@ use defmt::{write, Format, Formatter}; use heapless::{String, Vec}; -use super::network::{IpAddress, Port, Socket, TransportMode}; +use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode}; use super::wifi::ConnectionStatus; -use super::{Error, FirmwareVersion}; +use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER}; use core::cell::RefCell; diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index def890e..1412f2e 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -18,8 +18,6 @@ use embedded_hal::blocking::spi::Transfer; use core::convert::Infallible; -use super::wifi::ConnectionStatus; - // TODO: this should eventually move into NinaCommandHandler #[repr(u8)] #[derive(Debug)] diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 6304495..fb07899 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -175,8 +175,16 @@ where let port = self.port; if !hostname.is_empty() { - ip = self.protocol_handler.resolve(hostname.as_str()).ok().unwrap_or_default(); - defmt::debug!("Resolved ip: {:?} for hostname: {:?}", ip, hostname.as_str()); + ip = self + .protocol_handler + .resolve(hostname.as_str()) + .ok() + .unwrap_or_default(); + defmt::debug!( + "Resolved ip: {:?} for hostname: {:?}", + ip, + hostname.as_str() + ); } self.protocol_handler diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index baf73e8..82af832 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -1,106 +1,3 @@ -use defmt::{write, Format, Formatter}; - -/// An enumerated type that represents the current WiFi network connection status. -#[repr(u8)] -#[derive(Eq, PartialEq, PartialOrd, Debug)] -pub enum ConnectionStatus { - /// No device is connected to hardware - NoEsp32 = 255, - /// Temporary status while attempting to connect to WiFi network - Idle = 0, - /// No SSID is available - NoActiveSsid, - /// WiFi network scan has finished - ScanCompleted, - /// Device is connected to WiFi network - Connected, - /// Device failed to connect to WiFi network - Failed, - /// Device lost connection to WiFi network - Lost, - /// Device disconnected from WiFi network - Disconnected, - /// Device is listening for connections in Access Point mode - ApListening, - /// Device is connected in Access Point mode - ApConnected, - /// Device failed to make connection in Access Point mode - ApFailed, - /// Unexpected value returned from device, reset may be required - Invalid, -} - -impl From for ConnectionStatus { - fn from(status: u8) -> ConnectionStatus { - match status { - 0 => ConnectionStatus::Idle, - 1 => ConnectionStatus::NoActiveSsid, - 2 => ConnectionStatus::ScanCompleted, - 3 => ConnectionStatus::Connected, - 4 => ConnectionStatus::Failed, - 5 => ConnectionStatus::Lost, - 6 => ConnectionStatus::Disconnected, - 7 => ConnectionStatus::ApListening, - 8 => ConnectionStatus::ApConnected, - 9 => ConnectionStatus::ApFailed, - 255 => ConnectionStatus::NoEsp32, - _ => ConnectionStatus::Invalid, - } - } -} - -impl Format for ConnectionStatus { - fn format(&self, fmt: Formatter) { - match self { - ConnectionStatus::NoEsp32 => write!( - fmt,"No device is connected to hardware" - ), - ConnectionStatus::Idle => write!( - fmt, - "Temporary status while attempting to connect to WiFi network" - ), - ConnectionStatus::NoActiveSsid => write!( - fmt, - "No SSID is available" - ), - ConnectionStatus::ScanCompleted => write!( - fmt, - "WiFi network scan has finished" - ), - ConnectionStatus::Connected => write!( - fmt, - "Device is connected to WiFi network" - ), - ConnectionStatus::Failed => write!( - fmt, - "Device failed to connect to WiFi network" - ), - ConnectionStatus::Lost => write!( - fmt, - "Device lost connection to WiFi network" - ), - ConnectionStatus::Disconnected => write!( - fmt, - "Device disconnected from WiFi network" - ), - ConnectionStatus::ApListening => write!( - fmt, - "Device is lstening for connections in Access Point mode" - ), - ConnectionStatus::ApConnected => write!( - fmt, - "Device is connected in Access Point mode" - ), - ConnectionStatus::ApFailed => write!( - fmt, - "Device failed to make connection in Access Point mode" - ), - ConnectionStatus::Invalid => write!( - fmt, - "Unexpected value returned from device, reset may be required" - ), - } - use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; From 2a7c722b53e8f9e931c90507fccf3c0dab8e5a21 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 20 Dec 2022 08:56:59 -0500 Subject: [PATCH 093/106] commented out tests for tcp_client I added some tests for tcp_client but was unable to get things to compile. Seems like maybe an issue with TcpClient.connect(..) and perhaps the way we use closure. Everything compiles fine if I remove the call to connect(). Leaving this here commented out so that we can come back to it. --- host-tests/tests/spi.rs | 1 - host-tests/tests/tcp_client.rs | 107 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 host-tests/tests/tcp_client.rs diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index ebfa1be..dddeed1 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -3,7 +3,6 @@ use embedded_hal_mock::spi; use esp32_wroom_rp::gpio::EspControlInterface; use esp32_wroom_rp::wifi::Wifi; - struct EspControlMock {} impl EspControlInterface for EspControlMock { diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs new file mode 100644 index 0000000..89b32fb --- /dev/null +++ b/host-tests/tests/tcp_client.rs @@ -0,0 +1,107 @@ +// use embedded_hal_mock::delay::MockNoop; +// use embedded_hal_mock::spi; + +// use esp32_wroom_rp::gpio::EspControlInterface; +// use esp32_wroom_rp::wifi::Wifi; + +// use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; + +// use esp32_wroom_rp::network::{IpAddress, TransportMode, Port}; + +// struct EspControlMock {} + +// impl EspControlInterface for EspControlMock { +// fn init(&mut self) {} + +// fn reset(&mut self, _delay: &mut D) {} + +// fn get_esp_ack(&self) -> bool { +// true +// } + +// fn wait_for_esp_select(&mut self) {} + +// fn wait_for_esp_ack(&self) {} + +// fn wait_for_esp_ready(&self) {} + +// fn esp_select(&mut self) {} + +// fn esp_deselect(&mut self) {} + +// fn get_esp_ready(&self) -> bool { +// true +// } +// } + +// #[test] +// fn tcp_timeout_error() { +// let mut spi_expectations = vec![ +// // send_cmd() for get_socket() +// spi::Transaction::transfer(vec![0xe0], vec![0x0]), +// spi::Transaction::transfer(vec![0x3f], vec![0x0]), +// spi::Transaction::transfer(vec![0x0], vec![0x0]), +// spi::Transaction::transfer(vec![0xee], vec![0x0]), +// // wait_response_cmd() for get_socket() +// spi::Transaction::transfer(vec![0xff], vec![0xe0]), +// spi::Transaction::transfer(vec![0xff], vec![0xb7]), +// spi::Transaction::transfer(vec![0xff], vec![0x1]), +// // test relies on max number of parameters being 8. This will probably change +// // as we understand more. +// spi::Transaction::transfer(vec![0xff], vec![0x9]), + +// // send_cmd() for start_client_tcp() +// spi::Transaction::transfer(vec![0xe0], vec![0x0]), +// spi::Transaction::transfer(vec![0x2e], vec![0x0]), +// spi::Transaction::transfer(vec![0x0], vec![0x0]), +// spi::Transaction::transfer(vec![0xee], vec![0x0]), +// // wait_response_cmd() for start_client_tcp() +// spi::Transaction::transfer(vec![0xff], vec![0xe0]), +// spi::Transaction::transfer(vec![0xff], vec![0xb7]), +// spi::Transaction::transfer(vec![0xff], vec![0x1]), +// // test relies on max number of parameters being 8. This will probably change +// // as we understand more. +// spi::Transaction::transfer(vec![0xff], vec![0x9]), +// ]; + +// for _ in 0..10_000 { +// // send_cmd() for get_client_state_tcp +// spi_expectations.push(spi::Transaction::transfer(vec![0xe0], vec![0x0])); +// spi_expectations.push(spi::Transaction::transfer(vec![0x2f], vec![0x0])); +// spi_expectations.push(spi::Transaction::transfer(vec![0x0], vec![0x0])); +// spi_expectations.push(spi::Transaction::transfer(vec![0xee], vec![0x0])); + +// // wait_response_cmd() for get_client_state_tcp +// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); +// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xb7])); +// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); +// // test relies on max number of parameters being 8. This will probably change +// // as we understand more. +// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); +// } + +// let spi = spi::Mock::new(&spi_expectations); + +// let mut delay = MockNoop::new(); + +// let pins = EspControlMock {}; + +// let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); + +// let ip_address: IpAddress = [0, 0, 0, 0]; +// let port: Port = 4000; +// let mode: TransportMode = TransportMode::Tcp; + +// let result = TcpClient::build(&mut wifi).connect( +// ip_address, +// port, +// mode, +// &mut delay, +// |_tcp_client| {} +// ); + +// assert_eq!( +// result.unwrap_err(), +// esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) +// ); +// } From e9dffe0cb25dd6d7b732313e6b1bdd452a8f7468 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 21 Dec 2022 09:24:13 -0500 Subject: [PATCH 094/106] add support module for tests --- esp32-wroom-rp/src/tcp_client.rs | 15 +- host-tests/tests/spi.rs | 26 +--- host-tests/tests/support/mod.rs | 27 ++++ host-tests/tests/tcp_client.rs | 245 +++++++++++++++++-------------- 4 files changed, 171 insertions(+), 142 deletions(-) create mode 100644 host-tests/tests/support/mod.rs diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index fb07899..75265d6 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -10,10 +10,10 @@ use super::network::{ConnectionState, Hostname, IpAddress, Port, Socket, Transpo use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::spi::Transfer; -use defmt::{write, Format, Formatter}; - use heapless::String; +use defmt::{write, Format, Formatter}; + // TODO: find a good max length const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; @@ -180,11 +180,6 @@ where .resolve(hostname.as_str()) .ok() .unwrap_or_default(); - defmt::debug!( - "Resolved ip: {:?} for hostname: {:?}", - ip, - hostname.as_str() - ); } self.protocol_handler @@ -208,19 +203,17 @@ where return Ok(()); } Ok(status) => { - defmt::debug!("TCP client connection status: {:?}", status); + delay.delay_ms(100); + retry_limit -= 1; } Err(error) => { // At this point any error will likely be a protocol level error. // We do not currently consider any ConnectionState variants as errors. - defmt::error!("TCP client connection error: {:?}", error); self.protocol_handler.stop_client_tcp(socket, &mode)?; return Err(error); } } - delay.delay_ms(100); - retry_limit -= 1; } self.protocol_handler.stop_client_tcp(socket, &mode)?; diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index dddeed1..ee331bd 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -1,33 +1,11 @@ use embedded_hal_mock::delay::MockNoop; use embedded_hal_mock::spi; -use esp32_wroom_rp::gpio::EspControlInterface; use esp32_wroom_rp::wifi::Wifi; -struct EspControlMock {} -impl EspControlInterface for EspControlMock { - fn init(&mut self) {} +pub mod support; - fn reset(&mut self, _delay: &mut D) {} - - fn get_esp_ack(&self) -> bool { - true - } - - fn wait_for_esp_select(&mut self) {} - - fn wait_for_esp_ack(&self) {} - - fn wait_for_esp_ready(&self) {} - - fn esp_select(&mut self) {} - - fn esp_deselect(&mut self) {} - - fn get_esp_ready(&self) -> bool { - true - } -} +use support::EspControlMock; #[test] fn too_many_parameters_error() { diff --git a/host-tests/tests/support/mod.rs b/host-tests/tests/support/mod.rs new file mode 100644 index 0000000..2429d02 --- /dev/null +++ b/host-tests/tests/support/mod.rs @@ -0,0 +1,27 @@ +use esp32_wroom_rp::gpio::EspControlInterface; + +pub(crate) struct EspControlMock {} + +impl EspControlInterface for EspControlMock { + fn init(&mut self) {} + + fn reset(&mut self, _delay: &mut D) {} + + fn get_esp_ack(&self) -> bool { + true + } + + fn wait_for_esp_select(&mut self) {} + + fn wait_for_esp_ack(&self) {} + + fn wait_for_esp_ready(&self) {} + + fn esp_select(&mut self) {} + + fn esp_deselect(&mut self) {} + + fn get_esp_ready(&self) -> bool { + true + } +} \ No newline at end of file diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs index 89b32fb..bbc268b 100644 --- a/host-tests/tests/tcp_client.rs +++ b/host-tests/tests/tcp_client.rs @@ -1,107 +1,138 @@ -// use embedded_hal_mock::delay::MockNoop; -// use embedded_hal_mock::spi; - -// use esp32_wroom_rp::gpio::EspControlInterface; -// use esp32_wroom_rp::wifi::Wifi; - -// use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; - -// use esp32_wroom_rp::network::{IpAddress, TransportMode, Port}; - -// struct EspControlMock {} - -// impl EspControlInterface for EspControlMock { -// fn init(&mut self) {} - -// fn reset(&mut self, _delay: &mut D) {} - -// fn get_esp_ack(&self) -> bool { -// true -// } - -// fn wait_for_esp_select(&mut self) {} - -// fn wait_for_esp_ack(&self) {} - -// fn wait_for_esp_ready(&self) {} - -// fn esp_select(&mut self) {} - -// fn esp_deselect(&mut self) {} - -// fn get_esp_ready(&self) -> bool { -// true -// } -// } - -// #[test] -// fn tcp_timeout_error() { -// let mut spi_expectations = vec![ -// // send_cmd() for get_socket() -// spi::Transaction::transfer(vec![0xe0], vec![0x0]), -// spi::Transaction::transfer(vec![0x3f], vec![0x0]), -// spi::Transaction::transfer(vec![0x0], vec![0x0]), -// spi::Transaction::transfer(vec![0xee], vec![0x0]), -// // wait_response_cmd() for get_socket() -// spi::Transaction::transfer(vec![0xff], vec![0xe0]), -// spi::Transaction::transfer(vec![0xff], vec![0xb7]), -// spi::Transaction::transfer(vec![0xff], vec![0x1]), -// // test relies on max number of parameters being 8. This will probably change -// // as we understand more. -// spi::Transaction::transfer(vec![0xff], vec![0x9]), - -// // send_cmd() for start_client_tcp() -// spi::Transaction::transfer(vec![0xe0], vec![0x0]), -// spi::Transaction::transfer(vec![0x2e], vec![0x0]), -// spi::Transaction::transfer(vec![0x0], vec![0x0]), -// spi::Transaction::transfer(vec![0xee], vec![0x0]), -// // wait_response_cmd() for start_client_tcp() -// spi::Transaction::transfer(vec![0xff], vec![0xe0]), -// spi::Transaction::transfer(vec![0xff], vec![0xb7]), -// spi::Transaction::transfer(vec![0xff], vec![0x1]), -// // test relies on max number of parameters being 8. This will probably change -// // as we understand more. -// spi::Transaction::transfer(vec![0xff], vec![0x9]), -// ]; - -// for _ in 0..10_000 { -// // send_cmd() for get_client_state_tcp -// spi_expectations.push(spi::Transaction::transfer(vec![0xe0], vec![0x0])); -// spi_expectations.push(spi::Transaction::transfer(vec![0x2f], vec![0x0])); -// spi_expectations.push(spi::Transaction::transfer(vec![0x0], vec![0x0])); -// spi_expectations.push(spi::Transaction::transfer(vec![0xee], vec![0x0])); - -// // wait_response_cmd() for get_client_state_tcp -// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); -// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xb7])); -// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); -// // test relies on max number of parameters being 8. This will probably change -// // as we understand more. -// spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); -// } - -// let spi = spi::Mock::new(&spi_expectations); - -// let mut delay = MockNoop::new(); - -// let pins = EspControlMock {}; - -// let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); - -// let ip_address: IpAddress = [0, 0, 0, 0]; -// let port: Port = 4000; -// let mode: TransportMode = TransportMode::Tcp; - -// let result = TcpClient::build(&mut wifi).connect( -// ip_address, -// port, -// mode, -// &mut delay, -// |_tcp_client| {} -// ); - -// assert_eq!( -// result.unwrap_err(), -// esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) -// ); -// } +use embedded_hal_mock::delay::MockNoop; +use embedded_hal_mock::spi; + +use esp32_wroom_rp::wifi::Wifi; +use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; +use esp32_wroom_rp::network::{IpAddress, TransportMode, Port}; + +pub mod support; + +use support::EspControlMock; + +#[test] +fn tcp_timeout_error() { + let mut spi_expectations = vec![ + // send_cmd() for get_socket() + // send start byte + spi::Transaction::transfer(vec![0xe0], vec![0x0]), + // send command byte + spi::Transaction::transfer(vec![0x3f], vec![0x0]), + // send number of params + spi::Transaction::transfer(vec![0x0], vec![0x0]), + // send end command byte + spi::Transaction::transfer(vec![0xee], vec![0x0]), + + // wait_response_cmd() for get_socket() + // read start command + spi::Transaction::transfer(vec![0xff], vec![0xe0]), + // read command byte | reply byte + spi::Transaction::transfer(vec![0xff], vec![0xbf]), + // read number of params to receive + spi::Transaction::transfer(vec![0xff], vec![0x1]), + // test relies on max number of parameters being 8. This will probably change + // as we understand more. + spi::Transaction::transfer(vec![0xff], vec![0x8]), + + // read full 8 byte buffer + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + + // read end byte + spi::Transaction::transfer(vec![0xff], vec![0xee]), + + + // send_cmd() for start_client_tcp() + // send start byte + spi::Transaction::transfer(vec![0xe0], vec![0x0]), + // send command byte + spi::Transaction::transfer(vec![0x2e], vec![0x0]), + // send number of params + spi::Transaction::transfer(vec![0x0], vec![0x4]), + // send end command byte + spi::Transaction::transfer(vec![0xee], vec![0x0]), + + // wait_response_cmd() for get_socket() + // read start command + spi::Transaction::transfer(vec![0xff], vec![0xe0]), + // read command byte | reply byte + spi::Transaction::transfer(vec![0xff], vec![0xbf]), + // read number of params to receive + spi::Transaction::transfer(vec![0xff], vec![0x1]), + // test relies on max number of parameters being 8. This will probably change + // as we understand more. + spi::Transaction::transfer(vec![0xff], vec![0x8]), + + // read full 8 byte buffer + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + + // read end byte + spi::Transaction::transfer(vec![0xff], vec![0xee]), + + // // send_cmd() for start_client_tcp() + // spi::Transaction::transfer(vec![0xe0], vec![0x0]), + // spi::Transaction::transfer(vec![0x2e], vec![0x0]), + // spi::Transaction::transfer(vec![0x0], vec![0x0]), + // spi::Transaction::transfer(vec![0xee], vec![0x0]), + // // wait_response_cmd() for start_client_tcp() + // spi::Transaction::transfer(vec![0xff], vec![0xe0]), + // spi::Transaction::transfer(vec![0xff], vec![0xb7]), + // spi::Transaction::transfer(vec![0xff], vec![0x1]), + // // test relies on max number of parameters being 8. This will probably change + // // as we understand more. + // spi::Transaction::transfer(vec![0xff], vec![0x9]), + ]; + + // for _ in 0..10_000 { + // // send_cmd() for get_client_state_tcp + // spi_expectations.push(spi::Transaction::transfer(vec![0xe0], vec![0x0])); + // spi_expectations.push(spi::Transaction::transfer(vec![0x2f], vec![0x0])); + // spi_expectations.push(spi::Transaction::transfer(vec![0x0], vec![0x0])); + // spi_expectations.push(spi::Transaction::transfer(vec![0xee], vec![0x0])); + + // // wait_response_cmd() for get_client_state_tcp + // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); + // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xb7])); + // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); + // // test relies on max number of parameters being 8. This will probably change + // // as we understand more. + // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); + // } + + let spi = spi::Mock::new(&spi_expectations); + + let mut delay = MockNoop::new(); + + let pins = EspControlMock {}; + + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); + + let ip_address: IpAddress = [0, 0, 0, 0]; + let port: Port = 4000; + let mode: TransportMode = TransportMode::Tcp; + + let result = TcpClient::build(&mut wifi).connect( + ip_address, + port, + mode, + &mut delay, + |_tcp_client| {} + ); + + assert_eq!( + result.unwrap_err(), + esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) + ); +} From 021dd5645cfcdc95e437c15deba5f265fa1dd628 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 21 Dec 2022 10:04:02 -0500 Subject: [PATCH 095/106] use helper functions in tests --- esp32-wroom-rp/src/spi.rs | 2 +- host-tests/tests/spi.rs | 90 +++++++------ host-tests/tests/support/mod.rs | 47 ++++++- host-tests/tests/tcp_client.rs | 232 +++++++++++++------------------- 4 files changed, 190 insertions(+), 181 deletions(-) diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 1412f2e..f8bdca1 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -322,7 +322,7 @@ where return Err(ProtocolError::TooManyParameters.into()); } - let mut params: [u8; ARRAY_LENGTH_PLACEHOLDER] = [0; 8]; + let mut params: [u8; ARRAY_LENGTH_PLACEHOLDER] = [0; ARRAY_LENGTH_PLACEHOLDER]; for (index, _param) in params.into_iter().enumerate() { params[index] = self.get_byte().ok().unwrap() } diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index ee331bd..09a3c1d 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -5,25 +5,30 @@ use esp32_wroom_rp::wifi::Wifi; pub mod support; -use support::EspControlMock; +use support::*; #[test] fn too_many_parameters_error() { - let spi_expectations = vec![ - // send_cmd() - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - spi::Transaction::transfer(vec![0x37], vec![0x0]), - spi::Transaction::transfer(vec![0x0], vec![0x0]), - spi::Transaction::transfer(vec![0xee], vec![0x0]), + let command = 0x37; + let number_of_params = 0x0; + let mut expectations = mock_command(command, number_of_params); + + let mut too_man_parameters_expectations = vec![ // wait_response_cmd() + // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), - spi::Transaction::transfer(vec![0xff], vec![0xb7]), + // read command byte | reply byte + spi::Transaction::transfer(vec![0xff], vec![command_reply_byte(command)]), + // read number of params to receive spi::Transaction::transfer(vec![0xff], vec![0x1]), // test relies on max number of parameters being 8. This will probably change // as we understand more. spi::Transaction::transfer(vec![0xff], vec![0x9]), ]; - let spi = spi::Mock::new(&spi_expectations); + + expectations.append(&mut too_man_parameters_expectations); + + let spi = spi::Mock::new(&expectations); let mut delay = MockNoop::new(); @@ -42,18 +47,22 @@ fn too_many_parameters_error() { #[test] fn invalid_number_of_parameters_error() { - let spi_expectations = vec![ - // send_cmd() - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - spi::Transaction::transfer(vec![0x37], vec![0x0]), - spi::Transaction::transfer(vec![0x0], vec![0x0]), - spi::Transaction::transfer(vec![0xee], vec![0x0]), + let command = 0x37; + let number_of_params = 0x0; + let mut expectations = mock_command(command, number_of_params); + let mut invalid_number_of_parameters_expactations = vec![ // wait_response_cmd() + // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), - spi::Transaction::transfer(vec![0xff], vec![0xb7]), + // read command byte | reply byte + spi::Transaction::transfer(vec![0xff], vec![command_reply_byte(command)]), + // read number of params to receive (should be 1) spi::Transaction::transfer(vec![0xff], vec![0x0]), ]; - let spi = spi::Mock::new(&spi_expectations); + + expectations.append(&mut invalid_number_of_parameters_expactations); + + let spi = spi::Mock::new(&expectations); let mut delay = MockNoop::new(); @@ -74,17 +83,19 @@ fn invalid_number_of_parameters_error() { #[test] fn invalid_command_induces_invalid_command_error() { - let spi_expectations = vec![ - // send_cmd() - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - spi::Transaction::transfer(vec![0x37], vec![0x0]), - spi::Transaction::transfer(vec![0x0], vec![0x0]), - spi::Transaction::transfer(vec![0xee], vec![0x0]), + let command = 0x37; + let number_of_params = 0x0; + let mut expectations = mock_command(command, number_of_params); + let mut invalid_command_expactations = vec![ // wait_response_cmd() + // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), - spi::Transaction::transfer(vec![0xff], vec![0x0]), + // read command byte (should be command | reply byte) + spi::Transaction::transfer(vec![0xff], vec![0xff]), ]; - let spi = spi::Mock::new(&spi_expectations); + expectations.append(&mut invalid_command_expactations); + + let spi = spi::Mock::new(&expectations); let mut delay = MockNoop::new(); @@ -103,20 +114,16 @@ fn invalid_command_induces_invalid_command_error() { #[test] fn timeout_induces_communication_timeout_error() { - let mut spi_expectations = vec![ - // send_cmd() - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - spi::Transaction::transfer(vec![0x37], vec![0x0]), - spi::Transaction::transfer(vec![0x0], vec![0x0]), - spi::Transaction::transfer(vec![0xee], vec![0x0]), - ]; + let command = 0x37; + let number_of_params = 0x0; + let mut expectations = mock_command(command, number_of_params); // simulate reading 1000 bytes which will exhaust the retry limit. for _ in 0..1000 { - spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x0])) + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x0])) } - let spi = spi::Mock::new(&spi_expectations); + let spi = spi::Mock::new(&expectations); let mut delay = MockNoop::new(); @@ -137,16 +144,17 @@ fn timeout_induces_communication_timeout_error() { #[test] fn invalid_command_induces_nina_protocol_version_mismatch_error() { - let spi_expectations = vec![ - // send_cmd() - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - spi::Transaction::transfer(vec![0x37], vec![0x0]), - spi::Transaction::transfer(vec![0x0], vec![0x0]), - spi::Transaction::transfer(vec![0xee], vec![0x0]), + let command = 0x37; + let number_of_params = 0x0; + let mut expectations = mock_command(command, number_of_params); + let mut invalid_command_expactations = vec![ // wait_response_cmd() + // read start command (should be ee) spi::Transaction::transfer(vec![0xff], vec![0xef]), ]; - let spi = spi::Mock::new(&spi_expectations); + expectations.append(&mut invalid_command_expactations); + + let spi = spi::Mock::new(&expectations); let mut delay = MockNoop::new(); diff --git a/host-tests/tests/support/mod.rs b/host-tests/tests/support/mod.rs index 2429d02..801a94d 100644 --- a/host-tests/tests/support/mod.rs +++ b/host-tests/tests/support/mod.rs @@ -1,3 +1,4 @@ +use embedded_hal_mock::spi; use esp32_wroom_rp::gpio::EspControlInterface; pub(crate) struct EspControlMock {} @@ -24,4 +25,48 @@ impl EspControlInterface for EspControlMock { fn get_esp_ready(&self) -> bool { true } -} \ No newline at end of file +} + +pub fn mock_command(command_byte: u8, number_of_params: u8) -> Vec { + vec![ + // send_cmd() + // send start byte + spi::Transaction::transfer(vec![0xe0], vec![0x0]), + // send command byte + spi::Transaction::transfer(vec![command_byte], vec![0x0]), + // send number of params + spi::Transaction::transfer(vec![number_of_params], vec![0x0]), + // send end command byte + spi::Transaction::transfer(vec![0xee], vec![0x0]), + ] +} + +fn mock_response(command_byte: u8, number_of_params_to_receive: u8) -> Vec { + vec![ + // wait_response_cmd() + // read start command + spi::Transaction::transfer(vec![0xff], vec![0xe0]), + // read command byte | reply byte + spi::Transaction::transfer(vec![command_reply_byte(command_byte)], vec![0xbf]), + // read number of params to receive + spi::Transaction::transfer(vec![number_of_params_to_receive], vec![0x1]), + // test relies on max number of parameters being 8. This will probably change + // as we understand more. + spi::Transaction::transfer(vec![0xff], vec![0x8]), + // read full 8 byte buffer + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![0xff]), + // read end byte + spi::Transaction::transfer(vec![0xff], vec![0xee]), + ] +} + +pub fn command_reply_byte(command: u8) -> u8 { + command | 0x80 +} diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs index bbc268b..00c5192 100644 --- a/host-tests/tests/tcp_client.rs +++ b/host-tests/tests/tcp_client.rs @@ -1,138 +1,94 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::spi; - -use esp32_wroom_rp::wifi::Wifi; -use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; -use esp32_wroom_rp::network::{IpAddress, TransportMode, Port}; - -pub mod support; - -use support::EspControlMock; - -#[test] -fn tcp_timeout_error() { - let mut spi_expectations = vec![ - // send_cmd() for get_socket() - // send start byte - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - // send command byte - spi::Transaction::transfer(vec![0x3f], vec![0x0]), - // send number of params - spi::Transaction::transfer(vec![0x0], vec![0x0]), - // send end command byte - spi::Transaction::transfer(vec![0xee], vec![0x0]), - - // wait_response_cmd() for get_socket() - // read start command - spi::Transaction::transfer(vec![0xff], vec![0xe0]), - // read command byte | reply byte - spi::Transaction::transfer(vec![0xff], vec![0xbf]), - // read number of params to receive - spi::Transaction::transfer(vec![0xff], vec![0x1]), - // test relies on max number of parameters being 8. This will probably change - // as we understand more. - spi::Transaction::transfer(vec![0xff], vec![0x8]), - - // read full 8 byte buffer - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - - // read end byte - spi::Transaction::transfer(vec![0xff], vec![0xee]), - - - // send_cmd() for start_client_tcp() - // send start byte - spi::Transaction::transfer(vec![0xe0], vec![0x0]), - // send command byte - spi::Transaction::transfer(vec![0x2e], vec![0x0]), - // send number of params - spi::Transaction::transfer(vec![0x0], vec![0x4]), - // send end command byte - spi::Transaction::transfer(vec![0xee], vec![0x0]), - - // wait_response_cmd() for get_socket() - // read start command - spi::Transaction::transfer(vec![0xff], vec![0xe0]), - // read command byte | reply byte - spi::Transaction::transfer(vec![0xff], vec![0xbf]), - // read number of params to receive - spi::Transaction::transfer(vec![0xff], vec![0x1]), - // test relies on max number of parameters being 8. This will probably change - // as we understand more. - spi::Transaction::transfer(vec![0xff], vec![0x8]), - - // read full 8 byte buffer - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - - // read end byte - spi::Transaction::transfer(vec![0xff], vec![0xee]), - - // // send_cmd() for start_client_tcp() - // spi::Transaction::transfer(vec![0xe0], vec![0x0]), - // spi::Transaction::transfer(vec![0x2e], vec![0x0]), - // spi::Transaction::transfer(vec![0x0], vec![0x0]), - // spi::Transaction::transfer(vec![0xee], vec![0x0]), - // // wait_response_cmd() for start_client_tcp() - // spi::Transaction::transfer(vec![0xff], vec![0xe0]), - // spi::Transaction::transfer(vec![0xff], vec![0xb7]), - // spi::Transaction::transfer(vec![0xff], vec![0x1]), - // // test relies on max number of parameters being 8. This will probably change - // // as we understand more. - // spi::Transaction::transfer(vec![0xff], vec![0x9]), - ]; - - // for _ in 0..10_000 { - // // send_cmd() for get_client_state_tcp - // spi_expectations.push(spi::Transaction::transfer(vec![0xe0], vec![0x0])); - // spi_expectations.push(spi::Transaction::transfer(vec![0x2f], vec![0x0])); - // spi_expectations.push(spi::Transaction::transfer(vec![0x0], vec![0x0])); - // spi_expectations.push(spi::Transaction::transfer(vec![0xee], vec![0x0])); - - // // wait_response_cmd() for get_client_state_tcp - // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); - // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xb7])); - // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); - // // test relies on max number of parameters being 8. This will probably change - // // as we understand more. - // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); - // } - - let spi = spi::Mock::new(&spi_expectations); - - let mut delay = MockNoop::new(); - - let pins = EspControlMock {}; - - let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); - - let ip_address: IpAddress = [0, 0, 0, 0]; - let port: Port = 4000; - let mode: TransportMode = TransportMode::Tcp; - - let result = TcpClient::build(&mut wifi).connect( - ip_address, - port, - mode, - &mut delay, - |_tcp_client| {} - ); - - assert_eq!( - result.unwrap_err(), - esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) - ); -} +// use embedded_hal_mock::delay::MockNoop; +// use embedded_hal_mock::spi; + +// use esp32_wroom_rp::network::{IpAddress, Port, TransportMode}; +// use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; +// use esp32_wroom_rp::wifi::Wifi; + +// pub mod support; + +// use support::*; + +// #[test] +// fn tcp_timeout_error() { +// let mut spi_expectations = +// // send_cmd() for start_client_tcp() +// // send start byte +// spi::Transaction::transfer(vec![0xe0], vec![0x0]), +// // send command byte +// spi::Transaction::transfer(vec![0x2e], vec![0x0]), +// // send number of params +// spi::Transaction::transfer(vec![0x0], vec![0x4]), +// // send end command byte +// spi::Transaction::transfer(vec![0xee], vec![0x0]), +// // wait_response_cmd() for get_socket() +// // read start command +// spi::Transaction::transfer(vec![0xff], vec![0xe0]), +// // read command byte | reply byte +// spi::Transaction::transfer(vec![0xff], vec![0xbf]), +// // read number of params to receive +// spi::Transaction::transfer(vec![0xff], vec![0x1]), +// // test relies on max number of parameters being 8. This will probably change +// // as we understand more. +// spi::Transaction::transfer(vec![0xff], vec![0x8]), +// // read full 8 byte buffer +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// spi::Transaction::transfer(vec![0xff], vec![0xff]), +// // read end byte +// spi::Transaction::transfer(vec![0xff], vec![0xee]), +// // // send_cmd() for start_client_tcp() +// // spi::Transaction::transfer(vec![0xe0], vec![0x0]), +// // spi::Transaction::transfer(vec![0x2e], vec![0x0]), +// // spi::Transaction::transfer(vec![0x0], vec![0x0]), +// // spi::Transaction::transfer(vec![0xee], vec![0x0]), +// // // wait_response_cmd() for start_client_tcp() +// // spi::Transaction::transfer(vec![0xff], vec![0xe0]), +// // spi::Transaction::transfer(vec![0xff], vec![0xb7]), +// // spi::Transaction::transfer(vec![0xff], vec![0x1]), +// // // test relies on max number of parameters being 8. This will probably change +// // // as we understand more. +// // spi::Transaction::transfer(vec![0xff], vec![0x9]), +// ]; + +// // for _ in 0..10_000 { +// // // send_cmd() for get_client_state_tcp +// // spi_expectations.push(spi::Transaction::transfer(vec![0xe0], vec![0x0])); +// // spi_expectations.push(spi::Transaction::transfer(vec![0x2f], vec![0x0])); +// // spi_expectations.push(spi::Transaction::transfer(vec![0x0], vec![0x0])); +// // spi_expectations.push(spi::Transaction::transfer(vec![0xee], vec![0x0])); + +// // // wait_response_cmd() for get_client_state_tcp +// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); +// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xb7])); +// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); +// // // test relies on max number of parameters being 8. This will probably change +// // // as we understand more. +// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); +// // } + +// let spi = spi::Mock::new(&spi_expectations); + +// let mut delay = MockNoop::new(); + +// let pins = EspControlMock {}; + +// let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); + +// let ip_address: IpAddress = [0, 0, 0, 0]; +// let port: Port = 4000; +// let mode: TransportMode = TransportMode::Tcp; + +// let result = +// TcpClient::build(&mut wifi).connect(ip_address, port, mode, &mut delay, |_tcp_client| {}); + +// assert_eq!( +// result.unwrap_err(), +// esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) +// ); +// } From ffa1b90d59492f54772f517880825bd8bed10f81 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 21 Dec 2022 17:49:10 -0500 Subject: [PATCH 096/106] successful timeout error testing --- esp32-wroom-rp/src/tcp_client.rs | 2 +- host-tests/tests/spi.rs | 17 ++- host-tests/tests/support/mod.rs | 50 ++++++- host-tests/tests/tcp_client.rs | 225 ++++++++++++++++++------------- 4 files changed, 191 insertions(+), 103 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 75265d6..0ef8450 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -202,7 +202,7 @@ where return Ok(()); } - Ok(status) => { + Ok(_status) => { delay.delay_ms(100); retry_limit -= 1; } diff --git a/host-tests/tests/spi.rs b/host-tests/tests/spi.rs index 09a3c1d..bb1102d 100644 --- a/host-tests/tests/spi.rs +++ b/host-tests/tests/spi.rs @@ -13,12 +13,14 @@ fn too_many_parameters_error() { let number_of_params = 0x0; let mut expectations = mock_command(command, number_of_params); + expectations.append(&mut mock_end_byte()); + let mut too_man_parameters_expectations = vec![ // wait_response_cmd() // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), // read command byte | reply byte - spi::Transaction::transfer(vec![0xff], vec![command_reply_byte(command)]), + spi::Transaction::transfer(vec![0xff], vec![command_or_reply_byte(command)]), // read number of params to receive spi::Transaction::transfer(vec![0xff], vec![0x1]), // test relies on max number of parameters being 8. This will probably change @@ -50,12 +52,15 @@ fn invalid_number_of_parameters_error() { let command = 0x37; let number_of_params = 0x0; let mut expectations = mock_command(command, number_of_params); + + expectations.append(&mut mock_end_byte()); + let mut invalid_number_of_parameters_expactations = vec![ // wait_response_cmd() // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), // read command byte | reply byte - spi::Transaction::transfer(vec![0xff], vec![command_reply_byte(command)]), + spi::Transaction::transfer(vec![0xff], vec![command_or_reply_byte(command)]), // read number of params to receive (should be 1) spi::Transaction::transfer(vec![0xff], vec![0x0]), ]; @@ -86,6 +91,9 @@ fn invalid_command_induces_invalid_command_error() { let command = 0x37; let number_of_params = 0x0; let mut expectations = mock_command(command, number_of_params); + + expectations.append(&mut mock_end_byte()); + let mut invalid_command_expactations = vec![ // wait_response_cmd() // read start command @@ -118,6 +126,8 @@ fn timeout_induces_communication_timeout_error() { let number_of_params = 0x0; let mut expectations = mock_command(command, number_of_params); + expectations.append(&mut mock_end_byte()); + // simulate reading 1000 bytes which will exhaust the retry limit. for _ in 0..1000 { expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x0])) @@ -147,6 +157,9 @@ fn invalid_command_induces_nina_protocol_version_mismatch_error() { let command = 0x37; let number_of_params = 0x0; let mut expectations = mock_command(command, number_of_params); + + expectations.append(&mut mock_end_byte()); + let mut invalid_command_expactations = vec![ // wait_response_cmd() // read start command (should be ee) diff --git a/host-tests/tests/support/mod.rs b/host-tests/tests/support/mod.rs index 801a94d..642787e 100644 --- a/host-tests/tests/support/mod.rs +++ b/host-tests/tests/support/mod.rs @@ -33,28 +33,62 @@ pub fn mock_command(command_byte: u8, number_of_params: u8) -> Vec Vec { + let mut expectations = vec![spi::Transaction::transfer( + vec![number_of_param_bytes], + vec![0x0], + )]; + + for _ in 0..number_of_param_bytes { + expectations.push(spi::Transaction::transfer(vec![byte_value], vec![0x0])); + } + + expectations +} + +pub fn mock_padding(number_of_padding_bytes: u8) -> Vec { + let mut expectations = Vec::new(); + for _ in 0..number_of_padding_bytes { + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x0])); + } + + expectations +} + +pub fn mock_end_byte() -> Vec { + vec![ // send end command byte spi::Transaction::transfer(vec![0xee], vec![0x0]), ] } -fn mock_response(command_byte: u8, number_of_params_to_receive: u8) -> Vec { +pub fn mock_receive( + command_byte: u8, + number_of_params_to_receive: u8, + value_to_receive: u8, +) -> Vec { vec![ // wait_response_cmd() // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), // read command byte | reply byte - spi::Transaction::transfer(vec![command_reply_byte(command_byte)], vec![0xbf]), + spi::Transaction::transfer(vec![0xff], vec![command_or_reply_byte(command_byte)]), // read number of params to receive - spi::Transaction::transfer(vec![number_of_params_to_receive], vec![0x1]), + spi::Transaction::transfer(vec![0xff], vec![number_of_params_to_receive]), // test relies on max number of parameters being 8. This will probably change // as we understand more. spi::Transaction::transfer(vec![0xff], vec![0x8]), // read full 8 byte buffer - spi::Transaction::transfer(vec![0xff], vec![0xff]), + spi::Transaction::transfer(vec![0xff], vec![value_to_receive]), spi::Transaction::transfer(vec![0xff], vec![0xff]), spi::Transaction::transfer(vec![0xff], vec![0xff]), spi::Transaction::transfer(vec![0xff], vec![0xff]), @@ -67,6 +101,10 @@ fn mock_response(command_byte: u8, number_of_params_to_receive: u8) -> Vec u8 { +pub fn command_or_reply_byte(command: u8) -> u8 { command | 0x80 } + +pub fn command_and_reply_byte(command: u8) -> u8 { + (command as u8) & !(0x80 as u8) +} diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs index 00c5192..c1f13d9 100644 --- a/host-tests/tests/tcp_client.rs +++ b/host-tests/tests/tcp_client.rs @@ -1,94 +1,131 @@ -// use embedded_hal_mock::delay::MockNoop; -// use embedded_hal_mock::spi; - -// use esp32_wroom_rp::network::{IpAddress, Port, TransportMode}; -// use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; -// use esp32_wroom_rp::wifi::Wifi; - -// pub mod support; - -// use support::*; - -// #[test] -// fn tcp_timeout_error() { -// let mut spi_expectations = -// // send_cmd() for start_client_tcp() -// // send start byte -// spi::Transaction::transfer(vec![0xe0], vec![0x0]), -// // send command byte -// spi::Transaction::transfer(vec![0x2e], vec![0x0]), -// // send number of params -// spi::Transaction::transfer(vec![0x0], vec![0x4]), -// // send end command byte -// spi::Transaction::transfer(vec![0xee], vec![0x0]), -// // wait_response_cmd() for get_socket() -// // read start command -// spi::Transaction::transfer(vec![0xff], vec![0xe0]), -// // read command byte | reply byte -// spi::Transaction::transfer(vec![0xff], vec![0xbf]), -// // read number of params to receive -// spi::Transaction::transfer(vec![0xff], vec![0x1]), -// // test relies on max number of parameters being 8. This will probably change -// // as we understand more. -// spi::Transaction::transfer(vec![0xff], vec![0x8]), -// // read full 8 byte buffer -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// spi::Transaction::transfer(vec![0xff], vec![0xff]), -// // read end byte -// spi::Transaction::transfer(vec![0xff], vec![0xee]), -// // // send_cmd() for start_client_tcp() -// // spi::Transaction::transfer(vec![0xe0], vec![0x0]), -// // spi::Transaction::transfer(vec![0x2e], vec![0x0]), -// // spi::Transaction::transfer(vec![0x0], vec![0x0]), -// // spi::Transaction::transfer(vec![0xee], vec![0x0]), -// // // wait_response_cmd() for start_client_tcp() -// // spi::Transaction::transfer(vec![0xff], vec![0xe0]), -// // spi::Transaction::transfer(vec![0xff], vec![0xb7]), -// // spi::Transaction::transfer(vec![0xff], vec![0x1]), -// // // test relies on max number of parameters being 8. This will probably change -// // // as we understand more. -// // spi::Transaction::transfer(vec![0xff], vec![0x9]), -// ]; - -// // for _ in 0..10_000 { -// // // send_cmd() for get_client_state_tcp -// // spi_expectations.push(spi::Transaction::transfer(vec![0xe0], vec![0x0])); -// // spi_expectations.push(spi::Transaction::transfer(vec![0x2f], vec![0x0])); -// // spi_expectations.push(spi::Transaction::transfer(vec![0x0], vec![0x0])); -// // spi_expectations.push(spi::Transaction::transfer(vec![0xee], vec![0x0])); - -// // // wait_response_cmd() for get_client_state_tcp -// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); -// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xb7])); -// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); -// // // test relies on max number of parameters being 8. This will probably change -// // // as we understand more. -// // spi_expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); -// // } - -// let spi = spi::Mock::new(&spi_expectations); - -// let mut delay = MockNoop::new(); - -// let pins = EspControlMock {}; - -// let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); - -// let ip_address: IpAddress = [0, 0, 0, 0]; -// let port: Port = 4000; -// let mode: TransportMode = TransportMode::Tcp; - -// let result = -// TcpClient::build(&mut wifi).connect(ip_address, port, mode, &mut delay, |_tcp_client| {}); - -// assert_eq!( -// result.unwrap_err(), -// esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) -// ); -// } +use embedded_hal_mock::delay::MockNoop; +use embedded_hal_mock::spi; + +use esp32_wroom_rp::network::{IpAddress, Port, TransportMode}; +use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; +use esp32_wroom_rp::wifi::Wifi; + +pub mod support; + +use support::*; + +#[test] +fn tcp_timeout_error() { + let get_socket_command = 0x3f; + let mut number_of_params = 0x0; + let mut number_of_params_to_receive = 0x1; + + let mut expectations = mock_command(get_socket_command, number_of_params); + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + get_socket_command, + number_of_params_to_receive, + 0x0, + )); + + let start_client_tcp_command = 0x2d; + number_of_params = 0x4; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command( + start_client_tcp_command, + number_of_params, + )); + expectations.append(&mut mock_single_byte_size_params(4, 0x40)); // Send fake IP Address + expectations.append(&mut mock_single_byte_size_params(2, 0x11)); // Send fake Port + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Transport Mode + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + start_client_tcp_command, + number_of_params_to_receive, + 0x1, + )); + + let get_client_state_tcp_command = 0x2f; + number_of_params = 0x1; + + for _ in 0..10_000 { + expectations.append(&mut mock_command( + get_client_state_tcp_command, + number_of_params, + )); + + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(2)); + + // wait_response_cmd() + // read start command + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xe0])); + // read command byte | reply byte + expectations.push(spi::Transaction::transfer( + vec![0xff], + vec![command_or_reply_byte(get_client_state_tcp_command)], + )); + // read number of params to receive + expectations.push(spi::Transaction::transfer( + vec![0xff], + vec![number_of_params_to_receive], + )); + // test relies on max number of parameters being 8. This will probably change + // as we understand more. + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x8])); + // read full 8 byte buffer + // The first byte is the connection state. We only consider a 0x4 to be a successful state + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0x1])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xff])); + // read end byte + expectations.push(spi::Transaction::transfer(vec![0xff], vec![0xee])); + } + + let stop_client_tcp = 0x2e; + number_of_params = 0x1; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command(stop_client_tcp, number_of_params)); + + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(2)); + + expectations.append(&mut mock_receive( + stop_client_tcp, + number_of_params_to_receive, + 0x1, + )); + + let spi = spi::Mock::new(&expectations); + + let mut delay = MockNoop::new(); + + let pins = EspControlMock {}; + + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); + + let ip_address: IpAddress = [0x40, 0x40, 0x40, 0x40]; + let port: Port = 0x1111; + let mode: TransportMode = TransportMode::Tcp; + + let result = + TcpClient::build(&mut wifi).connect(ip_address, port, mode, &mut delay, |_tcp_client| {}); + + assert_eq!( + result.unwrap_err(), + esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) + ); +} From f502336a3add723233c0a5feb010c875560fa569 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 22 Dec 2022 15:47:21 -0500 Subject: [PATCH 097/106] continue writing tcp_client tests --- .vscode/settings.json | 3 +- cross/send_data_tcp/src/main.rs | 2 +- esp32-wroom-rp/src/tcp_client.rs | 16 +- host-tests/tests/support/mod.rs | 33 ++-- host-tests/tests/tcp_client.rs | 265 ++++++++++++++++++++++++++++++- 5 files changed, 289 insertions(+), 30 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bec2e33..88c613a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "rust.target": "thumbv6m-none-eabi", - "rust.all_targets": true + "rust.all_targets": true, + "editor.inlayHints.enabled": false } diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index bc1dd78..2f24d18 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -170,7 +170,7 @@ fn main() -> ! { port, mode, &mut delay, - |tcp_client| { + &mut |tcp_client| { defmt::info!( "TCP connection to {:?}:{:?} successful", hostname, diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 0ef8450..68d599f 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -36,13 +36,13 @@ impl Format for TcpError { /// makes it possible to implement and support IPv6 addresses. pub trait Connect<'a, S, B, C> { /// Connects to `server` on `port` using transport layer `mode`. - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, server: S, port: Port, mode: TransportMode, delay: &mut D, - f: F, + f: &mut F, ) -> Result<(), Error>; } @@ -62,13 +62,13 @@ where B: Transfer, C: EspControlInterface, { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, ip: IpAddress, port: Port, mode: TransportMode, delay: &mut D, - f: F, + f: &mut F, ) -> Result<(), Error> { let socket = self.get_socket()?; self.socket = Some(socket); @@ -86,13 +86,13 @@ where B: Transfer, C: EspControlInterface, { - fn connect), D: DelayMs>( + fn connect), D: DelayMs>( &mut self, server_hostname: Hostname, port: Port, mode: TransportMode, delay: &mut D, - f: F, + f: &mut F, ) -> Result<(), Error> { let socket = self.get_socket()?; self.socket = Some(socket); @@ -163,10 +163,10 @@ where // Provides the in-common connect() functionality used by the public interface's // connect(ip_address) or connect(hostname) instances. - fn connect_common), D: DelayMs>( + fn connect_common), D: DelayMs>( &mut self, delay: &mut D, - f: F, + mut f: F, ) -> Result<(), Error> { let socket = self.socket.unwrap_or_default(); let mode = self.mode; diff --git a/host-tests/tests/support/mod.rs b/host-tests/tests/support/mod.rs index 642787e..7207cd6 100644 --- a/host-tests/tests/support/mod.rs +++ b/host-tests/tests/support/mod.rs @@ -74,9 +74,20 @@ pub fn mock_end_byte() -> Vec { pub fn mock_receive( command_byte: u8, number_of_params_to_receive: u8, - value_to_receive: u8, + values_to_receive: &[u8], ) -> Vec { - vec![ + let mut buffer = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + + let length_of_values = if values_to_receive.len() > 0 { + values_to_receive.len() - 1 + } else { + 0 + }; + + // replace buffer values with values from values_to_receive + buffer.splice(0..length_of_values, values_to_receive.iter().cloned()); + + let mut expectations = vec![ // wait_response_cmd() // read start command spi::Transaction::transfer(vec![0xff], vec![0xe0]), @@ -87,18 +98,12 @@ pub fn mock_receive( // test relies on max number of parameters being 8. This will probably change // as we understand more. spi::Transaction::transfer(vec![0xff], vec![0x8]), - // read full 8 byte buffer - spi::Transaction::transfer(vec![0xff], vec![value_to_receive]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - spi::Transaction::transfer(vec![0xff], vec![0xff]), - // read end byte - spi::Transaction::transfer(vec![0xff], vec![0xee]), - ] + ]; + + for byte in buffer.iter().cloned() { + expectations.push(spi::Transaction::transfer(vec![0xff], vec![byte])); + } + expectations } pub fn command_or_reply_byte(command: u8) -> u8 { diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs index c1f13d9..0ce5585 100644 --- a/host-tests/tests/tcp_client.rs +++ b/host-tests/tests/tcp_client.rs @@ -1,7 +1,7 @@ use embedded_hal_mock::delay::MockNoop; use embedded_hal_mock::spi; -use esp32_wroom_rp::network::{IpAddress, Port, TransportMode}; +use esp32_wroom_rp::network::{Hostname, IpAddress, Port, TransportMode}; use esp32_wroom_rp::tcp_client::{Connect, TcpClient}; use esp32_wroom_rp::wifi::Wifi; @@ -9,6 +9,254 @@ pub mod support; use support::*; +#[test] +fn successful_tcp_connection_with_hostname_invokes_closure() { + // ----- get_socket ----- + + let get_socket_command = 0x3f; + let mut number_of_params = 0x0; + let mut number_of_params_to_receive = 0x1; + + let mut expectations = mock_command(get_socket_command, number_of_params); + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + get_socket_command, + number_of_params_to_receive, + &[0x0], + )); + + // ----- req_host_by_name ----- + + let req_host_by_name_command = 0x34; + number_of_params = 0x1; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command( + req_host_by_name_command, + number_of_params, + )); + + expectations.append(&mut mock_single_byte_size_params(4, 0x46)); // hostname is "FFFF" + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(1)); + + expectations.append(&mut mock_receive( + req_host_by_name_command, + number_of_params_to_receive, + &[0x46, 0x46, 0x46, 0x46], + )); + + // ----- get_host_by_name ----- + + let get_host_by_name_command = 0x35; + number_of_params = 0x0; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command( + get_host_by_name_command, + number_of_params, + )); + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + get_host_by_name_command, + number_of_params_to_receive, + &[], + )); + + // ----- start_client_tcp ----- + + let start_client_tcp_command = 0x2d; + number_of_params = 0x4; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command( + start_client_tcp_command, + number_of_params, + )); + expectations.append(&mut mock_single_byte_size_params(4, 0x40)); // Send fake IP Address + expectations.append(&mut mock_single_byte_size_params(2, 0x11)); // Send fake Port + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Transport Mode + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + start_client_tcp_command, + number_of_params_to_receive, + &[0x1], + )); + + let get_client_state_tcp_command = 0x2f; + number_of_params = 0x1; + + expectations.append(&mut mock_command( + get_client_state_tcp_command, + number_of_params, + )); + + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(2)); + + expectations.append(&mut mock_receive( + get_client_state_tcp_command, + number_of_params_to_receive, + &[0x4], // ConnectionState::Established + )); + + let stop_client_tcp_command = 0x2e; + number_of_params = 0x1; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command(stop_client_tcp_command, number_of_params)); + + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(2)); + + expectations.append(&mut mock_receive( + stop_client_tcp_command, + number_of_params_to_receive, + &[0x1], + )); + + let spi = spi::Mock::new(&expectations); + + let mut delay = MockNoop::new(); + + let pins = EspControlMock {}; + + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); + + let hostname: Hostname = "FFFF"; + let port: Port = 0x1111; + let mode: TransportMode = TransportMode::Tcp; + + // if the value is successfully updated inside the closure then + // we know the closure was invoked. + let mut value: u8 = 1; + let test_value = &mut value; + + TcpClient::build(&mut wifi) + .connect(hostname, port, mode, &mut delay, &mut |_tcp_client| { + *test_value = 2 + }) + .unwrap(); + + assert_eq!(value, 2); +} + +#[test] +fn successful_tcp_connection_with_ip_address_invokes_closure() { + let get_socket_command = 0x3f; + let mut number_of_params = 0x0; + let mut number_of_params_to_receive = 0x1; + + let mut expectations = mock_command(get_socket_command, number_of_params); + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + get_socket_command, + number_of_params_to_receive, + &[0x0], + )); + + let start_client_tcp_command = 0x2d; + number_of_params = 0x4; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command( + start_client_tcp_command, + number_of_params, + )); + expectations.append(&mut mock_single_byte_size_params(4, 0x40)); // Send fake IP Address + expectations.append(&mut mock_single_byte_size_params(2, 0x11)); // Send fake Port + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Transport Mode + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_receive( + start_client_tcp_command, + number_of_params_to_receive, + &[0x1], + )); + + let get_client_state_tcp_command = 0x2f; + number_of_params = 0x1; + + expectations.append(&mut mock_command( + get_client_state_tcp_command, + number_of_params, + )); + + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(2)); + + expectations.append(&mut mock_receive( + get_client_state_tcp_command, + number_of_params_to_receive, + &[0x4], // ConnectionState::Established + )); + + let stop_client_tcp_command = 0x2e; + number_of_params = 0x1; + number_of_params_to_receive = 0x1; + + expectations.append(&mut mock_command(stop_client_tcp_command, number_of_params)); + + expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket + + expectations.append(&mut mock_end_byte()); + + expectations.append(&mut mock_padding(2)); + + expectations.append(&mut mock_receive( + stop_client_tcp_command, + number_of_params_to_receive, + &[0x1], + )); + + let spi = spi::Mock::new(&expectations); + + let mut delay = MockNoop::new(); + + let pins = EspControlMock {}; + + let mut wifi = Wifi::init(spi, pins, &mut delay).ok().unwrap(); + + let ip_address: IpAddress = [0x40, 0x40, 0x40, 0x40]; + let port: Port = 0x1111; + let mode: TransportMode = TransportMode::Tcp; + + // if the value is successfully updated inside the closure then + // we know the closure was invoked. + let mut value: u8 = 1; + let test_value = &mut value; + + TcpClient::build(&mut wifi) + .connect(ip_address, port, mode, &mut delay, &mut |_tcp_client| { + *test_value = 2 + }) + .unwrap(); + + assert_eq!(value, 2); +} + #[test] fn tcp_timeout_error() { let get_socket_command = 0x3f; @@ -22,7 +270,7 @@ fn tcp_timeout_error() { expectations.append(&mut mock_receive( get_socket_command, number_of_params_to_receive, - 0x0, + &[0x0], )); let start_client_tcp_command = 0x2d; @@ -43,7 +291,7 @@ fn tcp_timeout_error() { expectations.append(&mut mock_receive( start_client_tcp_command, number_of_params_to_receive, - 0x1, + &[0x1], )); let get_client_state_tcp_command = 0x2f; @@ -106,7 +354,7 @@ fn tcp_timeout_error() { expectations.append(&mut mock_receive( stop_client_tcp, number_of_params_to_receive, - 0x1, + &[0x1], )); let spi = spi::Mock::new(&expectations); @@ -121,8 +369,13 @@ fn tcp_timeout_error() { let port: Port = 0x1111; let mode: TransportMode = TransportMode::Tcp; - let result = - TcpClient::build(&mut wifi).connect(ip_address, port, mode, &mut delay, |_tcp_client| {}); + let result = TcpClient::build(&mut wifi).connect( + ip_address, + port, + mode, + &mut delay, + &mut |_tcp_client| {}, + ); assert_eq!( result.unwrap_err(), From 3d2663058d1b7024bc6d4709061eda32cde251d9 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Fri, 23 Dec 2022 11:02:49 -0500 Subject: [PATCH 098/106] Remove unnecessary TODO --- cross/secrets/secrets.rs | 4 ++-- esp32-wroom-rp/src/wifi.rs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index e97157b..451e81e 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = ""; -const PASSPHRASE: &str = ""; +const SSID: &str = "Zion"; +const PASSPHRASE: &str = "Diesel12103465"; diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 82af832..629fb1f 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -141,9 +141,6 @@ where } /// Retrieves the current WiFi network connection status. - /// - /// NOTE: A future version will provide a enumerated type instead of the raw integer values - /// from the NINA firmware. pub fn get_connection_status(&mut self) -> Result { self.protocol_handler.borrow_mut().get_conn_status() } From 852df6f98b907c700696a1a2eb546e322eb271c3 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 25 Dec 2022 12:11:41 -0500 Subject: [PATCH 099/106] Move TcpError::Timeout to NetworkError::ConnectionTimeout --- esp32-wroom-rp/src/lib.rs | 11 ----------- esp32-wroom-rp/src/network.rs | 5 +++++ esp32-wroom-rp/src/tcp_client.rs | 19 ++----------------- host-tests/tests/tcp_client.rs | 4 ++-- 4 files changed, 9 insertions(+), 30 deletions(-) diff --git a/esp32-wroom-rp/src/lib.rs b/esp32-wroom-rp/src/lib.rs index bedda52..b384fcb 100644 --- a/esp32-wroom-rp/src/lib.rs +++ b/esp32-wroom-rp/src/lib.rs @@ -100,7 +100,6 @@ mod spi; use network::NetworkError; use protocol::ProtocolError; -use tcp_client::TcpError; use defmt::{write, Format, Formatter}; @@ -116,9 +115,6 @@ pub enum Error { /// Network related error Network(NetworkError), - - /// TCP related error - Tcp(TcpError), } impl Format for Error { @@ -131,7 +127,6 @@ impl Format for Error { e ), Error::Network(e) => write!(fmt, "Network error: {}", e), - Error::Tcp(e) => write!(fmt, "TCP error: {}", e), } } } @@ -148,12 +143,6 @@ impl From for Error { } } -impl From for Error { - fn from(err: tcp_client::TcpError) -> Self { - Error::Tcp(err) - } -} - /// A structured representation of a connected NINA firmware device's version number (e.g. 1.7.4). #[derive(Debug, Default, Eq, PartialEq)] pub struct FirmwareVersion { diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 13c030f..46fbdf0 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -83,6 +83,8 @@ impl Format for ConnectionState { pub enum NetworkError { /// Failed to resolve a hostname for the provided IP address. DnsResolveFailed, + /// Timed out while trying to connect to remote TCP server. + ConnectionTimeout, /// Failed to start up a new TCP/UDP client instance. StartClientFailed, /// Failed to stop an existing TCP/UDP client instance @@ -98,6 +100,9 @@ impl Format for NetworkError { "Failed to resolve a hostname for the provided IP address" ) } + NetworkError::ConnectionTimeout => { + write!(fmt, "Timed out while trying connect the remote TCP server") + } NetworkError::StartClientFailed => { write!(fmt, "Failed to start up a new TCP/UDP client instance") } diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 68d599f..75867f9 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,5 +1,5 @@ use super::{Error, ARRAY_LENGTH_PLACEHOLDER}; -use crate::wifi::Wifi; +use crate::{wifi::Wifi, network::NetworkError}; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; @@ -12,25 +12,10 @@ use embedded_hal::blocking::spi::Transfer; use heapless::String; -use defmt::{write, Format, Formatter}; - // TODO: find a good max length const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; -#[derive(Debug, Eq, PartialEq)] -pub enum TcpError { - Timeout, -} - -impl Format for TcpError { - fn format(&self, fmt: Formatter) { - match self { - TcpError::Timeout => write!(fmt, "Timeout Connecting to TCP Server"), - } - } -} - /// Connect trait that allows for a `TcpClient` instance to connect to a remote /// server by providing either a `Hostname` or an `IpAddress`. This trait also /// makes it possible to implement and support IPv6 addresses. @@ -218,6 +203,6 @@ where self.protocol_handler.stop_client_tcp(socket, &mode)?; - Err(TcpError::Timeout.into()) + Err(NetworkError::ConnectionTimeout.into()) } } diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs index 0ce5585..032f3b9 100644 --- a/host-tests/tests/tcp_client.rs +++ b/host-tests/tests/tcp_client.rs @@ -258,7 +258,7 @@ fn successful_tcp_connection_with_ip_address_invokes_closure() { } #[test] -fn tcp_timeout_error() { +fn tcp_connection_timeout_error() { let get_socket_command = 0x3f; let mut number_of_params = 0x0; let mut number_of_params_to_receive = 0x1; @@ -379,6 +379,6 @@ fn tcp_timeout_error() { assert_eq!( result.unwrap_err(), - esp32_wroom_rp::Error::Tcp(esp32_wroom_rp::tcp_client::TcpError::Timeout) + esp32_wroom_rp::Error::Network(esp32_wroom_rp::network::NetworkError::ConnectionTimeout) ); } From 648ebd139ebe1081750b169ff8fb4e47981c5791 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Sun, 25 Dec 2022 12:57:39 -0500 Subject: [PATCH 100/106] Remove StartClientFailed and StopClientFailed errors and convert to more appropriate ones for NetworkError. --- esp32-wroom-rp/src/network.rs | 16 ++++++++-------- esp32-wroom-rp/src/spi.rs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 46fbdf0..0eb665d 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -85,10 +85,10 @@ pub enum NetworkError { DnsResolveFailed, /// Timed out while trying to connect to remote TCP server. ConnectionTimeout, - /// Failed to start up a new TCP/UDP client instance. - StartClientFailed, - /// Failed to stop an existing TCP/UDP client instance - StopClientFailed, + /// Failed to connect to remote TCP server. + ConnectFailed, + /// Failed to disconnect from remote TCP server. + DisconnectFailed, } impl Format for NetworkError { @@ -103,11 +103,11 @@ impl Format for NetworkError { NetworkError::ConnectionTimeout => { write!(fmt, "Timed out while trying connect the remote TCP server") } - NetworkError::StartClientFailed => { - write!(fmt, "Failed to start up a new TCP/UDP client instance") + NetworkError::ConnectFailed => { + write!(fmt, "Failed to connect to remote TCP server") } - NetworkError::StopClientFailed => { - write!(fmt, "Failed to stop an existing TCP/UDP client instance") + NetworkError::DisconnectFailed => { + write!(fmt, "Failed to start up a new TCP/UDP client instance") } } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index f8bdca1..05ebc07 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -174,7 +174,7 @@ where if result[0] == 1 { Ok(()) } else { - Err(NetworkError::StartClientFailed.into()) + Err(NetworkError::ConnectFailed.into()) } } @@ -190,7 +190,7 @@ where if result[0] == 1 { Ok(()) } else { - Err(NetworkError::StopClientFailed.into()) + Err(NetworkError::DisconnectFailed.into()) } } From c96867d59f2fd8ea46236f1ab9b2c2eeaba40090 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Tue, 3 Jan 2023 16:49:36 -0800 Subject: [PATCH 101/106] happy path with hostname passes --- esp32-wroom-rp/src/tcp_client.rs | 2 +- host-tests/tests/support/mod.rs | 8 ++++++-- host-tests/tests/tcp_client.rs | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 75867f9..0db0fe0 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -1,5 +1,5 @@ use super::{Error, ARRAY_LENGTH_PLACEHOLDER}; -use crate::{wifi::Wifi, network::NetworkError}; +use crate::{network::NetworkError, wifi::Wifi}; use super::protocol::NinaProtocolHandler; use crate::gpio::EspControlInterface; diff --git a/host-tests/tests/support/mod.rs b/host-tests/tests/support/mod.rs index 7207cd6..e8b0838 100644 --- a/host-tests/tests/support/mod.rs +++ b/host-tests/tests/support/mod.rs @@ -76,7 +76,7 @@ pub fn mock_receive( number_of_params_to_receive: u8, values_to_receive: &[u8], ) -> Vec { - let mut buffer = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + let mut buffer = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21]; let length_of_values = if values_to_receive.len() > 0 { values_to_receive.len() - 1 @@ -101,7 +101,11 @@ pub fn mock_receive( ]; for byte in buffer.iter().cloned() { - expectations.push(spi::Transaction::transfer(vec![0xff], vec![byte])); + expectations.append(&mut vec![spi::Transaction::transfer( + vec![0xff], + vec![byte], + )]); + // expectations.push(spi::Transaction::transfer(vec![0xff], vec![byte])); } expectations } diff --git a/host-tests/tests/tcp_client.rs b/host-tests/tests/tcp_client.rs index 032f3b9..f632562 100644 --- a/host-tests/tests/tcp_client.rs +++ b/host-tests/tests/tcp_client.rs @@ -42,12 +42,12 @@ fn successful_tcp_connection_with_hostname_invokes_closure() { expectations.append(&mut mock_end_byte()); - expectations.append(&mut mock_padding(1)); + expectations.append(&mut mock_padding(3)); expectations.append(&mut mock_receive( req_host_by_name_command, number_of_params_to_receive, - &[0x46, 0x46, 0x46, 0x46], + &[0x1], )); // ----- get_host_by_name ----- @@ -66,7 +66,7 @@ fn successful_tcp_connection_with_hostname_invokes_closure() { expectations.append(&mut mock_receive( get_host_by_name_command, number_of_params_to_receive, - &[], + &[0x46, 0x46, 0x46, 0x46], )); // ----- start_client_tcp ----- @@ -79,7 +79,7 @@ fn successful_tcp_connection_with_hostname_invokes_closure() { start_client_tcp_command, number_of_params, )); - expectations.append(&mut mock_single_byte_size_params(4, 0x40)); // Send fake IP Address + expectations.append(&mut mock_single_byte_size_params(4, 0x46)); // Send fake IP Address expectations.append(&mut mock_single_byte_size_params(2, 0x11)); // Send fake Port expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Socket expectations.append(&mut mock_single_byte_size_params(1, 0x0)); // Send fake Transport Mode @@ -158,6 +158,8 @@ fn successful_tcp_connection_with_hostname_invokes_closure() { #[test] fn successful_tcp_connection_with_ip_address_invokes_closure() { + // ----- get_socket ----- + let get_socket_command = 0x3f; let mut number_of_params = 0x0; let mut number_of_params_to_receive = 0x1; @@ -172,6 +174,8 @@ fn successful_tcp_connection_with_ip_address_invokes_closure() { &[0x0], )); + // ------ start_client_tcp ------ + let start_client_tcp_command = 0x2d; number_of_params = 0x4; number_of_params_to_receive = 0x1; @@ -193,6 +197,8 @@ fn successful_tcp_connection_with_ip_address_invokes_closure() { &[0x1], )); + // ----- get_client_state_tcp ----- + let get_client_state_tcp_command = 0x2f; number_of_params = 0x1; @@ -259,6 +265,7 @@ fn successful_tcp_connection_with_ip_address_invokes_closure() { #[test] fn tcp_connection_timeout_error() { + // ----- get_socket ----- let get_socket_command = 0x3f; let mut number_of_params = 0x0; let mut number_of_params_to_receive = 0x1; @@ -273,6 +280,8 @@ fn tcp_connection_timeout_error() { &[0x0], )); + // ----- start_client_tcp ----- + let start_client_tcp_command = 0x2d; number_of_params = 0x4; number_of_params_to_receive = 0x1; From 83905ac5b4be976a53bf409f622347265ace807e Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Wed, 4 Jan 2023 07:00:07 -0800 Subject: [PATCH 102/106] remove clippy warnings --- cross/secrets/secrets.rs | 4 ++-- esp32-wroom-rp/src/network.rs | 16 ++++++++++++++++ esp32-wroom-rp/src/protocol.rs | 8 ++++---- esp32-wroom-rp/src/spi.rs | 14 ++++++-------- esp32-wroom-rp/src/tcp_client.rs | 4 ++-- esp32-wroom-rp/src/wifi.rs | 2 +- 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cross/secrets/secrets.rs b/cross/secrets/secrets.rs index 451e81e..e97157b 100644 --- a/cross/secrets/secrets.rs +++ b/cross/secrets/secrets.rs @@ -3,5 +3,5 @@ // all example applications // -const SSID: &str = "Zion"; -const PASSPHRASE: &str = "Diesel12103465"; +const SSID: &str = ""; +const PASSPHRASE: &str = ""; diff --git a/esp32-wroom-rp/src/network.rs b/esp32-wroom-rp/src/network.rs index 0eb665d..cb19af1 100644 --- a/esp32-wroom-rp/src/network.rs +++ b/esp32-wroom-rp/src/network.rs @@ -16,10 +16,15 @@ pub(crate) type Socket = u8; #[repr(u8)] #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum TransportMode { + /// TCP mode Tcp = 0, + /// UDP mode Udp = 1, + /// TLS mode Tls = 2, + /// UDP multicast mode UdpMulticast = 3, + /// TLS BearSSL mode TlsBearSsl = 4, } @@ -27,16 +32,27 @@ pub enum TransportMode { #[repr(u8)] #[derive(PartialEq, PartialOrd, Debug)] pub enum ConnectionState { + /// Closed Closed = 0, + /// Listening Listening = 1, + /// SynSent SynSent = 2, + /// SynReceived SynReceived = 3, + /// Established Established = 4, + /// FinWait1 FinWait1 = 5, + /// Finwait2 FinWait2 = 6, + /// CloseWait CloseWait = 7, + /// Closing Closing = 8, + /// LastAck LastAck = 9, + /// TimeWait TimeWait = 10, } diff --git a/esp32-wroom-rp/src/protocol.rs b/esp32-wroom-rp/src/protocol.rs index 244c0f7..dd8f3ea 100644 --- a/esp32-wroom-rp/src/protocol.rs +++ b/esp32-wroom-rp/src/protocol.rs @@ -128,7 +128,7 @@ impl NinaParam for NinaAbstractParam { } fn length(&self) -> u16 { - self.length as u16 + self.length } fn length_size(&self) -> u8 { @@ -220,7 +220,7 @@ impl NinaConcreteParam for NinaByteParam { } fn length_as_bytes(&self) -> Self::LengthAsBytes { - [self.length as u8] + [self.length] } } @@ -253,7 +253,7 @@ impl NinaConcreteParam for NinaWordParam { } fn length_as_bytes(&self) -> Self::LengthAsBytes { - [self.length as u8] + [self.length] } } @@ -286,7 +286,7 @@ impl NinaConcreteParam for NinaSmallArrayParam { } fn length_as_bytes(&self) -> Self::LengthAsBytes { - [self.length as u8] + [self.length] } } diff --git a/esp32-wroom-rp/src/spi.rs b/esp32-wroom-rp/src/spi.rs index 05ebc07..f132e9a 100644 --- a/esp32-wroom-rp/src/spi.rs +++ b/esp32-wroom-rp/src/spi.rs @@ -245,7 +245,7 @@ where operation.params.iter().for_each(|param| { self.send_param(param).ok(); - total_params_length += param.length() as u16; + total_params_length += param.length(); total_params_length_size += param.length_size() as u16; }); @@ -341,7 +341,7 @@ where fn get_byte(&mut self) -> Result { let word_out = &mut [ControlByte::Dummy as u8]; let word = self.bus.borrow_mut().transfer(word_out).ok().unwrap(); - Ok(word[0] as u8) + Ok(word[0]) } fn wait_for_byte(&mut self, wait_byte: u8) -> Result { @@ -369,18 +369,16 @@ where fn send_param(&mut self, param: &P) -> Result<(), Infallible> { self.send_param_length(param)?; - let data_length = param.length() as usize; - let bytes = param.data(); - for i in 0..data_length { - self.bus.borrow_mut().transfer(&mut [bytes[i]]).ok(); + for byte in param.data().iter() { + self.bus.borrow_mut().transfer(&mut [*byte]).ok(); } Ok(()) } fn send_param_length(&mut self, param: &P) -> Result<(), Infallible> { let bytes = param.length_as_bytes(); - for i in 0..param.length_size() as usize { - self.bus.borrow_mut().transfer(&mut [bytes[i]]).ok(); + for byte in bytes.iter().take(param.length_size() as usize) { + self.bus.borrow_mut().transfer(&mut [*byte]).ok(); } Ok(()) } diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 0db0fe0..2d6fd5a 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -12,8 +12,6 @@ use embedded_hal::blocking::spi::Transfer; use heapless::String; -// TODO: find a good max length -const MAX_DATA_LENGTH: usize = 512; const MAX_HOSTNAME_LENGTH: usize = 255; /// Connect trait that allows for a `TcpClient` instance to connect to a remote @@ -131,11 +129,13 @@ where } // TODO: Make this non-public + /// Requests a Socket pub fn get_socket(&mut self) -> Result { self.protocol_handler.get_socket() } // TODO: Make this non-public + /// Returns `Socket` reference set by calling `get_socket()` pub fn socket(&self) -> Socket { self.socket.unwrap() } diff --git a/esp32-wroom-rp/src/wifi.rs b/esp32-wroom-rp/src/wifi.rs index 629fb1f..a3c03ca 100644 --- a/esp32-wroom-rp/src/wifi.rs +++ b/esp32-wroom-rp/src/wifi.rs @@ -99,7 +99,7 @@ pub struct Wifi { pub(crate) protocol_handler: RefCell>, } -impl<'a, S, C> Wifi +impl Wifi where S: Transfer, C: EspControlInterface, From 467f8f0d1e8b86c922b9054ab86a1daa64648385 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Wed, 4 Jan 2023 10:04:30 -0600 Subject: [PATCH 103/106] Get rid of shadow variable to fix Clippy warnings --- cross/dns/src/main.rs | 3 +-- cross/join/src/main.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cross/dns/src/main.rs b/cross/dns/src/main.rs index 50973a4..9263cc0 100644 --- a/cross/dns/src/main.rs +++ b/cross/dns/src/main.rs @@ -115,13 +115,12 @@ fn main() -> ! { defmt::info!("Entering main loop"); - let sleep: u32 = 1500; + let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(status) => { defmt::info!("Get Connection Result: {:?}", status); - let mut sleep: u32 = 1500; delay.delay_ms(sleep); if status == ConnectionStatus::Connected { diff --git a/cross/join/src/main.rs b/cross/join/src/main.rs index 76a65f5..8f1e7ad 100644 --- a/cross/join/src/main.rs +++ b/cross/join/src/main.rs @@ -114,13 +114,12 @@ fn main() -> ! { defmt::info!("Entering main loop"); - let sleep: u32 = 1500; + let mut sleep: u32 = 1500; loop { match wifi.get_connection_status() { Ok(status) => { defmt::info!("Get Connection Result: {:?}", status); - let mut sleep: u32 = 1500; delay.delay_ms(sleep); if status == ConnectionStatus::Connected { From c50fceeb6310ef4a3e585aa713534a06b8088b95 Mon Sep 17 00:00:00 2001 From: Jim Hodapp Date: Wed, 4 Jan 2023 10:09:07 -0600 Subject: [PATCH 104/106] Give Dilyn Corner credit as co-author and up the version of every crate to be 0.3.0 to coincide with the current release milestone --- cross/dns/Cargo.toml | 5 +++-- cross/get_fw_version/Cargo.toml | 5 +++-- cross/join/Cargo.toml | 5 +++-- cross/send_data_tcp/Cargo.toml | 6 +++--- host-tests/Cargo.toml | 5 +++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/cross/dns/Cargo.toml b/cross/dns/Cargo.toml index c17ca5c..719897d 100644 --- a/cross/dns/Cargo.toml +++ b/cross/dns/Cargo.toml @@ -2,11 +2,12 @@ authors = [ "Jim Hodapp", "Caleb Bourg", - "Glyn Matthews" + "Glyn Matthews", + "Dilyn Corner" ] edition = "2021" name = "dns" -version = "0.1.0" +version = "0.3.0" description = "Example target application that demonstrates DNS functionality with the Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards." # makes `cargo check --all-targets` work diff --git a/cross/get_fw_version/Cargo.toml b/cross/get_fw_version/Cargo.toml index 9d67cde..2ad2227 100644 --- a/cross/get_fw_version/Cargo.toml +++ b/cross/get_fw_version/Cargo.toml @@ -2,11 +2,12 @@ authors = [ "Jim Hodapp", "Caleb Bourg", - "Glyn Matthews" + "Glyn Matthews", + "Dilyn Corner" ] edition = "2021" name = "get_fw_version" -version = "0.1.0" +version = "0.3.0" description = "Example target application that gets the Nina firmware version with the Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards." # makes `cargo check --all-targets` work diff --git a/cross/join/Cargo.toml b/cross/join/Cargo.toml index 5df0fcd..a8f8605 100644 --- a/cross/join/Cargo.toml +++ b/cross/join/Cargo.toml @@ -2,11 +2,12 @@ authors = [ "Jim Hodapp", "Caleb Bourg", - "Glyn Matthews" + "Glyn Matthews", + "Dilyn Corner" ] edition = "2021" name = "join" -version = "0.1.0" +version = "0.3.0" description = "Example target application that joins/leaves an SSID with the Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards." # makes `cargo check --all-targets` work diff --git a/cross/send_data_tcp/Cargo.toml b/cross/send_data_tcp/Cargo.toml index b11500a..dbdd02a 100644 --- a/cross/send_data_tcp/Cargo.toml +++ b/cross/send_data_tcp/Cargo.toml @@ -2,12 +2,12 @@ authors = [ "Jim Hodapp", "Caleb Bourg", - "Dilyn Corner", - "Glyn Matthews" + "Glyn Matthews", + "Dilyn Corner" ] edition = "2021" name = "send_data_tcp" -version = "0.1.0" +version = "0.3.0" description = "Example RP2040 target application that demonstrates how to send data to a remote server over TCP." # makes `cargo check --all-targets` work diff --git a/host-tests/Cargo.toml b/host-tests/Cargo.toml index bd54bbd..fb3b455 100644 --- a/host-tests/Cargo.toml +++ b/host-tests/Cargo.toml @@ -2,11 +2,12 @@ authors = [ "Jim Hodapp", "Caleb Bourg", - "Glyn Matthews" + "Glyn Matthews", + "Dilyn Corner" ] edition = "2021" name = "host-tests" -version = "0.1.0" +version = "0.3.0" publish = false description = "Host-side tests for the Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards." From 3fcd9b74dbeb8b265c96d8219212bc74a801a96f Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 5 Jan 2023 16:55:21 -0800 Subject: [PATCH 105/106] make socket() private --- cross/send_data_tcp/src/main.rs | 1 - esp32-wroom-rp/src/tcp_client.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cross/send_data_tcp/src/main.rs b/cross/send_data_tcp/src/main.rs index 2f24d18..7936bc5 100644 --- a/cross/send_data_tcp/src/main.rs +++ b/cross/send_data_tcp/src/main.rs @@ -177,7 +177,6 @@ fn main() -> ! { port ); defmt::info!("Hostname: {:?}", tcp_client.server_hostname()); - defmt::info!("Socket: {:?}", tcp_client.socket()); defmt::info!("Sending HTTP Document: {:?}", http_document.as_str()); match tcp_client.send_data(&http_document) { Ok(response) => { diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 2d6fd5a..0acb79d 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -141,7 +141,7 @@ where } /// Sends a string slice of data to a connected server. - pub fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.protocol_handler .send_data(data, self.socket.unwrap_or_default()) } From 36d9b3141036dc9949aabbb1908968452c610dc0 Mon Sep 17 00:00:00 2001 From: Caleb Bourg Date: Thu, 5 Jan 2023 17:05:19 -0800 Subject: [PATCH 106/106] make socket() private send_data() public --- esp32-wroom-rp/src/tcp_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32-wroom-rp/src/tcp_client.rs b/esp32-wroom-rp/src/tcp_client.rs index 0acb79d..66ff110 100644 --- a/esp32-wroom-rp/src/tcp_client.rs +++ b/esp32-wroom-rp/src/tcp_client.rs @@ -136,12 +136,12 @@ where // TODO: Make this non-public /// Returns `Socket` reference set by calling `get_socket()` - pub fn socket(&self) -> Socket { + fn socket(&self) -> Socket { self.socket.unwrap() } /// Sends a string slice of data to a connected server. - fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { + pub fn send_data(&mut self, data: &str) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error> { self.protocol_handler .send_data(data, self.socket.unwrap_or_default()) }