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