local fork

Dependencies:   Socket USBHostWANDongle_bleedingedge lwip-sys lwip

Dependents:   Encrypted

Fork of VodafoneUSBModem_bleedingedge by Donatien Garnier

Committer:
donatien
Date:
Thu May 24 16:40:40 2012 +0000
Revision:
0:3b2f052c333b
Initial Commit

Who changed what in which revision?

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