use std; use std::io::{Read, Write}; pub struct Modem { is_connected: bool, rx: R, tx: W, } pub enum ModemError { GprsAPConnectionError(String), ATCommandError(String), CommandError(String), } impl std::fmt::Display for ModemError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::GprsAPConnectionError(msg) => write!(f, "gprs connection error {}", msg), Self::ATCommandError(msg) => write!(f, "AT command error {}", msg), Self::CommandError(msg) => write!(f, "Modem command error {}", msg), } } } pub type Result = std::result::Result; impl Modem { pub fn new(rx: R, tx: W) -> Self { Self { is_connected: false, rx, tx, } } fn at_command(&mut self, cmd: &str) -> Result { let mut msg = "AT+".to_owned(); msg.push_str(cmd); self.send_command(msg.to_owned()) .map_err(|err| ModemError::ATCommandError(format!("{}", err))) } fn send_command(&mut self, cmd: String) -> Result { self.tx.write(cmd.as_bytes()) .map_err(|err| ModemError::CommandError(format!("{}", err)))?; let mut response = String::new(); self.rx.read_to_string(&mut response) .map_err(|err| ModemError::CommandError(format!("{}", err)))?; if cfg!(debug_assertions) { println!("{} = {}", cmd, response); } Ok(response) } pub fn connect_to_gprs_ap(&mut self, apn: &str, username: &str, password: &str)-> Result<()> { self.at_command("CGATTCGATT=1") .map(|_| { println!("connecting to {} with {}:{}", apn, username, password); self.is_connected = true; }) .map_err(|err| ModemError::GprsAPConnectionError(format!("{}", err))) } }