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.
Dependencies: nRF51_Vdd TextLCD BME280
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 // compares c against tag at current position and if this match fails 00930 // compares c against tag[0] and also resets match_pos to 0 00931 } else if (c == tag[match_pos] || ((match_pos = 1) && (c == tag[--match_pos]))) { 00932 match_pos++; 00933 if (match_pos == strlen(tag)) { 00934 if (!consume_tag) { 00935 _recv_pos -= strlen(tag); 00936 } 00937 return true; 00938 } 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 Jul 12 2022 15:15:40 by
