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.
ATHandler.cpp
00001 /* 00002 * Copyright (c) 2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "ATHandler.h" 00019 #include "mbed_poll.h" 00020 #include "FileHandle.h" 00021 #include "Timer.h" 00022 #include "mbed_wait_api.h" 00023 #include "mbed_debug.h" 00024 #ifdef MBED_CONF_RTOS_PRESENT 00025 #include "rtos/Thread.h" 00026 #endif 00027 #include "Kernel.h" 00028 #include "CellularUtil.h" 00029 00030 using namespace mbed; 00031 using namespace events; 00032 using namespace mbed_cellular_util; 00033 00034 //#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_DEBUG 00035 #include "CellularLog.h" 00036 00037 #if MBED_CONF_MBED_TRACE_ENABLE 00038 #define at_debug(format, ...) do { if (_debug_on) debug(format, ## __VA_ARGS__); } while (0) 00039 #else 00040 #define at_debug(...) 00041 #endif 00042 00043 const char *mbed::OK = "OK\r\n"; 00044 const uint8_t OK_LENGTH = 4; 00045 const char *mbed::CRLF = "\r\n"; 00046 const uint8_t CRLF_LENGTH = 2; 00047 const char *CME_ERROR = "+CME ERROR:"; 00048 const uint8_t CME_ERROR_LENGTH = 11; 00049 const char *CMS_ERROR = "+CMS ERROR:"; 00050 const uint8_t CMS_ERROR_LENGTH = 11; 00051 const char *ERROR_ = "ERROR\r\n"; 00052 const uint8_t ERROR_LENGTH = 7; 00053 const uint8_t MAX_RESP_LENGTH = CMS_ERROR_LENGTH; 00054 const char DEFAULT_DELIMITER = ','; 00055 00056 static const uint8_t map_3gpp_errors[][2] = { 00057 { 103, 3 }, { 106, 6 }, { 107, 7 }, { 108, 8 }, { 111, 11 }, { 112, 12 }, { 113, 13 }, { 114, 14 }, 00058 { 115, 15 }, { 122, 22 }, { 125, 25 }, { 172, 95 }, { 173, 96 }, { 174, 97 }, { 175, 99 }, { 176, 111 }, 00059 { 177, 8 }, { 126, 26 }, { 127, 27 }, { 128, 28 }, { 129, 29 }, { 130, 30 }, { 131, 31 }, { 132, 32 }, 00060 { 133, 33 }, { 134, 34 }, { 140, 40 }, { 141, 41 }, { 142, 42 }, { 143, 43 }, { 144, 44 }, { 145, 45 }, 00061 { 146, 46 }, { 178, 65 }, { 179, 66 }, { 180, 48 }, { 181, 83 }, { 171, 49 }, 00062 }; 00063 00064 ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char *output_delimiter, uint16_t send_delay) : 00065 _nextATHandler(0), 00066 _queue(queue), 00067 _last_err(NSAPI_ERROR_OK ), 00068 _last_3gpp_error(0), 00069 _oob_string_max_length(0), 00070 _oobs(NULL), 00071 _at_timeout(timeout), 00072 _previous_at_timeout(timeout), 00073 _at_send_delay(send_delay), 00074 _last_response_stop(0), 00075 _fh_sigio_set(false), 00076 _processing(false), 00077 _ref_count(1), 00078 _stop_tag(NULL), 00079 _delimiter(DEFAULT_DELIMITER), 00080 _prefix_matched(false), 00081 _urc_matched(false), 00082 _error_found(false), 00083 _max_resp_length(MAX_RESP_LENGTH), 00084 _debug_on(false), 00085 _cmd_start(false) 00086 { 00087 //enable_debug(true); 00088 00089 clear_error(); 00090 00091 if (output_delimiter) { 00092 _output_delimiter = new char[strlen(output_delimiter) + 1]; 00093 if (!_output_delimiter) { 00094 MBED_ASSERT(0); 00095 } else { 00096 memcpy(_output_delimiter, output_delimiter, strlen(output_delimiter) + 1); 00097 } 00098 } else { 00099 _output_delimiter = NULL; 00100 } 00101 00102 reset_buffer(); 00103 memset(_recv_buff, 0, sizeof(_recv_buff)); 00104 memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); 00105 00106 _current_scope = NotSet; 00107 set_tag(&_resp_stop, OK); 00108 set_tag(&_info_stop, CRLF); 00109 set_tag(&_elem_stop, ")"); 00110 00111 set_file_handle(fh); 00112 } 00113 00114 void ATHandler::enable_debug(bool enable) 00115 { 00116 _debug_on = enable; 00117 } 00118 00119 ATHandler::~ATHandler() 00120 { 00121 while (_oobs) { 00122 struct oob_t *oob = _oobs; 00123 _oobs = oob->next; 00124 delete oob; 00125 } 00126 if (_output_delimiter) { 00127 delete [] _output_delimiter; 00128 } 00129 } 00130 00131 void ATHandler::inc_ref_count() 00132 { 00133 _ref_count++; 00134 } 00135 00136 void ATHandler::dec_ref_count() 00137 { 00138 _ref_count--; 00139 } 00140 00141 int ATHandler::get_ref_count() 00142 { 00143 return _ref_count; 00144 } 00145 00146 FileHandle *ATHandler::get_file_handle() 00147 { 00148 return _fileHandle; 00149 } 00150 00151 void ATHandler::set_file_handle(FileHandle *fh) 00152 { 00153 _fh_sigio_set = false; 00154 _fileHandle = fh; 00155 _fileHandle->set_blocking(false); 00156 set_filehandle_sigio(); 00157 } 00158 00159 void ATHandler::set_filehandle_sigio() 00160 { 00161 if (_fh_sigio_set) { 00162 return; 00163 } 00164 00165 _fileHandle->sigio(mbed::Callback<void()>(this, &ATHandler::event)); 00166 _fh_sigio_set = true; 00167 } 00168 00169 nsapi_error_t ATHandler::set_urc_handler(const char *prefix, mbed::Callback<void()> callback) 00170 { 00171 if (find_urc_handler(prefix, callback)) { 00172 tr_warn("URC already added with prefix: %s", prefix); 00173 return NSAPI_ERROR_OK ; 00174 } 00175 00176 struct oob_t *oob = new struct oob_t; 00177 if (!oob) { 00178 return NSAPI_ERROR_NO_MEMORY ; 00179 } else { 00180 size_t prefix_len = strlen(prefix); 00181 if (prefix_len > _oob_string_max_length) { 00182 _oob_string_max_length = prefix_len; 00183 if (_oob_string_max_length > _max_resp_length) { 00184 _max_resp_length = _oob_string_max_length; 00185 } 00186 } 00187 00188 oob->prefix = prefix; 00189 oob->prefix_len = prefix_len; 00190 oob->cb = callback; 00191 oob->next = _oobs; 00192 _oobs = oob; 00193 } 00194 00195 return NSAPI_ERROR_OK ; 00196 } 00197 00198 void ATHandler::remove_urc_handler(const char *prefix, mbed::Callback<void()> callback) 00199 { 00200 struct oob_t *current = _oobs; 00201 struct oob_t *prev = NULL; 00202 while (current) { 00203 if (strcmp(prefix, current->prefix) == 0 && current->cb == callback) { 00204 if (prev) { 00205 prev->next = current->next; 00206 } else { 00207 _oobs = current->next; 00208 } 00209 delete current; 00210 break; 00211 } 00212 prev = current; 00213 current = prev->next; 00214 } 00215 } 00216 00217 bool ATHandler::find_urc_handler(const char *prefix, mbed::Callback<void()> callback) 00218 { 00219 struct oob_t *oob = _oobs; 00220 while (oob) { 00221 if (strcmp(prefix, oob->prefix) == 0 && oob->cb == callback) { 00222 return true; 00223 } 00224 oob = oob->next; 00225 } 00226 00227 return false; 00228 } 00229 00230 void ATHandler::event() 00231 { 00232 // _processing must be set before filehandle write/read to avoid repetitive sigio events 00233 if (!_processing) { 00234 _processing = true; 00235 (void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob)); 00236 } 00237 } 00238 00239 void ATHandler::lock() 00240 { 00241 #ifdef AT_HANDLER_MUTEX 00242 _fileHandleMutex.lock(); 00243 #endif 00244 _processing = true; 00245 clear_error(); 00246 } 00247 00248 void ATHandler::unlock() 00249 { 00250 _processing = false; 00251 #ifdef AT_HANDLER_MUTEX 00252 _fileHandleMutex.unlock(); 00253 #endif 00254 if (_fileHandle->readable() || (_recv_pos < _recv_len)) { 00255 (void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob)); 00256 } 00257 } 00258 00259 nsapi_error_t ATHandler::unlock_return_error() 00260 { 00261 nsapi_error_t err = _last_err; 00262 unlock(); 00263 return err; 00264 } 00265 00266 void ATHandler::set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout) 00267 { 00268 if (default_timeout) { 00269 _previous_at_timeout = timeout_milliseconds; 00270 _at_timeout = timeout_milliseconds; 00271 } else if (timeout_milliseconds != _at_timeout) { 00272 _previous_at_timeout = _at_timeout; 00273 _at_timeout = timeout_milliseconds; 00274 } 00275 } 00276 00277 void ATHandler::restore_at_timeout() 00278 { 00279 if (_previous_at_timeout != _at_timeout) { 00280 _at_timeout =_previous_at_timeout; 00281 } 00282 } 00283 00284 void ATHandler::process_oob() 00285 { 00286 lock(); 00287 tr_debug("process_oob %d", (_fileHandle->readable() || (_recv_pos < _recv_len))); 00288 if (_fileHandle->readable() || (_recv_pos < _recv_len)) { 00289 _current_scope = NotSet; 00290 Timer timer; 00291 timer.start(); 00292 do { 00293 if (match_urc()) { 00294 timer.reset(); 00295 if (_fileHandle->readable() || (_recv_pos < _recv_len)) { 00296 continue; 00297 } 00298 break; 00299 } 00300 // If no match found, look for CRLF and consume everything up to CRLF 00301 if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { 00302 consume_to_tag(CRLF, true); 00303 timer.reset(); 00304 } else { 00305 if (_fileHandle->readable()) { 00306 timer.reset(); 00307 fill_buffer(); 00308 } else { 00309 #ifdef MBED_CONF_RTOS_PRESENT 00310 rtos::Thread::yield(); 00311 #endif 00312 } 00313 } 00314 } while (timer.read_ms() < 100); // URC's are very short 00315 } 00316 tr_debug("process_oob exit"); 00317 00318 flush(); // consume anything that could not be handled 00319 00320 unlock(); 00321 } 00322 00323 void ATHandler::reset_buffer() 00324 { 00325 tr_debug("%s", __func__); 00326 _recv_pos = 0; 00327 _recv_len = 0; 00328 } 00329 00330 void ATHandler::rewind_buffer() 00331 { 00332 tr_debug("%s", __func__); 00333 if (_recv_pos > 0 && _recv_len >= _recv_pos) { 00334 _recv_len -= _recv_pos; 00335 // move what is not read to beginning of buffer 00336 memmove(_recv_buff, _recv_buff + _recv_pos, _recv_len); 00337 _recv_pos = 0; 00338 } 00339 } 00340 00341 // we are always expecting to receive something so there is wait timeout 00342 void ATHandler::fill_buffer() 00343 { 00344 tr_debug("%s", __func__); 00345 // Reset buffer when full 00346 if (sizeof(_recv_buff) == _recv_len) { 00347 reset_buffer(); 00348 } 00349 00350 Timer timer; 00351 timer.start(); 00352 do { 00353 ssize_t len = _fileHandle->read(_recv_buff + _recv_len, sizeof(_recv_buff) - _recv_len); 00354 if (len > 0) { 00355 _recv_len += len; 00356 at_debug("\n----------readable----------: %d\n", _recv_len); 00357 for (size_t i = _recv_pos; i < _recv_len; i++) { 00358 at_debug("%c", _recv_buff[i]); 00359 } 00360 at_debug("\n----------readable----------\n"); 00361 return; 00362 } else if (len != -EAGAIN && len != 0) { 00363 tr_warn("%s error: %d while reading", __func__, len); 00364 break; 00365 } 00366 #ifdef MBED_CONF_RTOS_PRESENT 00367 rtos::Thread::yield(); 00368 #endif 00369 } while ((uint32_t)timer.read_ms() < _at_timeout); 00370 00371 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00372 tr_debug("AT TIMEOUT, scope: %d timeout: %lu", _current_scope, _at_timeout); 00373 } 00374 00375 int ATHandler::get_char() 00376 { 00377 if (_recv_pos == _recv_len) { 00378 tr_debug("%s", __func__); 00379 reset_buffer(); // try to read as much as possible 00380 fill_buffer(); 00381 if (get_last_error()) { 00382 tr_debug("%s: -1", __func__); 00383 return -1; // timeout to read 00384 } 00385 } 00386 00387 tr_debug("%s: %c", __func__, _recv_buff[_recv_pos]); 00388 00389 return _recv_buff[_recv_pos++]; 00390 } 00391 00392 void ATHandler::skip_param(uint32_t count) 00393 { 00394 tr_debug("%s", __func__); 00395 if (_last_err || !_stop_tag || _stop_tag->found) { 00396 return; 00397 } 00398 00399 for (uint32_t i = 0; (i < count && !_stop_tag->found); i++) { 00400 size_t match_pos = 0; 00401 while (true) { 00402 int c = get_char(); 00403 if (c == -1) { 00404 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00405 return; 00406 } else if (c == _delimiter) { 00407 break; 00408 } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { 00409 match_pos++; 00410 if (match_pos == _stop_tag->len) { 00411 _stop_tag->found = true; 00412 break; 00413 } 00414 } else if (match_pos) { 00415 match_pos = 0; 00416 } 00417 } 00418 } 00419 return; 00420 } 00421 00422 void ATHandler::skip_param(ssize_t len, uint32_t count) 00423 { 00424 tr_debug("%s", __func__); 00425 if (_last_err || !_stop_tag || _stop_tag->found) { 00426 return; 00427 } 00428 00429 for (uint32_t i = 0; i < count; i++) { 00430 ssize_t read_len = 0; 00431 while (read_len < len) { 00432 int c = get_char(); 00433 if (c == -1) { 00434 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00435 return; 00436 } 00437 read_len++; 00438 } 00439 } 00440 return; 00441 } 00442 00443 ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len) 00444 { 00445 tr_debug("%s", __func__); 00446 if (_last_err) { 00447 return -1; 00448 } 00449 00450 size_t read_len = 0; 00451 for (; read_len < len; read_len++) { 00452 int c = get_char(); 00453 if (c == -1) { 00454 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00455 return -1; 00456 } 00457 buf[read_len] = c; 00458 } 00459 return read_len; 00460 } 00461 00462 ssize_t ATHandler::read(char *buf, size_t size, bool read_even_stop_tag, bool hex) 00463 { 00464 tr_debug("%s", __func__); 00465 at_debug("\n----------read buff:----------\n"); 00466 for (size_t i = _recv_pos; i < _recv_len; i++) { 00467 at_debug("%c", _recv_buff[i]); 00468 } 00469 at_debug("\n----------read end----------\n"); 00470 00471 if (_last_err || !_stop_tag || (_stop_tag->found && read_even_stop_tag == false)) { 00472 return -1; 00473 } 00474 00475 size_t match_pos = 0; 00476 size_t read_size = hex ? size*2 : size; 00477 00478 consume_char('\"'); 00479 00480 size_t read_idx = 0; 00481 size_t buf_idx = 0; 00482 char hexbuf[2]; 00483 00484 for (; read_idx < (read_size + match_pos); read_idx++) { 00485 int c = get_char(); 00486 buf_idx = hex ? read_idx/2 : read_idx; 00487 if (c == -1) { 00488 buf[buf_idx] = '\0'; 00489 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00490 return -1; 00491 } else if (c == _delimiter) { 00492 buf[buf_idx] = '\0'; 00493 break; 00494 } else if (c == '\"') { 00495 match_pos = 0; 00496 if (read_idx > 0) { 00497 read_idx--; 00498 } 00499 continue; 00500 } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { 00501 match_pos++; 00502 if (match_pos == _stop_tag->len) { 00503 _stop_tag->found = true; 00504 // remove tag from string if it was matched 00505 buf_idx -= (_stop_tag->len - 1); 00506 buf[buf_idx] = '\0'; 00507 break; 00508 } 00509 } else if (match_pos) { 00510 match_pos = 0; 00511 } 00512 00513 if (!hex) { 00514 buf[buf_idx] = c; 00515 } else { 00516 hexbuf[read_idx % 2] = c; 00517 if (read_idx % 2 == 1) { 00518 hex_str_to_char_str(hexbuf, 2, buf+buf_idx); 00519 } 00520 } 00521 } 00522 00523 return buf_idx; 00524 } 00525 00526 ssize_t ATHandler::read_string(char *buf, size_t size, bool read_even_stop_tag) 00527 { 00528 return read(buf, size, read_even_stop_tag, false); 00529 } 00530 00531 ssize_t ATHandler::read_hex_string(char *buf, size_t size) 00532 { 00533 return read(buf, size, false, true); 00534 } 00535 00536 int32_t ATHandler::read_int() 00537 { 00538 tr_debug("%s", __func__); 00539 00540 if (_last_err || !_stop_tag || _stop_tag->found) { 00541 return -1; 00542 } 00543 00544 char buff[BUFF_SIZE]; 00545 char *first_no_digit; 00546 00547 if (read_string(buff, (size_t)sizeof(buff)) == 0) { 00548 return -1; 00549 } 00550 00551 return std::strtol(buff, &first_no_digit, 10); 00552 } 00553 00554 void ATHandler::set_delimiter(char delimiter) 00555 { 00556 _delimiter = delimiter; 00557 } 00558 00559 void ATHandler::set_default_delimiter() 00560 { 00561 _delimiter = DEFAULT_DELIMITER; 00562 } 00563 00564 void ATHandler::set_tag(tag_t* tag_dst, const char *tag_seq) 00565 { 00566 if (tag_seq) { 00567 size_t tag_len = strlen(tag_seq); 00568 set_string(tag_dst->tag, tag_seq, tag_len); 00569 tag_dst->len = tag_len; 00570 tag_dst->found = false; 00571 } else { 00572 _stop_tag = NULL; 00573 } 00574 } 00575 00576 void ATHandler::set_stop_tag(const char *stop_tag_seq) 00577 { 00578 if (_last_err || !_stop_tag) { 00579 return; 00580 } 00581 00582 set_tag(_stop_tag, stop_tag_seq); 00583 } 00584 00585 void ATHandler::set_scope(ScopeType scope_type) 00586 { 00587 tr_debug("%s: %d", __func__, scope_type); 00588 if (_current_scope != scope_type) { 00589 _current_scope = scope_type; 00590 switch (_current_scope) { 00591 case RespType: 00592 _stop_tag = &_resp_stop; 00593 _stop_tag->found = false; 00594 break; 00595 case InfoType: 00596 _stop_tag = &_info_stop; 00597 _stop_tag->found = false; 00598 consume_char(' '); 00599 break; 00600 case ElemType: 00601 _stop_tag = &_elem_stop; 00602 _stop_tag->found = false; 00603 break; 00604 case NotSet: 00605 _stop_tag = NULL; 00606 return; 00607 default: 00608 break; 00609 } 00610 } 00611 } 00612 00613 // should match from recv_pos? 00614 bool ATHandler::match(const char* str, size_t size) 00615 { 00616 tr_debug("%s: %s", __func__, str); 00617 rewind_buffer(); 00618 00619 if ((_recv_len - _recv_pos) < size) { 00620 return false; 00621 } 00622 00623 if (str && memcmp(_recv_buff + _recv_pos, str, size) == 0) { 00624 // consume matching part 00625 _recv_pos += size; 00626 return true; 00627 } 00628 return false; 00629 } 00630 00631 bool ATHandler::match_urc() 00632 { 00633 tr_debug("%s", __func__); 00634 rewind_buffer(); 00635 size_t prefix_len = 0; 00636 for (struct oob_t *oob = _oobs; oob; oob = oob->next) { 00637 prefix_len = oob->prefix_len; 00638 if (_recv_len >= prefix_len) { 00639 if (match(oob->prefix, prefix_len)) { 00640 tr_debug("URC! %s\n", oob->prefix); 00641 set_scope(InfoType); 00642 if (oob->cb) { 00643 oob->cb(); 00644 } 00645 information_response_stop(); 00646 return true; 00647 } 00648 } 00649 } 00650 return false; 00651 } 00652 00653 bool ATHandler::match_error() 00654 { 00655 tr_debug("%s", __func__); 00656 00657 if (match(CME_ERROR, CME_ERROR_LENGTH)) { 00658 at_error(true, DeviceErrorTypeErrorCME); 00659 return true; 00660 } else if (match(CMS_ERROR, CMS_ERROR_LENGTH)) { 00661 at_error(true, DeviceErrorTypeErrorCMS); 00662 return true; 00663 } else if (match(ERROR_, ERROR_LENGTH)) { 00664 at_error(false, DeviceErrorTypeNoError); 00665 return true; 00666 } 00667 00668 return false; 00669 } 00670 00671 void ATHandler::clear_error() 00672 { 00673 _last_err = NSAPI_ERROR_OK ; 00674 _last_at_err.errCode = 0; 00675 _last_at_err.errType = DeviceErrorTypeNoError; 00676 _last_3gpp_error = 0; 00677 } 00678 00679 nsapi_error_t ATHandler::get_last_error() const 00680 { 00681 return _last_err; 00682 } 00683 00684 device_err_t ATHandler::get_last_device_error() const 00685 { 00686 return _last_at_err; 00687 } 00688 00689 void ATHandler::set_error(nsapi_error_t err) 00690 { 00691 if (_last_err == NSAPI_ERROR_OK ) { 00692 _last_err = err; 00693 } 00694 00695 if (_last_err != err) { 00696 tr_warn("AT error code changed from %d to %d!", _last_err, err); 00697 } 00698 } 00699 00700 int ATHandler::get_3gpp_error() 00701 { 00702 return _last_3gpp_error; 00703 } 00704 00705 void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type) 00706 { 00707 if (_last_3gpp_error) { // don't overwrite likely root cause error 00708 return; 00709 } 00710 00711 if (error_type == DeviceErrorTypeErrorCMS && err < 128) { 00712 // CMS errors 0-127 maps straight to 3GPP errors 00713 _last_3gpp_error = err; 00714 } else { 00715 for (size_t i = 0; i<sizeof(map_3gpp_errors)/sizeof(map_3gpp_errors[0]); i++) { 00716 if (map_3gpp_errors[i][0] == err) { 00717 _last_3gpp_error = map_3gpp_errors[i][1]; 00718 tr_debug("AT3GPP error code %d", get_3gpp_error()); 00719 break; 00720 } 00721 } 00722 } 00723 } 00724 00725 void ATHandler::at_error(bool error_code_expected, DeviceErrorType error_type) 00726 { 00727 if (error_code_expected && (error_type == DeviceErrorTypeErrorCMS || error_type == DeviceErrorTypeErrorCME)) { 00728 set_scope(InfoType); 00729 int32_t err = read_int(); 00730 00731 if (err != -1) { 00732 set_3gpp_error(err, error_type); 00733 _last_at_err.errCode = err; 00734 _last_at_err.errType = error_type; 00735 tr_debug("ATHandler ERROR: %d", err); 00736 } else { 00737 tr_debug("ATHandler ERROR reading failed"); 00738 } 00739 } 00740 00741 _last_err = NSAPI_ERROR_DEVICE_ERROR ; 00742 } 00743 00744 void ATHandler::resp(const char *prefix, bool check_urc) 00745 { 00746 tr_debug("%s: %s", __func__, prefix); 00747 00748 at_debug("\n----------resp buff:----------\n"); 00749 for (size_t i = _recv_pos; i < _recv_len; i++) { 00750 at_debug("%c", _recv_buff[i]); 00751 } 00752 at_debug("\n----------buff----------\n"); 00753 00754 _prefix_matched = false; 00755 _urc_matched = false; 00756 _error_found = false; 00757 00758 while (!get_last_error()) { 00759 00760 match(CRLF, CRLF_LENGTH); 00761 00762 if (match(OK, OK_LENGTH)) { 00763 set_scope(RespType); 00764 _stop_tag->found = true; 00765 return; 00766 } 00767 00768 if (match_error()) { 00769 _error_found = true; 00770 return; 00771 } 00772 00773 if (prefix && match(prefix, strlen(prefix))) { 00774 _prefix_matched = true; 00775 return; 00776 } 00777 00778 if (check_urc && match_urc()) { 00779 _urc_matched = true; 00780 } 00781 00782 // If no match found, look for CRLF and consume everything up to and including CRLF 00783 if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { 00784 // If no prefix, return on CRLF - means data to read 00785 if (!prefix) { 00786 return; 00787 } 00788 consume_to_tag(CRLF, true); 00789 } else { 00790 // If no prefix, no CRLF and no more chance to match for OK, ERROR or URC(since max resp length is already in buffer) 00791 // return so data could be read 00792 if (!prefix && ((_recv_len-_recv_pos) >= _max_resp_length)) { 00793 return; 00794 } 00795 fill_buffer(); 00796 } 00797 } 00798 00799 return; 00800 // something went wrong so application need to recover and retry 00801 } 00802 00803 void ATHandler::resp_start(const char *prefix, bool stop) 00804 { 00805 tr_debug("%s: %s", __func__, prefix); 00806 00807 if (_last_err) { 00808 return; 00809 } 00810 00811 // Try get as much data as possible 00812 rewind_buffer(); 00813 fill_buffer(); 00814 00815 if (prefix) { 00816 if ((strlen(prefix) < sizeof(_info_resp_prefix))) { 00817 strcpy(_info_resp_prefix, prefix); 00818 } else { 00819 MBED_ASSERT(0); 00820 } 00821 } 00822 00823 set_scope(RespType); 00824 00825 resp(prefix, true); 00826 00827 if (!stop && prefix && _prefix_matched) { 00828 set_scope(InfoType); 00829 } 00830 } 00831 00832 // check urc because of error as urc 00833 bool ATHandler::info_resp() 00834 { 00835 tr_debug("%s", __func__); 00836 if (_last_err || _resp_stop.found) { 00837 return false; 00838 } 00839 00840 if (_prefix_matched) { 00841 _prefix_matched = false; 00842 return true; 00843 } 00844 00845 // If coming here after another info response was started(looping), stop the previous one. 00846 // Trying to handle stopping in this level instead of doing it in upper level. 00847 if (get_scope() == InfoType) { 00848 information_response_stop(); 00849 } 00850 00851 resp(_info_resp_prefix, false); 00852 00853 if (_prefix_matched) { 00854 set_scope(InfoType); 00855 _prefix_matched = false; 00856 return true; 00857 } 00858 00859 // On mismatch go to response scope 00860 set_scope(RespType); 00861 return false; 00862 } 00863 00864 bool ATHandler::info_elem(char start_tag) 00865 { 00866 tr_debug("%s: %c", __func__, start_tag); 00867 if (_last_err) { 00868 return false; 00869 } 00870 00871 // If coming here after another info response element was started(looping), stop the previous one. 00872 // Trying to handle stopping in this level instead of doing it in upper level. 00873 if (get_scope() == ElemType) { 00874 information_response_element_stop(); 00875 } 00876 00877 consume_char(_delimiter); 00878 00879 if (consume_char(start_tag)) { 00880 _prefix_matched = true; 00881 set_scope(ElemType); 00882 return true; 00883 } 00884 00885 // On mismatch go to information response scope 00886 set_scope(InfoType); 00887 return false; 00888 } 00889 00890 bool ATHandler::consume_char(char ch) 00891 { 00892 tr_debug("%s: %c", __func__, ch); 00893 int read_char = get_char(); 00894 // If we read something else than ch, recover it 00895 if (read_char != ch && read_char != -1) { 00896 _recv_pos--; 00897 return false; 00898 } 00899 return true; 00900 } 00901 00902 bool ATHandler::consume_to_tag(const char *tag, bool consume_tag) 00903 { 00904 tr_debug("%s: %s", __func__, tag); 00905 size_t match_pos = 0; 00906 00907 while (true) { 00908 int c = get_char(); 00909 if (c == -1) { 00910 break; 00911 } else if (c == tag[match_pos]) { 00912 match_pos++; 00913 if (match_pos == strlen(tag)) { 00914 if (!consume_tag) { 00915 _recv_pos -= strlen(tag); 00916 } 00917 return true; 00918 } 00919 } else if (match_pos) { 00920 match_pos = 0; 00921 } 00922 } 00923 tr_debug("consume_to_tag not found"); 00924 return false; 00925 } 00926 00927 bool ATHandler::consume_to_stop_tag() 00928 { 00929 tr_debug("%s", __func__); 00930 00931 if (!_stop_tag || (_stop_tag && _stop_tag->found) || _error_found) { 00932 return true; 00933 } 00934 00935 if (consume_to_tag((const char*)_stop_tag->tag, true)) { 00936 return true; 00937 } 00938 00939 tr_debug("consume_to_stop_tag not found"); 00940 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00941 return false; 00942 } 00943 00944 // consume by size needed? 00945 00946 void ATHandler::resp_stop() 00947 { 00948 // Do not return on error so that we can consume whatever there is in the buffer 00949 00950 tr_debug("%s", __func__); 00951 00952 if (_current_scope == ElemType) { 00953 information_response_element_stop(); 00954 set_scope(InfoType); 00955 } 00956 00957 if (_current_scope == InfoType) { 00958 information_response_stop(); 00959 } 00960 00961 // Go for response stop_tag 00962 if (consume_to_stop_tag()) { 00963 set_scope(NotSet); 00964 } 00965 00966 // Restore stop tag to OK 00967 set_tag(&_resp_stop, OK); 00968 // Reset info resp prefix 00969 memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); 00970 00971 _last_response_stop = rtos::Kernel::get_ms_count(); 00972 } 00973 00974 void ATHandler::information_response_stop() 00975 { 00976 tr_debug("%s", __func__); 00977 if (consume_to_stop_tag()) { 00978 set_scope(RespType); 00979 } 00980 } 00981 00982 void ATHandler::information_response_element_stop() 00983 { 00984 tr_debug("%s", __func__); 00985 if (consume_to_stop_tag()) { 00986 set_scope(InfoType); 00987 } 00988 } 00989 00990 ATHandler::ScopeType ATHandler::get_scope() 00991 { 00992 return _current_scope; 00993 } 00994 00995 void ATHandler::set_string(char *dest, const char *src, size_t src_len) 00996 { 00997 memcpy(dest, src, src_len); 00998 dest[src_len] = '\0'; 00999 } 01000 01001 const char* ATHandler::mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len) 01002 { 01003 if (dest_len > src_len) { 01004 for(size_t i = 0; i < dest_len-src_len+1; ++i) { 01005 if(memcmp(dest+i, src, src_len) == 0) { 01006 return dest+i; 01007 } 01008 } 01009 } 01010 return NULL; 01011 } 01012 01013 void ATHandler::cmd_start(const char* cmd) 01014 { 01015 01016 if (_at_send_delay) { 01017 uint64_t current_time = rtos::Kernel::get_ms_count(); 01018 uint64_t time_difference = current_time - _last_response_stop; 01019 01020 if (time_difference < (uint64_t)_at_send_delay) { 01021 wait_ms((uint64_t)_at_send_delay - time_difference); 01022 tr_debug("AT wait %llu %llu", current_time, _last_response_stop); 01023 } 01024 } 01025 01026 at_debug("AT cmd %s (err %d)\n", cmd, _last_err); 01027 01028 if (_last_err != NSAPI_ERROR_OK ) { 01029 return; 01030 } 01031 01032 (void)write(cmd, strlen(cmd)); 01033 01034 _cmd_start = true; 01035 } 01036 01037 void ATHandler::write_int(int32_t param) 01038 { 01039 at_debug("AT int %d\n", param); 01040 // do common checks before sending subparameter 01041 if (check_cmd_send() == false) { 01042 return; 01043 } 01044 01045 // write the integer subparameter 01046 const int32_t str_len = 12; 01047 char number_string[str_len]; 01048 int32_t result = sprintf(number_string, "%ld", param); 01049 if (result > 0 && result < str_len) { 01050 (void)write(number_string, strlen(number_string)); 01051 } 01052 } 01053 01054 void ATHandler::write_string(const char* param, bool useQuotations) 01055 { 01056 at_debug("AT str %s (with quotes %d)\n", param, useQuotations); 01057 // do common checks before sending subparameter 01058 if (check_cmd_send() == false) { 01059 return; 01060 } 01061 01062 // we are writing string, surround it with quotes 01063 if (useQuotations && write("\"", 1) != 1) { 01064 return; 01065 } 01066 01067 (void)write(param, strlen(param)); 01068 01069 if (useQuotations) { 01070 // we are writing string, surround it with quotes 01071 (void)write("\"", 1); 01072 } 01073 } 01074 01075 void ATHandler::cmd_stop() 01076 { 01077 at_debug("AT stop %s (err %d)\n", _output_delimiter, _last_err); 01078 if (_last_err != NSAPI_ERROR_OK ) { 01079 return; 01080 } 01081 // Finish with CR 01082 (void)write(_output_delimiter, strlen(_output_delimiter)); 01083 } 01084 01085 size_t ATHandler::write_bytes(const uint8_t *data, size_t len) 01086 { 01087 at_debug("AT write bytes %d (err %d)\n", len, _last_err); 01088 01089 if (_last_err != NSAPI_ERROR_OK ) { 01090 return 0; 01091 } 01092 01093 return write(data, len); 01094 } 01095 01096 size_t ATHandler::write(const void *data, size_t len) 01097 { 01098 pollfh fhs; 01099 fhs.fh = _fileHandle; 01100 fhs.events = POLLOUT; 01101 size_t write_len = 0; 01102 for (; write_len < len; ) { 01103 int count = poll(&fhs, 1, _at_timeout); 01104 if (count <= 0 || !(fhs.revents & POLLOUT)) { 01105 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01106 return 0; 01107 } 01108 ssize_t ret = _fileHandle->write((uint8_t*)data + write_len, len - write_len); 01109 if (ret < 0) { 01110 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01111 return 0; 01112 } 01113 write_len += (size_t)ret; 01114 } 01115 01116 return write_len; 01117 } 01118 01119 // do common checks before sending subparameters 01120 bool ATHandler::check_cmd_send() 01121 { 01122 if (_last_err != NSAPI_ERROR_OK ) { 01123 return false; 01124 } 01125 01126 // Don't write delimiter if this is the first subparameter 01127 if (_cmd_start) { 01128 _cmd_start = false; 01129 } else { 01130 if (write(&_delimiter, 1) != 1) { 01131 // writing of delimiter failed, return. write() already have set the _last_err 01132 return false; 01133 } 01134 } 01135 01136 return true; 01137 } 01138 01139 void ATHandler::flush() 01140 { 01141 while (_fileHandle->readable()) { 01142 reset_buffer(); 01143 fill_buffer(); 01144 } 01145 reset_buffer(); 01146 }
Generated on Tue Jul 12 2022 18:18:27 by
