From c5aa6398381eacecf7a54d5c6ffb02069f6d44c9 Mon Sep 17 00:00:00 2001 From: DaneSlattery Date: Tue, 13 Aug 2024 16:36:32 +0000 Subject: [PATCH 1/7] Add EspModem to glue EspNetifDriver to TX/RX logic --- .github/configs/sdkconfig.defaults | 6 + Cargo.toml | 5 +- examples/lte_modem.rs | 123 +++++ src/lib.rs | 1 + src/modem.rs | 752 +++++++++++++++++++++++++++++ 5 files changed, 886 insertions(+), 1 deletion(-) create mode 100644 examples/lte_modem.rs create mode 100644 src/modem.rs diff --git a/.github/configs/sdkconfig.defaults b/.github/configs/sdkconfig.defaults index f43977a55bf..42ea2e3d6c1 100644 --- a/.github/configs/sdkconfig.defaults +++ b/.github/configs/sdkconfig.defaults @@ -17,6 +17,12 @@ CONFIG_ETH_SPI_ETHERNET_DM9051=y CONFIG_ETH_SPI_ETHERNET_W5500=y CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL=y +# GSM +CONFIG_LWIP_PPP_SUPPORT=y +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=2048 +CONFIG_LWIP_PPP_ENABLE_IPV6=n + + # We don't have an example for classic BT - yet - we need to enable class BT # specifically to workaround this bug in ESP IDF v5.2 (fixed in ESP IDF v5.2.1+): # https://github.com/espressif/esp-idf/issues/13113 diff --git a/Cargo.toml b/Cargo.toml index 6873bb2650b..f1dba92e8cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,9 +52,12 @@ uncased = { version = "0.9.7", default-features = false } embedded-hal-async = { version = "1", default-features = false } embedded-svc = { version = "0.28", default-features = false } esp-idf-hal = { version = "0.44", default-features = false } -embassy-time-driver = { version = "0.1", optional = true, features = ["tick-hz-1_000_000"] } +embassy-time-driver = { version = "0.1", optional = true, features = [ + "tick-hz-1_000_000", +] } embassy-futures = "0.1" futures-io = { version = "0.3", optional = true } +at-commands = "0.5.4" [build-dependencies] embuild = "0.32" diff --git a/examples/lte_modem.rs b/examples/lte_modem.rs new file mode 100644 index 00000000000..72c623a43ec --- /dev/null +++ b/examples/lte_modem.rs @@ -0,0 +1,123 @@ +//! Example of using blocking wifi. +//! +//! Add your own ssid and password + +use std::{thread::ScopedJoinHandle, time::Duration}; + +use embedded_svc::{ + http::{client::Client as HttpClient, Method}, + io::Write, + utils::io, +}; + +use esp_idf_hal::gpio; +use esp_idf_hal::uart::UartDriver; +use esp_idf_hal::units::Hertz; +use esp_idf_svc::log::EspLogger; +use esp_idf_svc::modem::sim::sim7600::SIM7600; +use esp_idf_svc::modem::sim::SimModem; +use esp_idf_svc::modem::EspModem; +use esp_idf_svc::{eventloop::EspSystemEventLoop, nvs::EspDefaultNvsPartition}; +use esp_idf_svc::{hal::prelude::Peripherals, http::client::EspHttpConnection}; + +use log::{error, info}; + +// const SSID: &str = env!("WIFI_SSID"); +// const PASSWORD: &str = env!("WIFI_PASS"); + +fn main() -> anyhow::Result<()> { + esp_idf_svc::sys::link_patches(); + EspLogger::initialize_default(); + + let peripherals = Peripherals::take()?; + let sys_loop = EspSystemEventLoop::take()?; + let nvs = EspDefaultNvsPartition::take()?; + let serial = peripherals.uart2; + let tx = peripherals.pins.gpio17; + let rx = peripherals.pins.gpio18; + let mut serial = UartDriver::new( + serial, + tx, + rx, + Option::::None, + Option::::None, + &esp_idf_hal::uart::UartConfig { + baudrate: Hertz(115200), + ..Default::default() + }, + )?; + log::info!("Hello"); + let mut sim_device = SIM7600::new(); + let buff = [0u8; 64]; + match sim_device.negotiate(&mut serial, buff) { + Err(x) => log::error!("Error = {}", x), + Ok(()) => log::info!("Device in PPP mode"), + } + + let mut modem = EspModem::new(&mut serial, sys_loop)?; + + let _scope = std::thread::scope::<_, anyhow::Result<()>>(|s| { + let my_thread: ScopedJoinHandle> = s.spawn(|| { + match modem.run(buff) { + Err(x) => log::error!("Error: {:?}", x), + Ok(_x) => (), + }; + Ok(()) + }); + std::thread::sleep(Duration::from_secs(10)); + + // while !modem.netif().is_up()? {} + // while !(modem.is_connected()?) {} + + let mut client = HttpClient::wrap(EspHttpConnection::new(&Default::default())?); + + // GET + loop { + std::thread::sleep(Duration::from_secs(10)); + match get_request(&mut client) { + Err(x) => log::error!("Failed, reason = {}", x), + Ok(_) => break, + } + } + my_thread.join().unwrap()?; + Ok(()) + }); + + std::thread::sleep(core::time::Duration::from_secs(5)); + + Ok(()) +} + +/// Send an HTTP GET request. +fn get_request(client: &mut HttpClient) -> anyhow::Result<()> { + // Prepare headers and URL + let headers = [("accept", "text/plain")]; + let url = "http://ifconfig.net/"; + + // Send request + // + // Note: If you don't want to pass in any headers, you can also use `client.get(url, headers)`. + let request = client.request(Method::Get, url, &headers)?; + info!("-> GET {}", url); + let mut response = request.submit()?; + + // Process response + let status = response.status(); + info!("<- {}", status); + let mut buf = [0u8; 1024]; + let bytes_read = io::try_read_full(&mut response, &mut buf).map_err(|e| e.0)?; + info!("Read {} bytes", bytes_read); + match std::str::from_utf8(&buf[0..bytes_read]) { + Ok(body_string) => info!( + "Response body (truncated to {} bytes): {:?}", + buf.len(), + body_string + ), + Err(e) => error!("Error decoding response body: {}", e), + }; + + // Drain the remaining response bytes + while response.read(&mut buf)? > 0 {} + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index aeeaf77ae9d..fa3713cb0d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ pub mod mdns; esp_idf_comp_mqtt_enabled, esp_idf_comp_esp_event_enabled ))] +pub mod modem; pub mod mqtt; #[cfg(esp_idf_lwip_ipv4_napt)] pub mod napt; diff --git a/src/modem.rs b/src/modem.rs new file mode 100644 index 00000000000..05cfe9e6c13 --- /dev/null +++ b/src/modem.rs @@ -0,0 +1,752 @@ +use crate::handle::RawHandle; +use core::{borrow::BorrowMut, ffi, marker::PhantomData, mem::MaybeUninit}; +use esp_idf_hal::{ + delay::BLOCK, + uart::{UartDriver, UartTxDriver}, +}; +use std::sync::Arc; + +use crate::{ + eventloop::{ + EspEventDeserializer, EspEventLoop, EspEventSource, EspSubscription, EspSystemEventLoop, + System, + }, + netif::{EspNetif, EspNetifDriver, NetifStack}, + private::mutex, + sys::*, +}; + +pub struct EspModem<'d, T> +where + T: BorrowMut>, +{ + serial: T, + status: Arc>, + _subscription: EspSubscription<'static, System>, + netif: EspNetif, + _d: PhantomData<&'d ()>, +} + +impl<'d, T> EspModem<'d, T> +where + T: BorrowMut> + Send, +{ + pub fn new(serial: T, sysloop: EspSystemEventLoop) -> Result { + let (status, subscription) = Self::subscribe(&sysloop)?; + + Ok(Self { + serial, + status, + _subscription: subscription, + netif: EspNetif::new(NetifStack::Ppp)?, + _d: PhantomData, + }) + } + + /// Run the modem network interface. Blocks until the PPP encounters an error. + pub fn run(&mut self, mut buffer: [u8; 64]) -> Result<(), EspError> { + self.status.lock().running = true; + + // now in ppp mode. + // let netif = EspNetif::new(NetifStack::Ppp)?; + + // subscribe to user event + esp!(unsafe { + esp_event_handler_register( + IP_EVENT, + ESP_EVENT_ANY_ID as _, + Some(Self::raw_on_ip_event), + self.netif.handle() as *mut core::ffi::c_void, + ) + })?; + esp!(unsafe { + esp_event_handler_register( + NETIF_PPP_STATUS, + ESP_EVENT_ANY_ID as _, + Some(Self::raw_on_ppp_changed), + self.netif.handle() as *mut core::ffi::c_void, + ) + })?; + let (mut tx, rx) = self.serial.borrow_mut().split(); + let driver = unsafe { + EspNetifDriver::new_nonstatic_ppp(&self.netif, move |x| Self::tx(&mut tx, x))? + }; + + loop { + if !self.status.lock().running { + break; + } + let len = rx.read(&mut buffer, BLOCK)?; + if len > 0 { + driver.rx(&buffer[..len])?; + } + } + + Ok(()) + } + + /// Returns the current [`ModemPPPError`] status, if any. + pub fn get_error(&self) -> Option { + self.status.lock().error.clone() + } + + /// Returns the current [`ModemPhaseStatus`] + pub fn get_phase_status(&self) -> ModemPhaseStatus { + self.status.lock().phase.clone() + } + + /// Returns the underlying [`EspNetif`] + pub fn netif(&self) -> &EspNetif { + &self.netif + } + + /// Returns the underlying [`EspNetif`], as mutable + pub fn netif_mut(&mut self) -> &mut EspNetif { + &mut self.netif + } + + /// Callback given to the LWIP API to write data to the PPP server. + fn tx(writer: &mut UartTxDriver, data: &[u8]) -> Result<(), EspError> { + esp_idf_hal::io::Write::write_all(writer, data).map_err(|w| w.0)?; + + Ok(()) + } + + fn subscribe( + sysloop: &EspEventLoop, + ) -> Result< + ( + Arc>, + EspSubscription<'static, System>, + ), + EspError, + > { + let status = Arc::new(mutex::Mutex::new(ModemDriverStatus { + error: None, + phase: ModemPhaseStatus::Disconnect, + running: false, + })); + + let s_status = status.clone(); + + let subscription = sysloop.subscribe::(move |event| { + let mut guard = s_status.lock(); + log::info!("Got event PPP: {:?}", event); + match event { + ModemEvent::ErrorNone => guard.error = None, + ModemEvent::ErrorParameter => guard.error = Some(ModemPPPError::Parameter), + ModemEvent::ErrorOpen => guard.error = Some(ModemPPPError::Open), + ModemEvent::ErrorDevice => guard.error = Some(ModemPPPError::Device), + ModemEvent::ErrorAlloc => guard.error = Some(ModemPPPError::Alloc), + ModemEvent::ErrorUser => guard.error = Some(ModemPPPError::User), + ModemEvent::ErrorDisconnect => guard.error = Some(ModemPPPError::Disconnect), + ModemEvent::ErrorAuthFail => guard.error = Some(ModemPPPError::AuthFail), + ModemEvent::ErrorProtocol => guard.error = Some(ModemPPPError::Protocol), + ModemEvent::ErrorPeerDead => guard.error = Some(ModemPPPError::PeerDead), + ModemEvent::ErrorIdleTimeout => guard.error = Some(ModemPPPError::IdleTimeout), + ModemEvent::ErrorMaxConnectTimeout => { + guard.error = Some(ModemPPPError::MaxConnectTimeout) + } + ModemEvent::ErrorLoopback => guard.error = Some(ModemPPPError::Loopback), + ModemEvent::PhaseDead => guard.phase = ModemPhaseStatus::Dead, + ModemEvent::PhaseMaster => guard.phase = ModemPhaseStatus::Master, + ModemEvent::PhaseHoldoff => guard.phase = ModemPhaseStatus::Holdoff, + ModemEvent::PhaseInitialize => guard.phase = ModemPhaseStatus::Initialize, + ModemEvent::PhaseSerialConnection => { + guard.phase = ModemPhaseStatus::SerialConnection + } + ModemEvent::PhaseDormant => guard.phase = ModemPhaseStatus::Dormant, + ModemEvent::PhaseEstablish => guard.phase = ModemPhaseStatus::Establish, + ModemEvent::PhaseAuthenticate => guard.phase = ModemPhaseStatus::Authenticate, + ModemEvent::PhaseCallback => guard.phase = ModemPhaseStatus::Callback, + ModemEvent::PhaseNetwork => guard.phase = ModemPhaseStatus::Network, + ModemEvent::PhaseRunning => guard.phase = ModemPhaseStatus::Running, + ModemEvent::PhaseTerminate => guard.phase = ModemPhaseStatus::Terminate, + ModemEvent::PhaseDisconnect => guard.phase = ModemPhaseStatus::Disconnect, + ModemEvent::PhaseFailed => guard.phase = ModemPhaseStatus::Failed, + } + })?; + + Ok((status, subscription)) + } + + fn on_ip_event(event_id: u32, event_data: *mut ::core::ffi::c_void) { + use log::info; + info!("Got event id: {}", event_id); + + if event_id == ip_event_t_IP_EVENT_PPP_GOT_IP { + let mut dns_info = esp_netif_dns_info_t::default(); + let event_data = unsafe { (event_data as *const ip_event_got_ip_t).as_ref() }.unwrap(); + info!(" ip_info = {:?} ", event_data.ip_info); + info!("modem connected to ppp server, info: {:?}", event_data); + + let netif = event_data.esp_netif; + esp!(unsafe { esp_netif_get_dns_info(netif, 0, &mut dns_info) }).unwrap(); + info!(" dns_info = {:?} ", unsafe { dns_info.ip.u_addr.ip4.addr }); + } else if event_id == ip_event_t_IP_EVENT_PPP_LOST_IP { + info!("Modem disconnected from ppp server"); + } + } + + unsafe extern "C" fn raw_on_ip_event( + _event_handler_arg: *mut ::core::ffi::c_void, + _event_base: esp_event_base_t, + event_id: i32, + event_data: *mut ::core::ffi::c_void, + ) { + Self::on_ip_event(event_id as _, event_data) + } + + fn on_ppp_changed(event_id: u32, _event_data: *mut ::core::ffi::c_void) { + use log::info; + info!("Got event id ppp changed: {}", event_id); + + if event_id == esp_netif_ppp_status_event_t_NETIF_PPP_ERRORUSER { + info!("user interrupted event from netif"); + } + } + + unsafe extern "C" fn raw_on_ppp_changed( + _event_handler_arg: *mut ::core::ffi::c_void, + _event_base: esp_event_base_t, + event_id: i32, + event_data: *mut ::core::ffi::c_void, + ) { + Self::on_ppp_changed(event_id as _, event_data) + } +} + +#[derive(Clone, Debug)] +pub enum ModemPPPError { + /// Invalid parameter. + Parameter, + /// Unable to open PPP session. + Open, + /// Invalid I/O device for PPP. + Device, + /// Unable to allocate resources. + Alloc, + /// User interrupt. + User, + /// Connection lost. + Disconnect, + /// Failed authentication challenge. + AuthFail, + /// Failed to meet protocol. + Protocol, + /// Connection timeout + PeerDead, + /// Idle Timeout + IdleTimeout, + /// Max connect time reached + MaxConnectTimeout, + /// Loopback detected + Loopback, +} +#[derive(Clone, Debug)] +pub enum ModemPhaseStatus { + Dead, + Master, + Holdoff, + Initialize, + SerialConnection, + Dormant, + Establish, + Authenticate, + Callback, + Network, + Running, + Terminate, + Disconnect, + Failed, +} + +#[derive(Clone, Debug)] +pub struct ModemDriverStatus { + pub error: Option, + pub phase: ModemPhaseStatus, + pub running: bool, +} + +#[derive(Debug)] +pub enum ModemEvent { + ErrorNone, + ErrorParameter, + ErrorOpen, + ErrorDevice, + ErrorAlloc, + ErrorUser, + ErrorDisconnect, + ErrorAuthFail, + ErrorProtocol, + ErrorPeerDead, + ErrorIdleTimeout, + ErrorMaxConnectTimeout, + ErrorLoopback, + PhaseDead, + PhaseMaster, + PhaseHoldoff, + PhaseInitialize, + PhaseSerialConnection, + PhaseDormant, + PhaseEstablish, + PhaseAuthenticate, + PhaseCallback, + PhaseNetwork, + PhaseRunning, + PhaseTerminate, + PhaseDisconnect, + PhaseFailed, +} + +unsafe impl EspEventSource for ModemEvent { + fn source() -> Option<&'static core::ffi::CStr> { + Some(unsafe { ffi::CStr::from_ptr(NETIF_PPP_STATUS) }) + } +} + +impl EspEventDeserializer for ModemEvent { + type Data<'a> = ModemEvent; + + #[allow(non_upper_case_globals, non_snake_case)] + fn deserialize<'a>(data: &crate::eventloop::EspEvent<'a>) -> Self::Data<'a> { + let event_id = data.event_id as u32; + + match event_id { + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORNONE => ModemEvent::ErrorNone, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPARAM => ModemEvent::ErrorParameter, + esp_netif_ppp_status_event_t_NETIF_PPP_ERROROPEN => ModemEvent::ErrorOpen, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORDEVICE => ModemEvent::ErrorDevice, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORALLOC => ModemEvent::ErrorAlloc, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORUSER => ModemEvent::ErrorUser, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORCONNECT => ModemEvent::ErrorDisconnect, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORAUTHFAIL => ModemEvent::ErrorAuthFail, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPROTOCOL => ModemEvent::ErrorProtocol, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPEERDEAD => ModemEvent::ErrorPeerDead, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORIDLETIMEOUT => ModemEvent::ErrorIdleTimeout, + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORCONNECTTIME => { + ModemEvent::ErrorMaxConnectTimeout + } + esp_netif_ppp_status_event_t_NETIF_PPP_ERRORLOOPBACK => ModemEvent::ErrorLoopback, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DEAD => ModemEvent::PhaseDead, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_MASTER => ModemEvent::PhaseMaster, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_HOLDOFF => ModemEvent::PhaseHoldoff, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_INITIALIZE => ModemEvent::PhaseInitialize, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_SERIALCONN => { + ModemEvent::PhaseSerialConnection + } + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DORMANT => ModemEvent::PhaseDormant, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_ESTABLISH => ModemEvent::PhaseEstablish, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_AUTHENTICATE => { + ModemEvent::PhaseAuthenticate + } + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_CALLBACK => ModemEvent::PhaseCallback, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_NETWORK => ModemEvent::PhaseNetwork, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_RUNNING => ModemEvent::PhaseRunning, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_TERMINATE => ModemEvent::PhaseTerminate, + esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DISCONNECT => ModemEvent::PhaseDisconnect, + esp_netif_ppp_status_event_t_NETIF_PPP_CONNECT_FAILED => ModemEvent::PhaseFailed, + _ => panic!("Unknown event ID: {}", event_id), + } + } +} + +pub mod sim { + //! SimModem + //! + //! Models a modem device with a sim card able to serve as a + //! network interface for the host. + use esp_idf_hal::uart::UartDriver; + + /// The generic device trait. Implementations of this trait should provide + /// relevant AT commands and confirm the modem replies to drive the modem + /// into PPPoS (data mode). + pub trait SimModem { + /// The current mode of the sim modem. + fn get_mode(&self) -> &CommunicationMode; + + /// Initialise the remote modem so that it is in PPPoS mode. + fn negotiate(&mut self, comm: &mut UartDriver, buffer: [u8; 64]) -> Result<(), ModemError>; + } + + /// State of the modem. + /// + /// In [CommunicationMode::Command] mode, AT commands will function, + /// serving to put the modem into [CommunicationMode::Data]. + /// + /// In [CommunicationMode::Data] the modem device will act as a Point-To-Point over Serial (PPPoS) + /// server. + pub enum CommunicationMode { + Command, + Data, + } + + #[derive(Debug)] + pub enum ModemError { + IO, + ATParse(at_commands::parser::ParseError), + ATBuild(usize), + } + + impl std::fmt::Display for ModemError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } + } + + impl std::error::Error for ModemError {} + + impl From for ModemError { + fn from(value: usize) -> Self { + ModemError::ATBuild(value) + } + } + + impl From for ModemError { + fn from(value: at_commands::parser::ParseError) -> Self { + ModemError::ATParse(value) + } + } + + pub mod sim7600 { + //! [super::SimModem] Implementation for the `SIMCOM 76XX` range of + //! modems. + + use core::{fmt::Display, time::Duration}; + + use at_commands::{builder::CommandBuilder, parser::CommandParser}; + use esp_idf_hal::{delay::TickType, uart::UartDriver}; + + use super::{CommunicationMode, ModemError, SimModem}; + pub struct SIM7600(CommunicationMode); + + impl SIM7600 { + pub fn new() -> Self { + Self(CommunicationMode::Command) + } + } + + pub enum BitErrorRate { + /// < 0.01% + LT001, + /// 0.01% - 0.1% + LT01, + /// 0.1% - 0.5% + LT05, + /// 0.5% - 1% + LT1, + /// 1% - 2% + LT2, + /// 2% - 4% + LT4, + /// 4% - 8% + LT8, + /// >=8% + GT8, + /// unknown or undetectable + Unknown, + } + impl Display for BitErrorRate { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + BitErrorRate::GT8 => write!(f, ">= 8%"), + BitErrorRate::LT001 => write!(f, "< 0.01%"), + BitErrorRate::LT01 => write!(f, "0.01% - 0.1%"), + BitErrorRate::LT05 => write!(f, "0.1% - 0.5%"), + BitErrorRate::LT1 => write!(f, "0.5% - 1%"), + BitErrorRate::LT2 => write!(f, "1% - 2%"), + BitErrorRate::LT4 => write!(f, "2% - 4%"), + BitErrorRate::LT8 => write!(f, "4% - 8%"), + BitErrorRate::Unknown => write!(f, "Unknown"), + } + } + } + + impl From for BitErrorRate { + fn from(value: i32) -> Self { + match value { + 0 => Self::LT001, + 1 => Self::LT01, + 2 => Self::LT05, + 3 => Self::LT1, + 4 => Self::LT2, + 5 => Self::LT4, + 6 => Self::LT8, + 7 => Self::GT8, + _ => Self::Unknown, + } + } + } + + /// Received Signal Strength Indication + pub enum RSSI { + /// -113 dBm or less + DBMLT113, + /// -111 dBm + DBM111, + /// -109 to -53 dBm + DBM109_53(i32), + /// -51 dBm or greater + DBMGT51, + /// not known or not detectable + Unknown, + /// -116 dBm or less + DBMLT116, + /// -115 dBm + DBM115, + /// -114 to -26 dBm + DBM114_26(i32), + /// -25 dBm or greater + DBMGT25, + } + + impl Display for RSSI { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + RSSI::DBMLT113 => write!(f, "<= -113 dBm"), + RSSI::DBM111 => write!(f, "-111 dBm"), + RSSI::DBM109_53(x) => write!(f, "{} dBm", x), + RSSI::DBMGT51 => write!(f, ">= -51 dBm"), + RSSI::DBM114_26(x) => write!(f, "{} dBm", x), + RSSI::DBM115 => write!(f, "-115 dBm"), + RSSI::DBMGT25 => write!(f, ">= -25 dBm"), + RSSI::DBMLT116 => write!(f, "<= -116 dBm"), + RSSI::Unknown => write!(f, "Unknown"), + } + } + } + + impl RSSI { + pub fn parse(raw: i32) -> RSSI { + match raw { + 0 => Self::DBMLT113, + 1 => Self::DBM111, + 2..=30 => Self::DBM109_53(RSSI::map2_30_to_109_53(raw)), + 31 => Self::DBMGT51, + 99 => Self::Unknown, + 100 => Self::DBMLT116, + 101 => Self::DBM115, + 102..=191 => Self::DBM114_26(RSSI::map102_191_to_114_26(raw)), + _ => Self::Unknown, + } + } + + fn map2_30_to_109_53(raw: i32) -> i32 { + const X1: i32 = 2; + const Y1: i32 = -109; + const X2: i32 = 30; + const Y2: i32 = -53; + const GRAD: i32 = (Y2 - Y1) / (X2 - X1); // 56/28 = 2 + const OFFSET: i32 = Y1 - (GRAD * X1); // -113 + (GRAD * raw) + OFFSET + } + + fn map102_191_to_114_26(raw: i32) -> i32 { + const X1: i32 = 102; + const Y1: i32 = -114; + // const X2: i32 = 191; + // const Y2: i32 = -26; + const GRAD: i32 = 1; + // requires #![feature(int_roundings)] + // const GRAD: i32 = (Y2 - Y1).div_ceil((X2 - X1)); // would be 88/89, so truncated to 0 + const OFFSET: i32 = Y1 - (GRAD * X1); // -216 + (GRAD * raw) + OFFSET + } + } + + impl Default for SIM7600 { + fn default() -> Self { + Self::new() + } + } + + impl SimModem for SIM7600 { + fn negotiate( + &mut self, + comm: &mut UartDriver, + mut buffer: [u8; 64], + ) -> Result<(), ModemError> { + reset(comm, &mut buffer)?; + + //disable echo + set_echo(comm, &mut buffer, false)?; + + // get signal quality + let (rssi, ber) = get_signal_quality(comm, &mut buffer)?; + log::info!("RSSI = {rssi}"); + log::info!("BER = {ber}"); + // get iccid + let iccid = get_iccid(comm, &mut buffer)?; + log::info!("ICCID = [{}]", iccid); + + // check pdp network reg + read_gprs_registration_status(comm, &mut buffer)?; + + //configure apn + set_pdp_context(comm, &mut buffer)?; + + // start ppp + set_data_mode(comm, &mut buffer)?; + + self.0 = CommunicationMode::Data; + Ok(()) + } + + fn get_mode(&self) -> &CommunicationMode { + &self.0 + } + } + + pub fn get_signal_quality( + comm: &mut UartDriver, + buff: &mut [u8], + ) -> Result<(RSSI, BitErrorRate), ModemError> { + let cmd = CommandBuilder::create_execute(buff, true) + .named("+CSQ") + .finish()?; + + comm.write(cmd).map_err(|_| ModemError::IO)?; + + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + // \r\n+CSQ: 19,99\r\n\r\nOK\r\n + let (raw_rssi, raw_ber) = CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\n+CSQ: ") + .expect_int_parameter() + .expect_int_parameter() + .expect_identifier(b"\r\n\r\nOK\r\n") + .finish()?; + + Ok((RSSI::parse(raw_rssi), raw_ber.into())) + } + + fn get_iccid( + comm: &mut UartDriver, + buff: &mut [u8], + ) -> Result, ModemError> { + let cmd = CommandBuilder::create_execute(buff, true) + .named("+CICCID") + .finish()?; + + comm.write(cmd).map_err(|_| ModemError::IO)?; + + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + let (ccid,) = CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\n+ICCID: ") + .expect_raw_string() + .expect_identifier(b"\r\n\r\nOK\r\n") + .finish()?; + + Ok(heapless::String::try_from(ccid).unwrap()) + } + + fn reset(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_execute(buff, false) + .named("ATZ0") + .finish()?; + log::info!("Send Reset"); + + comm.write(cmd).map_err(|_| ModemError::IO)?; + + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + CommandParser::parse(&buff[..len]) + .expect_identifier(b"ATZ0\r") + .expect_identifier(b"\r\nOK\r\n") + .finish()?; + Ok(()) + } + + fn set_echo(comm: &mut UartDriver, buff: &mut [u8], echo: bool) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_execute(buff, false) + .named(format!("ATE{}", i32::from(echo))) + .finish()?; + log::info!("Set echo "); + comm.write(cmd).map_err(|_| ModemError::IO)?; + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + CommandParser::parse(&buff[..len]) + .expect_identifier(b"ATE0\r") + .expect_identifier(b"\r\nOK\r\n") + .finish()?; + Ok(()) + } + + fn read_gprs_registration_status( + comm: &mut UartDriver, + buff: &mut [u8], + ) -> Result<(i32, i32, Option, Option), ModemError> { + let cmd = CommandBuilder::create_query(buff, true) + .named("+CGREG") + .finish()?; + log::info!("Get Registration Status"); + comm.write(cmd).map_err(|_| ModemError::IO)?; + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + Ok(CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\n+CGREG: ") + .expect_int_parameter() + .expect_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_identifier(b"\r\n\r\nOK\r\n") + .finish()?) + } + + fn set_pdp_context(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_set(buff, true) + .named("+CGDCONT") + .with_int_parameter(1) // context id + .with_string_parameter("IP") // pdp type + .with_string_parameter("flolive.net") // apn + .finish()?; + log::info!("Set PDP Context"); + comm.write(cmd).map_err(|_| ModemError::IO)?; + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\nOK\r\n") + .finish()?; + Ok(()) + } + + fn set_data_mode(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_execute(buff, false) + .named("ATD*99#") + .finish()?; + log::info!("Set Data mode"); + comm.write(cmd).map_err(|_| ModemError::IO)?; + let len = comm + .read(buff, TickType::new_millis(1000).ticks()) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + let (connect_parm,) = CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\nCONNECT ") + .expect_optional_raw_string() + .expect_identifier(b"\r\n") + .finish()?; + log::info!("connect {:?}", connect_parm); + Ok(()) + } + } +} From 52dc13a2fb081629d402622d44c2f0bb927f56a0 Mon Sep 17 00:00:00 2001 From: Dane Slattery Date: Mon, 26 Aug 2024 13:04:11 +0200 Subject: [PATCH 2/7] Refactor PPP events in modem --- examples/lte_modem.rs | 12 +-- src/modem.rs | 172 ++++++++++++------------------------------ 2 files changed, 53 insertions(+), 131 deletions(-) diff --git a/examples/lte_modem.rs b/examples/lte_modem.rs index 72c623a43ec..5abef194ec4 100644 --- a/examples/lte_modem.rs +++ b/examples/lte_modem.rs @@ -6,18 +6,17 @@ use std::{thread::ScopedJoinHandle, time::Duration}; use embedded_svc::{ http::{client::Client as HttpClient, Method}, - io::Write, utils::io, }; use esp_idf_hal::gpio; use esp_idf_hal::uart::UartDriver; use esp_idf_hal::units::Hertz; +use esp_idf_svc::eventloop::EspSystemEventLoop; use esp_idf_svc::log::EspLogger; use esp_idf_svc::modem::sim::sim7600::SIM7600; use esp_idf_svc::modem::sim::SimModem; use esp_idf_svc::modem::EspModem; -use esp_idf_svc::{eventloop::EspSystemEventLoop, nvs::EspDefaultNvsPartition}; use esp_idf_svc::{hal::prelude::Peripherals, http::client::EspHttpConnection}; use log::{error, info}; @@ -31,10 +30,11 @@ fn main() -> anyhow::Result<()> { let peripherals = Peripherals::take()?; let sys_loop = EspSystemEventLoop::take()?; - let nvs = EspDefaultNvsPartition::take()?; + let serial = peripherals.uart2; let tx = peripherals.pins.gpio17; let rx = peripherals.pins.gpio18; + let mut serial = UartDriver::new( serial, tx, @@ -46,9 +46,9 @@ fn main() -> anyhow::Result<()> { ..Default::default() }, )?; - log::info!("Hello"); + let mut sim_device = SIM7600::new(); - let buff = [0u8; 64]; + let mut buff = [0u8; 64]; match sim_device.negotiate(&mut serial, buff) { Err(x) => log::error!("Error = {}", x), Ok(()) => log::info!("Device in PPP mode"), @@ -58,7 +58,7 @@ fn main() -> anyhow::Result<()> { let _scope = std::thread::scope::<_, anyhow::Result<()>>(|s| { let my_thread: ScopedJoinHandle> = s.spawn(|| { - match modem.run(buff) { + match modem.run(&mut buff) { Err(x) => log::error!("Error: {:?}", x), Ok(_x) => (), }; diff --git a/src/modem.rs b/src/modem.rs index 05cfe9e6c13..e661c6c8130 100644 --- a/src/modem.rs +++ b/src/modem.rs @@ -1,5 +1,8 @@ -use crate::handle::RawHandle; -use core::{borrow::BorrowMut, ffi, marker::PhantomData, mem::MaybeUninit}; +use crate::{ + handle::RawHandle, + netif::{PppConfiguration, PppEvent}, +}; +use core::{borrow::BorrowMut, marker::PhantomData}; use esp_idf_hal::{ delay::BLOCK, uart::{UartDriver, UartTxDriver}, @@ -7,10 +10,7 @@ use esp_idf_hal::{ use std::sync::Arc; use crate::{ - eventloop::{ - EspEventDeserializer, EspEventLoop, EspEventSource, EspSubscription, EspSystemEventLoop, - System, - }, + eventloop::{EspEventLoop, EspSubscription, EspSystemEventLoop, System}, netif::{EspNetif, EspNetifDriver, NetifStack}, private::mutex, sys::*, @@ -44,7 +44,7 @@ where } /// Run the modem network interface. Blocks until the PPP encounters an error. - pub fn run(&mut self, mut buffer: [u8; 64]) -> Result<(), EspError> { + pub fn run(&mut self, buffer: &mut [u8]) -> Result<(), EspError> { self.status.lock().running = true; // now in ppp mode. @@ -68,15 +68,22 @@ where ) })?; let (mut tx, rx) = self.serial.borrow_mut().split(); - let driver = unsafe { - EspNetifDriver::new_nonstatic_ppp(&self.netif, move |x| Self::tx(&mut tx, x))? - }; + let driver = EspNetifDriver::new_nonstatic( + &mut self.netif, + move |x| { + x.set_ppp_conf(&PppConfiguration { + phase_events_enabled: true, + error_events_enabled: true, + }) + }, + |data| Self::tx(&mut tx, data), + )?; loop { if !self.status.lock().running { break; } - let len = rx.read(&mut buffer, BLOCK)?; + let len = rx.read(buffer, BLOCK)?; if len > 0 { driver.rx(&buffer[..len])?; } @@ -129,41 +136,39 @@ where let s_status = status.clone(); - let subscription = sysloop.subscribe::(move |event| { + let subscription = sysloop.subscribe::(move |event| { let mut guard = s_status.lock(); log::info!("Got event PPP: {:?}", event); match event { - ModemEvent::ErrorNone => guard.error = None, - ModemEvent::ErrorParameter => guard.error = Some(ModemPPPError::Parameter), - ModemEvent::ErrorOpen => guard.error = Some(ModemPPPError::Open), - ModemEvent::ErrorDevice => guard.error = Some(ModemPPPError::Device), - ModemEvent::ErrorAlloc => guard.error = Some(ModemPPPError::Alloc), - ModemEvent::ErrorUser => guard.error = Some(ModemPPPError::User), - ModemEvent::ErrorDisconnect => guard.error = Some(ModemPPPError::Disconnect), - ModemEvent::ErrorAuthFail => guard.error = Some(ModemPPPError::AuthFail), - ModemEvent::ErrorProtocol => guard.error = Some(ModemPPPError::Protocol), - ModemEvent::ErrorPeerDead => guard.error = Some(ModemPPPError::PeerDead), - ModemEvent::ErrorIdleTimeout => guard.error = Some(ModemPPPError::IdleTimeout), - ModemEvent::ErrorMaxConnectTimeout => { + PppEvent::NoError => guard.error = None, + PppEvent::ParameterError => guard.error = Some(ModemPPPError::Parameter), + PppEvent::OpenError => guard.error = Some(ModemPPPError::Open), + PppEvent::DeviceError => guard.error = Some(ModemPPPError::Device), + PppEvent::AllocError => guard.error = Some(ModemPPPError::Alloc), + PppEvent::UserError => guard.error = Some(ModemPPPError::User), + PppEvent::DisconnectError => guard.error = Some(ModemPPPError::Disconnect), + PppEvent::AuthFailError => guard.error = Some(ModemPPPError::AuthFail), + PppEvent::ProtocolError => guard.error = Some(ModemPPPError::Protocol), + PppEvent::PeerDeadError => guard.error = Some(ModemPPPError::PeerDead), + PppEvent::IdleTimeoutError => guard.error = Some(ModemPPPError::IdleTimeout), + PppEvent::MaxConnectTimeoutError => { guard.error = Some(ModemPPPError::MaxConnectTimeout) } - ModemEvent::ErrorLoopback => guard.error = Some(ModemPPPError::Loopback), - ModemEvent::PhaseDead => guard.phase = ModemPhaseStatus::Dead, - ModemEvent::PhaseMaster => guard.phase = ModemPhaseStatus::Master, - ModemEvent::PhaseHoldoff => guard.phase = ModemPhaseStatus::Holdoff, - ModemEvent::PhaseInitialize => guard.phase = ModemPhaseStatus::Initialize, - ModemEvent::PhaseSerialConnection => { - guard.phase = ModemPhaseStatus::SerialConnection - } - ModemEvent::PhaseDormant => guard.phase = ModemPhaseStatus::Dormant, - ModemEvent::PhaseEstablish => guard.phase = ModemPhaseStatus::Establish, - ModemEvent::PhaseAuthenticate => guard.phase = ModemPhaseStatus::Authenticate, - ModemEvent::PhaseCallback => guard.phase = ModemPhaseStatus::Callback, - ModemEvent::PhaseNetwork => guard.phase = ModemPhaseStatus::Network, - ModemEvent::PhaseRunning => guard.phase = ModemPhaseStatus::Running, - ModemEvent::PhaseTerminate => guard.phase = ModemPhaseStatus::Terminate, - ModemEvent::PhaseDisconnect => guard.phase = ModemPhaseStatus::Disconnect, - ModemEvent::PhaseFailed => guard.phase = ModemPhaseStatus::Failed, + PppEvent::LoopbackError => guard.error = Some(ModemPPPError::Loopback), + PppEvent::PhaseDead => guard.phase = ModemPhaseStatus::Dead, + PppEvent::PhaseMaster => guard.phase = ModemPhaseStatus::Master, + PppEvent::PhaseHoldoff => guard.phase = ModemPhaseStatus::Holdoff, + PppEvent::PhaseInitialize => guard.phase = ModemPhaseStatus::Initialize, + PppEvent::PhaseSerialConnection => guard.phase = ModemPhaseStatus::SerialConnection, + PppEvent::PhaseDormant => guard.phase = ModemPhaseStatus::Dormant, + PppEvent::PhaseEstablish => guard.phase = ModemPhaseStatus::Establish, + PppEvent::PhaseAuthenticate => guard.phase = ModemPhaseStatus::Authenticate, + PppEvent::PhaseCallback => guard.phase = ModemPhaseStatus::Callback, + PppEvent::PhaseNetwork => guard.phase = ModemPhaseStatus::Network, + PppEvent::PhaseRunning => guard.phase = ModemPhaseStatus::Running, + PppEvent::PhaseTerminate => guard.phase = ModemPhaseStatus::Terminate, + PppEvent::PhaseDisconnect => guard.phase = ModemPhaseStatus::Disconnect, + PppEvent::PhaseFailed => guard.phase = ModemPhaseStatus::Failed, } })?; @@ -268,89 +273,6 @@ pub struct ModemDriverStatus { pub running: bool, } -#[derive(Debug)] -pub enum ModemEvent { - ErrorNone, - ErrorParameter, - ErrorOpen, - ErrorDevice, - ErrorAlloc, - ErrorUser, - ErrorDisconnect, - ErrorAuthFail, - ErrorProtocol, - ErrorPeerDead, - ErrorIdleTimeout, - ErrorMaxConnectTimeout, - ErrorLoopback, - PhaseDead, - PhaseMaster, - PhaseHoldoff, - PhaseInitialize, - PhaseSerialConnection, - PhaseDormant, - PhaseEstablish, - PhaseAuthenticate, - PhaseCallback, - PhaseNetwork, - PhaseRunning, - PhaseTerminate, - PhaseDisconnect, - PhaseFailed, -} - -unsafe impl EspEventSource for ModemEvent { - fn source() -> Option<&'static core::ffi::CStr> { - Some(unsafe { ffi::CStr::from_ptr(NETIF_PPP_STATUS) }) - } -} - -impl EspEventDeserializer for ModemEvent { - type Data<'a> = ModemEvent; - - #[allow(non_upper_case_globals, non_snake_case)] - fn deserialize<'a>(data: &crate::eventloop::EspEvent<'a>) -> Self::Data<'a> { - let event_id = data.event_id as u32; - - match event_id { - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORNONE => ModemEvent::ErrorNone, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPARAM => ModemEvent::ErrorParameter, - esp_netif_ppp_status_event_t_NETIF_PPP_ERROROPEN => ModemEvent::ErrorOpen, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORDEVICE => ModemEvent::ErrorDevice, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORALLOC => ModemEvent::ErrorAlloc, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORUSER => ModemEvent::ErrorUser, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORCONNECT => ModemEvent::ErrorDisconnect, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORAUTHFAIL => ModemEvent::ErrorAuthFail, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPROTOCOL => ModemEvent::ErrorProtocol, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORPEERDEAD => ModemEvent::ErrorPeerDead, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORIDLETIMEOUT => ModemEvent::ErrorIdleTimeout, - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORCONNECTTIME => { - ModemEvent::ErrorMaxConnectTimeout - } - esp_netif_ppp_status_event_t_NETIF_PPP_ERRORLOOPBACK => ModemEvent::ErrorLoopback, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DEAD => ModemEvent::PhaseDead, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_MASTER => ModemEvent::PhaseMaster, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_HOLDOFF => ModemEvent::PhaseHoldoff, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_INITIALIZE => ModemEvent::PhaseInitialize, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_SERIALCONN => { - ModemEvent::PhaseSerialConnection - } - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DORMANT => ModemEvent::PhaseDormant, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_ESTABLISH => ModemEvent::PhaseEstablish, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_AUTHENTICATE => { - ModemEvent::PhaseAuthenticate - } - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_CALLBACK => ModemEvent::PhaseCallback, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_NETWORK => ModemEvent::PhaseNetwork, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_RUNNING => ModemEvent::PhaseRunning, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_TERMINATE => ModemEvent::PhaseTerminate, - esp_netif_ppp_status_event_t_NETIF_PPP_PHASE_DISCONNECT => ModemEvent::PhaseDisconnect, - esp_netif_ppp_status_event_t_NETIF_PPP_CONNECT_FAILED => ModemEvent::PhaseFailed, - _ => panic!("Unknown event ID: {}", event_id), - } - } -} - pub mod sim { //! SimModem //! @@ -412,7 +334,7 @@ pub mod sim { //! [super::SimModem] Implementation for the `SIMCOM 76XX` range of //! modems. - use core::{fmt::Display, time::Duration}; + use core::fmt::Display; use at_commands::{builder::CommandBuilder, parser::CommandParser}; use esp_idf_hal::{delay::TickType, uart::UartDriver}; From 0121093ade9302a3c481a93069a7837c08c5e411 Mon Sep 17 00:00:00 2001 From: Dane Slattery Date: Thu, 17 Oct 2024 08:03:15 +0200 Subject: [PATCH 3/7] Stash changes to modem.rs --- .cargo/config.toml | 3 +- Cargo.toml | 3 +- espflash.toml | 8 ++ src/modem.rs | 268 ++++++++++++++++++++++----------------------- 4 files changed, 145 insertions(+), 137 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 0656ef2bf6a..d2261023fa1 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,7 @@ [build] -target = "riscv32imc-esp-espidf" +# target = "riscv32imc-esp-espidf" #target = "xtensa-esp32-espidf" +target = "xtensa-esp32s3-espidf" [target.xtensa-esp32-espidf] linker = "ldproxy" diff --git a/Cargo.toml b/Cargo.toml index f1dba92e8cc..bf04efbb7ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,8 @@ log = { version = "0.4", default-features = false } uncased = { version = "0.9.7", default-features = false } embedded-hal-async = { version = "1", default-features = false } embedded-svc = { version = "0.28", default-features = false } -esp-idf-hal = { version = "0.44", default-features = false } +# esp-idf-hal = { version = "0.44", default-features = false } +esp-idf-hal ={path = "../esp-idf-hal"} embassy-time-driver = { version = "0.1", optional = true, features = [ "tick-hz-1_000_000", ] } diff --git a/espflash.toml b/espflash.toml index d22b92e7795..13c279b9aa3 100644 --- a/espflash.toml +++ b/espflash.toml @@ -1 +1,9 @@ partition_table = "partitions.csv" + +[connection] + +[[usb_device]] +vid = "303a" +pid = "1001" + +[flash] diff --git a/src/modem.rs b/src/modem.rs index e661c6c8130..73b41418ecf 100644 --- a/src/modem.rs +++ b/src/modem.rs @@ -18,7 +18,7 @@ use crate::{ pub struct EspModem<'d, T> where - T: BorrowMut>, + T: BorrowMut> + Send, { serial: T, status: Arc>, @@ -59,14 +59,7 @@ where self.netif.handle() as *mut core::ffi::c_void, ) })?; - esp!(unsafe { - esp_event_handler_register( - NETIF_PPP_STATUS, - ESP_EVENT_ANY_ID as _, - Some(Self::raw_on_ppp_changed), - self.netif.handle() as *mut core::ffi::c_void, - ) - })?; + let (mut tx, rx) = self.serial.borrow_mut().split(); let driver = EspNetifDriver::new_nonstatic( &mut self.netif, @@ -201,23 +194,21 @@ where ) { Self::on_ip_event(event_id as _, event_data) } +} - fn on_ppp_changed(event_id: u32, _event_data: *mut ::core::ffi::c_void) { - use log::info; - info!("Got event id ppp changed: {}", event_id); - - if event_id == esp_netif_ppp_status_event_t_NETIF_PPP_ERRORUSER { - info!("user interrupted event from netif"); - } - } - - unsafe extern "C" fn raw_on_ppp_changed( - _event_handler_arg: *mut ::core::ffi::c_void, - _event_base: esp_event_base_t, - event_id: i32, - event_data: *mut ::core::ffi::c_void, - ) { - Self::on_ppp_changed(event_id as _, event_data) +impl<'d, T> Drop for EspModem<'d, T> +where + T: BorrowMut> + Send, +{ + fn drop(&mut self) { + esp!(unsafe { + esp_event_handler_unregister( + IP_EVENT, + ESP_EVENT_ANY_ID as _, + Some(Self::raw_on_ip_event), + ) + }) + .unwrap(); } } @@ -278,7 +269,6 @@ pub mod sim { //! //! Models a modem device with a sim card able to serve as a //! network interface for the host. - use esp_idf_hal::uart::UartDriver; /// The generic device trait. Implementations of this trait should provide /// relevant AT commands and confirm the modem replies to drive the modem @@ -288,7 +278,11 @@ pub mod sim { fn get_mode(&self) -> &CommunicationMode; /// Initialise the remote modem so that it is in PPPoS mode. - fn negotiate(&mut self, comm: &mut UartDriver, buffer: [u8; 64]) -> Result<(), ModemError>; + fn negotiate( + &mut self, + comm: &mut T, + buffer: [u8; 64], + ) -> Result<(), ModemError>; } /// State of the modem. @@ -337,7 +331,7 @@ pub mod sim { use core::fmt::Display; use at_commands::{builder::CommandBuilder, parser::CommandParser}; - use esp_idf_hal::{delay::TickType, uart::UartDriver}; + use esp_idf_hal::{delay::TickType, io::BufReader, uart::UartDriver}; use super::{CommunicationMode, ModemError, SimModem}; pub struct SIM7600(CommunicationMode); @@ -483,32 +477,33 @@ pub mod sim { } impl SimModem for SIM7600 { - fn negotiate( + fn negotiate( &mut self, - comm: &mut UartDriver, + comm: &mut T, mut buffer: [u8; 64], ) -> Result<(), ModemError> { + let mut read_buf = BufReader::new(T); reset(comm, &mut buffer)?; - //disable echo - set_echo(comm, &mut buffer, false)?; + // //disable echo + // set_echo(comm, &mut buffer, false)?; - // get signal quality - let (rssi, ber) = get_signal_quality(comm, &mut buffer)?; - log::info!("RSSI = {rssi}"); - log::info!("BER = {ber}"); - // get iccid - let iccid = get_iccid(comm, &mut buffer)?; - log::info!("ICCID = [{}]", iccid); + // // get signal quality + // let (rssi, ber) = get_signal_quality(comm, &mut buffer)?; + // log::info!("RSSI = {rssi}"); + // log::info!("BER = {ber}"); + // // get iccid + // let iccid = get_iccid(comm, &mut buffer)?; + // log::info!("ICCID = [{}]", iccid); - // check pdp network reg - read_gprs_registration_status(comm, &mut buffer)?; + // // check pdp network reg + // read_gprs_registration_status(comm, &mut buffer)?; - //configure apn - set_pdp_context(comm, &mut buffer)?; + // //configure apn + // set_pdp_context(comm, &mut buffer)?; - // start ppp - set_data_mode(comm, &mut buffer)?; + // // start ppp + // set_data_mode(comm, &mut buffer)?; self.0 = CommunicationMode::Data; Ok(()) @@ -570,7 +565,10 @@ pub mod sim { Ok(heapless::String::try_from(ccid).unwrap()) } - fn reset(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { + fn reset( + comm: &mut T, + buff: &mut [u8], + ) -> Result<(), ModemError> { let cmd = CommandBuilder::create_execute(buff, false) .named("ATZ0") .finish()?; @@ -578,97 +576,97 @@ pub mod sim { comm.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) - .map_err(|_| ModemError::IO)?; - log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - CommandParser::parse(&buff[..len]) - .expect_identifier(b"ATZ0\r") - .expect_identifier(b"\r\nOK\r\n") - .finish()?; - Ok(()) - } - - fn set_echo(comm: &mut UartDriver, buff: &mut [u8], echo: bool) -> Result<(), ModemError> { - let cmd = CommandBuilder::create_execute(buff, false) - .named(format!("ATE{}", i32::from(echo))) - .finish()?; - log::info!("Set echo "); - comm.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) - .map_err(|_| ModemError::IO)?; - log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - CommandParser::parse(&buff[..len]) - .expect_identifier(b"ATE0\r") - .expect_identifier(b"\r\nOK\r\n") - .finish()?; - Ok(()) - } - - fn read_gprs_registration_status( - comm: &mut UartDriver, - buff: &mut [u8], - ) -> Result<(i32, i32, Option, Option), ModemError> { - let cmd = CommandBuilder::create_query(buff, true) - .named("+CGREG") - .finish()?; - log::info!("Get Registration Status"); - comm.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) - .map_err(|_| ModemError::IO)?; - log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - Ok(CommandParser::parse(&buff[..len]) - .expect_identifier(b"\r\n+CGREG: ") - .expect_int_parameter() - .expect_int_parameter() - .expect_optional_int_parameter() - .expect_optional_int_parameter() - .expect_identifier(b"\r\n\r\nOK\r\n") - .finish()?) - } - - fn set_pdp_context(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { - let cmd = CommandBuilder::create_set(buff, true) - .named("+CGDCONT") - .with_int_parameter(1) // context id - .with_string_parameter("IP") // pdp type - .with_string_parameter("flolive.net") // apn - .finish()?; - log::info!("Set PDP Context"); - comm.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) - .map_err(|_| ModemError::IO)?; - log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - CommandParser::parse(&buff[..len]) - .expect_identifier(b"\r\nOK\r\n") - .finish()?; + // let len = comm + // .read(buff, TickType::new_millis(1000).ticks()) + // .map_err(|_| ModemError::IO)?; + // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + // CommandParser::parse(&buff[..len]) + // .expect_identifier(b"ATZ0\r") + // .expect_identifier(b"\r\nOK\r\n") + // .finish()?; Ok(()) } - fn set_data_mode(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { - let cmd = CommandBuilder::create_execute(buff, false) - .named("ATD*99#") - .finish()?; - log::info!("Set Data mode"); - comm.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) - .map_err(|_| ModemError::IO)?; - log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - let (connect_parm,) = CommandParser::parse(&buff[..len]) - .expect_identifier(b"\r\nCONNECT ") - .expect_optional_raw_string() - .expect_identifier(b"\r\n") - .finish()?; - log::info!("connect {:?}", connect_parm); - Ok(()) - } + // fn set_echo(comm: &mut UartDriver, buff: &mut [u8], echo: bool) -> Result<(), ModemError> { + // let cmd = CommandBuilder::create_execute(buff, false) + // .named(format!("ATE{}", i32::from(echo))) + // .finish()?; + // log::info!("Set echo "); + // comm.write(cmd).map_err(|_| ModemError::IO)?; + // let len = comm + // .read(buff, TickType::new_millis(1000).ticks()) + // .map_err(|_| ModemError::IO)?; + // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + // CommandParser::parse(&buff[..len]) + // .expect_identifier(b"ATE0\r") + // .expect_identifier(b"\r\nOK\r\n") + // .finish()?; + // Ok(()) + // } + + // fn read_gprs_registration_status( + // comm: &mut UartDriver, + // buff: &mut [u8], + // ) -> Result<(i32, i32, Option, Option), ModemError> { + // let cmd = CommandBuilder::create_query(buff, true) + // .named("+CGREG") + // .finish()?; + // log::info!("Get Registration Status"); + // comm.write(cmd).map_err(|_| ModemError::IO)?; + // let len = comm + // .read(buff, TickType::new_millis(1000).ticks()) + // .map_err(|_| ModemError::IO)?; + // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + // Ok(CommandParser::parse(&buff[..len]) + // .expect_identifier(b"\r\n+CGREG: ") + // .expect_int_parameter() + // .expect_int_parameter() + // .expect_optional_int_parameter() + // .expect_optional_int_parameter() + // .expect_identifier(b"\r\n\r\nOK\r\n") + // .finish()?) + // } + + // fn set_pdp_context(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { + // let cmd = CommandBuilder::create_set(buff, true) + // .named("+CGDCONT") + // .with_int_parameter(1) // context id + // .with_string_parameter("IP") // pdp type + // .with_string_parameter("flolive.net") // apn + // .finish()?; + // log::info!("Set PDP Context"); + // comm.write(cmd).map_err(|_| ModemError::IO)?; + // let len = comm + // .read(buff, TickType::new_millis(1000).ticks()) + // .map_err(|_| ModemError::IO)?; + // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + // CommandParser::parse(&buff[..len]) + // .expect_identifier(b"\r\nOK\r\n") + // .finish()?; + // Ok(()) + // } + + // fn set_data_mode(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { + // let cmd = CommandBuilder::create_execute(buff, false) + // .named("ATD*99#") + // .finish()?; + // log::info!("Set Data mode"); + // comm.write(cmd).map_err(|_| ModemError::IO)?; + // let len = comm + // .read(buff, TickType::new_millis(1000).ticks()) + // .map_err(|_| ModemError::IO)?; + // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + // let (connect_parm,) = CommandParser::parse(&buff[..len]) + // .expect_identifier(b"\r\nCONNECT ") + // .expect_optional_raw_string() + // .expect_identifier(b"\r\n") + // .finish()?; + // log::info!("connect {:?}", connect_parm); + // Ok(()) + // } } } From 0b2fe94b07b1c70a08435956a853fba6c260fbf7 Mon Sep 17 00:00:00 2001 From: DaneSlattery Date: Tue, 22 Oct 2024 13:08:01 +0000 Subject: [PATCH 4/7] Add buffreader to EspModem and SimModem --- Cargo.toml | 4 +- examples/lte_modem.rs | 19 +- src/modem.rs | 518 ++++++++++++++++++++++++++++++------------ 3 files changed, 382 insertions(+), 159 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf04efbb7ba..79f02904866 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,8 +51,8 @@ log = { version = "0.4", default-features = false } uncased = { version = "0.9.7", default-features = false } embedded-hal-async = { version = "1", default-features = false } embedded-svc = { version = "0.28", default-features = false } -# esp-idf-hal = { version = "0.44", default-features = false } -esp-idf-hal ={path = "../esp-idf-hal"} +esp-idf-hal = { version = "0.44", default-features = false } +# esp-idf-hal ={path = "../esp-idf-hal"} embassy-time-driver = { version = "0.1", optional = true, features = [ "tick-hz-1_000_000", ] } diff --git a/examples/lte_modem.rs b/examples/lte_modem.rs index 5abef194ec4..a50d5d12c76 100644 --- a/examples/lte_modem.rs +++ b/examples/lte_modem.rs @@ -12,12 +12,12 @@ use embedded_svc::{ use esp_idf_hal::gpio; use esp_idf_hal::uart::UartDriver; use esp_idf_hal::units::Hertz; -use esp_idf_svc::eventloop::EspSystemEventLoop; -use esp_idf_svc::log::EspLogger; use esp_idf_svc::modem::sim::sim7600::SIM7600; use esp_idf_svc::modem::sim::SimModem; use esp_idf_svc::modem::EspModem; +use esp_idf_svc::{eventloop::EspSystemEventLoop, modem::BufferedRead}; use esp_idf_svc::{hal::prelude::Peripherals, http::client::EspHttpConnection}; +use esp_idf_svc::{log::EspLogger, modem::ModemPhaseStatus}; use log::{error, info}; @@ -47,14 +47,20 @@ fn main() -> anyhow::Result<()> { }, )?; - let mut sim_device = SIM7600::new(); let mut buff = [0u8; 64]; - match sim_device.negotiate(&mut serial, buff) { + + let (mut tx, rx) = serial.split(); + + let buf_reader = BufferedRead::new(rx, &mut buff); + + let mut sim_device = SIM7600::new(); + + match sim_device.negotiate(&mut tx, &mut buf_reader) { Err(x) => log::error!("Error = {}", x), Ok(()) => log::info!("Device in PPP mode"), } - let mut modem = EspModem::new(&mut serial, sys_loop)?; + let mut modem = EspModem::new(&mut tx, &mut buf_reader, sys_loop)?; let _scope = std::thread::scope::<_, anyhow::Result<()>>(|s| { let my_thread: ScopedJoinHandle> = s.spawn(|| { @@ -66,8 +72,7 @@ fn main() -> anyhow::Result<()> { }); std::thread::sleep(Duration::from_secs(10)); - // while !modem.netif().is_up()? {} - // while !(modem.is_connected()?) {} + let mut client = HttpClient::wrap(EspHttpConnection::new(&Default::default())?); diff --git a/src/modem.rs b/src/modem.rs index 73b41418ecf..0e6359683f1 100644 --- a/src/modem.rs +++ b/src/modem.rs @@ -2,12 +2,17 @@ use crate::{ handle::RawHandle, netif::{PppConfiguration, PppEvent}, }; -use core::{borrow::BorrowMut, marker::PhantomData}; +use core::{ + borrow::{Borrow, BorrowMut}, + cell::RefCell, + marker::PhantomData, +}; use esp_idf_hal::{ delay::BLOCK, + io::{Error, EspIOError}, uart::{UartDriver, UartTxDriver}, }; -use std::sync::Arc; +use std::{boxed::Box, rc::Rc, sync::Arc}; use crate::{ eventloop::{EspEventLoop, EspSubscription, EspSystemEventLoop, System}, @@ -16,67 +21,211 @@ use crate::{ sys::*, }; -pub struct EspModem<'d, T> +/// Unable to bypass the current buffered reader or writer because there are buffered bytes. +#[derive(Debug)] +pub struct BypassError; + +/// A buffered [`Read`] +/// +/// The BufferedRead will read into the provided buffer to avoid small reads to the inner reader. +pub struct BufferedRead<'buf, T: embedded_svc::io::Read> { + inner: T, + buf: &'buf mut [u8], + offset: usize, + available: usize, +} + +impl<'buf, T: embedded_svc::io::Read> BufferedRead<'buf, T> { + /// Create a new buffered reader + pub fn new(inner: T, buf: &'buf mut [u8]) -> Self { + Self { + inner, + buf, + offset: 0, + available: 0, + } + } + + /// Create a new buffered reader with the first `available` bytes readily available at `offset`. + /// + /// This is useful if for some reason the inner reader was previously consumed by a greedy reader + /// in a way such that the BufferedRead must inherit these excess bytes. + pub fn new_with_data(inner: T, buf: &'buf mut [u8], offset: usize, available: usize) -> Self { + assert!(offset + available <= buf.len()); + Self { + inner, + buf, + offset, + available, + } + } + + /// Get whether there are any bytes readily available + pub fn is_empty(&self) -> bool { + self.available == 0 + } + + /// Get the number of bytes that are readily availbale + pub fn available(&self) -> usize { + self.available + } + + /// Get the inner reader if there are no currently buffered, available bytes + pub fn bypass(&mut self) -> Result<&mut T, BypassError> { + match self.available { + 0 => Ok(&mut self.inner), + _ => Err(BypassError), + } + } + + /// Release and get the inner reader + pub fn release(self) -> T { + self.inner + } +} + +impl embedded_svc::io::ErrorType for BufferedRead<'_, T> { + type Error = T::Error; +} + +impl embedded_svc::io::Write + for BufferedRead<'_, T> +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.inner.write(buf) + } + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.inner.write_all(buf) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.inner.flush() + } +} + +impl embedded_svc::io::Read for BufferedRead<'_, T> { + fn read(&mut self, buf: &mut [u8]) -> Result { + if self.available == 0 { + if buf.len() >= self.buf.len() { + // Fast path - bypass local buffer + return self.inner.read(buf); + } + self.offset = 0; + self.available = self.inner.read(self.buf)?; + } + + let len = usize::min(self.available, buf.len()); + buf[..len].copy_from_slice(&self.buf[self.offset..self.offset + len]); + if len < self.available { + // There are still bytes left + self.offset += len; + self.available -= len; + } else { + // The buffer is drained + self.available = 0; + } + + Ok(len) + } +} + +impl embedded_svc::io::BufRead for BufferedRead<'_, T> { + fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + if self.available == 0 { + self.offset = 0; + self.available = self.inner.read(self.buf)?; + } + + Ok(&self.buf[self.offset..self.offset + self.available]) + } + + fn consume(&mut self, amt: usize) { + assert!(amt <= self.available); + self.offset += amt; + self.available -= amt; + } +} + +pub struct EspModem<'d, T, R, E> where - T: BorrowMut> + Send, + T: embedded_svc::io::Write + Send, + R: embedded_svc::io::BufRead, + EspIOError: From, { - serial: T, + writer: Arc>, + reader: Arc>, status: Arc>, _subscription: EspSubscription<'static, System>, - netif: EspNetif, + netif: Arc>, _d: PhantomData<&'d ()>, } -impl<'d, T> EspModem<'d, T> +impl<'d, T, R, E> EspModem<'d, T, R, E> where - T: BorrowMut> + Send, + T: embedded_svc::io::Write + Send, + R: embedded_svc::io::BufRead, + EspIOError: From, // EspError: From<::Error>, + // EspError: From<::Error>, { - pub fn new(serial: T, sysloop: EspSystemEventLoop) -> Result { + pub fn new(writer: T, reader: R, sysloop: EspSystemEventLoop) -> Result { let (status, subscription) = Self::subscribe(&sysloop)?; Ok(Self { - serial, + writer: Arc::new(mutex::Mutex::new(writer)), + reader: Arc::new(mutex::Mutex::new(reader)), status, _subscription: subscription, - netif: EspNetif::new(NetifStack::Ppp)?, + netif: Arc::new(mutex::Mutex::new(EspNetif::new(NetifStack::Ppp)?)), _d: PhantomData, }) } /// Run the modem network interface. Blocks until the PPP encounters an error. - pub fn run(&mut self, buffer: &mut [u8]) -> Result<(), EspError> { + pub fn run(&self, buffer: &mut [u8]) -> Result<(), EspError> { self.status.lock().running = true; // now in ppp mode. - // let netif = EspNetif::new(NetifStack::Ppp)?; - // subscribe to user event + let handle = self.netif.as_ref().lock().handle(); esp!(unsafe { esp_event_handler_register( IP_EVENT, ESP_EVENT_ANY_ID as _, Some(Self::raw_on_ip_event), - self.netif.handle() as *mut core::ffi::c_void, + handle as *mut core::ffi::c_void, ) })?; - let (mut tx, rx) = self.serial.borrow_mut().split(); + let netif = Arc::clone(&self.netif); + let mut netif = (*netif).lock(); + let netif = (*netif).borrow_mut(); + + let writer = self.writer.clone(); let driver = EspNetifDriver::new_nonstatic( - &mut self.netif, + netif, move |x| { x.set_ppp_conf(&PppConfiguration { phase_events_enabled: true, error_events_enabled: true, }) }, - |data| Self::tx(&mut tx, data), + move |data| Self::tx(writer.clone(), data), )?; + use embedded_svc::io::Read; + loop { if !self.status.lock().running { break; } - let len = rx.read(buffer, BLOCK)?; + let len = self + .reader + .lock() + .fill_buf() + .map_err(|w| Into::::into(w).0)? + .read(buffer) + .unwrap(); if len > 0 { driver.rx(&buffer[..len])?; } @@ -94,20 +243,26 @@ where pub fn get_phase_status(&self) -> ModemPhaseStatus { self.status.lock().phase.clone() } - - /// Returns the underlying [`EspNetif`] - pub fn netif(&self) -> &EspNetif { - &self.netif + pub fn is_connected(&self) -> Result { + let netif = (*self.netif).borrow(); + netif.lock().is_up() } + // /// Returns the underlying [`EspNetif`] + // pub fn netif(&self) -> &EspNetif { + // &self.netif.borrow() + // } - /// Returns the underlying [`EspNetif`], as mutable - pub fn netif_mut(&mut self) -> &mut EspNetif { - &mut self.netif - } + // /// Returns the underlying [`EspNetif`], as mutable + // pub fn netif_mut(&mut self) -> &mut EspNetif { + // &mut self.netif + // } /// Callback given to the LWIP API to write data to the PPP server. - fn tx(writer: &mut UartTxDriver, data: &[u8]) -> Result<(), EspError> { - esp_idf_hal::io::Write::write_all(writer, data).map_err(|w| w.0)?; + fn tx(writer: Arc>, data: &[u8]) -> Result<(), EspError> { + writer + .lock() + .write_all(data) + .map_err(|w| Into::::into(w).0)?; Ok(()) } @@ -196,9 +351,11 @@ where } } -impl<'d, T> Drop for EspModem<'d, T> +impl<'d, T, R, E> Drop for EspModem<'d, T, R, E> where - T: BorrowMut> + Send, + T: embedded_svc::io::Write + Send, + R: embedded_svc::io::BufRead, + EspIOError: From, { fn drop(&mut self) { esp!(unsafe { @@ -278,10 +435,13 @@ pub mod sim { fn get_mode(&self) -> &CommunicationMode; /// Initialise the remote modem so that it is in PPPoS mode. - fn negotiate( + fn negotiate< + T: embedded_svc::io::Write, + R: embedded_svc::io::BufRead + embedded_svc::io::Read, + >( &mut self, - comm: &mut T, - buffer: [u8; 64], + tx: &mut T, + rx: &mut R, ) -> Result<(), ModemError>; } @@ -329,9 +489,9 @@ pub mod sim { //! modems. use core::fmt::Display; + use std::io::Read; use at_commands::{builder::CommandBuilder, parser::CommandParser}; - use esp_idf_hal::{delay::TickType, io::BufReader, uart::UartDriver}; use super::{CommunicationMode, ModemError, SimModem}; pub struct SIM7600(CommunicationMode); @@ -477,33 +637,36 @@ pub mod sim { } impl SimModem for SIM7600 { - fn negotiate( + fn negotiate< + T: embedded_svc::io::Write, + R: embedded_svc::io::BufRead + embedded_svc::io::Read, + >( &mut self, - comm: &mut T, - mut buffer: [u8; 64], + tx: &mut T, + rx: &mut R, ) -> Result<(), ModemError> { - let mut read_buf = BufReader::new(T); - reset(comm, &mut buffer)?; + let mut buffer = [0u8; 64]; + reset(tx, rx, &mut buffer)?; - // //disable echo - // set_echo(comm, &mut buffer, false)?; + //disable echo + set_echo(tx, rx, &mut buffer, false)?; - // // get signal quality - // let (rssi, ber) = get_signal_quality(comm, &mut buffer)?; - // log::info!("RSSI = {rssi}"); - // log::info!("BER = {ber}"); - // // get iccid - // let iccid = get_iccid(comm, &mut buffer)?; - // log::info!("ICCID = [{}]", iccid); + // get signal quality + let (rssi, ber) = get_signal_quality(tx, rx, &mut buffer)?; + log::info!("RSSI = {rssi}"); + log::info!("BER = {ber}"); + // get iccid + let iccid = get_iccid(tx, rx, &mut buffer)?; + log::info!("ICCID = [{}]", iccid); - // // check pdp network reg - // read_gprs_registration_status(comm, &mut buffer)?; + // check pdp network reg + read_gprs_registration_status(tx, rx, &mut buffer)?; - // //configure apn - // set_pdp_context(comm, &mut buffer)?; + //configure apn + set_pdp_context(tx, rx, &mut buffer)?; - // // start ppp - // set_data_mode(comm, &mut buffer)?; + // start ppp + set_data_mode(tx, rx, &mut buffer)?; self.0 = CommunicationMode::Data; Ok(()) @@ -514,18 +677,21 @@ pub mod sim { } } - pub fn get_signal_quality( - comm: &mut UartDriver, + pub fn get_signal_quality( + tx: &mut T, + rx: &mut R, buff: &mut [u8], ) -> Result<(RSSI, BitErrorRate), ModemError> { let cmd = CommandBuilder::create_execute(buff, true) .named("+CSQ") .finish()?; - comm.write(cmd).map_err(|_| ModemError::IO)?; + tx.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) + let len = rx + .fill_buf() + .map_err(|_| ModemError::IO)? + .read(buff) .map_err(|_| ModemError::IO)?; log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); @@ -537,22 +703,26 @@ pub mod sim { .expect_int_parameter() .expect_identifier(b"\r\n\r\nOK\r\n") .finish()?; + rx.consume(len); Ok((RSSI::parse(raw_rssi), raw_ber.into())) } - fn get_iccid( - comm: &mut UartDriver, + fn get_iccid( + tx: &mut T, + rx: &mut R, buff: &mut [u8], ) -> Result, ModemError> { let cmd = CommandBuilder::create_execute(buff, true) .named("+CICCID") .finish()?; - comm.write(cmd).map_err(|_| ModemError::IO)?; + tx.write(cmd).map_err(|_| ModemError::IO)?; - let len = comm - .read(buff, TickType::new_millis(1000).ticks()) + let len = rx + .fill_buf() + .map_err(|_| ModemError::IO)? + .read(buff) .map_err(|_| ModemError::IO)?; log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); @@ -561,12 +731,13 @@ pub mod sim { .expect_raw_string() .expect_identifier(b"\r\n\r\nOK\r\n") .finish()?; - + rx.consume(len); Ok(heapless::String::try_from(ccid).unwrap()) } - fn reset( - comm: &mut T, + fn reset( + tx: &mut T, + rx: &R, buff: &mut [u8], ) -> Result<(), ModemError> { let cmd = CommandBuilder::create_execute(buff, false) @@ -574,7 +745,7 @@ pub mod sim { .finish()?; log::info!("Send Reset"); - comm.write(cmd).map_err(|_| ModemError::IO)?; + tx.write(cmd).map_err(|_| ModemError::IO)?; // let len = comm // .read(buff, TickType::new_millis(1000).ticks()) @@ -587,86 +758,133 @@ pub mod sim { Ok(()) } - // fn set_echo(comm: &mut UartDriver, buff: &mut [u8], echo: bool) -> Result<(), ModemError> { - // let cmd = CommandBuilder::create_execute(buff, false) - // .named(format!("ATE{}", i32::from(echo))) - // .finish()?; - // log::info!("Set echo "); - // comm.write(cmd).map_err(|_| ModemError::IO)?; - // let len = comm - // .read(buff, TickType::new_millis(1000).ticks()) - // .map_err(|_| ModemError::IO)?; - // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - // CommandParser::parse(&buff[..len]) - // .expect_identifier(b"ATE0\r") - // .expect_identifier(b"\r\nOK\r\n") - // .finish()?; - // Ok(()) - // } - - // fn read_gprs_registration_status( - // comm: &mut UartDriver, - // buff: &mut [u8], - // ) -> Result<(i32, i32, Option, Option), ModemError> { - // let cmd = CommandBuilder::create_query(buff, true) - // .named("+CGREG") - // .finish()?; - // log::info!("Get Registration Status"); - // comm.write(cmd).map_err(|_| ModemError::IO)?; - // let len = comm - // .read(buff, TickType::new_millis(1000).ticks()) - // .map_err(|_| ModemError::IO)?; - // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - // Ok(CommandParser::parse(&buff[..len]) - // .expect_identifier(b"\r\n+CGREG: ") - // .expect_int_parameter() - // .expect_int_parameter() - // .expect_optional_int_parameter() - // .expect_optional_int_parameter() - // .expect_identifier(b"\r\n\r\nOK\r\n") - // .finish()?) - // } - - // fn set_pdp_context(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { - // let cmd = CommandBuilder::create_set(buff, true) - // .named("+CGDCONT") - // .with_int_parameter(1) // context id - // .with_string_parameter("IP") // pdp type - // .with_string_parameter("flolive.net") // apn - // .finish()?; - // log::info!("Set PDP Context"); - // comm.write(cmd).map_err(|_| ModemError::IO)?; - // let len = comm - // .read(buff, TickType::new_millis(1000).ticks()) - // .map_err(|_| ModemError::IO)?; - // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - // CommandParser::parse(&buff[..len]) - // .expect_identifier(b"\r\nOK\r\n") - // .finish()?; - // Ok(()) - // } - - // fn set_data_mode(comm: &mut UartDriver, buff: &mut [u8]) -> Result<(), ModemError> { - // let cmd = CommandBuilder::create_execute(buff, false) - // .named("ATD*99#") - // .finish()?; - // log::info!("Set Data mode"); - // comm.write(cmd).map_err(|_| ModemError::IO)?; - // let len = comm - // .read(buff, TickType::new_millis(1000).ticks()) - // .map_err(|_| ModemError::IO)?; - // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - - // let (connect_parm,) = CommandParser::parse(&buff[..len]) - // .expect_identifier(b"\r\nCONNECT ") - // .expect_optional_raw_string() - // .expect_identifier(b"\r\n") - // .finish()?; - // log::info!("connect {:?}", connect_parm); - // Ok(()) - // } + fn set_echo< + T: embedded_svc::io::Write, + R: embedded_svc::io::BufRead + embedded_svc::io::Read, + >( + tx: &mut T, + rx: &mut R, + buff: &mut [u8], + echo: bool, + ) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_execute(buff, false) + .named(format!("ATE{}", i32::from(echo))) + .finish()?; + log::info!("Set echo "); + tx.write(cmd).map_err(|_| ModemError::IO)?; + + let len = rx + .fill_buf() + .map_err(|_| ModemError::IO)? + .read(buff) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + CommandParser::parse(&buff[..len]) + .expect_identifier(b"ATE0\r") + .expect_identifier(b"\r\nOK\r\n") + .finish()?; + + rx.consume(len); + Ok(()) + } + + fn read_gprs_registration_status< + T: embedded_svc::io::Write, + R: embedded_svc::io::BufRead + embedded_svc::io::Read, + >( + tx: &mut T, + rx: &mut R, + buff: &mut [u8], + ) -> Result<(i32, i32, Option, Option), ModemError> { + let cmd = CommandBuilder::create_query(buff, true) + .named("+CGREG") + .finish()?; + log::info!("Get Registration Status"); + tx.write(cmd).map_err(|_| ModemError::IO)?; + let len = rx + .fill_buf() + .map_err(|_| ModemError::IO)? + .read(buff) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + let (a, b, c, d) = CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\n+CGREG: ") + .expect_int_parameter() + .expect_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_identifier(b"\r\n\r\nOK\r\n") + .finish()?; + + rx.consume(len); + Ok((a, b, c, d)) + } + + fn set_pdp_context< + T: embedded_svc::io::Write, + R: embedded_svc::io::BufRead + embedded_svc::io::Read, + >( + tx: &mut T, + rx: &mut R, + buff: &mut [u8], + ) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_set(buff, true) + .named("+CGDCONT") + .with_int_parameter(1) // context id + .with_string_parameter("IP") // pdp type + .with_string_parameter("flolive.net") // apn + .finish()?; + log::info!("Set PDP Context"); + tx.write(cmd).map_err(|_| ModemError::IO)?; + let len = rx + .fill_buf() + .map_err(|_| ModemError::IO)? + .read(buff) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\nOK\r\n") + .finish()?; + rx.consume(len); + Ok(()) + } + + fn set_data_mode< + T: embedded_svc::io::Write, + R: embedded_svc::io::BufRead + embedded_svc::io::Read, + >( + tx: &mut T, + rx: &mut R, + buff: &mut [u8], + ) -> Result<(), ModemError> { + let cmd = CommandBuilder::create_execute(buff, false) + .named("ATD*99#") + .finish()?; + log::info!("Set Data mode"); + tx.write(cmd).map_err(|_| ModemError::IO)?; + let len = rx + .fill_buf() + .map_err(|_| ModemError::IO)? + .read(buff) + .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + + let (connect_parm,) = CommandParser::parse(&buff[..len]) + .expect_identifier(b"\r\nCONNECT ") + .expect_optional_raw_string() + .expect_identifier(b"\r\n") + .finish()?; + log::info!("connect {:?}", connect_parm); + // consume only pre-PPP bytes from the buffer + rx.consume(10); + if let Some(connect_str) = connect_parm { + rx.consume(connect_str.len()); + } + rx.consume(2); + Ok(()) + } } } From ef394f2c07d62a2a03cc6e7095e8c67eddbcaf23 Mon Sep 17 00:00:00 2001 From: DaneSlattery Date: Tue, 22 Oct 2024 13:30:26 +0000 Subject: [PATCH 5/7] Clean up traits --- src/modem.rs | 95 ++++++++++++++++------------------------------------ 1 file changed, 29 insertions(+), 66 deletions(-) diff --git a/src/modem.rs b/src/modem.rs index 0e6359683f1..31ab761ea96 100644 --- a/src/modem.rs +++ b/src/modem.rs @@ -150,7 +150,7 @@ impl embedded_svc::io::BufRead for BufferedRead<'_, T pub struct EspModem<'d, T, R, E> where T: embedded_svc::io::Write + Send, - R: embedded_svc::io::BufRead, + R: embedded_svc::io::Read, EspIOError: From, { writer: Arc>, @@ -164,7 +164,7 @@ where impl<'d, T, R, E> EspModem<'d, T, R, E> where T: embedded_svc::io::Write + Send, - R: embedded_svc::io::BufRead, + R: embedded_svc::io::Read, EspIOError: From, // EspError: From<::Error>, // EspError: From<::Error>, { @@ -213,8 +213,6 @@ where move |data| Self::tx(writer.clone(), data), )?; - use embedded_svc::io::Read; - loop { if !self.status.lock().running { break; @@ -222,10 +220,9 @@ where let len = self .reader .lock() - .fill_buf() - .map_err(|w| Into::::into(w).0)? .read(buffer) - .unwrap(); + .map_err(|w| Into::::into(w).0)?; + if len > 0 { driver.rx(&buffer[..len])?; } @@ -354,7 +351,7 @@ where impl<'d, T, R, E> Drop for EspModem<'d, T, R, E> where T: embedded_svc::io::Write + Send, - R: embedded_svc::io::BufRead, + R: embedded_svc::io::Read, EspIOError: From, { fn drop(&mut self) { @@ -427,6 +424,8 @@ pub mod sim { //! Models a modem device with a sim card able to serve as a //! network interface for the host. + use embedded_svc::io::{BufRead, Read, Write}; + /// The generic device trait. Implementations of this trait should provide /// relevant AT commands and confirm the modem replies to drive the modem /// into PPPoS (data mode). @@ -435,10 +434,7 @@ pub mod sim { fn get_mode(&self) -> &CommunicationMode; /// Initialise the remote modem so that it is in PPPoS mode. - fn negotiate< - T: embedded_svc::io::Write, - R: embedded_svc::io::BufRead + embedded_svc::io::Read, - >( + fn negotiate( &mut self, tx: &mut T, rx: &mut R, @@ -488,10 +484,9 @@ pub mod sim { //! [super::SimModem] Implementation for the `SIMCOM 76XX` range of //! modems. - use core::fmt::Display; - use std::io::Read; - use at_commands::{builder::CommandBuilder, parser::CommandParser}; + use core::fmt::Display; + use embedded_svc::io::{BufRead, Read, Write}; use super::{CommunicationMode, ModemError, SimModem}; pub struct SIM7600(CommunicationMode); @@ -637,10 +632,7 @@ pub mod sim { } impl SimModem for SIM7600 { - fn negotiate< - T: embedded_svc::io::Write, - R: embedded_svc::io::BufRead + embedded_svc::io::Read, - >( + fn negotiate( &mut self, tx: &mut T, rx: &mut R, @@ -735,9 +727,9 @@ pub mod sim { Ok(heapless::String::try_from(ccid).unwrap()) } - fn reset( + fn reset( tx: &mut T, - rx: &R, + _rx: &R, buff: &mut [u8], ) -> Result<(), ModemError> { let cmd = CommandBuilder::create_execute(buff, false) @@ -747,6 +739,7 @@ pub mod sim { tx.write(cmd).map_err(|_| ModemError::IO)?; + // not sure if I need this or not // let len = comm // .read(buff, TickType::new_millis(1000).ticks()) // .map_err(|_| ModemError::IO)?; @@ -758,10 +751,7 @@ pub mod sim { Ok(()) } - fn set_echo< - T: embedded_svc::io::Write, - R: embedded_svc::io::BufRead + embedded_svc::io::Read, - >( + fn set_echo( tx: &mut T, rx: &mut R, buff: &mut [u8], @@ -773,26 +763,16 @@ pub mod sim { log::info!("Set echo "); tx.write(cmd).map_err(|_| ModemError::IO)?; - let len = rx - .fill_buf() - .map_err(|_| ModemError::IO)? - .read(buff) - .map_err(|_| ModemError::IO)?; + let len = rx.read(buff).map_err(|_| ModemError::IO)?; log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - CommandParser::parse(&buff[..len]) + Ok(CommandParser::parse(&buff[..len]) .expect_identifier(b"ATE0\r") .expect_identifier(b"\r\nOK\r\n") - .finish()?; - - rx.consume(len); - Ok(()) + .finish()?) } - fn read_gprs_registration_status< - T: embedded_svc::io::Write, - R: embedded_svc::io::BufRead + embedded_svc::io::Read, - >( + fn read_gprs_registration_status( tx: &mut T, rx: &mut R, buff: &mut [u8], @@ -802,30 +782,20 @@ pub mod sim { .finish()?; log::info!("Get Registration Status"); tx.write(cmd).map_err(|_| ModemError::IO)?; - let len = rx - .fill_buf() - .map_err(|_| ModemError::IO)? - .read(buff) - .map_err(|_| ModemError::IO)?; + let len = rx.read(buff).map_err(|_| ModemError::IO)?; log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - let (a, b, c, d) = CommandParser::parse(&buff[..len]) + Ok(CommandParser::parse(&buff[..len]) .expect_identifier(b"\r\n+CGREG: ") .expect_int_parameter() .expect_int_parameter() .expect_optional_int_parameter() .expect_optional_int_parameter() .expect_identifier(b"\r\n\r\nOK\r\n") - .finish()?; - - rx.consume(len); - Ok((a, b, c, d)) + .finish()?) } - fn set_pdp_context< - T: embedded_svc::io::Write, - R: embedded_svc::io::BufRead + embedded_svc::io::Read, - >( + fn set_pdp_context( tx: &mut T, rx: &mut R, buff: &mut [u8], @@ -838,24 +808,15 @@ pub mod sim { .finish()?; log::info!("Set PDP Context"); tx.write(cmd).map_err(|_| ModemError::IO)?; - let len = rx - .fill_buf() - .map_err(|_| ModemError::IO)? - .read(buff) - .map_err(|_| ModemError::IO)?; + let len = rx.read(buff).map_err(|_| ModemError::IO)?; log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - CommandParser::parse(&buff[..len]) + Ok(CommandParser::parse(&buff[..len]) .expect_identifier(b"\r\nOK\r\n") - .finish()?; - rx.consume(len); - Ok(()) + .finish()?) } - fn set_data_mode< - T: embedded_svc::io::Write, - R: embedded_svc::io::BufRead + embedded_svc::io::Read, - >( + fn set_data_mode( tx: &mut T, rx: &mut R, buff: &mut [u8], @@ -865,11 +826,13 @@ pub mod sim { .finish()?; log::info!("Set Data mode"); tx.write(cmd).map_err(|_| ModemError::IO)?; + let len = rx .fill_buf() .map_err(|_| ModemError::IO)? .read(buff) .map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); let (connect_parm,) = CommandParser::parse(&buff[..len]) From e75d6cbef43bef69f853f551cba13017054aa1f2 Mon Sep 17 00:00:00 2001 From: Dane Slattery Date: Fri, 25 Oct 2024 09:54:54 +0200 Subject: [PATCH 6/7] Build example --- Cargo.toml | 4 ++-- examples/lte_modem.rs | 31 +++++++++++++++++++++++++------ src/modem.rs | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 79f02904866..cdf6e83e487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,8 +51,8 @@ log = { version = "0.4", default-features = false } uncased = { version = "0.9.7", default-features = false } embedded-hal-async = { version = "1", default-features = false } embedded-svc = { version = "0.28", default-features = false } -esp-idf-hal = { version = "0.44", default-features = false } -# esp-idf-hal ={path = "../esp-idf-hal"} +# esp-idf-hal = { version = "0.44", default-features = false } +esp-idf-hal = { path = "../esp-idf-hal" } embassy-time-driver = { version = "0.1", optional = true, features = [ "tick-hz-1_000_000", ] } diff --git a/examples/lte_modem.rs b/examples/lte_modem.rs index a50d5d12c76..eb970a5f815 100644 --- a/examples/lte_modem.rs +++ b/examples/lte_modem.rs @@ -9,9 +9,12 @@ use embedded_svc::{ utils::io, }; -use esp_idf_hal::gpio; use esp_idf_hal::uart::UartDriver; use esp_idf_hal::units::Hertz; +use esp_idf_hal::{ + delay, + gpio::{self, PinDriver}, +}; use esp_idf_svc::modem::sim::sim7600::SIM7600; use esp_idf_svc::modem::sim::SimModem; use esp_idf_svc::modem::EspModem; @@ -35,6 +38,22 @@ fn main() -> anyhow::Result<()> { let tx = peripherals.pins.gpio17; let rx = peripherals.pins.gpio18; + let mut lte_reset = PinDriver::output(peripherals.pins.gpio42).unwrap(); + lte_reset.set_low().unwrap(); + + let mut lte_power = PinDriver::output(peripherals.pins.gpio41).unwrap(); + let mut lte_on = PinDriver::output(peripherals.pins.gpio40).unwrap(); + // turn lte device on + log::info!("Reset GSM Device"); + lte_power.set_high().unwrap(); + let delay = delay::Delay::new_default(); + delay.delay_ms(100); + lte_on.set_high().unwrap(); + delay.delay_ms(100); + lte_on.set_low().unwrap(); + delay.delay_ms(10000); + log::info!("Reset Complete"); + let mut serial = UartDriver::new( serial, tx, @@ -47,11 +66,11 @@ fn main() -> anyhow::Result<()> { }, )?; - let mut buff = [0u8; 64]; + let mut buff = [0u8; 1024]; let (mut tx, rx) = serial.split(); - let buf_reader = BufferedRead::new(rx, &mut buff); + let mut buf_reader = BufferedRead::new(rx, &mut buff); let mut sim_device = SIM7600::new(); @@ -60,10 +79,12 @@ fn main() -> anyhow::Result<()> { Ok(()) => log::info!("Device in PPP mode"), } - let mut modem = EspModem::new(&mut tx, &mut buf_reader, sys_loop)?; + let modem = EspModem::new(&mut tx, &mut buf_reader, sys_loop)?; let _scope = std::thread::scope::<_, anyhow::Result<()>>(|s| { let my_thread: ScopedJoinHandle> = s.spawn(|| { + let mut buff = [0u8; 64]; + match modem.run(&mut buff) { Err(x) => log::error!("Error: {:?}", x), Ok(_x) => (), @@ -72,8 +93,6 @@ fn main() -> anyhow::Result<()> { }); std::thread::sleep(Duration::from_secs(10)); - - let mut client = HttpClient::wrap(EspHttpConnection::new(&Default::default())?); // GET diff --git a/src/modem.rs b/src/modem.rs index 31ab761ea96..0d6d6f68bae 100644 --- a/src/modem.rs +++ b/src/modem.rs @@ -348,6 +348,22 @@ where } } +unsafe impl Send for EspModem<'_, T, R, E> +where + T: embedded_svc::io::Write + Send, + R: embedded_svc::io::Read, + EspIOError: From, +{ +} + +unsafe impl Sync for EspModem<'_, T, R, E> +where + T: embedded_svc::io::Write + Send, + R: embedded_svc::io::Read, + EspIOError: From, +{ +} + impl<'d, T, R, E> Drop for EspModem<'d, T, R, E> where T: embedded_svc::io::Write + Send, @@ -729,7 +745,7 @@ pub mod sim { fn reset( tx: &mut T, - _rx: &R, + rx: &mut R, buff: &mut [u8], ) -> Result<(), ModemError> { let cmd = CommandBuilder::create_execute(buff, false) @@ -740,14 +756,19 @@ pub mod sim { tx.write(cmd).map_err(|_| ModemError::IO)?; // not sure if I need this or not - // let len = comm - // .read(buff, TickType::new_millis(1000).ticks()) - // .map_err(|_| ModemError::IO)?; - // log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); - // CommandParser::parse(&buff[..len]) - // .expect_identifier(b"ATZ0\r") - // .expect_identifier(b"\r\nOK\r\n") - // .finish()?; + let len = rx.read(buff).map_err(|_| ModemError::IO)?; + log::info!("got response{:?}", std::str::from_utf8(&buff[..len])); + if CommandParser::parse(&buff[..len]) + .expect_identifier(b"ATZ0\r") + .expect_identifier(b"\r\nOK\r\n") + .finish() + .is_err() + { + CommandParser::parse(&buff[..len]) + .expect_identifier(b"ATZ0\r") + .expect_identifier(b"\r\nERROR\r\n") + .finish()? + } Ok(()) } From 0661bb86728c156491652a5cb3762d1b21710bce Mon Sep 17 00:00:00 2001 From: Dane Slattery Date: Thu, 31 Oct 2024 08:55:51 +0200 Subject: [PATCH 7/7] patch esp-idf-hal --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cdf6e83e487..a958c64a28b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,8 +51,8 @@ log = { version = "0.4", default-features = false } uncased = { version = "0.9.7", default-features = false } embedded-hal-async = { version = "1", default-features = false } embedded-svc = { version = "0.28", default-features = false } -# esp-idf-hal = { version = "0.44", default-features = false } -esp-idf-hal = { path = "../esp-idf-hal" } +esp-idf-hal = { version = "0.44", default-features = false } +# esp-idf-hal = { path = "../esp-idf-hal" } embassy-time-driver = { version = "0.1", optional = true, features = [ "tick-hz-1_000_000", ] }