Integrating the ublox LISA C200 modem

Fork of SprintUSBModemHTTPClientTest by Donatien Garnier

Committer:
sam_grove
Date:
Thu Sep 26 00:44:20 2013 -0500
Revision:
5:3f93dd1d4cb3
Exported program and replaced contents of the repo with the source
to build and debug using keil mdk. Libs NOT upto date are lwip, lwip-sys
and socket. these have newer versions under mbed_official but were starting
from a know working point

Who changed what in which revision?

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