PHS module SMA-01 library. see: https://developer.mbed.org/users/phsfan/notebook/abitusbmodem/

Dependencies:   Socket lwip-sys lwip

Dependents:   AbitUSBModem_HTTPTest AbitUSBModem_MQTTTest AbitUSBModem_WebsocketTest AbitUSBModem_SMSTest

Fork of VodafoneUSBModem by mbed official

/media/uploads/phsfan/sma01_003.png

Committer:
phsfan
Date:
Wed Feb 25 14:34:13 2015 +0000
Revision:
99:514e67a69ad6
Parent:
97:7d9cc95e2ea7
supported SMS

Who changed what in which revision?

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