From 7a22f14e1f211e54929a963cb7fa1589402c198c Mon Sep 17 00:00:00 2001 From: Vladan Popovic Date: Mon, 20 Feb 2023 16:35:54 +0100 Subject: [PATCH] move code around to make the modem restartable --- src/main.rs | 67 ++++++++++++++++++++------ src/modem.rs | 131 +++++++++++++++++---------------------------------- 2 files changed, 95 insertions(+), 103 deletions(-) diff --git a/src/main.rs b/src/main.rs index 948a843..dd62fb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,10 @@ mod gps; use anyhow; use std::{thread::{self, JoinHandle}, time::Duration}; use esp_idf_hal::peripherals::Peripherals; +use esp_idf_hal::prelude::*; +use esp_idf_hal::serial::{Pins, config::Config, Serial, UART1, Uart}; +use embedded_hal::digital::v2::OutputPin; + use types::*; fn main() -> anyhow::Result<()> { @@ -19,6 +23,27 @@ fn main() -> anyhow::Result<()> { println!("Rust main thread: {:?}", thread::current()); + let mut threads: Vec>> = vec![]; + + // // Rx/Tx pins for the GPS modem + let gps_rx = dp.pins.gpio32; + let gps_tx = dp.pins.gpio33; + // // UART interface for the GPS modem + let gps_uart = dp.uart2; + + + let (gps_sender, receiver) = std::sync::mpsc::sync_channel::(10); + //let accel_sender = gps_sender.clone(); + + //let _ = gps::main(gps_tx, gps_rx, gps_uart, gps_sender)?; + threads.push(thread::spawn(move || gps::main(gps_tx, gps_rx, gps_uart, gps_sender))); + thread::sleep(Duration::from_millis(1000)); + //threads.push(thread::spawn(move || accel::main(accel_sender))); + + // ================================== + // MODEM INITIALIZATION AND MAIN LOOP + // ================================== + // LilyGo TTGO T-Call sim800l board serial pins. let modem_rx = dp.pins.gpio26; let modem_tx = dp.pins.gpio27; @@ -29,24 +54,36 @@ fn main() -> anyhow::Result<()> { // UART interface for the GSM modem let modem_uart = dp.uart1; - let mut threads: Vec>> = vec![]; + let serial_pins = Pins { + tx: modem_tx, + rx: modem_rx, + cts: None, + rts: None, + }; - // // Rx/Tx pins for the GPS modem - let gps_rx = dp.pins.gpio32; - let gps_tx = dp.pins.gpio33; - // // UART interface for the GPS modem - let gps_uart = dp.uart2; + let serial: Serial = Serial::new( + modem_uart, + serial_pins, + Config::default().baudrate(Hertz(115200)), + )?; + let (tx, rx) = serial.split(); + type PwrkeyOutput = esp_idf_hal::gpio::Gpio4; + type ResetOutput = esp_idf_hal::gpio::Gpio5; + type PowerOutput = esp_idf_hal::gpio::Gpio23; - let (gps_sender, receiver) = std::sync::mpsc::sync_channel::(1); - //let accel_sender = gps_sender.clone(); + let mut mdm: modem::Modem = modem::Modem::new(tx, rx, modem_pwrkey, modem_rst, modem_power, receiver); - //let _ = gps::main(gps_tx, gps_rx, gps_uart, gps_sender)?; - threads.push(thread::spawn(move || gps::main(gps_tx, gps_rx, gps_uart, gps_sender))); - thread::sleep(Duration::from_millis(1000)); - //threads.push(thread::spawn(move || accel::main(accel_sender))); + let mqtt_username = include_str!("../secret/username").trim(); + let mqtt_password = include_str!("../secret/password").trim(); - let _ = modem::main(modem_rx, modem_tx, modem_uart, modem_pwrkey, modem_rst, modem_power, receiver)?; - - Ok(()) + loop { + println!("======================= MAIN ======================="); + mdm.init().unwrap_or(()); + let _ = mdm.echo(false).unwrap_or(()); + println!("resetting modem ... "); + println!("======================= MODEM ======================="); + let _ = mdm.start_sending(mqtt_username, mqtt_password).unwrap_or(()); + thread::sleep(Duration::from_millis(1500)); + } } diff --git a/src/modem.rs b/src/modem.rs index 4b3b3ce..c040bf3 100644 --- a/src/modem.rs +++ b/src/modem.rs @@ -13,7 +13,6 @@ use std::{ sync::mpsc::Receiver, }; -use esp_idf_hal::prelude::*; use esp_idf_hal::serial::{self, Rx, Tx}; use embedded_hal::digital::v2::OutputPin; @@ -33,10 +32,6 @@ use serde_json_core; pub type Result = std::result::Result; -pub struct Modem { - serial: SerialIO, -} - #[derive(Debug)] pub enum ModemError { CommandError(String), @@ -54,10 +49,22 @@ impl std::fmt::Display for ModemError { } } -impl Modem { - pub fn new(tx: Tx, rx: Rx) -> Self { +pub struct Modem { + serial: SerialIO, + reset: RST, + power: PW, + power_key: PWK, + receiver: Receiver, +} + +impl Modem { + pub fn new(tx: Tx, rx: Rx, mut pwrkey: PWK, mut rst: RST, mut power: PW, receiver: Receiver) -> Self { Self { serial: SerialIO::new(tx, rx), + reset: rst, + power, + power_key: pwrkey, + receiver, } } @@ -76,22 +83,23 @@ impl Modem { /// /// modem::init(modem_pwrkey, modem_rst, modem_power); /// ``` - pub fn init(&mut self, mut pwrkey: impl OutputPin, mut rst: impl OutputPin, mut power: impl OutputPin) -> Result<()> { + pub fn init(&mut self) -> Result<()> { println!("Turning SIM800L on ..."); - power.set_high().map_err(|_| ModemError::SetupError("Error setting POWER to high.".to_string()))?; - rst.set_high().map_err(|_| ModemError::SetupError("Error setting RST to high.".to_string()))?; + self.power.set_high().map_err(|_| ModemError::SetupError("Error setting POWER to high.".to_string()))?; + self.reset.set_high().map_err(|_| ModemError::SetupError("Error setting RST to high.".to_string()))?; // Pull down PWRKEY for more than 1 second according to manual requirements - pwrkey.set_high().map_err(|_| ModemError::SetupError("Error setting PWRKEY to high.".to_string()))?; + self.power_key.set_high().map_err(|_| ModemError::SetupError("Error setting PWRKEY to high.".to_string()))?; thread::sleep(Duration::from_millis(1500)); - pwrkey.set_low().map_err(|_| ModemError::SetupError("Error setting PWRKEY to low.".to_string()))?; + self.power_key.set_low().map_err(|_| ModemError::SetupError("Error setting PWRKEY to low.".to_string()))?; thread::sleep(Duration::from_millis(1000)); - pwrkey.set_high().map_err(|_| ModemError::SetupError("Error setting PWRKEY to high.".to_string()))?; + self.power_key.set_high().map_err(|_| ModemError::SetupError("Error setting PWRKEY to high.".to_string()))?; println!("Waiting for sim module to come online ..."); thread::sleep(Duration::from_millis(3000)); for _ in 0..10 { let _ = self.send_command(Command::probe()).unwrap_or("".to_string()); thread::sleep(Duration::from_millis(1000)); } + self.serial.clear(); Ok(()) } @@ -142,6 +150,7 @@ impl Modem { } fn send(&mut self, at_command: &str, contains: &str) -> Result { + self.serial.clear(); println!("-----------------------------------------------------------"); println!("Sending {} ...", at_command); @@ -303,8 +312,8 @@ impl Modem { } pub fn tcp_manual_send(&mut self, buf: &[u8]) -> Result<()> { - thread::sleep(Duration::from_millis(200)); - self.serial.clear(); + thread::sleep(Duration::from_millis(200)); + // self.serial.clear(); self.tcp_manual_send_data(buf) .map(|_| ()) } @@ -360,8 +369,8 @@ impl Modem { } } - pub fn tcp_close_connection(&mut self) -> Result { - self.send_command(Command::tcp_close()) + pub fn tcp_close_connection(&mut self) -> Result<()> { + self.send_command(Command::tcp_close()).map(|_| ()) } pub fn http_post(&mut self, url: &str, token: &str, content: &[u8]) -> Result { @@ -506,96 +515,43 @@ impl Modem { self.tcp_manual_send(&mut buf)?; Ok(()) } -} -impl std::io::Read for Modem { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self.tcp_receive(buf).map_err(|_| std::io::Error::from(std::io::ErrorKind::ConnectionAborted)) - } -} - -pub fn main -( - rx: PRx, - tx: PTx, - uart: serial::UART1, - pwrkey: DPK, - rst: DR, - power: DP, - receiver: Receiver, -) -> std::result::Result<(), anyhow::Error> -where - PRx: esp_idf_hal::gpio::Pin + esp_idf_hal::gpio::InputPin + esp_idf_hal::gpio::OutputPin, - PTx: esp_idf_hal::gpio::Pin + esp_idf_hal::gpio::InputPin + esp_idf_hal::gpio::OutputPin, - DPK: embedded_hal::digital::v2::OutputPin, - DR: embedded_hal::digital::v2::OutputPin, - DP: embedded_hal::digital::v2::OutputPin, -{ - let serial_pins = serial::Pins { - tx, - rx, - cts: None, - rts: None, - }; - - let serial: serial::Serial = serial::Serial::new( - uart, - serial_pins, - serial::config::Config::default().baudrate(Hertz(115200)), - )?; - - let (tx, rx) = serial.split(); - let mut mdm = Modem::new(tx, rx); - - let mqtt_username = include_str!("../secret/username").trim(); - let mqtt_password = include_str!("../secret/password").trim(); - - // thread::sleep(Duration::from_millis(500)); - - //println!("setting up client TLS cert"); - //let client_cert = include_bytes!("../certs/full-bin.p12"); - //let client_cert_path = "C:\\USER\\fullchain.pem"; - - //let _ = mdm.upload_cert(client_cert_path, client_cert)?; - //let _ = mdm.ssl_set_client_cert(client_cert_path, "t")?; - //let _ = mdm.fs_list("C:\\USER\\")?; - - fn start_sending(mdm: &mut Modem, mqtt_username: &str, mqtt_password: &str, receiver: Receiver) -> anyhow::Result<()> { - if !mdm.is_gprs_attached()? { - let _ = mdm.gprs_attach_ap(crate::config::MTS)?; - let _ = mdm.try_connect_gprs()?; + pub fn start_sending(&mut self, mqtt_username: &str, mqtt_password: &str) -> anyhow::Result<()> { + if !self.is_gprs_attached()? { + let _ = self.gprs_attach_ap(crate::config::MTS)?; + let _ = self.try_connect_gprs()?; } // When command AT+CIPQSEND=0, it is in normal sending mode. In this mode, after user // sends data by AT+CIPSEND, if the server receives TCP data, it will give ACK message // to module, and the module will respond SEND OK. - let _ = mdm.send("AT+CIPQSEND=0", "OK"); + let _ = self.send("AT+CIPQSEND=0", "OK"); // Enables getting data from network manually. - let _ = mdm.send("AT+CIPRXGET=1", "OK"); + let _ = self.send("AT+CIPRXGET=1", "OK"); for _ in 0..5 { - if let Ok(_) = mdm.tcp_connect("51.158.66.64", 7887) { + if let Ok(_) = self.tcp_connect("51.158.66.64", 7887) { break } } let device_id = "c36a72df-5bd6-4f9b-995d-059433bc3267"; println!("connecting to MQTT with ({}:{})", mqtt_username, mqtt_password); - let _ = mdm.mqtt_connect(device_id, mqtt_username, mqtt_password)?; + let _ = self.mqtt_connect(device_id, mqtt_username, mqtt_password)?; println!("entering queue receive loop ..."); let mut err_count = 0; let _ = loop { - match receiver.recv() { + match self.receiver.recv() { Ok(Msg::Gps(solution)) => { println!("received GPS solution {:?} | sending to mqtt ...", solution); serde_json_core::ser::to_string::(&solution) .map_err(|e| anyhow::Error::new(e)) - .and_then(|sol| mdm.mqtt_publish(device_id, &sol))?; + .and_then(|sol| self.mqtt_publish(device_id, &sol))?; err_count = 0; }, Ok(Msg::Accelerometer(acc)) => { println!("received accel {} | sending to mqtt ...", acc); - let _ = mdm.mqtt_publish(device_id, &format!("{:?}", acc))?; + let _ = self.mqtt_publish(device_id, &format!("{:?}", acc))?; err_count = 0; } Err(e) => { @@ -612,11 +568,10 @@ where Ok(()) } - - mdm.init(pwrkey, rst, power)?; - let _ = mdm.echo(false)?; - let _ = start_sending(&mut mdm, mqtt_username, mqtt_password, receiver)?; - let _ = mdm.tcp_close_connection()?; - - Ok(()) +} + +impl std::io::Read for Modem { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.tcp_receive(buf).map_err(|_| std::io::Error::from(std::io::ErrorKind::ConnectionAborted)) + } }