Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ATCommandsInterface.cpp
00001 /* ATCommandsInterface.cpp */ 00002 /* 00003 Copyright (C) 2012 ARM Limited. 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy of 00006 this software and associated documentation files (the "Software"), to deal in 00007 the Software without restriction, including without limitation the rights to 00008 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 00009 of the Software, and to permit persons to whom the Software is furnished to do 00010 so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in all 00013 copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00021 SOFTWARE. 00022 */ 00023 00024 #define __DEBUG__ 4//2//ERR+WARN 00025 #ifndef __MODULE__ 00026 #define __MODULE__ "ATCommandsInterface.cpp" 00027 #endif 00028 00029 #include "core/fwk.h" 00030 00031 #include <cstdio> 00032 //#include <cstring> //For memset, strstr... 00033 00034 using std::memmove; 00035 00036 #include "ATCommandsInterface.h" 00037 00038 ATCommandsInterface::ATCommandsInterface(IOStream* pStream) : 00039 m_pStream(pStream), m_open(false), m_env2AT(), m_AT2Env(), m_processingMtx(), 00040 m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192), 00041 m_eventsMtx() 00042 { 00043 memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*)); 00044 00045 m_processingMtx.lock(); 00046 } 00047 00048 //Open connection to AT Interface in order to execute command & register/unregister events 00049 int ATCommandsInterface::open() 00050 { 00051 if( m_open ) 00052 { 00053 WARN("AT interface is already open"); 00054 return OK; 00055 } 00056 DBG("Opening AT interface"); 00057 //Start processing 00058 m_processingThread.signal_set(AT_SIG_PROCESSING_START); 00059 00060 m_processingMtx.unlock(); 00061 00062 m_open = true; 00063 00064 //Advertize this to events handlers 00065 m_eventsMtx.lock(); 00066 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot 00067 { 00068 if( m_eventsHandlers[i] != NULL ) 00069 { 00070 m_eventsHandlers[i]->onDispatchStart(); 00071 } 00072 } 00073 m_eventsMtx.unlock(); 00074 00075 DBG("AT interface opened"); 00076 00077 return OK; 00078 } 00079 00080 //Initialize AT link 00081 int ATCommandsInterface::init() 00082 { 00083 DBG("Sending ATZ E1 V1"); 00084 //Should we flush m_pStream at this point ??? 00085 int err; 00086 int tries = 5; 00087 do 00088 { 00089 err = executeSimple("ATZ E1 V1", NULL, 3000); //Enable echo and verbosity 00090 if(err && tries) 00091 { 00092 WARN("No response, trying again"); 00093 Thread::wait(1000); //Give dongle time to recover 00094 } 00095 } while(err && tries--); 00096 if( err ) 00097 { 00098 ERR("Sending ATZ E1 V1 returned with err code %d", err); 00099 return err; 00100 } 00101 00102 DBG("AT interface initialized"); 00103 00104 return OK; 00105 } 00106 00107 //Close connection 00108 int ATCommandsInterface::close() 00109 { 00110 if( !m_open ) 00111 { 00112 WARN("AT interface is already closed"); 00113 return OK; 00114 } 00115 00116 DBG("Closing AT interface"); 00117 00118 //Stop processing 00119 m_processingThread.signal_set(AT_SIG_PROCESSING_STOP); 00120 //m_stopSphre.release(); 00121 00122 int* msg = m_env2AT.alloc(osWaitForever); 00123 *msg = AT_STOP; 00124 m_env2AT.put(msg); //Used to unstall the process if needed 00125 00126 //Unlock process routine (abort read) 00127 m_pStream->abortRead(); //This is thread-safe 00128 m_processingMtx.lock(); 00129 m_open = false; 00130 00131 //Advertize this to events handlers 00132 m_eventsMtx.lock(); 00133 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot 00134 { 00135 if( m_eventsHandlers[i] != NULL ) 00136 { 00137 m_eventsHandlers[i]->onDispatchStop(); 00138 } 00139 } 00140 m_eventsMtx.unlock(); 00141 00142 DBG("AT interface closed"); 00143 return OK; 00144 } 00145 00146 bool ATCommandsInterface::isOpen() 00147 { 00148 return m_open; 00149 } 00150 00151 int ATCommandsInterface::executeSimple(const char* command, ATResult* pResult, uint32_t timeout/*=1000*/) 00152 { 00153 return execute(command, this, pResult, timeout); 00154 } 00155 00156 int ATCommandsInterface::execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/) 00157 { 00158 DBG("Executing command %s", command); 00159 if(!m_open) 00160 { 00161 WARN("Interface is not open!"); 00162 return NET_INVALID; 00163 } 00164 00165 //Lock transaction mutex 00166 m_transactionMtx.lock(); 00167 00168 //Discard previous result if it arrived too late 00169 osEvent evt = m_AT2Env.get(0); 00170 00171 if(evt.status == osEventMail) 00172 { 00173 m_AT2Env.free((int*)evt.value.p); 00174 WARN("Previous result discarded"); 00175 } 00176 00177 //Send params to the process routine 00178 m_transactionCommand = command; 00179 if(pProcessor != NULL) 00180 { 00181 m_pTransactionProcessor = pProcessor; 00182 } 00183 else 00184 { 00185 m_pTransactionProcessor = this; //Use default behaviour 00186 } 00187 00188 Thread::wait(100); //FIXME find stg else 00189 00190 DBG("Sending command ready signal to AT thread & aborting current blocking read operation"); 00191 00192 //Produce command ready signal 00193 int* msg = m_env2AT.alloc(osWaitForever); 00194 *msg = AT_CMD_READY; 00195 m_env2AT.put(msg); 00196 00197 DBG("Trying to enter abortRead()"); 00198 //Unlock process routine (abort read) 00199 m_pStream->abortRead(); //This is thread-safe 00200 00201 //Wait for a result (get result message) 00202 evt = m_AT2Env.get(timeout); 00203 00204 if(evt.status != osEventMail) 00205 { 00206 //Cancel request 00207 msg = m_env2AT.alloc(osWaitForever); 00208 *msg = AT_TIMEOUT; 00209 m_env2AT.put(msg); 00210 00211 DBG("Trying to enter abortRead()"); 00212 //Unlock process routine (abort read) 00213 m_pStream->abortRead(); //This is thread-safe 00214 00215 WARN("Command returned no message"); 00216 m_transactionMtx.unlock(); 00217 return NET_TIMEOUT; 00218 } 00219 DBG("Command returned with message %d", *msg); 00220 00221 m_AT2Env.free((int*)evt.value.p); 00222 00223 if(pResult != NULL) 00224 { 00225 *pResult = m_transactionResult; 00226 } 00227 00228 int ret = ATResultToReturnCode(m_transactionResult); 00229 if(ret != OK) 00230 { 00231 WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code); 00232 } 00233 00234 DBG("Command returned successfully"); 00235 00236 //Unlock transaction mutex 00237 m_transactionMtx.unlock(); 00238 00239 return ret; 00240 } 00241 00242 int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr) 00243 { 00244 m_eventsMtx.lock(); 00245 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot 00246 { 00247 if( m_eventsHandlers[i] == NULL ) 00248 { 00249 m_eventsHandlers[i] = pHdlr; 00250 m_eventsMtx.unlock(); 00251 return OK; 00252 } 00253 } 00254 m_eventsMtx.unlock(); 00255 return NET_OOM; //No room left 00256 } 00257 00258 int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr) 00259 { 00260 m_eventsMtx.lock(); 00261 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find handler in list 00262 { 00263 if( m_eventsHandlers[i] == pHdlr ) 00264 { 00265 m_eventsHandlers[i] = NULL; 00266 m_eventsMtx.unlock(); 00267 return OK; 00268 } 00269 } 00270 m_eventsMtx.unlock(); 00271 return NET_NOTFOUND; //Not found 00272 } 00273 00274 00275 int ATCommandsInterface::tryReadLine() 00276 { 00277 static bool lineDetected = false; 00278 00279 //Block on serial read or incoming command 00280 DBG("Trying to read a new line from stream"); 00281 int ret = m_pStream->waitAvailable(); //This can be aborted 00282 size_t readLen = 0; 00283 if(ret == OK) 00284 { 00285 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 00286 } 00287 if(ret == OK) 00288 { 00289 m_inputPos+=readLen; 00290 m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions 00291 DBG("In buffer: [%s]", m_inputBuf); 00292 } 00293 00294 if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted 00295 { 00296 DBG("Read was interrupted"); 00297 return NET_INTERRUPTED; //0 chars were read 00298 } 00299 else if(readLen == 0) 00300 { 00301 DBG("Nothing read"); 00302 return OK; //0 chars were read 00303 } 00304 00305 DBG("Trying to process incoming line"); 00306 bool lineProcessed = false; 00307 00308 do 00309 { 00310 lineProcessed = false; //Reset flag 00311 00312 DBG("New iteration"); 00313 00314 //Look for a new line 00315 if(!lineDetected) 00316 { 00317 DBG("No line detected yet"); 00318 //Try to look for a starting CRLF 00319 char* crPtr = strchr(m_inputBuf, CR); 00320 /* 00321 Different cases at this point: 00322 - CRLF%c sequence: this is the start of a line 00323 - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one) 00324 - LF: this is the trailing LF char of the previous line, discard 00325 - CR / CRLF incomplete sequence: more data is needed to determine which action to take 00326 - %c ... CR sequence: this should be the echo of the previous sequence 00327 - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take 00328 00329 In every case, move mem at the beginning 00330 */ 00331 if(crPtr != NULL) 00332 { 00333 DBG("CR char found"); 00334 00335 #if 0 00336 //Discard all preceding characters (can do nothing if m_inputBuf == crPtr) 00337 memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well 00338 m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos 00339 #endif 00340 00341 //If the line starts with CR, this should be a result code 00342 if( crPtr == m_inputBuf ) 00343 { 00344 //To determine the sequence we need at least 3 chars 00345 if(m_inputPos >= 3) 00346 { 00347 //Look for a LF char next to the CR char 00348 if(m_inputBuf[1] == LF) 00349 { 00350 //At this point we can check whether this is the end of a preceding line or the beginning of a new one 00351 if(m_inputBuf[2] != CR) 00352 { 00353 DBG("Beginning of new line found"); 00354 //Beginning of a line 00355 lineDetected = true; //Move to next state-machine step 00356 } 00357 else 00358 { 00359 //End of an unprocessed line 00360 WARN("End of unprocessed line"); 00361 } 00362 //In both cases discard CRLF 00363 DBG("Discarding CRLF"); 00364 memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well 00365 m_inputPos = m_inputPos - 2; //Adjust m_inputPos 00366 } 00367 else 00368 { 00369 //This is completely unexpected, discard the CR char to try to recover good state 00370 WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]); 00371 memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well 00372 m_inputPos = m_inputPos - 1; //Adjust m_inputPos 00373 } 00374 } 00375 } 00376 //if the line does NOT begin with CR, this can be an echo of the previous command, process it 00377 else 00378 { 00379 int crPos = crPtr - m_inputBuf; 00380 int lfOff = 0; //Offset for LF if present 00381 DBG("New line found (possible echo of command)"); 00382 //This is the end of line 00383 //Replace m_inputBuf[crPos] with null-terminating char 00384 m_inputBuf[crPos] = '\0'; 00385 //Check if there is a LF char afterwards 00386 if(m_inputPos - crPos >= 1) 00387 { 00388 if(m_inputBuf[crPos+1] == LF) 00389 { 00390 lfOff++; //We will discard LF char as well 00391 } 00392 } 00393 //Process line 00394 processReadLine(); 00395 //Shift remaining data to beginning of buffer 00396 memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well 00397 m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos 00398 DBG("One line was successfully processed"); 00399 lineProcessed = true; //Line was processed with success 00400 lineDetected = false; //Search now for a new line 00401 } 00402 } 00403 else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it 00404 { 00405 DBG("Discarding single LF char"); 00406 memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well 00407 m_inputPos = m_inputPos - 1; //Adjust m_inputPos 00408 } 00409 } 00410 00411 //Look for the end of line 00412 if(lineDetected) 00413 { 00414 DBG("Looking for end of line"); 00415 //Try to look for a terminating CRLF 00416 char* crPtr = strchr(m_inputBuf, CR); 00417 /* 00418 Different cases at this point: 00419 - CRLF sequence: this is the end of the line 00420 - CR%c sequence : unexpected 00421 - CR incomplete sequence: more data is needed to determine which action to take 00422 */ 00423 00424 //Try to look for a '>' (greater than character) that marks an entry prompt 00425 char* greaterThanPtr = strchr(m_inputBuf, GD); 00426 /* 00427 This character must be detected as there is no CRLF sequence at the end of an entry prompt 00428 */ 00429 00430 if(crPtr != NULL) 00431 { 00432 DBG("CR char found"); 00433 int crPos = crPtr - m_inputBuf; 00434 //To determine the sequence we need at least 2 chars 00435 if(m_inputPos - crPos >= 2) 00436 { 00437 //Look for a LF char next to the CR char 00438 if(m_inputBuf[crPos + 1] == LF) 00439 { 00440 DBG("End of new line found"); 00441 //This is the end of line 00442 //Replace m_inputBuf[crPos] with null-terminating char 00443 m_inputBuf[crPos] = '\0'; 00444 //Process line 00445 int ret = processReadLine(); 00446 if(ret) 00447 { 00448 m_inputPos = 0; 00449 lineDetected = false; 00450 return ret; 00451 } 00452 00453 //If sendData has been called, all incoming data has been discarded 00454 if(m_inputPos > 0) 00455 { 00456 //Shift remaining data to beginning of buffer 00457 memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well 00458 m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos 00459 } 00460 00461 DBG("One line was successfully processed"); 00462 lineProcessed = true; //Line was processed with success 00463 } 00464 else 00465 { 00466 //This is completely unexpected, discard all chars till the CR char to try to recover good state 00467 WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]); 00468 memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well 00469 m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos 00470 } 00471 lineDetected = false; //In both case search now for a new line 00472 } 00473 } 00474 else if(greaterThanPtr != NULL) 00475 { 00476 DBG("> char found"); 00477 int gdPos = greaterThanPtr - m_inputBuf; 00478 //To determine the sequence we need at least 2 chars 00479 if(m_inputPos - gdPos >= 2) 00480 { 00481 //Look for a space char next to the GD char 00482 if(m_inputBuf[gdPos + 1] == ' ') 00483 { 00484 //This is an entry prompt 00485 //Replace m_inputBuf[gdPos] with null-terminating char 00486 m_inputBuf[gdPos] = '\0'; 00487 00488 //Shift remaining data to beginning of buffer 00489 memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well 00490 m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos 00491 00492 //Process prompt 00493 ret = processEntryPrompt(); 00494 if(ret) 00495 { 00496 m_inputPos = 0; 00497 lineDetected = false; 00498 return ret; 00499 } 00500 00501 DBG("One line was successfully processed"); 00502 lineProcessed = true; //Line was processed with success 00503 } 00504 else 00505 { 00506 //This is completely unexpected, discard all chars till the GD char to try to recover good state 00507 WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]); 00508 memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well 00509 m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos 00510 } 00511 lineDetected = false; //In both case search now for a new line 00512 } 00513 } 00514 } 00515 } while(lineProcessed); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again 00516 00517 //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) 00518 if(m_inputPos == AT_INPUT_BUF_SIZE - 1) 00519 { 00520 //Discard everything 00521 m_inputPos = 0; 00522 WARN("Incoming buffer is too short to process incoming line"); 00523 //Look for a new line 00524 lineDetected = false; 00525 } 00526 00527 DBG("Processed every full incoming lines"); 00528 00529 return OK; 00530 } 00531 00532 int ATCommandsInterface::trySendCommand() 00533 { 00534 osEvent evt = m_env2AT.get(0); 00535 DBG("status = %d, msg = %d", evt.status, evt.value.p); 00536 if(evt.status == osEventMail) 00537 { 00538 int* msg = (int*) evt.value.p; 00539 if( *msg == AT_CMD_READY ) //Command pending 00540 { 00541 if(m_transactionState != IDLE) 00542 { 00543 WARN("Previous command not processed!"); 00544 } 00545 DBG("Sending pending command"); 00546 m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever); 00547 char cr = CR; 00548 m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator 00549 m_transactionState = COMMAND_SENT; 00550 } 00551 else 00552 { 00553 m_transactionState = IDLE; //State-machine reset 00554 } 00555 m_env2AT.free(msg); 00556 } 00557 return OK; 00558 } 00559 00560 int ATCommandsInterface::processReadLine() 00561 { 00562 DBG("Processing read line [%s]", m_inputBuf); 00563 //The line is stored in m_inputBuf 00564 if(m_transactionState == COMMAND_SENT) 00565 { 00566 //If the command has been sent, checks echo to see if it has been received properly 00567 if( strcmp(m_transactionCommand, m_inputBuf) == 0 ) 00568 { 00569 DBG("Command echo received"); 00570 //If so, it means that the following lines will only be solicited results 00571 m_transactionState = READING_RESULT; 00572 return OK; 00573 } 00574 } 00575 if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT) 00576 { 00577 bool found = false; 00578 char* pSemicol = strchr(m_inputBuf, ':'); 00579 char* pData = NULL; 00580 if( pSemicol != NULL ) //Split the identifier & the result code (if it exists) 00581 { 00582 *pSemicol = '\0'; 00583 pData = pSemicol + 1; 00584 if(pData[0]==' ') 00585 { 00586 pData++; //Suppress whitespace 00587 } 00588 } 00589 //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 00590 m_eventsMtx.lock(); 00591 //Go through the list 00592 for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot 00593 { 00594 if( m_eventsHandlers[i] != NULL ) 00595 { 00596 if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) ) 00597 { 00598 m_eventsHandlers[i]->onEvent(m_inputBuf, pData); 00599 found = true; //Do not break here as there might be multiple handlers for one event type 00600 } 00601 } 00602 } 00603 m_eventsMtx.unlock(); 00604 if(found) 00605 { 00606 return OK; 00607 } 00608 } 00609 if(m_transactionState == READING_RESULT) 00610 { 00611 //The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s) 00612 if(strcmp("OK", m_inputBuf) == 0) 00613 { 00614 DBG("OK result received"); 00615 m_transactionResult.code = 0; 00616 m_transactionResult.result = ATResult::AT_OK; 00617 m_transactionState = IDLE; 00618 int* msg = m_AT2Env.alloc(osWaitForever); 00619 *msg = AT_RESULT_READY; 00620 m_AT2Env.put(msg); //Command has been processed 00621 return OK; 00622 } 00623 else if(strcmp("ERROR", m_inputBuf) == 0) 00624 { 00625 DBG("ERROR result received"); 00626 m_transactionResult.code = 0; 00627 m_transactionResult.result = ATResult::AT_ERROR; 00628 m_transactionState = IDLE; 00629 int* msg = m_AT2Env.alloc(osWaitForever); 00630 *msg = AT_RESULT_READY; 00631 m_AT2Env.put(msg); //Command has been processed 00632 return OK; 00633 } 00634 else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate 00635 { 00636 DBG("CONNECT result received"); 00637 m_transactionResult.code = 0; 00638 m_transactionResult.result = ATResult::AT_CONNECT; 00639 m_transactionState = IDLE; 00640 int* msg = m_AT2Env.alloc(osWaitForever); 00641 *msg = AT_RESULT_READY; 00642 m_AT2Env.put(msg); //Command has been processed 00643 return OK; 00644 } 00645 else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized 00646 { 00647 DBG("COMMAND NOT SUPPORT result received"); 00648 m_transactionResult.code = 0; 00649 m_transactionResult.result = ATResult::AT_ERROR; 00650 m_transactionState = IDLE; 00651 int* msg = m_AT2Env.alloc(osWaitForever); 00652 *msg = AT_RESULT_READY; 00653 m_AT2Env.put(msg); //Command has been processed 00654 return OK; 00655 } 00656 else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error 00657 { 00658 std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code); 00659 DBG("+CME ERROR: %d result received", m_transactionResult.code); 00660 m_transactionResult.result = ATResult::AT_CME_ERROR; 00661 m_transactionState = IDLE; 00662 int* msg = m_AT2Env.alloc(osWaitForever); 00663 *msg = AT_RESULT_READY; 00664 m_AT2Env.put(msg); //Command has been processed 00665 return OK; 00666 } 00667 else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error 00668 { 00669 std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code); 00670 DBG("+CMS ERROR: %d result received", m_transactionResult.code); 00671 m_transactionResult.result = ATResult::AT_CMS_ERROR; 00672 m_transactionState = IDLE; 00673 int* msg = m_AT2Env.alloc(osWaitForever); 00674 *msg = AT_RESULT_READY; 00675 m_AT2Env.put(msg); //Command has been processed 00676 return OK; 00677 } 00678 else 00679 { 00680 DBG("Unprocessed result received: '%s'", m_inputBuf); 00681 //Must call transaction processor to complete line processing 00682 int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called 00683 return ret; 00684 } 00685 } 00686 00687 return OK; 00688 } 00689 00690 int ATCommandsInterface::processEntryPrompt() 00691 { 00692 DBG("Calling prompt handler"); 00693 int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called 00694 00695 if( ret != NET_MOREINFO ) //A new prompt is expected 00696 { 00697 DBG("Sending break character"); 00698 //Send CTRL+Z (break sequence) to exit prompt 00699 char seq[2] = {BRK, 0x00}; 00700 sendData(seq); 00701 } 00702 return OK; 00703 } 00704 00705 //Commands that can be called during onNewATResponseLine callback, additionally to close() 00706 //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution) 00707 int ATCommandsInterface::sendData(const char* data) 00708 { 00709 //m_inputBuf is cleared at this point (and MUST therefore be empty) 00710 int dataLen = strlen(data); 00711 DBG("Sending raw string of length %d", dataLen); 00712 int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever); 00713 if(ret) 00714 { 00715 WARN("Could not write to stream (returned %d)", ret); 00716 return ret; 00717 } 00718 00719 int dataPos = 0; 00720 do 00721 { 00722 //Read echo 00723 size_t readLen; 00724 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 00725 if(ret) 00726 { 00727 WARN("Could not read from stream (returned %d)", ret); 00728 return ret; 00729 }; 00730 00731 if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 ) 00732 { 00733 //Echo does not match output 00734 WARN("Echo does not match output"); 00735 return NET_DIFF; 00736 } 00737 00738 dataPos += readLen; 00739 //If all characters have not been read yet 00740 00741 } while(dataPos < dataLen); 00742 00743 DBG("String sent successfully"); 00744 00745 m_inputPos = 0; //Reset input buffer state 00746 00747 return OK; 00748 } 00749 00750 /*static*/ void ATCommandsInterface::staticCallback(void const* p) 00751 { 00752 ((ATCommandsInterface*)p)->process(); 00753 } 00754 00755 int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper 00756 { 00757 if(result.result == ATResult::AT_OK) 00758 { 00759 return OK; 00760 } 00761 else 00762 { 00763 return NET_MOREINFO; 00764 } 00765 } 00766 00767 /*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling 00768 { 00769 return OK; 00770 } 00771 00772 /*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away) 00773 { 00774 return OK; 00775 } 00776 00777 void ATCommandsInterface::process() //Processing thread 00778 { 00779 DBG("AT Thread started"); 00780 while(true) 00781 { 00782 DBG("AT Processing on hold"); 00783 m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started 00784 00785 m_processingMtx.lock(); 00786 DBG("AT Processing started"); 00787 //First of all discard buffer 00788 int ret; 00789 size_t readLen; 00790 do //Drop everything 00791 { 00792 ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point 00793 } while(ret == OK); 00794 m_inputPos = 0; //Clear input buffer 00795 do 00796 { 00797 DBG("Trying to read a new line"); 00798 tryReadLine(); 00799 DBG("Trying to send a pending command"); 00800 trySendCommand(); 00801 } while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted 00802 m_processingMtx.unlock(); 00803 DBG("AT Processing stopped"); 00804 } 00805 } 00806
Generated on Tue Jul 12 2022 17:50:55 by
