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:
Mon Dec 16 09:00:24 2013 +0000
Revision:
4:3fc75e611736
Parent:
1:4a23efdf0da9
Child:
7:0fd95907b5b3
Synchronized with git revision 170ac6562b7b2b5bb43f8ecf82b2af18b37eeb9c

Full URL: https://github.com/mbedmicro/mbed/commit/170ac6562b7b2b5bb43f8ecf82b2af18b37eeb9c/

improve USB host library and cellular modem stack

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
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");
bogdanm 1:4a23efdf0da9 273 return NET_TIMEOUT;
bogdanm 1:4a23efdf0da9 274 }
bogdanm 1:4a23efdf0da9 275 DBG("Command returned with message %d", *msg);
bogdanm 1:4a23efdf0da9 276
bogdanm 1:4a23efdf0da9 277 m_AT2Env.free((int*)evt.value.p);
bogdanm 1:4a23efdf0da9 278
bogdanm 1:4a23efdf0da9 279 if(pResult != NULL)
bogdanm 1:4a23efdf0da9 280 {
bogdanm 1:4a23efdf0da9 281 *pResult = m_transactionResult;
bogdanm 1:4a23efdf0da9 282 }
bogdanm 1:4a23efdf0da9 283
bogdanm 1:4a23efdf0da9 284 int ret = ATResultToReturnCode(m_transactionResult);
bogdanm 1:4a23efdf0da9 285 if(ret != OK)
bogdanm 1:4a23efdf0da9 286 {
bogdanm 1:4a23efdf0da9 287 WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code);
bogdanm 1:4a23efdf0da9 288 }
bogdanm 1:4a23efdf0da9 289
bogdanm 1:4a23efdf0da9 290 DBG("Command returned successfully");
bogdanm 1:4a23efdf0da9 291
bogdanm 1:4a23efdf0da9 292 return ret;
bogdanm 1:4a23efdf0da9 293 }
bogdanm 1:4a23efdf0da9 294
bogdanm 1:4a23efdf0da9 295 int ATCommandsInterface::tryReadLine()
bogdanm 1:4a23efdf0da9 296 {
bogdanm 1:4a23efdf0da9 297 static bool lineDetected = false;
bogdanm 1:4a23efdf0da9 298
bogdanm 1:4a23efdf0da9 299 //Block on serial read or incoming command
bogdanm 1:4a23efdf0da9 300 DBG("Trying to read a new line from stream");
bogdanm 1:4a23efdf0da9 301 int ret = m_pStream->waitAvailable(); //This can be aborted
bogdanm 1:4a23efdf0da9 302 size_t readLen = 0;
bogdanm 1:4a23efdf0da9 303 if(ret == OK)
bogdanm 1:4a23efdf0da9 304 {
bogdanm 1:4a23efdf0da9 305 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 306 }
bogdanm 1:4a23efdf0da9 307 if(ret == OK)
bogdanm 1:4a23efdf0da9 308 {
bogdanm 1:4a23efdf0da9 309 m_inputPos+=readLen;
bogdanm 1:4a23efdf0da9 310 m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions
bogdanm 1:4a23efdf0da9 311 DBG("In buffer: [%s]", m_inputBuf);
bogdanm 1:4a23efdf0da9 312 }
bogdanm 1:4a23efdf0da9 313
bogdanm 1:4a23efdf0da9 314 if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted
bogdanm 1:4a23efdf0da9 315 {
bogdanm 1:4a23efdf0da9 316 DBG("Read was interrupted");
bogdanm 1:4a23efdf0da9 317 return NET_INTERRUPTED; //0 chars were read
bogdanm 1:4a23efdf0da9 318 }
bogdanm 1:4a23efdf0da9 319 else if(readLen == 0)
bogdanm 1:4a23efdf0da9 320 {
bogdanm 1:4a23efdf0da9 321 DBG("Nothing read");
bogdanm 1:4a23efdf0da9 322 return OK; //0 chars were read
bogdanm 1:4a23efdf0da9 323 }
bogdanm 1:4a23efdf0da9 324
bogdanm 1:4a23efdf0da9 325 DBG("Trying to process incoming line");
bogdanm 1:4a23efdf0da9 326 bool lineProcessed = false;
bogdanm 1:4a23efdf0da9 327
bogdanm 1:4a23efdf0da9 328 do
bogdanm 1:4a23efdf0da9 329 {
bogdanm 1:4a23efdf0da9 330 lineProcessed = false; //Reset flag
bogdanm 1:4a23efdf0da9 331
bogdanm 1:4a23efdf0da9 332 DBG("New iteration");
bogdanm 1:4a23efdf0da9 333
bogdanm 1:4a23efdf0da9 334 //Look for a new line
bogdanm 1:4a23efdf0da9 335 if(!lineDetected)
bogdanm 1:4a23efdf0da9 336 {
bogdanm 1:4a23efdf0da9 337 DBG("No line detected yet");
bogdanm 1:4a23efdf0da9 338 //Try to look for a starting CRLF
bogdanm 1:4a23efdf0da9 339 char* crPtr = strchr(m_inputBuf, CR);
bogdanm 1:4a23efdf0da9 340 /*
bogdanm 1:4a23efdf0da9 341 Different cases at this point:
bogdanm 1:4a23efdf0da9 342 - CRLF%c sequence: this is the start of a line
bogdanm 1:4a23efdf0da9 343 - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one)
bogdanm 1:4a23efdf0da9 344 - LF: this is the trailing LF char of the previous line, discard
bogdanm 1:4a23efdf0da9 345 - CR / CRLF incomplete sequence: more data is needed to determine which action to take
bogdanm 1:4a23efdf0da9 346 - %c ... CR sequence: this should be the echo of the previous sequence
bogdanm 1:4a23efdf0da9 347 - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take
bogdanm 1:4a23efdf0da9 348
bogdanm 1:4a23efdf0da9 349 In every case, move mem at the beginning
bogdanm 1:4a23efdf0da9 350 */
bogdanm 1:4a23efdf0da9 351 if(crPtr != NULL)
bogdanm 1:4a23efdf0da9 352 {
bogdanm 1:4a23efdf0da9 353 DBG("CR char found");
bogdanm 1:4a23efdf0da9 354
bogdanm 1:4a23efdf0da9 355 #if 0
bogdanm 1:4a23efdf0da9 356 //Discard all preceding characters (can do nothing if m_inputBuf == crPtr)
bogdanm 1:4a23efdf0da9 357 memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 358 m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 359 #endif
bogdanm 1:4a23efdf0da9 360
bogdanm 1:4a23efdf0da9 361 //If the line starts with CR, this should be a result code
bogdanm 1:4a23efdf0da9 362 if( crPtr == m_inputBuf )
bogdanm 1:4a23efdf0da9 363 {
bogdanm 1:4a23efdf0da9 364 //To determine the sequence we need at least 3 chars
bogdanm 1:4a23efdf0da9 365 if(m_inputPos >= 3)
bogdanm 1:4a23efdf0da9 366 {
bogdanm 1:4a23efdf0da9 367 //Look for a LF char next to the CR char
bogdanm 1:4a23efdf0da9 368 if(m_inputBuf[1] == LF)
bogdanm 1:4a23efdf0da9 369 {
bogdanm 1:4a23efdf0da9 370 //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 371 if(m_inputBuf[2] != CR)
bogdanm 1:4a23efdf0da9 372 {
bogdanm 1:4a23efdf0da9 373 DBG("Beginning of new line found");
bogdanm 1:4a23efdf0da9 374 //Beginning of a line
bogdanm 1:4a23efdf0da9 375 lineDetected = true; //Move to next state-machine step
bogdanm 1:4a23efdf0da9 376 }
bogdanm 1:4a23efdf0da9 377 else
bogdanm 1:4a23efdf0da9 378 {
bogdanm 1:4a23efdf0da9 379 //End of an unprocessed line
bogdanm 1:4a23efdf0da9 380 WARN("End of unprocessed line");
bogdanm 1:4a23efdf0da9 381 }
bogdanm 1:4a23efdf0da9 382 //In both cases discard CRLF
bogdanm 1:4a23efdf0da9 383 DBG("Discarding CRLF");
bogdanm 1:4a23efdf0da9 384 memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 385 m_inputPos = m_inputPos - 2; //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 386 }
bogdanm 1:4a23efdf0da9 387 else
bogdanm 1:4a23efdf0da9 388 {
bogdanm 1:4a23efdf0da9 389 //This is completely unexpected, discard the CR char to try to recover good state
bogdanm 1:4a23efdf0da9 390 WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]);
bogdanm 1:4a23efdf0da9 391 memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 392 m_inputPos = m_inputPos - 1; //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 393 }
bogdanm 1:4a23efdf0da9 394 }
bogdanm 1:4a23efdf0da9 395 }
bogdanm 1:4a23efdf0da9 396 //if the line does NOT begin with CR, this can be an echo of the previous command, process it
bogdanm 1:4a23efdf0da9 397 else
bogdanm 1:4a23efdf0da9 398 {
bogdanm 1:4a23efdf0da9 399 int crPos = crPtr - m_inputBuf;
bogdanm 1:4a23efdf0da9 400 int lfOff = 0; //Offset for LF if present
bogdanm 1:4a23efdf0da9 401 DBG("New line found (possible echo of command)");
bogdanm 1:4a23efdf0da9 402 //This is the end of line
bogdanm 1:4a23efdf0da9 403 //Replace m_inputBuf[crPos] with null-terminating char
bogdanm 1:4a23efdf0da9 404 m_inputBuf[crPos] = '\0';
bogdanm 1:4a23efdf0da9 405 //Check if there is a LF char afterwards
bogdanm 1:4a23efdf0da9 406 if(m_inputPos - crPos >= 1)
bogdanm 1:4a23efdf0da9 407 {
bogdanm 1:4a23efdf0da9 408 if(m_inputBuf[crPos+1] == LF)
bogdanm 1:4a23efdf0da9 409 {
bogdanm 1:4a23efdf0da9 410 lfOff++; //We will discard LF char as well
bogdanm 1:4a23efdf0da9 411 }
bogdanm 1:4a23efdf0da9 412 }
bogdanm 1:4a23efdf0da9 413 //Process line
bogdanm 1:4a23efdf0da9 414 int ret = processReadLine();
bogdanm 1:4a23efdf0da9 415 if(ret)
bogdanm 1:4a23efdf0da9 416 {
bogdanm 1:4a23efdf0da9 417 m_inputPos = 0;
bogdanm 1:4a23efdf0da9 418 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 419 lineDetected = false;
bogdanm 1:4a23efdf0da9 420 return ret;
bogdanm 1:4a23efdf0da9 421 }
bogdanm 1:4a23efdf0da9 422
bogdanm 1:4a23efdf0da9 423 //If sendData has been called, all incoming data has been discarded
bogdanm 1:4a23efdf0da9 424 if(m_inputPos > 0)
bogdanm 1:4a23efdf0da9 425 {
bogdanm 1:4a23efdf0da9 426 memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 427 m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 428 }
bogdanm 1:4a23efdf0da9 429 DBG("One line was successfully processed");
bogdanm 1:4a23efdf0da9 430 lineProcessed = true; //Line was processed with success
bogdanm 1:4a23efdf0da9 431 lineDetected = false; //Search now for a new line
bogdanm 1:4a23efdf0da9 432 }
bogdanm 1:4a23efdf0da9 433 }
bogdanm 1:4a23efdf0da9 434 else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it
bogdanm 1:4a23efdf0da9 435 {
bogdanm 1:4a23efdf0da9 436 DBG("Discarding single LF char");
bogdanm 1:4a23efdf0da9 437 memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 438 m_inputPos = m_inputPos - 1; //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 439 }
bogdanm 1:4a23efdf0da9 440 }
bogdanm 1:4a23efdf0da9 441
bogdanm 1:4a23efdf0da9 442 //Look for the end of line
bogdanm 1:4a23efdf0da9 443 if(lineDetected)
bogdanm 1:4a23efdf0da9 444 {
bogdanm 1:4a23efdf0da9 445 DBG("Looking for end of line");
bogdanm 1:4a23efdf0da9 446 //Try to look for a terminating CRLF
bogdanm 1:4a23efdf0da9 447 char* crPtr = strchr(m_inputBuf, CR);
bogdanm 1:4a23efdf0da9 448 /*
bogdanm 1:4a23efdf0da9 449 Different cases at this point:
bogdanm 1:4a23efdf0da9 450 - CRLF sequence: this is the end of the line
bogdanm 1:4a23efdf0da9 451 - CR%c sequence : unexpected
bogdanm 1:4a23efdf0da9 452 - CR incomplete sequence: more data is needed to determine which action to take
bogdanm 1:4a23efdf0da9 453 */
bogdanm 1:4a23efdf0da9 454
bogdanm 1:4a23efdf0da9 455 //Try to look for a '>' (greater than character) that marks an entry prompt
bogdanm 1:4a23efdf0da9 456 char* greaterThanPtr = strchr(m_inputBuf, GD);
bogdanm 1:4a23efdf0da9 457 /*
bogdanm 1:4a23efdf0da9 458 This character must be detected as there is no CRLF sequence at the end of an entry prompt
bogdanm 1:4a23efdf0da9 459 */
bogdanm 1:4a23efdf0da9 460
bogdanm 1:4a23efdf0da9 461 if(crPtr != NULL)
bogdanm 1:4a23efdf0da9 462 {
bogdanm 1:4a23efdf0da9 463 DBG("CR char found");
bogdanm 1:4a23efdf0da9 464 int crPos = crPtr - m_inputBuf;
bogdanm 1:4a23efdf0da9 465 //To determine the sequence we need at least 2 chars
bogdanm 1:4a23efdf0da9 466 if(m_inputPos - crPos >= 2)
bogdanm 1:4a23efdf0da9 467 {
bogdanm 1:4a23efdf0da9 468 //Look for a LF char next to the CR char
bogdanm 1:4a23efdf0da9 469 if(m_inputBuf[crPos + 1] == LF)
bogdanm 1:4a23efdf0da9 470 {
bogdanm 1:4a23efdf0da9 471 DBG("End of new line found");
bogdanm 1:4a23efdf0da9 472 //This is the end of line
bogdanm 1:4a23efdf0da9 473 //Replace m_inputBuf[crPos] with null-terminating char
bogdanm 1:4a23efdf0da9 474 m_inputBuf[crPos] = '\0';
bogdanm 1:4a23efdf0da9 475 //Process line
bogdanm 1:4a23efdf0da9 476 int ret = processReadLine();
bogdanm 1:4a23efdf0da9 477 if(ret)
bogdanm 1:4a23efdf0da9 478 {
bogdanm 1:4a23efdf0da9 479 m_inputPos = 0;
bogdanm 1:4a23efdf0da9 480 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 481 lineDetected = false;
bogdanm 1:4a23efdf0da9 482 return ret;
bogdanm 1:4a23efdf0da9 483 }
bogdanm 1:4a23efdf0da9 484
bogdanm 1:4a23efdf0da9 485 //If sendData has been called, all incoming data has been discarded
bogdanm 1:4a23efdf0da9 486 if(m_inputPos > 0)
bogdanm 1:4a23efdf0da9 487 {
bogdanm 1:4a23efdf0da9 488 //Shift remaining data to beginning of buffer
bogdanm 1:4a23efdf0da9 489 memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 490 m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 491 }
bogdanm 1:4a23efdf0da9 492
bogdanm 1:4a23efdf0da9 493 DBG("One line was successfully processed");
bogdanm 1:4a23efdf0da9 494 lineProcessed = true; //Line was processed with success
bogdanm 1:4a23efdf0da9 495 }
bogdanm 1:4a23efdf0da9 496 else
bogdanm 1:4a23efdf0da9 497 {
bogdanm 1:4a23efdf0da9 498 //This is completely unexpected, discard all chars till the CR char to try to recover good state
bogdanm 1:4a23efdf0da9 499 WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]);
bogdanm 1:4a23efdf0da9 500 memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 501 m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 502 }
bogdanm 1:4a23efdf0da9 503 lineDetected = false; //In both case search now for a new line
bogdanm 1:4a23efdf0da9 504 }
bogdanm 1:4a23efdf0da9 505 }
bogdanm 1:4a23efdf0da9 506 else if(greaterThanPtr != NULL)
bogdanm 1:4a23efdf0da9 507 {
bogdanm 1:4a23efdf0da9 508 DBG("> char found");
bogdanm 1:4a23efdf0da9 509 int gdPos = greaterThanPtr - m_inputBuf;
bogdanm 1:4a23efdf0da9 510 //To determine the sequence we need at least 2 chars
bogdanm 1:4a23efdf0da9 511 if(m_inputPos - gdPos >= 2)
bogdanm 1:4a23efdf0da9 512 {
bogdanm 1:4a23efdf0da9 513 //Look for a space char next to the GD char
bogdanm 1:4a23efdf0da9 514 if(m_inputBuf[gdPos + 1] == ' ')
bogdanm 1:4a23efdf0da9 515 {
bogdanm 1:4a23efdf0da9 516 //This is an entry prompt
bogdanm 1:4a23efdf0da9 517 //Replace m_inputBuf[gdPos] with null-terminating char
bogdanm 1:4a23efdf0da9 518 m_inputBuf[gdPos] = '\0';
bogdanm 1:4a23efdf0da9 519
bogdanm 1:4a23efdf0da9 520 //Shift remaining data to beginning of buffer
bogdanm 1:4a23efdf0da9 521 memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 522 m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 523
bogdanm 1:4a23efdf0da9 524 //Process prompt
bogdanm 1:4a23efdf0da9 525 ret = processEntryPrompt();
bogdanm 1:4a23efdf0da9 526 if(ret)
bogdanm 1:4a23efdf0da9 527 {
bogdanm 1:4a23efdf0da9 528 m_inputPos = 0;
bogdanm 1:4a23efdf0da9 529 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 530 lineDetected = false;
bogdanm 1:4a23efdf0da9 531 return ret;
bogdanm 1:4a23efdf0da9 532 }
bogdanm 1:4a23efdf0da9 533
bogdanm 1:4a23efdf0da9 534 DBG("One line was successfully processed");
bogdanm 1:4a23efdf0da9 535 lineProcessed = true; //Line was processed with success
bogdanm 1:4a23efdf0da9 536 }
bogdanm 1:4a23efdf0da9 537 else
bogdanm 1:4a23efdf0da9 538 {
bogdanm 1:4a23efdf0da9 539 //This is completely unexpected, discard all chars till the GD char to try to recover good state
bogdanm 1:4a23efdf0da9 540 WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]);
bogdanm 1:4a23efdf0da9 541 memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
bogdanm 1:4a23efdf0da9 542 m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
bogdanm 1:4a23efdf0da9 543 }
bogdanm 1:4a23efdf0da9 544 lineDetected = false; //In both case search now for a new line
bogdanm 1:4a23efdf0da9 545 }
bogdanm 1:4a23efdf0da9 546 }
bogdanm 1:4a23efdf0da9 547 }
bogdanm 1:4a23efdf0da9 548 } 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 549
bogdanm 1:4a23efdf0da9 550 //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 551 if(m_inputPos == AT_INPUT_BUF_SIZE - 1)
bogdanm 1:4a23efdf0da9 552 {
bogdanm 1:4a23efdf0da9 553 //Discard everything
bogdanm 1:4a23efdf0da9 554 m_inputPos = 0;
bogdanm 1:4a23efdf0da9 555 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 556 WARN("Incoming buffer is too short to process incoming line");
bogdanm 1:4a23efdf0da9 557 //Look for a new line
bogdanm 1:4a23efdf0da9 558 lineDetected = false;
bogdanm 1:4a23efdf0da9 559 }
bogdanm 1:4a23efdf0da9 560
bogdanm 1:4a23efdf0da9 561 DBG("Processed every full incoming lines");
bogdanm 1:4a23efdf0da9 562
bogdanm 1:4a23efdf0da9 563 return OK;
bogdanm 1:4a23efdf0da9 564 }
bogdanm 1:4a23efdf0da9 565
bogdanm 1:4a23efdf0da9 566 int ATCommandsInterface::trySendCommand()
bogdanm 1:4a23efdf0da9 567 {
bogdanm 1:4a23efdf0da9 568 osEvent evt = m_env2AT.get(0);
bogdanm 1:4a23efdf0da9 569 DBG("status = %d, msg = %d", evt.status, evt.value.p);
bogdanm 1:4a23efdf0da9 570 if(evt.status == osEventMail)
bogdanm 1:4a23efdf0da9 571 {
bogdanm 1:4a23efdf0da9 572 int* msg = (int*) evt.value.p;
bogdanm 1:4a23efdf0da9 573 if( *msg == AT_CMD_READY ) //Command pending
bogdanm 1:4a23efdf0da9 574 {
bogdanm 1:4a23efdf0da9 575 if(m_transactionState != IDLE)
bogdanm 1:4a23efdf0da9 576 {
bogdanm 1:4a23efdf0da9 577 WARN("Previous command not processed!");
bogdanm 1:4a23efdf0da9 578 }
bogdanm 1:4a23efdf0da9 579 DBG("Sending pending command");
bogdanm 1:4a23efdf0da9 580 m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever);
bogdanm 1:4a23efdf0da9 581 char cr = CR;
bogdanm 1:4a23efdf0da9 582 m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator
bogdanm 1:4a23efdf0da9 583 m_transactionState = COMMAND_SENT;
bogdanm 1:4a23efdf0da9 584 }
bogdanm 1:4a23efdf0da9 585 else //Timeout
bogdanm 1:4a23efdf0da9 586 {
bogdanm 1:4a23efdf0da9 587 //Acknowledge
bogdanm 1:4a23efdf0da9 588 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 589 *msg = AT_TIMEOUT;
bogdanm 1:4a23efdf0da9 590 m_AT2Env.put(msg); //Command has timed out
bogdanm 1:4a23efdf0da9 591 m_transactionState = IDLE; //State-machine reset
bogdanm 1:4a23efdf0da9 592 }
bogdanm 1:4a23efdf0da9 593 m_env2AT.free(msg);
bogdanm 1:4a23efdf0da9 594 }
bogdanm 1:4a23efdf0da9 595 return OK;
bogdanm 1:4a23efdf0da9 596 }
bogdanm 1:4a23efdf0da9 597
bogdanm 1:4a23efdf0da9 598 int ATCommandsInterface::processReadLine()
bogdanm 1:4a23efdf0da9 599 {
bogdanm 1:4a23efdf0da9 600 DBG("Processing read line [%s]", m_inputBuf);
bogdanm 1:4a23efdf0da9 601 //The line is stored in m_inputBuf
bogdanm 1:4a23efdf0da9 602 if(m_transactionState == COMMAND_SENT)
bogdanm 1:4a23efdf0da9 603 {
bogdanm 1:4a23efdf0da9 604 //If the command has been sent, checks echo to see if it has been received properly
bogdanm 1:4a23efdf0da9 605 if( strcmp(m_transactionCommand, m_inputBuf) == 0 )
bogdanm 1:4a23efdf0da9 606 {
bogdanm 1:4a23efdf0da9 607 DBG("Command echo received");
bogdanm 1:4a23efdf0da9 608 //If so, it means that the following lines will only be solicited results
bogdanm 1:4a23efdf0da9 609 m_transactionState = READING_RESULT;
bogdanm 1:4a23efdf0da9 610 return OK;
bogdanm 1:4a23efdf0da9 611 }
bogdanm 1:4a23efdf0da9 612 }
bogdanm 1:4a23efdf0da9 613 if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT)
bogdanm 1:4a23efdf0da9 614 {
bogdanm 1:4a23efdf0da9 615 bool found = false;
bogdanm 1:4a23efdf0da9 616 char* pSemicol = strchr(m_inputBuf, ':');
bogdanm 1:4a23efdf0da9 617 char* pData = NULL;
bogdanm 1:4a23efdf0da9 618 if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
bogdanm 1:4a23efdf0da9 619 {
bogdanm 1:4a23efdf0da9 620 *pSemicol = '\0';
bogdanm 1:4a23efdf0da9 621 pData = pSemicol + 1;
bogdanm 1:4a23efdf0da9 622 if(pData[0]==' ')
bogdanm 1:4a23efdf0da9 623 {
bogdanm 1:4a23efdf0da9 624 pData++; //Suppress whitespace
bogdanm 1:4a23efdf0da9 625 }
bogdanm 1:4a23efdf0da9 626 }
bogdanm 1:4a23efdf0da9 627 //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 628 m_eventsProcessingMtx.lock();
bogdanm 1:4a23efdf0da9 629 //Go through the list
bogdanm 1:4a23efdf0da9 630 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
bogdanm 1:4a23efdf0da9 631 {
bogdanm 1:4a23efdf0da9 632 if( m_eventsHandlers[i] != NULL )
bogdanm 1:4a23efdf0da9 633 {
bogdanm 1:4a23efdf0da9 634 if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) )
bogdanm 1:4a23efdf0da9 635 {
bogdanm 1:4a23efdf0da9 636 m_eventsHandlers[i]->onEvent(m_inputBuf, pData);
bogdanm 1:4a23efdf0da9 637 found = true; //Do not break here as there might be multiple handlers for one event type
bogdanm 1:4a23efdf0da9 638 }
bogdanm 1:4a23efdf0da9 639 }
bogdanm 1:4a23efdf0da9 640 }
bogdanm 1:4a23efdf0da9 641 m_eventsProcessingMtx.unlock();
bogdanm 1:4a23efdf0da9 642 if(found)
bogdanm 1:4a23efdf0da9 643 {
bogdanm 1:4a23efdf0da9 644 return OK;
bogdanm 1:4a23efdf0da9 645 }
bogdanm 1:4a23efdf0da9 646 }
bogdanm 1:4a23efdf0da9 647 if(m_transactionState == READING_RESULT)
bogdanm 1:4a23efdf0da9 648 {
bogdanm 1:4a23efdf0da9 649 //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 650 if(strcmp("OK", m_inputBuf) == 0)
bogdanm 1:4a23efdf0da9 651 {
bogdanm 1:4a23efdf0da9 652 DBG("OK result received");
bogdanm 1:4a23efdf0da9 653 m_transactionResult.code = 0;
bogdanm 1:4a23efdf0da9 654 m_transactionResult.result = ATResult::AT_OK;
bogdanm 1:4a23efdf0da9 655 m_transactionState = IDLE;
bogdanm 1:4a23efdf0da9 656 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 657 *msg = AT_RESULT_READY;
bogdanm 1:4a23efdf0da9 658 m_AT2Env.put(msg); //Command has been processed
bogdanm 1:4a23efdf0da9 659 return OK;
bogdanm 1:4a23efdf0da9 660 }
bogdanm 1:4a23efdf0da9 661 else if(strcmp("ERROR", m_inputBuf) == 0)
bogdanm 1:4a23efdf0da9 662 {
bogdanm 1:4a23efdf0da9 663 DBG("ERROR result received");
bogdanm 1:4a23efdf0da9 664 m_transactionResult.code = 0;
bogdanm 1:4a23efdf0da9 665 m_transactionResult.result = ATResult::AT_ERROR;
bogdanm 1:4a23efdf0da9 666 m_transactionState = IDLE;
bogdanm 1:4a23efdf0da9 667 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 668 *msg = AT_RESULT_READY;
bogdanm 1:4a23efdf0da9 669 m_AT2Env.put(msg); //Command has been processed
bogdanm 1:4a23efdf0da9 670 return OK;
bogdanm 1:4a23efdf0da9 671 }
bogdanm 1:4a23efdf0da9 672 else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate
bogdanm 1:4a23efdf0da9 673 {
bogdanm 1:4a23efdf0da9 674 DBG("CONNECT result received");
bogdanm 1:4a23efdf0da9 675 m_transactionResult.code = 0;
bogdanm 1:4a23efdf0da9 676 m_transactionResult.result = ATResult::AT_CONNECT;
bogdanm 1:4a23efdf0da9 677 m_transactionState = IDLE;
bogdanm 1:4a23efdf0da9 678 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 679 *msg = AT_RESULT_READY;
bogdanm 1:4a23efdf0da9 680 m_AT2Env.put(msg); //Command has been processed
bogdanm 1:4a23efdf0da9 681 return OK;
bogdanm 1:4a23efdf0da9 682 }
bogdanm 1:4a23efdf0da9 683 else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized
bogdanm 1:4a23efdf0da9 684 {
bogdanm 1:4a23efdf0da9 685 DBG("COMMAND NOT SUPPORT result received");
bogdanm 1:4a23efdf0da9 686 m_transactionResult.code = 0;
bogdanm 1:4a23efdf0da9 687 m_transactionResult.result = ATResult::AT_ERROR;
bogdanm 1:4a23efdf0da9 688 m_transactionState = IDLE;
bogdanm 1:4a23efdf0da9 689 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 690 *msg = AT_RESULT_READY;
bogdanm 1:4a23efdf0da9 691 m_AT2Env.put(msg); //Command has been processed
bogdanm 1:4a23efdf0da9 692 return OK;
bogdanm 1:4a23efdf0da9 693 }
bogdanm 1:4a23efdf0da9 694 else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error
bogdanm 1:4a23efdf0da9 695 {
bogdanm 1:4a23efdf0da9 696 std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
bogdanm 1:4a23efdf0da9 697 DBG("+CME ERROR: %d result received", m_transactionResult.code);
bogdanm 1:4a23efdf0da9 698 m_transactionResult.result = ATResult::AT_CME_ERROR;
bogdanm 1:4a23efdf0da9 699 m_transactionState = IDLE;
bogdanm 1:4a23efdf0da9 700 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 701 *msg = AT_RESULT_READY;
bogdanm 1:4a23efdf0da9 702 m_AT2Env.put(msg); //Command has been processed
bogdanm 1:4a23efdf0da9 703 return OK;
bogdanm 1:4a23efdf0da9 704 }
bogdanm 1:4a23efdf0da9 705 else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error
bogdanm 1:4a23efdf0da9 706 {
bogdanm 1:4a23efdf0da9 707 std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
bogdanm 1:4a23efdf0da9 708 DBG("+CMS ERROR: %d result received", m_transactionResult.code);
bogdanm 1:4a23efdf0da9 709 m_transactionResult.result = ATResult::AT_CMS_ERROR;
bogdanm 1:4a23efdf0da9 710 m_transactionState = IDLE;
bogdanm 1:4a23efdf0da9 711 int* msg = m_AT2Env.alloc(osWaitForever);
bogdanm 1:4a23efdf0da9 712 *msg = AT_RESULT_READY;
bogdanm 1:4a23efdf0da9 713 m_AT2Env.put(msg); //Command has been processed
bogdanm 1:4a23efdf0da9 714 return OK;
bogdanm 1:4a23efdf0da9 715 }
bogdanm 1:4a23efdf0da9 716 else
bogdanm 1:4a23efdf0da9 717 {
bogdanm 1:4a23efdf0da9 718 DBG("Unprocessed result received: '%s'", m_inputBuf);
bogdanm 1:4a23efdf0da9 719 //Must call transaction processor to complete line processing
bogdanm 1:4a23efdf0da9 720 int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called
bogdanm 1:4a23efdf0da9 721 return ret;
bogdanm 1:4a23efdf0da9 722 }
bogdanm 1:4a23efdf0da9 723 }
bogdanm 1:4a23efdf0da9 724
bogdanm 1:4a23efdf0da9 725 return OK;
bogdanm 1:4a23efdf0da9 726 }
bogdanm 1:4a23efdf0da9 727
bogdanm 1:4a23efdf0da9 728 int ATCommandsInterface::processEntryPrompt()
bogdanm 1:4a23efdf0da9 729 {
bogdanm 1:4a23efdf0da9 730 DBG("Calling prompt handler");
bogdanm 1:4a23efdf0da9 731 int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called
bogdanm 1:4a23efdf0da9 732
bogdanm 1:4a23efdf0da9 733 if( ret != NET_MOREINFO ) //A new prompt is expected
bogdanm 1:4a23efdf0da9 734 {
bogdanm 1:4a23efdf0da9 735 DBG("Sending break character");
bogdanm 1:4a23efdf0da9 736 //Send CTRL+Z (break sequence) to exit prompt
bogdanm 1:4a23efdf0da9 737 char seq[2] = {BRK, 0x00};
bogdanm 1:4a23efdf0da9 738 sendData(seq);
bogdanm 1:4a23efdf0da9 739 }
bogdanm 1:4a23efdf0da9 740 return OK;
bogdanm 1:4a23efdf0da9 741 }
bogdanm 1:4a23efdf0da9 742
bogdanm 1:4a23efdf0da9 743 //This will be called on initialization & after the execution of a command
bogdanm 1:4a23efdf0da9 744 void ATCommandsInterface::enableEvents()
bogdanm 1:4a23efdf0da9 745 {
bogdanm 1:4a23efdf0da9 746 //Advertize this to events handlers
bogdanm 1:4a23efdf0da9 747 m_eventsMgmtMtx.lock();
bogdanm 1:4a23efdf0da9 748 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
bogdanm 1:4a23efdf0da9 749 {
bogdanm 1:4a23efdf0da9 750 if( m_eventsHandlers[i] != NULL )
bogdanm 1:4a23efdf0da9 751 {
bogdanm 1:4a23efdf0da9 752 m_eventsHandlers[i]->onDispatchStart();
bogdanm 1:4a23efdf0da9 753 //Enable this kind of events
bogdanm 1:4a23efdf0da9 754 if(m_eventsHandlers[i]->getEventsEnableCommand() != NULL)
bogdanm 1:4a23efdf0da9 755 {
bogdanm 1:4a23efdf0da9 756 int ret = executeInternal(m_eventsHandlers[i]->getEventsEnableCommand(), this, NULL); //Execute enable command
bogdanm 1:4a23efdf0da9 757 if(ret)
bogdanm 1:4a23efdf0da9 758 {
bogdanm 1:4a23efdf0da9 759 WARN("Events enabling command failed");
bogdanm 1:4a23efdf0da9 760 }
bogdanm 1:4a23efdf0da9 761 }
bogdanm 1:4a23efdf0da9 762 }
bogdanm 1:4a23efdf0da9 763 }
bogdanm 1:4a23efdf0da9 764 m_eventsMgmtMtx.unlock();
bogdanm 1:4a23efdf0da9 765 }
bogdanm 1:4a23efdf0da9 766
bogdanm 1:4a23efdf0da9 767 //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 768 void ATCommandsInterface::disableEvents()
bogdanm 1:4a23efdf0da9 769 {
bogdanm 1:4a23efdf0da9 770 //Advertize this to events handlers
bogdanm 1:4a23efdf0da9 771 m_eventsMgmtMtx.lock();
bogdanm 1:4a23efdf0da9 772 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
bogdanm 1:4a23efdf0da9 773 {
bogdanm 1:4a23efdf0da9 774 if( m_eventsHandlers[i] != NULL )
bogdanm 1:4a23efdf0da9 775 {
bogdanm 1:4a23efdf0da9 776 m_eventsHandlers[i]->onDispatchStart();
bogdanm 1:4a23efdf0da9 777 //Disable this kind of events
bogdanm 1:4a23efdf0da9 778 if(m_eventsHandlers[i]->getEventsDisableCommand() != NULL)
bogdanm 1:4a23efdf0da9 779 {
bogdanm 1:4a23efdf0da9 780 int ret = executeInternal(m_eventsHandlers[i]->getEventsDisableCommand(), this, NULL); //Execute disable command
bogdanm 1:4a23efdf0da9 781 if(ret)
bogdanm 1:4a23efdf0da9 782 {
bogdanm 1:4a23efdf0da9 783 WARN("Events disabling command failed");
bogdanm 1:4a23efdf0da9 784 }
bogdanm 1:4a23efdf0da9 785 }
bogdanm 1:4a23efdf0da9 786 }
bogdanm 1:4a23efdf0da9 787 }
bogdanm 1:4a23efdf0da9 788 m_eventsMgmtMtx.unlock();
bogdanm 1:4a23efdf0da9 789 }
bogdanm 1:4a23efdf0da9 790
bogdanm 1:4a23efdf0da9 791 //Commands that can be called during onNewATResponseLine callback, additionally to close()
bogdanm 1:4a23efdf0da9 792 //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
bogdanm 1:4a23efdf0da9 793 int ATCommandsInterface::sendData(const char* data)
bogdanm 1:4a23efdf0da9 794 {
bogdanm 1:4a23efdf0da9 795 //m_inputBuf is cleared at this point (and MUST therefore be empty)
bogdanm 1:4a23efdf0da9 796 int dataLen = strlen(data);
bogdanm 1:4a23efdf0da9 797 DBG("Sending raw string of length %d", dataLen);
bogdanm 1:4a23efdf0da9 798 int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever);
bogdanm 1:4a23efdf0da9 799 if(ret)
bogdanm 1:4a23efdf0da9 800 {
bogdanm 1:4a23efdf0da9 801 WARN("Could not write to stream (returned %d)", ret);
bogdanm 1:4a23efdf0da9 802 return ret;
bogdanm 1:4a23efdf0da9 803 }
bogdanm 1:4a23efdf0da9 804
bogdanm 1:4a23efdf0da9 805 int dataPos = 0;
bogdanm 1:4a23efdf0da9 806 do
bogdanm 1:4a23efdf0da9 807 {
bogdanm 1:4a23efdf0da9 808 //Read echo
bogdanm 1:4a23efdf0da9 809 size_t readLen;
bogdanm 1:4a23efdf0da9 810 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 811 if(ret)
bogdanm 1:4a23efdf0da9 812 {
bogdanm 1:4a23efdf0da9 813 WARN("Could not read from stream (returned %d)", ret);
bogdanm 1:4a23efdf0da9 814 m_inputPos = 0; //Reset input buffer state
bogdanm 1:4a23efdf0da9 815 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 816 return ret;
bogdanm 1:4a23efdf0da9 817 }
bogdanm 1:4a23efdf0da9 818
bogdanm 1:4a23efdf0da9 819 if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 )
bogdanm 1:4a23efdf0da9 820 {
bogdanm 1:4a23efdf0da9 821 //Echo does not match output
bogdanm 1:4a23efdf0da9 822 m_inputBuf[readLen] = '\0';
bogdanm 1:4a23efdf0da9 823 WARN("Echo does not match output, got '%s' instead", m_inputBuf);
bogdanm 1:4a23efdf0da9 824 m_inputPos = 0; //Reset input buffer state
bogdanm 1:4a23efdf0da9 825 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 826 return NET_DIFF;
bogdanm 1:4a23efdf0da9 827 }
bogdanm 1:4a23efdf0da9 828
bogdanm 1:4a23efdf0da9 829 dataPos += readLen;
bogdanm 1:4a23efdf0da9 830 //If all characters have not been read yet
bogdanm 1:4a23efdf0da9 831
bogdanm 1:4a23efdf0da9 832 } while(dataPos < dataLen);
bogdanm 1:4a23efdf0da9 833
bogdanm 1:4a23efdf0da9 834 DBG("String sent successfully");
bogdanm 1:4a23efdf0da9 835
bogdanm 1:4a23efdf0da9 836 m_inputPos = 0; //Reset input buffer state
bogdanm 1:4a23efdf0da9 837 m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
bogdanm 1:4a23efdf0da9 838
bogdanm 1:4a23efdf0da9 839 return OK;
bogdanm 1:4a23efdf0da9 840 }
bogdanm 1:4a23efdf0da9 841
bogdanm 1:4a23efdf0da9 842 /*static*/ void ATCommandsInterface::staticCallback(void const* p)
bogdanm 1:4a23efdf0da9 843 {
bogdanm 1:4a23efdf0da9 844 ((ATCommandsInterface*)p)->process();
bogdanm 1:4a23efdf0da9 845 }
bogdanm 1:4a23efdf0da9 846
bogdanm 1:4a23efdf0da9 847 int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper
bogdanm 1:4a23efdf0da9 848 {
bogdanm 1:4a23efdf0da9 849 if(result.result == ATResult::AT_OK)
bogdanm 1:4a23efdf0da9 850 {
bogdanm 1:4a23efdf0da9 851 return OK;
bogdanm 1:4a23efdf0da9 852 }
bogdanm 1:4a23efdf0da9 853 else
bogdanm 1:4a23efdf0da9 854 {
bogdanm 1:4a23efdf0da9 855 return NET_MOREINFO;
bogdanm 1:4a23efdf0da9 856 }
bogdanm 1:4a23efdf0da9 857 }
bogdanm 1:4a23efdf0da9 858
bogdanm 1:4a23efdf0da9 859 /*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling
bogdanm 1:4a23efdf0da9 860 {
bogdanm 1:4a23efdf0da9 861 return OK;
bogdanm 1:4a23efdf0da9 862 }
bogdanm 1:4a23efdf0da9 863
bogdanm 1:4a23efdf0da9 864 /*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away)
bogdanm 1:4a23efdf0da9 865 {
bogdanm 1:4a23efdf0da9 866 return OK;
bogdanm 1:4a23efdf0da9 867 }
bogdanm 1:4a23efdf0da9 868
bogdanm 1:4a23efdf0da9 869 void ATCommandsInterface::process() //Processing thread
bogdanm 1:4a23efdf0da9 870 {
bogdanm 1:4a23efdf0da9 871 DBG("AT Thread started");
bogdanm 1:4a23efdf0da9 872 while(true)
bogdanm 1:4a23efdf0da9 873 {
bogdanm 1:4a23efdf0da9 874 DBG("AT Processing on hold");
bogdanm 1:4a23efdf0da9 875 m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started
bogdanm 1:4a23efdf0da9 876
bogdanm 1:4a23efdf0da9 877 m_processingMtx.lock();
bogdanm 1:4a23efdf0da9 878 DBG("AT Processing started");
bogdanm 1:4a23efdf0da9 879 //First of all discard buffer
bogdanm 1:4a23efdf0da9 880 int ret;
bogdanm 1:4a23efdf0da9 881 size_t readLen;
bogdanm 1:4a23efdf0da9 882 do //Drop everything
bogdanm 1:4a23efdf0da9 883 {
bogdanm 1:4a23efdf0da9 884 ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point
bogdanm 1:4a23efdf0da9 885 } while(ret == OK);
bogdanm 1:4a23efdf0da9 886 m_inputPos = 0; //Clear input buffer
bogdanm 1:4a23efdf0da9 887 do
bogdanm 1:4a23efdf0da9 888 {
bogdanm 1:4a23efdf0da9 889 DBG("Trying to send a pending command");
bogdanm 1:4a23efdf0da9 890 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 891 DBG("Trying to read a new line");
bogdanm 1:4a23efdf0da9 892 tryReadLine();
bogdanm 1:4a23efdf0da9 893 } while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted
bogdanm 1:4a23efdf0da9 894 m_processingMtx.unlock();
bogdanm 1:4a23efdf0da9 895 DBG("AT Processing stopped");
bogdanm 1:4a23efdf0da9 896 }
bogdanm 1:4a23efdf0da9 897 }
bogdanm 1:4a23efdf0da9 898