Base library for cellular modem implementations

Dependencies:   Socket lwip-sys lwip

Dependents:   CellularUSBModem CellularUSBModem

Deprecated

This is an mbed 2 networking library. For mbed 5, the networking libraries have been revised to better support additional network stacks and thread safety here.

Committer:
mbed_official
Date:
Tue Mar 04 10:00:52 2014 +0000
Revision:
7:0fd95907b5b3
Parent:
4:3fc75e611736
Synchronized with git revision e4faeb42a7013bfc4d1dccf0a6d905d10aca5c00

Full URL: https://github.com/mbedmicro/mbed/commit/e4faeb42a7013bfc4d1dccf0a6d905d10aca5c00/

Update of cellular modem

Who changed what in which revision?

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