USB Host Library for Sprint Dongles

Dependencies:   Socket USBHostWANDongleSprint lwip-sys lwip

Dependents:   SprintUSBModemWebsocketTest SprintUSBModemHTTPClientTest SprintUSBModemNTPClientTest SprintUSBModemSMSTest ... more

Fork of SprintUSBModem_bleedingedge by Donatien Garnier

Committer:
donatien
Date:
Mon Dec 10 18:23:49 2012 +0000
Revision:
14:f6f17843e5ef
Parent:
10:35496211da8f
Separate USB/Sprint dev flows, fix regression in mbed rev. 41+ lib

Who changed what in which revision?

UserRevisionLine numberNew contents of line
donatien 0:8f57713b2147 1 /* ATCommandsInterface.cpp */
donatien 0:8f57713b2147 2 /* Copyright (C) 2012 mbed.org, MIT License
donatien 0:8f57713b2147 3 *
donatien 0:8f57713b2147 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
donatien 0:8f57713b2147 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
donatien 0:8f57713b2147 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
donatien 0:8f57713b2147 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
donatien 0:8f57713b2147 8 * furnished to do so, subject to the following conditions:
donatien 0:8f57713b2147 9 *
donatien 0:8f57713b2147 10 * The above copyright notice and this permission notice shall be included in all copies or
donatien 0:8f57713b2147 11 * substantial portions of the Software.
donatien 0:8f57713b2147 12 *
donatien 0:8f57713b2147 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
donatien 0:8f57713b2147 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
donatien 0:8f57713b2147 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
donatien 0:8f57713b2147 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
donatien 0:8f57713b2147 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
donatien 0:8f57713b2147 18 */
donatien 0:8f57713b2147 19
donatien 10:35496211da8f 20 #define __DEBUG__ 2 //ERR+WARN
donatien 0:8f57713b2147 21 #ifndef __MODULE__
donatien 0:8f57713b2147 22 #define __MODULE__ "ATCommandsInterface.cpp"
donatien 0:8f57713b2147 23 #endif
donatien 0:8f57713b2147 24
donatien 0:8f57713b2147 25 #include "core/fwk.h"
donatien 0:8f57713b2147 26
donatien 0:8f57713b2147 27 #include <cstdio>
donatien 0:8f57713b2147 28 //#include <cstring> //For memset, strstr...
donatien 0:8f57713b2147 29
donatien 0:8f57713b2147 30 using std::memmove;
donatien 0:8f57713b2147 31
donatien 0:8f57713b2147 32 #include "ATCommandsInterface.h"
donatien 0:8f57713b2147 33
donatien 0:8f57713b2147 34 ATCommandsInterface::ATCommandsInterface(IOStream* pStream) :
donatien 0:8f57713b2147 35 m_pStream(pStream), m_open(false), m_env2AT(), m_AT2Env(), m_processingMtx(),
donatien 0:8f57713b2147 36 m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192),
donatien 10:35496211da8f 37 m_eventsMgmtMtx(), m_eventsProcessingMtx()
donatien 0:8f57713b2147 38 {
donatien 0:8f57713b2147 39 memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*));
donatien 0:8f57713b2147 40
donatien 0:8f57713b2147 41 m_processingMtx.lock();
donatien 0:8f57713b2147 42 }
donatien 0:8f57713b2147 43
donatien 0:8f57713b2147 44 //Open connection to AT Interface in order to execute command & register/unregister events
donatien 0:8f57713b2147 45 int ATCommandsInterface::open()
donatien 0:8f57713b2147 46 {
donatien 0:8f57713b2147 47 if( m_open )
donatien 0:8f57713b2147 48 {
donatien 0:8f57713b2147 49 WARN("AT interface is already open");
donatien 0:8f57713b2147 50 return OK;
donatien 0:8f57713b2147 51 }
donatien 0:8f57713b2147 52 DBG("Opening AT interface");
donatien 0:8f57713b2147 53 //Start processing
donatien 0:8f57713b2147 54 m_processingThread.signal_set(AT_SIG_PROCESSING_START);
donatien 0:8f57713b2147 55
donatien 0:8f57713b2147 56 m_processingMtx.unlock();
donatien 0:8f57713b2147 57
donatien 0:8f57713b2147 58 m_open = true;
donatien 0:8f57713b2147 59
donatien 0:8f57713b2147 60 DBG("AT interface opened");
donatien 10:35496211da8f 61
donatien 0:8f57713b2147 62 return OK;
donatien 0:8f57713b2147 63 }
donatien 0:8f57713b2147 64
donatien 10:35496211da8f 65 //Initialize AT link & start events processing
donatien 0:8f57713b2147 66 int ATCommandsInterface::init()
donatien 0:8f57713b2147 67 {
donatien 0:8f57713b2147 68 DBG("Sending ATZ E1 V1");
donatien 10:35496211da8f 69
donatien 10:35496211da8f 70 //Lock transaction mutex
donatien 10:35496211da8f 71 m_transactionMtx.lock();
donatien 10:35496211da8f 72
donatien 0:8f57713b2147 73 //Should we flush m_pStream at this point ???
donatien 0:8f57713b2147 74 int err;
donatien 0:8f57713b2147 75 int tries = 5;
donatien 0:8f57713b2147 76 do
donatien 0:8f57713b2147 77 {
donatien 10:35496211da8f 78 err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
donatien 0:8f57713b2147 79 if(err && tries)
donatien 0:8f57713b2147 80 {
donatien 0:8f57713b2147 81 WARN("No response, trying again");
donatien 0:8f57713b2147 82 Thread::wait(1000); //Give dongle time to recover
donatien 0:8f57713b2147 83 }
donatien 0:8f57713b2147 84 } while(err && tries--);
donatien 0:8f57713b2147 85 if( err )
donatien 0:8f57713b2147 86 {
donatien 0:8f57713b2147 87 ERR("Sending ATZ E1 V1 returned with err code %d", err);
donatien 10:35496211da8f 88 m_transactionMtx.unlock();
donatien 0:8f57713b2147 89 return err;
donatien 0:8f57713b2147 90 }
donatien 10:35496211da8f 91
donatien 10:35496211da8f 92 //Enable events handling and execute events enabling commands
donatien 10:35496211da8f 93 enableEvents();
donatien 0:8f57713b2147 94
donatien 0:8f57713b2147 95 DBG("AT interface initialized");
donatien 10:35496211da8f 96
donatien 10:35496211da8f 97 //Unlock transaction mutex
donatien 10:35496211da8f 98 m_transactionMtx.unlock();
donatien 0:8f57713b2147 99
donatien 0:8f57713b2147 100 return OK;
donatien 0:8f57713b2147 101 }
donatien 0:8f57713b2147 102
donatien 0:8f57713b2147 103 //Close connection
donatien 0:8f57713b2147 104 int ATCommandsInterface::close()
donatien 0:8f57713b2147 105 {
donatien 0:8f57713b2147 106 if( !m_open )
donatien 0:8f57713b2147 107 {
donatien 0:8f57713b2147 108 WARN("AT interface is already closed");
donatien 0:8f57713b2147 109 return OK;
donatien 0:8f57713b2147 110 }
donatien 0:8f57713b2147 111
donatien 0:8f57713b2147 112 DBG("Closing AT interface");
donatien 0:8f57713b2147 113
donatien 0:8f57713b2147 114 //Stop processing
donatien 0:8f57713b2147 115 m_processingThread.signal_set(AT_SIG_PROCESSING_STOP);
donatien 0:8f57713b2147 116 //m_stopSphre.release();
donatien 0:8f57713b2147 117
donatien 0:8f57713b2147 118 int* msg = m_env2AT.alloc(osWaitForever);
donatien 0:8f57713b2147 119 *msg = AT_STOP;
donatien 0:8f57713b2147 120 m_env2AT.put(msg); //Used to unstall the process if needed
donatien 0:8f57713b2147 121
donatien 0:8f57713b2147 122 //Unlock process routine (abort read)
donatien 0:8f57713b2147 123 m_pStream->abortRead(); //This is thread-safe
donatien 0:8f57713b2147 124 m_processingMtx.lock();
donatien 0:8f57713b2147 125 m_open = false;
donatien 0:8f57713b2147 126
donatien 10:35496211da8f 127 //Disable events handling and advertize this to the events handlers
donatien 10:35496211da8f 128 disableEvents();
donatien 0:8f57713b2147 129
donatien 0:8f57713b2147 130 DBG("AT interface closed");
donatien 0:8f57713b2147 131 return OK;
donatien 0:8f57713b2147 132 }
donatien 0:8f57713b2147 133
donatien 0:8f57713b2147 134 bool ATCommandsInterface::isOpen()
donatien 0:8f57713b2147 135 {
donatien 0:8f57713b2147 136 return m_open;
donatien 0:8f57713b2147 137 }
donatien 0:8f57713b2147 138
donatien 0:8f57713b2147 139 int ATCommandsInterface::executeSimple(const char* command, ATResult* pResult, uint32_t timeout/*=1000*/)
donatien 0:8f57713b2147 140 {
donatien 0:8f57713b2147 141 return execute(command, this, pResult, timeout);
donatien 0:8f57713b2147 142 }
donatien 0:8f57713b2147 143
donatien 0:8f57713b2147 144 int ATCommandsInterface::execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
donatien 0:8f57713b2147 145 {
donatien 0:8f57713b2147 146 if(!m_open)
donatien 0:8f57713b2147 147 {
donatien 0:8f57713b2147 148 WARN("Interface is not open!");
donatien 0:8f57713b2147 149 return NET_INVALID;
donatien 0:8f57713b2147 150 }
donatien 0:8f57713b2147 151
donatien 0:8f57713b2147 152 //Lock transaction mutex
donatien 0:8f57713b2147 153 m_transactionMtx.lock();
donatien 10:35496211da8f 154
donatien 10:35496211da8f 155 disableEvents(); //Disable unsollicited result codes
donatien 10:35496211da8f 156 int ret = executeInternal(command, pProcessor, pResult, timeout);
donatien 10:35496211da8f 157 enableEvents(); //Re-enable unsollicited result codes whatever the result of the command is
donatien 10:35496211da8f 158
donatien 10:35496211da8f 159 //Unlock transaction mutex
donatien 10:35496211da8f 160 m_transactionMtx.unlock();
donatien 10:35496211da8f 161
donatien 10:35496211da8f 162 return ret;
donatien 10:35496211da8f 163 }
donatien 10:35496211da8f 164
donatien 10:35496211da8f 165 int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr)
donatien 10:35496211da8f 166 {
donatien 10:35496211da8f 167 m_eventsMgmtMtx.lock();
donatien 10:35496211da8f 168 m_eventsProcessingMtx.lock();
donatien 10:35496211da8f 169 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
donatien 10:35496211da8f 170 {
donatien 10:35496211da8f 171 if( m_eventsHandlers[i] == NULL )
donatien 10:35496211da8f 172 {
donatien 10:35496211da8f 173 m_eventsHandlers[i] = pHdlr;
donatien 10:35496211da8f 174 m_eventsProcessingMtx.unlock();
donatien 10:35496211da8f 175 m_eventsMgmtMtx.unlock();
donatien 10:35496211da8f 176 return OK;
donatien 10:35496211da8f 177 }
donatien 10:35496211da8f 178 }
donatien 10:35496211da8f 179 m_eventsProcessingMtx.unlock();
donatien 10:35496211da8f 180 m_eventsMgmtMtx.unlock();
donatien 10:35496211da8f 181 return NET_OOM; //No room left
donatien 10:35496211da8f 182 }
donatien 10:35496211da8f 183
donatien 10:35496211da8f 184 int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr)
donatien 10:35496211da8f 185 {
donatien 10:35496211da8f 186 m_eventsMgmtMtx.lock();
donatien 10:35496211da8f 187 m_eventsProcessingMtx.lock();
donatien 10:35496211da8f 188 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find handler in list
donatien 10:35496211da8f 189 {
donatien 10:35496211da8f 190 if( m_eventsHandlers[i] == pHdlr )
donatien 10:35496211da8f 191 {
donatien 10:35496211da8f 192 m_eventsHandlers[i] = NULL;
donatien 10:35496211da8f 193 m_eventsProcessingMtx.unlock();
donatien 10:35496211da8f 194 m_eventsMgmtMtx.unlock();
donatien 10:35496211da8f 195 return OK;
donatien 10:35496211da8f 196 }
donatien 10:35496211da8f 197 }
donatien 10:35496211da8f 198 m_eventsProcessingMtx.unlock();
donatien 10:35496211da8f 199 m_eventsMgmtMtx.unlock();
donatien 10:35496211da8f 200 return NET_NOTFOUND; //Not found
donatien 10:35496211da8f 201 }
donatien 10:35496211da8f 202
donatien 10:35496211da8f 203 //Private methods
donatien 10:35496211da8f 204
donatien 10:35496211da8f 205 int ATCommandsInterface::executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
donatien 10:35496211da8f 206 {
donatien 10:35496211da8f 207 DBG("Executing command %s", command);
donatien 0:8f57713b2147 208
donatien 0:8f57713b2147 209 //Discard previous result if it arrived too late
donatien 0:8f57713b2147 210 osEvent evt = m_AT2Env.get(0);
donatien 0:8f57713b2147 211
donatien 0:8f57713b2147 212 if(evt.status == osEventMail)
donatien 0:8f57713b2147 213 {
donatien 0:8f57713b2147 214 m_AT2Env.free((int*)evt.value.p);
donatien 0:8f57713b2147 215 WARN("Previous result discarded");
donatien 0:8f57713b2147 216 }
donatien 0:8f57713b2147 217
donatien 0:8f57713b2147 218 //Send params to the process routine
donatien 0:8f57713b2147 219 m_transactionCommand = command;
donatien 0:8f57713b2147 220 if(pProcessor != NULL)
donatien 0:8f57713b2147 221 {
donatien 0:8f57713b2147 222 m_pTransactionProcessor = pProcessor;
donatien 0:8f57713b2147 223 }
donatien 0:8f57713b2147 224 else
donatien 0:8f57713b2147 225 {
donatien 0:8f57713b2147 226 m_pTransactionProcessor = this; //Use default behaviour
donatien 0:8f57713b2147 227 }
donatien 0:8f57713b2147 228
donatien 0:8f57713b2147 229 DBG("Sending command ready signal to AT thread & aborting current blocking read operation");
donatien 0:8f57713b2147 230
donatien 0:8f57713b2147 231 //Produce command ready signal
donatien 0:8f57713b2147 232 int* msg = m_env2AT.alloc(osWaitForever);
donatien 0:8f57713b2147 233 *msg = AT_CMD_READY;
donatien 0:8f57713b2147 234 m_env2AT.put(msg);
donatien 0:8f57713b2147 235
donatien 0:8f57713b2147 236 DBG("Trying to enter abortRead()");
donatien 0:8f57713b2147 237 //Unlock process routine (abort read)
donatien 0:8f57713b2147 238 m_pStream->abortRead(); //This is thread-safe
donatien 0:8f57713b2147 239
donatien 0:8f57713b2147 240 //Wait for a result (get result message)
donatien 0:8f57713b2147 241 evt = m_AT2Env.get(timeout);
donatien 0:8f57713b2147 242
donatien 0:8f57713b2147 243 if(evt.status != osEventMail)
donatien 0:8f57713b2147 244 {
donatien 0:8f57713b2147 245 //Cancel request
donatien 0:8f57713b2147 246 msg = m_env2AT.alloc(osWaitForever);
donatien 0:8f57713b2147 247 *msg = AT_TIMEOUT;
donatien 0:8f57713b2147 248 m_env2AT.put(msg);
donatien 0:8f57713b2147 249
donatien 0:8f57713b2147 250 DBG("Trying to enter abortRead()");
donatien 0:8f57713b2147 251 //Unlock process routine (abort read)
donatien 0:8f57713b2147 252 m_pStream->abortRead(); //This is thread-safe
donatien 0:8f57713b2147 253
donatien 0:8f57713b2147 254 WARN("Command returned no message");
donatien 0:8f57713b2147 255 return NET_TIMEOUT;
donatien 0:8f57713b2147 256 }
donatien 0:8f57713b2147 257 DBG("Command returned with message %d", *msg);
donatien 0:8f57713b2147 258
donatien 0:8f57713b2147 259 m_AT2Env.free((int*)evt.value.p);
donatien 0:8f57713b2147 260
donatien 0:8f57713b2147 261 if(pResult != NULL)
donatien 0:8f57713b2147 262 {
donatien 0:8f57713b2147 263 *pResult = m_transactionResult;
donatien 0:8f57713b2147 264 }
donatien 0:8f57713b2147 265
donatien 0:8f57713b2147 266 int ret = ATResultToReturnCode(m_transactionResult);
donatien 0:8f57713b2147 267 if(ret != OK)
donatien 0:8f57713b2147 268 {
donatien 0:8f57713b2147 269 WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code);
donatien 0:8f57713b2147 270 }
donatien 0:8f57713b2147 271
donatien 0:8f57713b2147 272 DBG("Command returned successfully");
donatien 0:8f57713b2147 273
donatien 0:8f57713b2147 274 return ret;
donatien 0:8f57713b2147 275 }
donatien 0:8f57713b2147 276
donatien 0:8f57713b2147 277 int ATCommandsInterface::tryReadLine()
donatien 0:8f57713b2147 278 {
donatien 0:8f57713b2147 279 static bool lineDetected = false;
donatien 0:8f57713b2147 280
donatien 0:8f57713b2147 281 //Block on serial read or incoming command
donatien 0:8f57713b2147 282 DBG("Trying to read a new line from stream");
donatien 0:8f57713b2147 283 int ret = m_pStream->waitAvailable(); //This can be aborted
donatien 0:8f57713b2147 284 size_t readLen = 0;
donatien 0:8f57713b2147 285 if(ret == OK)
donatien 0:8f57713b2147 286 {
donatien 0:8f57713b2147 287 ret = m_pStream->read((uint8_t*)m_inputBuf + m_inputPos, &readLen, AT_INPUT_BUF_SIZE - 1 - m_inputPos, 0); //Do NOT wait at this point
donatien 0:8f57713b2147 288 }
donatien 0:8f57713b2147 289 if(ret == OK)
donatien 0:8f57713b2147 290 {
donatien 0:8f57713b2147 291 m_inputPos+=readLen;
donatien 0:8f57713b2147 292 m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions
donatien 0:8f57713b2147 293 DBG("In buffer: [%s]", m_inputBuf);
donatien 0:8f57713b2147 294 }
donatien 0:8f57713b2147 295
donatien 0:8f57713b2147 296 if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted
donatien 0:8f57713b2147 297 {
donatien 0:8f57713b2147 298 DBG("Read was interrupted");
donatien 0:8f57713b2147 299 return NET_INTERRUPTED; //0 chars were read
donatien 0:8f57713b2147 300 }
donatien 0:8f57713b2147 301 else if(readLen == 0)
donatien 0:8f57713b2147 302 {
donatien 0:8f57713b2147 303 DBG("Nothing read");
donatien 0:8f57713b2147 304 return OK; //0 chars were read
donatien 0:8f57713b2147 305 }
donatien 0:8f57713b2147 306
donatien 0:8f57713b2147 307 DBG("Trying to process incoming line");
donatien 0:8f57713b2147 308 bool lineProcessed = false;
donatien 0:8f57713b2147 309
donatien 0:8f57713b2147 310 do
donatien 0:8f57713b2147 311 {
donatien 0:8f57713b2147 312 lineProcessed = false; //Reset flag
donatien 0:8f57713b2147 313
donatien 0:8f57713b2147 314 DBG("New iteration");
donatien 0:8f57713b2147 315
donatien 0:8f57713b2147 316 //Look for a new line
donatien 0:8f57713b2147 317 if(!lineDetected)
donatien 0:8f57713b2147 318 {
donatien 0:8f57713b2147 319 DBG("No line detected yet");
donatien 0:8f57713b2147 320 //Try to look for a starting CRLF
donatien 0:8f57713b2147 321 char* crPtr = strchr(m_inputBuf, CR);
donatien 0:8f57713b2147 322 /*
donatien 0:8f57713b2147 323 Different cases at this point:
donatien 0:8f57713b2147 324 - CRLF%c sequence: this is the start of a line
donatien 0:8f57713b2147 325 - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one)
donatien 0:8f57713b2147 326 - LF: this is the trailing LF char of the previous line, discard
donatien 0:8f57713b2147 327 - CR / CRLF incomplete sequence: more data is needed to determine which action to take
donatien 0:8f57713b2147 328 - %c ... CR sequence: this should be the echo of the previous sequence
donatien 0:8f57713b2147 329 - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take
donatien 0:8f57713b2147 330
donatien 0:8f57713b2147 331 In every case, move mem at the beginning
donatien 0:8f57713b2147 332 */
donatien 0:8f57713b2147 333 if(crPtr != NULL)
donatien 0:8f57713b2147 334 {
donatien 0:8f57713b2147 335 DBG("CR char found");
donatien 0:8f57713b2147 336
donatien 0:8f57713b2147 337 #if 0
donatien 0:8f57713b2147 338 //Discard all preceding characters (can do nothing if m_inputBuf == crPtr)
donatien 0:8f57713b2147 339 memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well
donatien 0:8f57713b2147 340 m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos
donatien 0:8f57713b2147 341 #endif
donatien 0:8f57713b2147 342
donatien 0:8f57713b2147 343 //If the line starts with CR, this should be a result code
donatien 0:8f57713b2147 344 if( crPtr == m_inputBuf )
donatien 0:8f57713b2147 345 {
donatien 0:8f57713b2147 346 //To determine the sequence we need at least 3 chars
donatien 0:8f57713b2147 347 if(m_inputPos >= 3)
donatien 0:8f57713b2147 348 {
donatien 0:8f57713b2147 349 //Look for a LF char next to the CR char
donatien 0:8f57713b2147 350 if(m_inputBuf[1] == LF)
donatien 0:8f57713b2147 351 {
donatien 0:8f57713b2147 352 //At this point we can check whether this is the end of a preceding line or the beginning of a new one
donatien 0:8f57713b2147 353 if(m_inputBuf[2] != CR)
donatien 0:8f57713b2147 354 {
donatien 0:8f57713b2147 355 DBG("Beginning of new line found");
donatien 0:8f57713b2147 356 //Beginning of a line
donatien 0:8f57713b2147 357 lineDetected = true; //Move to next state-machine step
donatien 0:8f57713b2147 358 }
donatien 0:8f57713b2147 359 else
donatien 0:8f57713b2147 360 {
donatien 0:8f57713b2147 361 //End of an unprocessed line
donatien 0:8f57713b2147 362 WARN("End of unprocessed line");
donatien 0:8f57713b2147 363 }
donatien 0:8f57713b2147 364 //In both cases discard CRLF
donatien 0:8f57713b2147 365 DBG("Discarding CRLF");
donatien 0:8f57713b2147 366 memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well
donatien 0:8f57713b2147 367 m_inputPos = m_inputPos - 2; //Adjust m_inputPos
donatien 0:8f57713b2147 368 }
donatien 0:8f57713b2147 369 else
donatien 0:8f57713b2147 370 {
donatien 0:8f57713b2147 371 //This is completely unexpected, discard the CR char to try to recover good state
donatien 0:8f57713b2147 372 WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]);
donatien 0:8f57713b2147 373 memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
donatien 0:8f57713b2147 374 m_inputPos = m_inputPos - 1; //Adjust m_inputPos
donatien 0:8f57713b2147 375 }
donatien 0:8f57713b2147 376 }
donatien 0:8f57713b2147 377 }
donatien 0:8f57713b2147 378 //if the line does NOT begin with CR, this can be an echo of the previous command, process it
donatien 0:8f57713b2147 379 else
donatien 0:8f57713b2147 380 {
donatien 0:8f57713b2147 381 int crPos = crPtr - m_inputBuf;
donatien 0:8f57713b2147 382 int lfOff = 0; //Offset for LF if present
donatien 0:8f57713b2147 383 DBG("New line found (possible echo of command)");
donatien 0:8f57713b2147 384 //This is the end of line
donatien 0:8f57713b2147 385 //Replace m_inputBuf[crPos] with null-terminating char
donatien 0:8f57713b2147 386 m_inputBuf[crPos] = '\0';
donatien 0:8f57713b2147 387 //Check if there is a LF char afterwards
donatien 0:8f57713b2147 388 if(m_inputPos - crPos >= 1)
donatien 0:8f57713b2147 389 {
donatien 0:8f57713b2147 390 if(m_inputBuf[crPos+1] == LF)
donatien 0:8f57713b2147 391 {
donatien 0:8f57713b2147 392 lfOff++; //We will discard LF char as well
donatien 0:8f57713b2147 393 }
donatien 0:8f57713b2147 394 }
donatien 0:8f57713b2147 395 //Process line
donatien 4:23100b0757d6 396 int ret = processReadLine();
donatien 4:23100b0757d6 397 if(ret)
donatien 4:23100b0757d6 398 {
donatien 4:23100b0757d6 399 m_inputPos = 0;
donatien 4:23100b0757d6 400 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 4:23100b0757d6 401 lineDetected = false;
donatien 4:23100b0757d6 402 return ret;
donatien 4:23100b0757d6 403 }
donatien 4:23100b0757d6 404
donatien 4:23100b0757d6 405 //If sendData has been called, all incoming data has been discarded
donatien 4:23100b0757d6 406 if(m_inputPos > 0)
donatien 4:23100b0757d6 407 {
donatien 4:23100b0757d6 408 memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well
donatien 4:23100b0757d6 409 m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos
donatien 4:23100b0757d6 410 }
donatien 0:8f57713b2147 411 DBG("One line was successfully processed");
donatien 0:8f57713b2147 412 lineProcessed = true; //Line was processed with success
donatien 0:8f57713b2147 413 lineDetected = false; //Search now for a new line
donatien 0:8f57713b2147 414 }
donatien 0:8f57713b2147 415 }
donatien 0:8f57713b2147 416 else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it
donatien 0:8f57713b2147 417 {
donatien 0:8f57713b2147 418 DBG("Discarding single LF char");
donatien 0:8f57713b2147 419 memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
donatien 0:8f57713b2147 420 m_inputPos = m_inputPos - 1; //Adjust m_inputPos
donatien 0:8f57713b2147 421 }
donatien 0:8f57713b2147 422 }
donatien 0:8f57713b2147 423
donatien 0:8f57713b2147 424 //Look for the end of line
donatien 0:8f57713b2147 425 if(lineDetected)
donatien 0:8f57713b2147 426 {
donatien 0:8f57713b2147 427 DBG("Looking for end of line");
donatien 0:8f57713b2147 428 //Try to look for a terminating CRLF
donatien 0:8f57713b2147 429 char* crPtr = strchr(m_inputBuf, CR);
donatien 0:8f57713b2147 430 /*
donatien 0:8f57713b2147 431 Different cases at this point:
donatien 0:8f57713b2147 432 - CRLF sequence: this is the end of the line
donatien 0:8f57713b2147 433 - CR%c sequence : unexpected
donatien 0:8f57713b2147 434 - CR incomplete sequence: more data is needed to determine which action to take
donatien 0:8f57713b2147 435 */
donatien 0:8f57713b2147 436
donatien 0:8f57713b2147 437 //Try to look for a '>' (greater than character) that marks an entry prompt
donatien 0:8f57713b2147 438 char* greaterThanPtr = strchr(m_inputBuf, GD);
donatien 0:8f57713b2147 439 /*
donatien 0:8f57713b2147 440 This character must be detected as there is no CRLF sequence at the end of an entry prompt
donatien 0:8f57713b2147 441 */
donatien 0:8f57713b2147 442
donatien 0:8f57713b2147 443 if(crPtr != NULL)
donatien 0:8f57713b2147 444 {
donatien 0:8f57713b2147 445 DBG("CR char found");
donatien 0:8f57713b2147 446 int crPos = crPtr - m_inputBuf;
donatien 0:8f57713b2147 447 //To determine the sequence we need at least 2 chars
donatien 0:8f57713b2147 448 if(m_inputPos - crPos >= 2)
donatien 0:8f57713b2147 449 {
donatien 0:8f57713b2147 450 //Look for a LF char next to the CR char
donatien 0:8f57713b2147 451 if(m_inputBuf[crPos + 1] == LF)
donatien 0:8f57713b2147 452 {
donatien 0:8f57713b2147 453 DBG("End of new line found");
donatien 0:8f57713b2147 454 //This is the end of line
donatien 0:8f57713b2147 455 //Replace m_inputBuf[crPos] with null-terminating char
donatien 0:8f57713b2147 456 m_inputBuf[crPos] = '\0';
donatien 0:8f57713b2147 457 //Process line
donatien 0:8f57713b2147 458 int ret = processReadLine();
donatien 0:8f57713b2147 459 if(ret)
donatien 0:8f57713b2147 460 {
donatien 0:8f57713b2147 461 m_inputPos = 0;
donatien 4:23100b0757d6 462 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 0:8f57713b2147 463 lineDetected = false;
donatien 0:8f57713b2147 464 return ret;
donatien 0:8f57713b2147 465 }
donatien 0:8f57713b2147 466
donatien 0:8f57713b2147 467 //If sendData has been called, all incoming data has been discarded
donatien 0:8f57713b2147 468 if(m_inputPos > 0)
donatien 0:8f57713b2147 469 {
donatien 0:8f57713b2147 470 //Shift remaining data to beginning of buffer
donatien 0:8f57713b2147 471 memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well
donatien 0:8f57713b2147 472 m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos
donatien 0:8f57713b2147 473 }
donatien 0:8f57713b2147 474
donatien 0:8f57713b2147 475 DBG("One line was successfully processed");
donatien 0:8f57713b2147 476 lineProcessed = true; //Line was processed with success
donatien 0:8f57713b2147 477 }
donatien 0:8f57713b2147 478 else
donatien 0:8f57713b2147 479 {
donatien 0:8f57713b2147 480 //This is completely unexpected, discard all chars till the CR char to try to recover good state
donatien 0:8f57713b2147 481 WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]);
donatien 0:8f57713b2147 482 memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well
donatien 0:8f57713b2147 483 m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos
donatien 0:8f57713b2147 484 }
donatien 0:8f57713b2147 485 lineDetected = false; //In both case search now for a new line
donatien 0:8f57713b2147 486 }
donatien 0:8f57713b2147 487 }
donatien 0:8f57713b2147 488 else if(greaterThanPtr != NULL)
donatien 0:8f57713b2147 489 {
donatien 0:8f57713b2147 490 DBG("> char found");
donatien 0:8f57713b2147 491 int gdPos = greaterThanPtr - m_inputBuf;
donatien 0:8f57713b2147 492 //To determine the sequence we need at least 2 chars
donatien 0:8f57713b2147 493 if(m_inputPos - gdPos >= 2)
donatien 0:8f57713b2147 494 {
donatien 0:8f57713b2147 495 //Look for a space char next to the GD char
donatien 0:8f57713b2147 496 if(m_inputBuf[gdPos + 1] == ' ')
donatien 0:8f57713b2147 497 {
donatien 0:8f57713b2147 498 //This is an entry prompt
donatien 0:8f57713b2147 499 //Replace m_inputBuf[gdPos] with null-terminating char
donatien 0:8f57713b2147 500 m_inputBuf[gdPos] = '\0';
donatien 0:8f57713b2147 501
donatien 0:8f57713b2147 502 //Shift remaining data to beginning of buffer
donatien 0:8f57713b2147 503 memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
donatien 0:8f57713b2147 504 m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
donatien 0:8f57713b2147 505
donatien 0:8f57713b2147 506 //Process prompt
donatien 0:8f57713b2147 507 ret = processEntryPrompt();
donatien 0:8f57713b2147 508 if(ret)
donatien 0:8f57713b2147 509 {
donatien 0:8f57713b2147 510 m_inputPos = 0;
donatien 4:23100b0757d6 511 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 0:8f57713b2147 512 lineDetected = false;
donatien 0:8f57713b2147 513 return ret;
donatien 0:8f57713b2147 514 }
donatien 0:8f57713b2147 515
donatien 0:8f57713b2147 516 DBG("One line was successfully processed");
donatien 0:8f57713b2147 517 lineProcessed = true; //Line was processed with success
donatien 0:8f57713b2147 518 }
donatien 0:8f57713b2147 519 else
donatien 0:8f57713b2147 520 {
donatien 0:8f57713b2147 521 //This is completely unexpected, discard all chars till the GD char to try to recover good state
donatien 0:8f57713b2147 522 WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]);
donatien 0:8f57713b2147 523 memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
donatien 0:8f57713b2147 524 m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
donatien 0:8f57713b2147 525 }
donatien 0:8f57713b2147 526 lineDetected = false; //In both case search now for a new line
donatien 0:8f57713b2147 527 }
donatien 0:8f57713b2147 528 }
donatien 0:8f57713b2147 529 }
donatien 0:8f57713b2147 530 } while(lineProcessed); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again
donatien 0:8f57713b2147 531
donatien 0:8f57713b2147 532 //If the line could not be processed AND buffer is full, it means that we won't ever be able to process it (buffer too short)
donatien 0:8f57713b2147 533 if(m_inputPos == AT_INPUT_BUF_SIZE - 1)
donatien 0:8f57713b2147 534 {
donatien 0:8f57713b2147 535 //Discard everything
donatien 0:8f57713b2147 536 m_inputPos = 0;
donatien 4:23100b0757d6 537 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 0:8f57713b2147 538 WARN("Incoming buffer is too short to process incoming line");
donatien 0:8f57713b2147 539 //Look for a new line
donatien 0:8f57713b2147 540 lineDetected = false;
donatien 0:8f57713b2147 541 }
donatien 0:8f57713b2147 542
donatien 0:8f57713b2147 543 DBG("Processed every full incoming lines");
donatien 0:8f57713b2147 544
donatien 0:8f57713b2147 545 return OK;
donatien 0:8f57713b2147 546 }
donatien 0:8f57713b2147 547
donatien 0:8f57713b2147 548 int ATCommandsInterface::trySendCommand()
donatien 0:8f57713b2147 549 {
donatien 0:8f57713b2147 550 osEvent evt = m_env2AT.get(0);
donatien 0:8f57713b2147 551 DBG("status = %d, msg = %d", evt.status, evt.value.p);
donatien 0:8f57713b2147 552 if(evt.status == osEventMail)
donatien 0:8f57713b2147 553 {
donatien 0:8f57713b2147 554 int* msg = (int*) evt.value.p;
donatien 0:8f57713b2147 555 if( *msg == AT_CMD_READY ) //Command pending
donatien 0:8f57713b2147 556 {
donatien 0:8f57713b2147 557 if(m_transactionState != IDLE)
donatien 0:8f57713b2147 558 {
donatien 0:8f57713b2147 559 WARN("Previous command not processed!");
donatien 0:8f57713b2147 560 }
donatien 0:8f57713b2147 561 DBG("Sending pending command");
donatien 0:8f57713b2147 562 m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever);
donatien 0:8f57713b2147 563 char cr = CR;
donatien 0:8f57713b2147 564 m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator
donatien 0:8f57713b2147 565 m_transactionState = COMMAND_SENT;
donatien 0:8f57713b2147 566 }
donatien 0:8f57713b2147 567 else
donatien 0:8f57713b2147 568 {
donatien 0:8f57713b2147 569 m_transactionState = IDLE; //State-machine reset
donatien 0:8f57713b2147 570 }
donatien 0:8f57713b2147 571 m_env2AT.free(msg);
donatien 0:8f57713b2147 572 }
donatien 0:8f57713b2147 573 return OK;
donatien 0:8f57713b2147 574 }
donatien 0:8f57713b2147 575
donatien 0:8f57713b2147 576 int ATCommandsInterface::processReadLine()
donatien 0:8f57713b2147 577 {
donatien 0:8f57713b2147 578 DBG("Processing read line [%s]", m_inputBuf);
donatien 0:8f57713b2147 579 //The line is stored in m_inputBuf
donatien 0:8f57713b2147 580 if(m_transactionState == COMMAND_SENT)
donatien 0:8f57713b2147 581 {
donatien 0:8f57713b2147 582 //If the command has been sent, checks echo to see if it has been received properly
donatien 0:8f57713b2147 583 if( strcmp(m_transactionCommand, m_inputBuf) == 0 )
donatien 0:8f57713b2147 584 {
donatien 0:8f57713b2147 585 DBG("Command echo received");
donatien 0:8f57713b2147 586 //If so, it means that the following lines will only be solicited results
donatien 0:8f57713b2147 587 m_transactionState = READING_RESULT;
donatien 0:8f57713b2147 588 return OK;
donatien 0:8f57713b2147 589 }
donatien 0:8f57713b2147 590 }
donatien 0:8f57713b2147 591 if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT)
donatien 0:8f57713b2147 592 {
donatien 0:8f57713b2147 593 bool found = false;
donatien 0:8f57713b2147 594 char* pSemicol = strchr(m_inputBuf, ':');
donatien 0:8f57713b2147 595 char* pData = NULL;
donatien 0:8f57713b2147 596 if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
donatien 0:8f57713b2147 597 {
donatien 0:8f57713b2147 598 *pSemicol = '\0';
donatien 0:8f57713b2147 599 pData = pSemicol + 1;
donatien 0:8f57713b2147 600 if(pData[0]==' ')
donatien 0:8f57713b2147 601 {
donatien 0:8f57713b2147 602 pData++; //Suppress whitespace
donatien 0:8f57713b2147 603 }
donatien 0:8f57713b2147 604 }
donatien 0:8f57713b2147 605 //Looks for a unsolicited result code; we can have m_transactionState == COMMAND_SENT as the code may have arrived just before we sent the command
donatien 10:35496211da8f 606 m_eventsProcessingMtx.lock();
donatien 0:8f57713b2147 607 //Go through the list
donatien 0:8f57713b2147 608 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
donatien 0:8f57713b2147 609 {
donatien 0:8f57713b2147 610 if( m_eventsHandlers[i] != NULL )
donatien 0:8f57713b2147 611 {
donatien 0:8f57713b2147 612 if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) )
donatien 0:8f57713b2147 613 {
donatien 0:8f57713b2147 614 m_eventsHandlers[i]->onEvent(m_inputBuf, pData);
donatien 0:8f57713b2147 615 found = true; //Do not break here as there might be multiple handlers for one event type
donatien 0:8f57713b2147 616 }
donatien 0:8f57713b2147 617 }
donatien 0:8f57713b2147 618 }
donatien 10:35496211da8f 619 m_eventsProcessingMtx.unlock();
donatien 0:8f57713b2147 620 if(found)
donatien 0:8f57713b2147 621 {
donatien 0:8f57713b2147 622 return OK;
donatien 0:8f57713b2147 623 }
donatien 0:8f57713b2147 624 }
donatien 0:8f57713b2147 625 if(m_transactionState == READING_RESULT)
donatien 0:8f57713b2147 626 {
donatien 0:8f57713b2147 627 //The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s)
donatien 0:8f57713b2147 628 if(strcmp("OK", m_inputBuf) == 0)
donatien 0:8f57713b2147 629 {
donatien 0:8f57713b2147 630 DBG("OK result received");
donatien 0:8f57713b2147 631 m_transactionResult.code = 0;
donatien 0:8f57713b2147 632 m_transactionResult.result = ATResult::AT_OK;
donatien 0:8f57713b2147 633 m_transactionState = IDLE;
donatien 0:8f57713b2147 634 int* msg = m_AT2Env.alloc(osWaitForever);
donatien 0:8f57713b2147 635 *msg = AT_RESULT_READY;
donatien 0:8f57713b2147 636 m_AT2Env.put(msg); //Command has been processed
donatien 0:8f57713b2147 637 return OK;
donatien 0:8f57713b2147 638 }
donatien 0:8f57713b2147 639 else if(strcmp("ERROR", m_inputBuf) == 0)
donatien 0:8f57713b2147 640 {
donatien 0:8f57713b2147 641 DBG("ERROR result received");
donatien 0:8f57713b2147 642 m_transactionResult.code = 0;
donatien 0:8f57713b2147 643 m_transactionResult.result = ATResult::AT_ERROR;
donatien 0:8f57713b2147 644 m_transactionState = IDLE;
donatien 0:8f57713b2147 645 int* msg = m_AT2Env.alloc(osWaitForever);
donatien 0:8f57713b2147 646 *msg = AT_RESULT_READY;
donatien 0:8f57713b2147 647 m_AT2Env.put(msg); //Command has been processed
donatien 0:8f57713b2147 648 return OK;
donatien 0:8f57713b2147 649 }
donatien 0:8f57713b2147 650 else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate
donatien 0:8f57713b2147 651 {
donatien 0:8f57713b2147 652 DBG("CONNECT result received");
donatien 0:8f57713b2147 653 m_transactionResult.code = 0;
donatien 0:8f57713b2147 654 m_transactionResult.result = ATResult::AT_CONNECT;
donatien 0:8f57713b2147 655 m_transactionState = IDLE;
donatien 0:8f57713b2147 656 int* msg = m_AT2Env.alloc(osWaitForever);
donatien 0:8f57713b2147 657 *msg = AT_RESULT_READY;
donatien 0:8f57713b2147 658 m_AT2Env.put(msg); //Command has been processed
donatien 0:8f57713b2147 659 return OK;
donatien 0:8f57713b2147 660 }
donatien 0:8f57713b2147 661 else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized
donatien 0:8f57713b2147 662 {
donatien 0:8f57713b2147 663 DBG("COMMAND NOT SUPPORT result received");
donatien 0:8f57713b2147 664 m_transactionResult.code = 0;
donatien 0:8f57713b2147 665 m_transactionResult.result = ATResult::AT_ERROR;
donatien 0:8f57713b2147 666 m_transactionState = IDLE;
donatien 0:8f57713b2147 667 int* msg = m_AT2Env.alloc(osWaitForever);
donatien 0:8f57713b2147 668 *msg = AT_RESULT_READY;
donatien 0:8f57713b2147 669 m_AT2Env.put(msg); //Command has been processed
donatien 0:8f57713b2147 670 return OK;
donatien 0:8f57713b2147 671 }
donatien 0:8f57713b2147 672 else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error
donatien 0:8f57713b2147 673 {
donatien 0:8f57713b2147 674 std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
donatien 0:8f57713b2147 675 DBG("+CME ERROR: %d result received", m_transactionResult.code);
donatien 0:8f57713b2147 676 m_transactionResult.result = ATResult::AT_CME_ERROR;
donatien 0:8f57713b2147 677 m_transactionState = IDLE;
donatien 0:8f57713b2147 678 int* msg = m_AT2Env.alloc(osWaitForever);
donatien 0:8f57713b2147 679 *msg = AT_RESULT_READY;
donatien 0:8f57713b2147 680 m_AT2Env.put(msg); //Command has been processed
donatien 0:8f57713b2147 681 return OK;
donatien 0:8f57713b2147 682 }
donatien 0:8f57713b2147 683 else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error
donatien 0:8f57713b2147 684 {
donatien 0:8f57713b2147 685 std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
donatien 0:8f57713b2147 686 DBG("+CMS ERROR: %d result received", m_transactionResult.code);
donatien 0:8f57713b2147 687 m_transactionResult.result = ATResult::AT_CMS_ERROR;
donatien 0:8f57713b2147 688 m_transactionState = IDLE;
donatien 0:8f57713b2147 689 int* msg = m_AT2Env.alloc(osWaitForever);
donatien 0:8f57713b2147 690 *msg = AT_RESULT_READY;
donatien 0:8f57713b2147 691 m_AT2Env.put(msg); //Command has been processed
donatien 0:8f57713b2147 692 return OK;
donatien 0:8f57713b2147 693 }
donatien 0:8f57713b2147 694 else
donatien 0:8f57713b2147 695 {
donatien 0:8f57713b2147 696 DBG("Unprocessed result received: '%s'", m_inputBuf);
donatien 0:8f57713b2147 697 //Must call transaction processor to complete line processing
donatien 0:8f57713b2147 698 int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called
donatien 0:8f57713b2147 699 return ret;
donatien 0:8f57713b2147 700 }
donatien 0:8f57713b2147 701 }
donatien 0:8f57713b2147 702
donatien 0:8f57713b2147 703 return OK;
donatien 0:8f57713b2147 704 }
donatien 0:8f57713b2147 705
donatien 0:8f57713b2147 706 int ATCommandsInterface::processEntryPrompt()
donatien 0:8f57713b2147 707 {
donatien 0:8f57713b2147 708 DBG("Calling prompt handler");
donatien 0:8f57713b2147 709 int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called
donatien 0:8f57713b2147 710
donatien 0:8f57713b2147 711 if( ret != NET_MOREINFO ) //A new prompt is expected
donatien 0:8f57713b2147 712 {
donatien 0:8f57713b2147 713 DBG("Sending break character");
donatien 0:8f57713b2147 714 //Send CTRL+Z (break sequence) to exit prompt
donatien 0:8f57713b2147 715 char seq[2] = {BRK, 0x00};
donatien 0:8f57713b2147 716 sendData(seq);
donatien 0:8f57713b2147 717 }
donatien 0:8f57713b2147 718 return OK;
donatien 0:8f57713b2147 719 }
donatien 0:8f57713b2147 720
donatien 10:35496211da8f 721 //This will be called on initialization & after the execution of a command
donatien 10:35496211da8f 722 void ATCommandsInterface::enableEvents()
donatien 10:35496211da8f 723 {
donatien 10:35496211da8f 724 //Advertize this to events handlers
donatien 10:35496211da8f 725 m_eventsMgmtMtx.lock();
donatien 10:35496211da8f 726 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
donatien 10:35496211da8f 727 {
donatien 10:35496211da8f 728 if( m_eventsHandlers[i] != NULL )
donatien 10:35496211da8f 729 {
donatien 10:35496211da8f 730 m_eventsHandlers[i]->onDispatchStart();
donatien 10:35496211da8f 731 //Enable this kind of events
donatien 10:35496211da8f 732 if(m_eventsHandlers[i]->getEventsEnableCommand() != NULL)
donatien 10:35496211da8f 733 {
donatien 10:35496211da8f 734 int ret = executeInternal(m_eventsHandlers[i]->getEventsEnableCommand(), this, NULL); //Execute enable command
donatien 10:35496211da8f 735 if(ret)
donatien 10:35496211da8f 736 {
donatien 10:35496211da8f 737 WARN("Events enabling command failed");
donatien 10:35496211da8f 738 }
donatien 10:35496211da8f 739 }
donatien 10:35496211da8f 740 }
donatien 10:35496211da8f 741 }
donatien 10:35496211da8f 742 m_eventsMgmtMtx.unlock();
donatien 10:35496211da8f 743 }
donatien 10:35496211da8f 744
donatien 10:35496211da8f 745 //This will be called on de-initialization & before the execution of a command to prevent unsollicited result codes from polluting the results
donatien 10:35496211da8f 746 void ATCommandsInterface::disableEvents()
donatien 10:35496211da8f 747 {
donatien 10:35496211da8f 748 //Advertize this to events handlers
donatien 10:35496211da8f 749 m_eventsMgmtMtx.lock();
donatien 10:35496211da8f 750 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
donatien 10:35496211da8f 751 {
donatien 10:35496211da8f 752 if( m_eventsHandlers[i] != NULL )
donatien 10:35496211da8f 753 {
donatien 10:35496211da8f 754 m_eventsHandlers[i]->onDispatchStart();
donatien 10:35496211da8f 755 //Disable this kind of events
donatien 10:35496211da8f 756 if(m_eventsHandlers[i]->getEventsDisableCommand() != NULL)
donatien 10:35496211da8f 757 {
donatien 10:35496211da8f 758 int ret = executeInternal(m_eventsHandlers[i]->getEventsDisableCommand(), this, NULL); //Execute disable command
donatien 10:35496211da8f 759 if(ret)
donatien 10:35496211da8f 760 {
donatien 10:35496211da8f 761 WARN("Events disabling command failed");
donatien 10:35496211da8f 762 }
donatien 10:35496211da8f 763 }
donatien 10:35496211da8f 764 }
donatien 10:35496211da8f 765 }
donatien 10:35496211da8f 766 m_eventsMgmtMtx.unlock();
donatien 10:35496211da8f 767 }
donatien 10:35496211da8f 768
donatien 0:8f57713b2147 769 //Commands that can be called during onNewATResponseLine callback, additionally to close()
donatien 0:8f57713b2147 770 //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
donatien 0:8f57713b2147 771 int ATCommandsInterface::sendData(const char* data)
donatien 0:8f57713b2147 772 {
donatien 0:8f57713b2147 773 //m_inputBuf is cleared at this point (and MUST therefore be empty)
donatien 0:8f57713b2147 774 int dataLen = strlen(data);
donatien 0:8f57713b2147 775 DBG("Sending raw string of length %d", dataLen);
donatien 0:8f57713b2147 776 int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever);
donatien 0:8f57713b2147 777 if(ret)
donatien 0:8f57713b2147 778 {
donatien 0:8f57713b2147 779 WARN("Could not write to stream (returned %d)", ret);
donatien 0:8f57713b2147 780 return ret;
donatien 0:8f57713b2147 781 }
donatien 0:8f57713b2147 782
donatien 0:8f57713b2147 783 int dataPos = 0;
donatien 0:8f57713b2147 784 do
donatien 0:8f57713b2147 785 {
donatien 0:8f57713b2147 786 //Read echo
donatien 0:8f57713b2147 787 size_t readLen;
donatien 0:8f57713b2147 788 int ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, MIN(dataLen - dataPos, AT_INPUT_BUF_SIZE - 1), osWaitForever); //Make sure we do not read more than needed otherwise it could break the parser
donatien 0:8f57713b2147 789 if(ret)
donatien 0:8f57713b2147 790 {
donatien 0:8f57713b2147 791 WARN("Could not read from stream (returned %d)", ret);
donatien 4:23100b0757d6 792 m_inputPos = 0; //Reset input buffer state
donatien 4:23100b0757d6 793 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 0:8f57713b2147 794 return ret;
donatien 4:23100b0757d6 795 }
donatien 0:8f57713b2147 796
donatien 0:8f57713b2147 797 if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 )
donatien 0:8f57713b2147 798 {
donatien 0:8f57713b2147 799 //Echo does not match output
donatien 10:35496211da8f 800 m_inputBuf[readLen] = '\0';
donatien 10:35496211da8f 801 WARN("Echo does not match output, got '%s' instead", m_inputBuf);
donatien 4:23100b0757d6 802 m_inputPos = 0; //Reset input buffer state
donatien 4:23100b0757d6 803 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 0:8f57713b2147 804 return NET_DIFF;
donatien 0:8f57713b2147 805 }
donatien 0:8f57713b2147 806
donatien 0:8f57713b2147 807 dataPos += readLen;
donatien 0:8f57713b2147 808 //If all characters have not been read yet
donatien 0:8f57713b2147 809
donatien 0:8f57713b2147 810 } while(dataPos < dataLen);
donatien 0:8f57713b2147 811
donatien 0:8f57713b2147 812 DBG("String sent successfully");
donatien 0:8f57713b2147 813
donatien 0:8f57713b2147 814 m_inputPos = 0; //Reset input buffer state
donatien 4:23100b0757d6 815 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
donatien 0:8f57713b2147 816
donatien 0:8f57713b2147 817 return OK;
donatien 0:8f57713b2147 818 }
donatien 0:8f57713b2147 819
donatien 0:8f57713b2147 820 /*static*/ void ATCommandsInterface::staticCallback(void const* p)
donatien 0:8f57713b2147 821 {
donatien 0:8f57713b2147 822 ((ATCommandsInterface*)p)->process();
donatien 0:8f57713b2147 823 }
donatien 0:8f57713b2147 824
donatien 0:8f57713b2147 825 int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper
donatien 0:8f57713b2147 826 {
donatien 0:8f57713b2147 827 if(result.result == ATResult::AT_OK)
donatien 0:8f57713b2147 828 {
donatien 0:8f57713b2147 829 return OK;
donatien 0:8f57713b2147 830 }
donatien 0:8f57713b2147 831 else
donatien 0:8f57713b2147 832 {
donatien 0:8f57713b2147 833 return NET_MOREINFO;
donatien 0:8f57713b2147 834 }
donatien 0:8f57713b2147 835 }
donatien 0:8f57713b2147 836
donatien 0:8f57713b2147 837 /*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling
donatien 0:8f57713b2147 838 {
donatien 0:8f57713b2147 839 return OK;
donatien 0:8f57713b2147 840 }
donatien 0:8f57713b2147 841
donatien 0:8f57713b2147 842 /*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away)
donatien 0:8f57713b2147 843 {
donatien 0:8f57713b2147 844 return OK;
donatien 0:8f57713b2147 845 }
donatien 0:8f57713b2147 846
donatien 0:8f57713b2147 847 void ATCommandsInterface::process() //Processing thread
donatien 0:8f57713b2147 848 {
donatien 0:8f57713b2147 849 DBG("AT Thread started");
donatien 0:8f57713b2147 850 while(true)
donatien 0:8f57713b2147 851 {
donatien 0:8f57713b2147 852 DBG("AT Processing on hold");
donatien 0:8f57713b2147 853 m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started
donatien 0:8f57713b2147 854
donatien 0:8f57713b2147 855 m_processingMtx.lock();
donatien 0:8f57713b2147 856 DBG("AT Processing started");
donatien 0:8f57713b2147 857 //First of all discard buffer
donatien 0:8f57713b2147 858 int ret;
donatien 0:8f57713b2147 859 size_t readLen;
donatien 0:8f57713b2147 860 do //Drop everything
donatien 0:8f57713b2147 861 {
donatien 0:8f57713b2147 862 ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point
donatien 0:8f57713b2147 863 } while(ret == OK);
donatien 0:8f57713b2147 864 m_inputPos = 0; //Clear input buffer
donatien 0:8f57713b2147 865 do
donatien 0:8f57713b2147 866 {
donatien 10:35496211da8f 867 DBG("Trying to send a pending command");
donatien 10:35496211da8f 868 trySendCommand(); //This must be tried first as we discarded the buffer before and therefore would be blocking though there is a pending command
donatien 0:8f57713b2147 869 DBG("Trying to read a new line");
donatien 0:8f57713b2147 870 tryReadLine();
donatien 0:8f57713b2147 871 } while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted
donatien 0:8f57713b2147 872 m_processingMtx.unlock();
donatien 0:8f57713b2147 873 DBG("AT Processing stopped");
donatien 0:8f57713b2147 874 }
donatien 0:8f57713b2147 875 }