Skip to content

Commit

Permalink
First attempt at binding, currently struggling
Browse files Browse the repository at this point in the history
  • Loading branch information
DaneSlattery committed Aug 13, 2024
1 parent bf47d2b commit 0a37e21
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/configs/sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/target
/Cargo.lock
**/*.rs.bk
/.devcontainer
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ 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-futures = "0.1"
atat = {version="0.23.0", default-features = false, features=["bytes","derive","heapless","serde_at"]}
at-commands = "0.5.4"

[build-dependencies]
embuild = "0.32"
Expand Down
55 changes: 55 additions & 0 deletions examples/lte_modem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//! Example of using blocking wifi.
//!
//! Add your own ssid and password

use core::convert::TryInto;

use embedded_svc::wifi::{AuthMethod, ClientConfiguration, Configuration};

use esp_idf_hal::gpio;
use esp_idf_hal::uart::UartDriver;
use esp_idf_hal::units::Hertz;
use esp_idf_svc::hal::prelude::Peripherals;
use esp_idf_svc::log::EspLogger;
use esp_idf_svc::modem::EspModem;
use esp_idf_svc::wifi::{BlockingWifi, EspWifi};
use esp_idf_svc::{eventloop::EspSystemEventLoop, nvs::EspDefaultNvsPartition};

use log::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.gpio16;
let mut serial = UartDriver::new(
serial,
tx,
rx,
Option::<gpio::Gpio0>::None,
Option::<gpio::Gpio0>::None,
&esp_idf_hal::uart::UartConfig {
baudrate: Hertz(115200),
..Default::default()
},
)?;
log::error!("Hello");
let mut modem = EspModem::new(&mut serial)?;

match modem.setup_data_mode() {
Err(x) => log::error!("Error: {:?}", x),
Ok(x) => (),
}

std::thread::sleep(core::time::Duration::from_secs(5));

Ok(())
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
259 changes: 259 additions & 0 deletions src/modem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
use at_commands::{builder::CommandBuilder, parser::CommandParser};
use atat::{self, AtatCmd};
use core::{borrow::BorrowMut, ffi::c_void, marker::PhantomData};
use esp_idf_hal::{delay::TickType, uart::UartDriver};

use crate::{
handle::RawHandle,
netif::{EspNetif, NetifStack},
sys::*,
};

pub struct PppNetif<'d, T>
where
T: BorrowMut<UartDriver<'d>>,
{
serial: T,
base: esp_netif_driver_base_t,
netif: EspNetif,
_d: PhantomData<&'d ()>,
}

impl<'d, T> PppNetif<'d, T>
where
T: BorrowMut<UartDriver<'d>>,
{
pub fn new(serial: T) -> Result<Self, EspError> {
let netif = EspNetif::new(NetifStack::Ppp)?;
let mut base = esp_netif_driver_base_t {
netif: netif.handle(),
post_attach: Some(Self::post_attach),
};
let base_ptr: *mut c_void = &mut base as *mut _ as *mut c_void;
esp!(unsafe { esp_netif_attach(netif.handle(), base_ptr) })?;
Ok(Self {
serial,
netif,
base,
_d: PhantomData,
})
}

unsafe extern "C" fn post_attach(netif: *mut esp_netif_obj, args: *mut c_void) -> i32 {
let driver= unsafe{std::ptr::slice_from_raw_parts_mut(args, size_of::<ppp_netif_driver())}
let ifconfig = esp_netif_driver_ifconfig_t{handle}
}
}

pub struct EspModem<'d, T>
where
T: BorrowMut<UartDriver<'d>>,
{
serial: T,

_d: PhantomData<&'d ()>,
}

impl<'d, T> EspModem<'d, T>
where
T: BorrowMut<UartDriver<'d>>,
{
pub fn new(serial: T) -> Self {
Self {
serial,
_d: PhantomData,
}
}

pub fn send_cmd<CMD: AtatCmd>(&mut self, cmd: &CMD) -> Result<CMD::Response, atat::Error> {
let mut buff = [0u8; 64];
// flush the channel
// self.serial
// .borrow_mut()
// .clear_rx()
// .map_err(|_err| atat::Error::Write)?;

// write the command to the uart
let len = cmd.write(&mut buff);
log::info!("about to write {:?}", &buff[..len]);
self.serial
.borrow_mut()
.write(&buff[..len])
.map_err(|_err| atat::Error::Write)?;

// now read the uart to get the response

let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())
.map_err(|_err| atat::Error::Read)?;
log::info!("got response {:?}", &buff[..len]);
cmd.parse(Ok(&buff[..len]))
}

pub fn setup_data_mode(&mut self) -> Result<(), EspError> {
self.reset()?;
//disable echo
self.set_echo(false)?;

// check pdp network reg
self.read_gprs_registration_status()?;

//configure apn
self.set_pdp_context()?;

// start ppp
self.set_data_mode()?;

// now in ppp mode.
// self.netif.

Ok(())
}

fn get_signal_quality(&mut self) -> Result<(), EspError> {
let mut buff = [0u8; 64];
let cmd = CommandBuilder::create_execute(&mut buff, true)
.named("+CSQ")
.finish()
.unwrap();
self.serial.borrow_mut().write(cmd)?;
let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())?;
log::info!("got response {:?}", &buff[..len]);

// \r\n+CSQ: 19,99\r\n\r\nOK\r\n
let (rssi, 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()
.unwrap();
log::info!("Signal Quality: rssi: {} ber: {}", rssi, ber);
Ok(())
}

fn reset(&mut self) -> Result<(), EspError> {
let mut buff = [0u8; 64];
let cmd = CommandBuilder::create_execute(&mut buff, false)
.named("ATZ0")
.finish()
.unwrap();
self.serial.borrow_mut().write(cmd)?;
let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())?;
log::info!("got response {:?}", &buff[..len]);
CommandParser::parse(&buff[..len])
.expect_identifier(b"ATZ0\r")
.expect_identifier(b"\r\nOK\r\n")
.finish()
.unwrap();
Ok(())
}

fn set_echo(&mut self, echo: bool) -> Result<(), EspError> {
let mut buff = [0u8; 64];
let cmd = CommandBuilder::create_execute(&mut buff, false)
.named(format!("ATE{}", i32::from(echo)))
.finish()
.unwrap();
self.serial.borrow_mut().write(cmd)?;
let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())?;
log::info!("got response {:?}", &buff[..len]);

CommandParser::parse(&buff[..len])
.expect_identifier(b"ATE0\r")
.expect_identifier(b"\r\nOK\r\n")
.finish()
.unwrap();
Ok(())
}

fn read_gprs_registration_status(&mut self) -> Result<(), EspError> {
let mut buff = [0u8; 64];
let cmd = CommandBuilder::create_query(&mut buff, true)
.named("+CGREG")
.finish()
.unwrap();
self.serial.borrow_mut().write(cmd)?;
let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())?;
log::info!("got response {:?}", &buff[..len]);

let (n, stat, lac, ci) = 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()
.unwrap();
log::info!(
"CGREG: n: {}stat: {}, lac: {:?}, ci: {:?} ",
n,
stat,
lac,
ci
);
Ok(())
}

fn set_pdp_context(&mut self) -> Result<(), EspError> {
let mut buff = [0u8; 64];
let cmd = CommandBuilder::create_set(&mut buff, true)
.named("+CGDCONT")
.with_int_parameter(1) // context id
.with_string_parameter("IP") // pdp type
.with_string_parameter("internet")
.finish()
.unwrap();
self.serial.borrow_mut().write(cmd)?;
let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())?;
log::info!("got response {:?}", &buff[..len]);

CommandParser::parse(&buff[..len])
.expect_identifier(b"\r\nOK\r\n")
.finish()
.unwrap();

Ok(())
}

fn set_data_mode(&mut self) -> Result<(), EspError> {
let mut buff = [0u8; 64];
let cmd = CommandBuilder::create_execute(&mut buff, false)
.named("ATD*99#")
.finish()
.unwrap();
self.serial.borrow_mut().write(cmd)?;
let len = self
.serial
.borrow_mut()
.read(&mut buff, TickType::new_millis(1000).ticks())?;
log::info!("got response {:?}", &buff[..len]);

let (connect_parm,) = CommandParser::parse(&buff[..len])
.expect_identifier(b"\r\nCONNECT ")
.expect_optional_raw_string()
.expect_identifier(b"\r\n")
.finish()
.unwrap();
log::info!("connect {:?}", connect_parm);
Ok(())
}
}

0 comments on commit 0a37e21

Please sign in to comment.