Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Committer:
clemounet
Date:
Tue Apr 14 13:27:07 2015 +0000
Revision:
2:61ac95f0af72
Parent:
0:67daedd6f74f
.up (working)

Who changed what in which revision?

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