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:
bogdanm
Date:
Thu Oct 17 12:29:05 2013 +0300
Revision:
1:4a23efdf0da9
Child:
4:3fc75e611736
Initial release of the CellularModem library

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