1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
//! # AT Sockets for nrfxlib //! //! AT socket related code. AT commands are sent to the modem down a socket //! using the Nordic-specific `SOCK_PROTO_AT`. //! //! Copyright (c) 42 Technology Ltd 2019 //! //! Dual-licensed under MIT and Apache 2.0. See the [README](../README.md) for //! more details. //****************************************************************************** // Sub-Modules //****************************************************************************** // None //****************************************************************************** // Imports //****************************************************************************** use crate::{raw::*, AtError, Error}; //****************************************************************************** // Types //****************************************************************************** /// Represents a connection to the modem using AT Commands. #[derive(Debug)] pub struct AtSocket(Socket); //****************************************************************************** // Constants //****************************************************************************** // None //****************************************************************************** // Global Variables //****************************************************************************** // None //****************************************************************************** // Macros //****************************************************************************** // None //****************************************************************************** // Public Functions and Impl on Public Types //****************************************************************************** impl AtSocket { /// Create a new AT socket. pub fn new() -> Result<AtSocket, Error> { let skt = Socket::new(SocketDomain::Lte, SocketType::Datagram, SocketProtocol::At)?; Ok(AtSocket(skt)) } /// Send an AT command to the modem pub fn send_command(&self, command: &str) -> Result<(), Error> { self.0.write(command.as_bytes()).map(|_count| ()) } /// Read from the AT socket until we get something that indicates the command has completed. /// /// Commands are completed by `OK`, `ERROR`, `+CME ERROR:xxx` or `+CMS /// ERROR:xxx`. These are mapped to a Rust `Result` type. /// /// Any other data received is deemed to be a command result and passed to the given fn `callback_function`. pub fn poll_response<F>(&mut self, mut callback_function: F) -> Result<(), Error> where F: FnMut(&str), { let result; 'outer: loop { let mut buf = [0u8; 256]; let length = 'inner: loop { match self.recv(&mut buf)? { None => { // EAGAIN } Some(n) => break 'inner n, }; }; let s = unsafe { core::str::from_utf8_unchecked(&buf[0..length - 1]) }; for line in s.lines() { let line = line.trim(); match line { "OK" => { result = Ok(()); break 'outer; } "ERROR" => { result = Err(Error::AtError(AtError::Error)); break 'outer; } err if err.starts_with("+CME ERROR:") => { let num_str = &err[11..]; let value = num_str.trim().parse().unwrap_or(-1); result = Err(Error::AtError(AtError::CmeError(value))); break 'outer; } err if err.starts_with("+CMS ERROR:") => { let num_str = &err[11..]; let value = num_str.trim().parse().unwrap_or(-1); result = Err(Error::AtError(AtError::CmsError(value))); break 'outer; } data => { callback_function(data); } } } } result } } impl Pollable for AtSocket { /// Get the underlying socket ID for this socket. fn get_fd(&self) -> i32 { self.0.fd } } impl core::ops::DerefMut for AtSocket { fn deref_mut(&mut self) -> &mut Socket { &mut self.0 } } impl core::ops::Deref for AtSocket { type Target = Socket; fn deref(&self) -> &Socket { &self.0 } } /// Sends an AT command to the modem and calls the given closure with any /// indications received. Indications have any whitespace or newlines trimmed. /// /// Creates and destroys a new NRF_AF_LTE/NRF_PROTO_AT socket. Will block /// until we get 'OK' or some sort of error response from the modem. pub fn send_at_command<F>(command: &str, function: F) -> Result<(), Error> where F: FnMut(&str), { let mut skt = AtSocket::new()?; skt.send_command(command)?; skt.poll_response(function) } //****************************************************************************** // Private Functions and Impl on Private Types //****************************************************************************** // None //****************************************************************************** // End of File //******************************************************************************