Skip to content

Commit 0a37e21

Browse files
author
DaneSlattery
committed
First attempt at binding, currently struggling
1 parent bf47d2b commit 0a37e21

File tree

6 files changed

+324
-0
lines changed

6 files changed

+324
-0
lines changed

.github/configs/sdkconfig.defaults

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ CONFIG_ETH_SPI_ETHERNET_DM9051=y
1717
CONFIG_ETH_SPI_ETHERNET_W5500=y
1818
CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL=y
1919

20+
# GSM
21+
CONFIG_LWIP_PPP_SUPPORT=y
22+
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=2048
23+
CONFIG_LWIP_PPP_ENABLE_IPV6=n
24+
25+
2026
# We don't have an example for classic BT - yet - we need to enable class BT
2127
# specifically to workaround this bug in ESP IDF v5.2 (fixed in ESP IDF v5.2.1+):
2228
# https://github.com/espressif/esp-idf/issues/13113

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
/target
55
/Cargo.lock
66
**/*.rs.bk
7+
/.devcontainer

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ embedded-svc = { version = "0.28", default-features = false }
5353
esp-idf-hal = { version = "0.44", default-features = false }
5454
embassy-time-driver = { version = "0.1", optional = true, features = ["tick-hz-1_000_000"] }
5555
embassy-futures = "0.1"
56+
atat = {version="0.23.0", default-features = false, features=["bytes","derive","heapless","serde_at"]}
57+
at-commands = "0.5.4"
5658

5759
[build-dependencies]
5860
embuild = "0.32"

examples/lte_modem.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! Example of using blocking wifi.
2+
//!
3+
//! Add your own ssid and password
4+
5+
use core::convert::TryInto;
6+
7+
use embedded_svc::wifi::{AuthMethod, ClientConfiguration, Configuration};
8+
9+
use esp_idf_hal::gpio;
10+
use esp_idf_hal::uart::UartDriver;
11+
use esp_idf_hal::units::Hertz;
12+
use esp_idf_svc::hal::prelude::Peripherals;
13+
use esp_idf_svc::log::EspLogger;
14+
use esp_idf_svc::modem::EspModem;
15+
use esp_idf_svc::wifi::{BlockingWifi, EspWifi};
16+
use esp_idf_svc::{eventloop::EspSystemEventLoop, nvs::EspDefaultNvsPartition};
17+
18+
use log::info;
19+
20+
// const SSID: &str = env!("WIFI_SSID");
21+
// const PASSWORD: &str = env!("WIFI_PASS");
22+
23+
fn main() -> anyhow::Result<()> {
24+
esp_idf_svc::sys::link_patches();
25+
EspLogger::initialize_default();
26+
27+
let peripherals = Peripherals::take()?;
28+
let sys_loop = EspSystemEventLoop::take()?;
29+
let nvs = EspDefaultNvsPartition::take()?;
30+
let serial = peripherals.uart2;
31+
let tx = peripherals.pins.gpio17;
32+
let rx = peripherals.pins.gpio16;
33+
let mut serial = UartDriver::new(
34+
serial,
35+
tx,
36+
rx,
37+
Option::<gpio::Gpio0>::None,
38+
Option::<gpio::Gpio0>::None,
39+
&esp_idf_hal::uart::UartConfig {
40+
baudrate: Hertz(115200),
41+
..Default::default()
42+
},
43+
)?;
44+
log::error!("Hello");
45+
let mut modem = EspModem::new(&mut serial)?;
46+
47+
match modem.setup_data_mode() {
48+
Err(x) => log::error!("Error: {:?}", x),
49+
Ok(x) => (),
50+
}
51+
52+
std::thread::sleep(core::time::Duration::from_secs(5));
53+
54+
Ok(())
55+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub mod mdns;
7878
esp_idf_comp_mqtt_enabled,
7979
esp_idf_comp_esp_event_enabled
8080
))]
81+
pub mod modem;
8182
pub mod mqtt;
8283
#[cfg(esp_idf_lwip_ipv4_napt)]
8384
pub mod napt;

src/modem.rs

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
use at_commands::{builder::CommandBuilder, parser::CommandParser};
2+
use atat::{self, AtatCmd};
3+
use core::{borrow::BorrowMut, ffi::c_void, marker::PhantomData};
4+
use esp_idf_hal::{delay::TickType, uart::UartDriver};
5+
6+
use crate::{
7+
handle::RawHandle,
8+
netif::{EspNetif, NetifStack},
9+
sys::*,
10+
};
11+
12+
pub struct PppNetif<'d, T>
13+
where
14+
T: BorrowMut<UartDriver<'d>>,
15+
{
16+
serial: T,
17+
base: esp_netif_driver_base_t,
18+
netif: EspNetif,
19+
_d: PhantomData<&'d ()>,
20+
}
21+
22+
impl<'d, T> PppNetif<'d, T>
23+
where
24+
T: BorrowMut<UartDriver<'d>>,
25+
{
26+
pub fn new(serial: T) -> Result<Self, EspError> {
27+
let netif = EspNetif::new(NetifStack::Ppp)?;
28+
let mut base = esp_netif_driver_base_t {
29+
netif: netif.handle(),
30+
post_attach: Some(Self::post_attach),
31+
};
32+
let base_ptr: *mut c_void = &mut base as *mut _ as *mut c_void;
33+
esp!(unsafe { esp_netif_attach(netif.handle(), base_ptr) })?;
34+
Ok(Self {
35+
serial,
36+
netif,
37+
base,
38+
_d: PhantomData,
39+
})
40+
}
41+
42+
unsafe extern "C" fn post_attach(netif: *mut esp_netif_obj, args: *mut c_void) -> i32 {
43+
let driver= unsafe{std::ptr::slice_from_raw_parts_mut(args, size_of::<ppp_netif_driver())}
44+
let ifconfig = esp_netif_driver_ifconfig_t{handle}
45+
}
46+
}
47+
48+
pub struct EspModem<'d, T>
49+
where
50+
T: BorrowMut<UartDriver<'d>>,
51+
{
52+
serial: T,
53+
54+
_d: PhantomData<&'d ()>,
55+
}
56+
57+
impl<'d, T> EspModem<'d, T>
58+
where
59+
T: BorrowMut<UartDriver<'d>>,
60+
{
61+
pub fn new(serial: T) -> Self {
62+
Self {
63+
serial,
64+
_d: PhantomData,
65+
}
66+
}
67+
68+
pub fn send_cmd<CMD: AtatCmd>(&mut self, cmd: &CMD) -> Result<CMD::Response, atat::Error> {
69+
let mut buff = [0u8; 64];
70+
// flush the channel
71+
// self.serial
72+
// .borrow_mut()
73+
// .clear_rx()
74+
// .map_err(|_err| atat::Error::Write)?;
75+
76+
// write the command to the uart
77+
let len = cmd.write(&mut buff);
78+
log::info!("about to write {:?}", &buff[..len]);
79+
self.serial
80+
.borrow_mut()
81+
.write(&buff[..len])
82+
.map_err(|_err| atat::Error::Write)?;
83+
84+
// now read the uart to get the response
85+
86+
let len = self
87+
.serial
88+
.borrow_mut()
89+
.read(&mut buff, TickType::new_millis(1000).ticks())
90+
.map_err(|_err| atat::Error::Read)?;
91+
log::info!("got response {:?}", &buff[..len]);
92+
cmd.parse(Ok(&buff[..len]))
93+
}
94+
95+
pub fn setup_data_mode(&mut self) -> Result<(), EspError> {
96+
self.reset()?;
97+
//disable echo
98+
self.set_echo(false)?;
99+
100+
// check pdp network reg
101+
self.read_gprs_registration_status()?;
102+
103+
//configure apn
104+
self.set_pdp_context()?;
105+
106+
// start ppp
107+
self.set_data_mode()?;
108+
109+
// now in ppp mode.
110+
// self.netif.
111+
112+
Ok(())
113+
}
114+
115+
fn get_signal_quality(&mut self) -> Result<(), EspError> {
116+
let mut buff = [0u8; 64];
117+
let cmd = CommandBuilder::create_execute(&mut buff, true)
118+
.named("+CSQ")
119+
.finish()
120+
.unwrap();
121+
self.serial.borrow_mut().write(cmd)?;
122+
let len = self
123+
.serial
124+
.borrow_mut()
125+
.read(&mut buff, TickType::new_millis(1000).ticks())?;
126+
log::info!("got response {:?}", &buff[..len]);
127+
128+
// \r\n+CSQ: 19,99\r\n\r\nOK\r\n
129+
let (rssi, ber) = CommandParser::parse(&buff[..len])
130+
.expect_identifier(b"\r\n+CSQ: ")
131+
.expect_int_parameter()
132+
.expect_int_parameter()
133+
.expect_identifier(b"\r\n\r\nOK\r\n")
134+
.finish()
135+
.unwrap();
136+
log::info!("Signal Quality: rssi: {} ber: {}", rssi, ber);
137+
Ok(())
138+
}
139+
140+
fn reset(&mut self) -> Result<(), EspError> {
141+
let mut buff = [0u8; 64];
142+
let cmd = CommandBuilder::create_execute(&mut buff, false)
143+
.named("ATZ0")
144+
.finish()
145+
.unwrap();
146+
self.serial.borrow_mut().write(cmd)?;
147+
let len = self
148+
.serial
149+
.borrow_mut()
150+
.read(&mut buff, TickType::new_millis(1000).ticks())?;
151+
log::info!("got response {:?}", &buff[..len]);
152+
CommandParser::parse(&buff[..len])
153+
.expect_identifier(b"ATZ0\r")
154+
.expect_identifier(b"\r\nOK\r\n")
155+
.finish()
156+
.unwrap();
157+
Ok(())
158+
}
159+
160+
fn set_echo(&mut self, echo: bool) -> Result<(), EspError> {
161+
let mut buff = [0u8; 64];
162+
let cmd = CommandBuilder::create_execute(&mut buff, false)
163+
.named(format!("ATE{}", i32::from(echo)))
164+
.finish()
165+
.unwrap();
166+
self.serial.borrow_mut().write(cmd)?;
167+
let len = self
168+
.serial
169+
.borrow_mut()
170+
.read(&mut buff, TickType::new_millis(1000).ticks())?;
171+
log::info!("got response {:?}", &buff[..len]);
172+
173+
CommandParser::parse(&buff[..len])
174+
.expect_identifier(b"ATE0\r")
175+
.expect_identifier(b"\r\nOK\r\n")
176+
.finish()
177+
.unwrap();
178+
Ok(())
179+
}
180+
181+
fn read_gprs_registration_status(&mut self) -> Result<(), EspError> {
182+
let mut buff = [0u8; 64];
183+
let cmd = CommandBuilder::create_query(&mut buff, true)
184+
.named("+CGREG")
185+
.finish()
186+
.unwrap();
187+
self.serial.borrow_mut().write(cmd)?;
188+
let len = self
189+
.serial
190+
.borrow_mut()
191+
.read(&mut buff, TickType::new_millis(1000).ticks())?;
192+
log::info!("got response {:?}", &buff[..len]);
193+
194+
let (n, stat, lac, ci) = CommandParser::parse(&buff[..len])
195+
.expect_identifier(b"\r\n+CGREG: ")
196+
.expect_int_parameter()
197+
.expect_int_parameter()
198+
.expect_optional_int_parameter()
199+
.expect_optional_int_parameter()
200+
.expect_identifier(b"\r\n\r\nOK\r\n")
201+
.finish()
202+
.unwrap();
203+
log::info!(
204+
"CGREG: n: {}stat: {}, lac: {:?}, ci: {:?} ",
205+
n,
206+
stat,
207+
lac,
208+
ci
209+
);
210+
Ok(())
211+
}
212+
213+
fn set_pdp_context(&mut self) -> Result<(), EspError> {
214+
let mut buff = [0u8; 64];
215+
let cmd = CommandBuilder::create_set(&mut buff, true)
216+
.named("+CGDCONT")
217+
.with_int_parameter(1) // context id
218+
.with_string_parameter("IP") // pdp type
219+
.with_string_parameter("internet")
220+
.finish()
221+
.unwrap();
222+
self.serial.borrow_mut().write(cmd)?;
223+
let len = self
224+
.serial
225+
.borrow_mut()
226+
.read(&mut buff, TickType::new_millis(1000).ticks())?;
227+
log::info!("got response {:?}", &buff[..len]);
228+
229+
CommandParser::parse(&buff[..len])
230+
.expect_identifier(b"\r\nOK\r\n")
231+
.finish()
232+
.unwrap();
233+
234+
Ok(())
235+
}
236+
237+
fn set_data_mode(&mut self) -> Result<(), EspError> {
238+
let mut buff = [0u8; 64];
239+
let cmd = CommandBuilder::create_execute(&mut buff, false)
240+
.named("ATD*99#")
241+
.finish()
242+
.unwrap();
243+
self.serial.borrow_mut().write(cmd)?;
244+
let len = self
245+
.serial
246+
.borrow_mut()
247+
.read(&mut buff, TickType::new_millis(1000).ticks())?;
248+
log::info!("got response {:?}", &buff[..len]);
249+
250+
let (connect_parm,) = CommandParser::parse(&buff[..len])
251+
.expect_identifier(b"\r\nCONNECT ")
252+
.expect_optional_raw_string()
253+
.expect_identifier(b"\r\n")
254+
.finish()
255+
.unwrap();
256+
log::info!("connect {:?}", connect_parm);
257+
Ok(())
258+
}
259+
}

0 commit comments

Comments
 (0)