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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 <errno.h> 00022 #include "ATHandler.h" 00023 #include "mbed_poll.h" 00024 #include "FileHandle.h" 00025 #include "mbed_debug.h" 00026 #include "rtos/ThisThread.h" 00027 #include "Kernel.h" 00028 #include "CellularUtil.h" 00029 #include "SingletonPtr.h" 00030 #include "ScopedLock.h" 00031 00032 using namespace mbed; 00033 using namespace events; 00034 using namespace mbed_cellular_util; 00035 00036 #include "CellularLog.h" 00037 00038 // URCs should be handled fast, if you add debug traces within URC processing then you also need to increase this time 00039 #define PROCESS_URC_TIME 20 00040 00041 // Suppress logging of very big packet payloads, maxlen is approximate due to write/read are cached 00042 #define DEBUG_MAXLEN 60 00043 #define DEBUG_END_MARK "..\r" 00044 00045 const char *mbed::OK = "OK\r\n"; 00046 const uint8_t OK_LENGTH = 4; 00047 const char *mbed::CRLF = "\r\n"; 00048 const uint8_t CRLF_LENGTH = 2; 00049 const char *CME_ERROR = "+CME ERROR:"; 00050 const uint8_t CME_ERROR_LENGTH = 11; 00051 const char *CMS_ERROR = "+CMS ERROR:"; 00052 const uint8_t CMS_ERROR_LENGTH = 11; 00053 const char *ERROR_ = "ERROR\r\n"; 00054 const uint8_t ERROR_LENGTH = 7; 00055 const uint8_t MAX_RESP_LENGTH = CMS_ERROR_LENGTH; 00056 const char DEFAULT_DELIMITER = ','; 00057 00058 static const uint8_t map_3gpp_errors[][2] = { 00059 { 103, 3 }, { 106, 6 }, { 107, 7 }, { 108, 8 }, { 111, 11 }, { 112, 12 }, { 113, 13 }, { 114, 14 }, 00060 { 115, 15 }, { 122, 22 }, { 125, 25 }, { 172, 95 }, { 173, 96 }, { 174, 97 }, { 175, 99 }, { 176, 111 }, 00061 { 177, 8 }, { 126, 26 }, { 127, 27 }, { 128, 28 }, { 129, 29 }, { 130, 30 }, { 131, 31 }, { 132, 32 }, 00062 { 133, 33 }, { 134, 34 }, { 140, 40 }, { 141, 41 }, { 142, 42 }, { 143, 43 }, { 144, 44 }, { 145, 45 }, 00063 { 146, 46 }, { 178, 65 }, { 179, 66 }, { 180, 48 }, { 181, 83 }, { 171, 49 }, 00064 }; 00065 00066 ATHandler *ATHandler::_atHandlers = NULL; 00067 00068 // each parser is associated with one filehandle (that is UART) 00069 ATHandler *ATHandler::get_instance(FileHandle *fileHandle, events::EventQueue &queue, uint32_t timeout, 00070 const char *delimiter, uint16_t send_delay, bool debug_on) 00071 { 00072 if (!fileHandle) { 00073 return NULL; 00074 } 00075 00076 singleton_lock(); 00077 ATHandler *atHandler = _atHandlers; 00078 while (atHandler) { 00079 if (atHandler->get_file_handle() == fileHandle) { 00080 atHandler->inc_ref_count(); 00081 singleton_unlock(); 00082 return atHandler; 00083 } 00084 atHandler = atHandler->_nextATHandler; 00085 } 00086 00087 atHandler = new ATHandler(fileHandle, queue, timeout, delimiter, send_delay); 00088 if (debug_on) { 00089 atHandler->set_debug(debug_on); 00090 } 00091 atHandler->_nextATHandler = _atHandlers; 00092 _atHandlers = atHandler; 00093 00094 singleton_unlock(); 00095 return atHandler; 00096 } 00097 00098 nsapi_error_t ATHandler::close() 00099 { 00100 if (get_ref_count() == 0) { 00101 return NSAPI_ERROR_PARAMETER ; 00102 } 00103 00104 singleton_lock(); 00105 dec_ref_count(); 00106 if (get_ref_count() == 0) { 00107 // we can delete this at_handler 00108 ATHandler *atHandler = _atHandlers; 00109 ATHandler *prev = NULL; 00110 while (atHandler) { 00111 if (atHandler == this) { 00112 if (prev == NULL) { 00113 _atHandlers = _atHandlers->_nextATHandler; 00114 } else { 00115 prev->_nextATHandler = atHandler->_nextATHandler; 00116 } 00117 delete this; 00118 break; 00119 } else { 00120 prev = atHandler; 00121 atHandler = atHandler->_nextATHandler; 00122 } 00123 } 00124 } 00125 singleton_unlock(); 00126 return NSAPI_ERROR_OK ; 00127 } 00128 00129 void ATHandler::set_at_timeout_list(uint32_t timeout_milliseconds, bool default_timeout) 00130 { 00131 ATHandler *atHandler = _atHandlers; 00132 singleton_lock(); 00133 while (atHandler) { 00134 atHandler->set_at_timeout(timeout_milliseconds, default_timeout); 00135 atHandler = atHandler->_nextATHandler; 00136 } 00137 singleton_unlock(); 00138 } 00139 00140 void ATHandler::set_debug_list(bool debug_on) 00141 { 00142 ATHandler *atHandler = _atHandlers; 00143 singleton_lock(); 00144 while (atHandler) { 00145 atHandler->set_debug(debug_on); 00146 atHandler = atHandler->_nextATHandler; 00147 } 00148 singleton_unlock(); 00149 } 00150 00151 bool ATHandler::ok_to_proceed() 00152 { 00153 if (_last_err != NSAPI_ERROR_OK ) { 00154 return false; 00155 } 00156 00157 if (!_is_fh_usable) { 00158 _last_err = NSAPI_ERROR_BUSY ; 00159 return false; 00160 } 00161 return true; 00162 } 00163 00164 ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay) : 00165 _nextATHandler(0), 00166 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT 00167 _oobCv(_fileHandleMutex), 00168 #endif 00169 _fileHandle(NULL), // filehandle is set by set_file_handle() 00170 _queue(queue), 00171 _last_err(NSAPI_ERROR_OK ), 00172 _last_3gpp_error(0), 00173 _oob_string_max_length(0), 00174 _oobs(NULL), 00175 _at_timeout(timeout), 00176 _previous_at_timeout(timeout), 00177 _at_send_delay(send_delay), 00178 _last_response_stop(0), 00179 _ref_count(1), 00180 _is_fh_usable(false), 00181 _stop_tag(NULL), 00182 _delimiter(DEFAULT_DELIMITER), 00183 _prefix_matched(false), 00184 _urc_matched(false), 00185 _error_found(false), 00186 _max_resp_length(MAX_RESP_LENGTH), 00187 _debug_on(MBED_CONF_CELLULAR_DEBUG_AT), 00188 _cmd_start(false), 00189 _use_delimiter(true), 00190 _start_time(0), 00191 _event_id(0) 00192 { 00193 clear_error(); 00194 00195 if (output_delimiter) { 00196 _output_delimiter = new char[strlen(output_delimiter) + 1]; 00197 memcpy(_output_delimiter, output_delimiter, strlen(output_delimiter) + 1); 00198 } else { 00199 _output_delimiter = NULL; 00200 } 00201 00202 reset_buffer(); 00203 memset(_recv_buff, 0, sizeof(_recv_buff)); 00204 memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); 00205 00206 _current_scope = NotSet; 00207 set_tag(&_resp_stop, OK); 00208 set_tag(&_info_stop, CRLF); 00209 set_tag(&_elem_stop, ")"); 00210 00211 set_file_handle(fh); 00212 } 00213 00214 void ATHandler::set_debug(bool debug_on) 00215 { 00216 _debug_on = debug_on; 00217 } 00218 00219 bool ATHandler::get_debug() const 00220 { 00221 return _debug_on; 00222 } 00223 00224 ATHandler::~ATHandler() 00225 { 00226 ScopedLock <ATHandler> lock(*this); 00227 set_file_handle(NULL); 00228 00229 if (_event_id != 0 && _queue.cancel(_event_id)) { 00230 _event_id = 0; 00231 } 00232 00233 while (_event_id != 0) { 00234 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT 00235 _oobCv.wait(); 00236 #else 00237 // Cancel will always work in a single threaded environment 00238 MBED_ASSERT(false); 00239 #endif // AT_HANDLER_MUTEX 00240 } 00241 00242 while (_oobs) { 00243 struct oob_t *oob = _oobs; 00244 _oobs = oob->next; 00245 delete oob; 00246 } 00247 if (_output_delimiter) { 00248 delete [] _output_delimiter; 00249 } 00250 } 00251 00252 void ATHandler::inc_ref_count() 00253 { 00254 _ref_count++; 00255 } 00256 00257 void ATHandler::dec_ref_count() 00258 { 00259 _ref_count--; 00260 } 00261 00262 int ATHandler::get_ref_count() 00263 { 00264 return _ref_count; 00265 } 00266 00267 FileHandle *ATHandler::get_file_handle() 00268 { 00269 return _fileHandle; 00270 } 00271 00272 void ATHandler::set_file_handle(FileHandle *fh) 00273 { 00274 ScopedLock<ATHandler> lock(*this); 00275 if (_fileHandle) { 00276 set_is_filehandle_usable(false); 00277 } 00278 _fileHandle = fh; 00279 if (_fileHandle) { 00280 set_is_filehandle_usable(true); 00281 } 00282 } 00283 00284 void ATHandler::set_is_filehandle_usable(bool usable) 00285 { 00286 ScopedLock<ATHandler> lock(*this); 00287 if (_fileHandle) { 00288 if (usable) { 00289 _fileHandle->set_blocking(false); 00290 _fileHandle->sigio(Callback<void()>(this, &ATHandler::event)); 00291 } else { 00292 _fileHandle->set_blocking(true); // set back to default state 00293 _fileHandle->sigio(NULL); 00294 } 00295 _is_fh_usable = usable; 00296 } 00297 } 00298 00299 void ATHandler::set_urc_handler(const char *prefix, Callback<void()> callback) 00300 { 00301 if (!callback) { 00302 remove_urc_handler(prefix); 00303 return; 00304 } 00305 00306 if (find_urc_handler(prefix)) { 00307 tr_warn("URC already added with prefix: %s", prefix); 00308 return; 00309 } 00310 00311 struct oob_t *oob = new struct oob_t; 00312 size_t prefix_len = strlen(prefix); 00313 if (prefix_len > _oob_string_max_length) { 00314 _oob_string_max_length = prefix_len; 00315 if (_oob_string_max_length > _max_resp_length) { 00316 _max_resp_length = _oob_string_max_length; 00317 } 00318 } 00319 00320 oob->prefix = prefix; 00321 oob->prefix_len = prefix_len; 00322 oob->cb = callback; 00323 oob->next = _oobs; 00324 _oobs = oob; 00325 } 00326 00327 void ATHandler::remove_urc_handler(const char *prefix) 00328 { 00329 struct oob_t *current = _oobs; 00330 struct oob_t *prev = NULL; 00331 while (current) { 00332 if (strcmp(prefix, current->prefix) == 0) { 00333 if (prev) { 00334 prev->next = current->next; 00335 } else { 00336 _oobs = current->next; 00337 } 00338 delete current; 00339 break; 00340 } 00341 prev = current; 00342 current = prev->next; 00343 } 00344 } 00345 00346 bool ATHandler::find_urc_handler(const char *prefix) 00347 { 00348 struct oob_t *oob = _oobs; 00349 while (oob) { 00350 if (strcmp(prefix, oob->prefix) == 0) { 00351 return true; 00352 } 00353 oob = oob->next; 00354 } 00355 00356 return false; 00357 } 00358 00359 void ATHandler::event() 00360 { 00361 if (_event_id == 0) { 00362 _event_id = _queue.call(callback(this, &ATHandler::process_oob)); 00363 } 00364 } 00365 00366 void ATHandler::lock() 00367 { 00368 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT 00369 _fileHandleMutex.lock(); 00370 #endif 00371 clear_error(); 00372 _start_time = rtos::Kernel::get_ms_count(); 00373 } 00374 00375 void ATHandler::unlock() 00376 { 00377 if (_is_fh_usable && (_fileHandle->readable() || (_recv_pos < _recv_len))) { 00378 _event_id = _queue.call(callback(this, &ATHandler::process_oob)); 00379 } 00380 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT 00381 _fileHandleMutex.unlock(); 00382 #endif 00383 } 00384 00385 nsapi_error_t ATHandler::unlock_return_error() 00386 { 00387 nsapi_error_t err = _last_err; 00388 unlock(); 00389 return err; 00390 } 00391 00392 void ATHandler::set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout) 00393 { 00394 lock(); 00395 if (default_timeout) { 00396 _previous_at_timeout = timeout_milliseconds; 00397 _at_timeout = timeout_milliseconds; 00398 } else if (timeout_milliseconds != _at_timeout) { 00399 _previous_at_timeout = _at_timeout; 00400 _at_timeout = timeout_milliseconds; 00401 } 00402 unlock(); 00403 } 00404 00405 void ATHandler::restore_at_timeout() 00406 { 00407 lock(); 00408 if (_previous_at_timeout != _at_timeout) { 00409 _at_timeout = _previous_at_timeout; 00410 } 00411 unlock(); 00412 } 00413 00414 void ATHandler::process_oob() 00415 { 00416 ScopedLock<ATHandler> lock(*this); 00417 if (!_is_fh_usable) { 00418 tr_debug("process_oob, filehandle is not usable, return..."); 00419 _event_id = 0; 00420 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT 00421 _oobCv.notify_all(); 00422 #endif 00423 return; 00424 } 00425 if (_fileHandle->readable() || (_recv_pos < _recv_len)) { 00426 tr_debug("AT OoB readable %d, len %u", _fileHandle->readable(), _recv_len - _recv_pos); 00427 _current_scope = NotSet; 00428 uint32_t timeout = _at_timeout; 00429 while (true) { 00430 _at_timeout = timeout; 00431 if (match_urc()) { 00432 if (!(_fileHandle->readable() || (_recv_pos < _recv_len))) { 00433 break; // we have nothing to read anymore 00434 } 00435 } else if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { // If no match found, look for CRLF and consume everything up to CRLF 00436 _at_timeout = PROCESS_URC_TIME; 00437 consume_to_tag(CRLF, true); 00438 } else { 00439 _at_timeout = PROCESS_URC_TIME; 00440 if (!fill_buffer()) { 00441 reset_buffer(); // consume anything that could not be handled 00442 break; 00443 } 00444 } 00445 _start_time = rtos::Kernel::get_ms_count(); 00446 } 00447 _at_timeout = timeout; 00448 tr_debug("AT OoB done"); 00449 } 00450 _event_id = 0; 00451 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT 00452 _oobCv.notify_all(); 00453 #endif 00454 } 00455 00456 void ATHandler::reset_buffer() 00457 { 00458 _recv_pos = 0; 00459 _recv_len = 0; 00460 } 00461 00462 void ATHandler::rewind_buffer() 00463 { 00464 if (_recv_pos > 0 && _recv_len >= _recv_pos) { 00465 _recv_len -= _recv_pos; 00466 // move what is not read to beginning of buffer 00467 memmove(_recv_buff, _recv_buff + _recv_pos, _recv_len); 00468 _recv_pos = 0; 00469 } 00470 } 00471 00472 int ATHandler::poll_timeout(bool wait_for_timeout) 00473 { 00474 int timeout; 00475 if (wait_for_timeout) { 00476 uint64_t now = rtos::Kernel::get_ms_count(); 00477 if (now >= _start_time + _at_timeout) { 00478 timeout = 0; 00479 } else if (_start_time + _at_timeout - now > INT_MAX) { 00480 timeout = INT_MAX; 00481 } else { 00482 timeout = _start_time + _at_timeout - now; 00483 } 00484 } else { 00485 timeout = 0; 00486 } 00487 return timeout; 00488 } 00489 00490 bool ATHandler::fill_buffer(bool wait_for_timeout) 00491 { 00492 // Reset buffer when full 00493 if (sizeof(_recv_buff) == _recv_len) { 00494 tr_error("AT overflow"); 00495 debug_print(_recv_buff, _recv_len, AT_ERR); 00496 reset_buffer(); 00497 } 00498 00499 pollfh fhs; 00500 fhs.fh = _fileHandle; 00501 fhs.events = POLLIN; 00502 int count = poll(&fhs, 1, poll_timeout(wait_for_timeout)); 00503 if (count > 0 && (fhs.revents & POLLIN)) { 00504 ssize_t len = _fileHandle->read(_recv_buff + _recv_len, sizeof(_recv_buff) - _recv_len); 00505 if (len > 0) { 00506 debug_print(_recv_buff + _recv_len, len, AT_RX); 00507 _recv_len += len; 00508 return true; 00509 } 00510 } 00511 00512 return false; 00513 } 00514 00515 int ATHandler::get_char() 00516 { 00517 if (_recv_pos == _recv_len) { 00518 reset_buffer(); // try to read as much as possible 00519 if (!fill_buffer()) { 00520 tr_warn("AT timeout"); 00521 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00522 return -1; // timeout to read 00523 } 00524 } 00525 00526 return _recv_buff[_recv_pos++]; 00527 } 00528 00529 void ATHandler::skip_param(uint32_t count) 00530 { 00531 if (!ok_to_proceed() || !_stop_tag || _stop_tag->found) { 00532 return; 00533 } 00534 00535 for (uint32_t i = 0; (i < count && !_stop_tag->found); i++) { 00536 size_t match_pos = 0; 00537 while (true) { 00538 int c = get_char(); 00539 if (c == -1) { 00540 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00541 return; 00542 } else if (c == _delimiter) { 00543 break; 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 break; 00549 } 00550 } else if (match_pos) { 00551 match_pos = 0; 00552 if (c == _stop_tag->tag[match_pos]) { 00553 match_pos++; 00554 } 00555 } 00556 } 00557 } 00558 return; 00559 } 00560 00561 void ATHandler::skip_param(ssize_t len, uint32_t count) 00562 { 00563 if (!ok_to_proceed() || !_stop_tag || _stop_tag->found) { 00564 return; 00565 } 00566 00567 for (uint32_t i = 0; i < count; i++) { 00568 ssize_t read_len = 0; 00569 while (read_len < len) { 00570 int c = get_char(); 00571 if (c == -1) { 00572 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00573 return; 00574 } 00575 read_len++; 00576 } 00577 } 00578 return; 00579 } 00580 00581 ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len) 00582 { 00583 if (!ok_to_proceed()) { 00584 return -1; 00585 } 00586 00587 bool debug_on = _debug_on; 00588 bool disabled_debug = false; 00589 if (len > DEBUG_MAXLEN) { 00590 _debug_on = false; 00591 disabled_debug = true; 00592 } 00593 00594 size_t read_len = 0; 00595 for (; read_len < len; read_len++) { 00596 int c = get_char(); 00597 if (c == -1) { 00598 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00599 _debug_on = debug_on; 00600 return -1; 00601 } 00602 buf[read_len] = c; 00603 } 00604 00605 #if MBED_CONF_CELLULAR_DEBUG_AT 00606 if (debug_on && disabled_debug) { 00607 tr_info("read_bytes trace suppressed (total length %d)", read_len); 00608 } 00609 #else 00610 (void)disabled_debug; // Remove compiler warning 00611 #endif 00612 00613 _debug_on = debug_on; 00614 return read_len; 00615 } 00616 00617 ssize_t ATHandler::read_string(char *buf, size_t size, bool read_even_stop_tag) 00618 { 00619 if (!ok_to_proceed() || !_stop_tag || (_stop_tag->found && read_even_stop_tag == false)) { 00620 return -1; 00621 } 00622 00623 unsigned int len = 0; 00624 size_t match_pos = 0; 00625 bool delimiter_found = false; 00626 00627 for (; len < (size - 1 + match_pos); len++) { 00628 int c = get_char(); 00629 if (c == -1) { 00630 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00631 return -1; 00632 } else if (c == _delimiter) { 00633 buf[len] = '\0'; 00634 delimiter_found = true; 00635 break; 00636 } else if (c == '\"') { 00637 match_pos = 0; 00638 len--; 00639 continue; 00640 } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { 00641 match_pos++; 00642 if (match_pos == _stop_tag->len) { 00643 _stop_tag->found = true; 00644 // remove tag from string if it was matched 00645 len -= (_stop_tag->len - 1); 00646 buf[len] = '\0'; 00647 break; 00648 } 00649 } else if (match_pos) { 00650 match_pos = 0; 00651 if (c == _stop_tag->tag[match_pos]) { 00652 match_pos++; 00653 } 00654 } 00655 00656 buf[len] = c; 00657 } 00658 00659 if (len && (len == size - 1 + match_pos)) { 00660 buf[len] = '\0'; 00661 } 00662 00663 // Consume to delimiter or stop_tag 00664 if (!delimiter_found && !_stop_tag->found) { 00665 match_pos = 0; 00666 while (1) { 00667 int c = get_char(); 00668 if (c == -1) { 00669 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00670 break; 00671 } else if (c == _delimiter) { 00672 break; 00673 } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { 00674 match_pos++; 00675 if (match_pos == _stop_tag->len) { 00676 _stop_tag->found = true; 00677 break; 00678 } 00679 } 00680 } 00681 } 00682 00683 return len; 00684 } 00685 00686 ssize_t ATHandler::read_hex_string(char *buf, size_t size) 00687 { 00688 if (!ok_to_proceed() || !_stop_tag || _stop_tag->found) { 00689 return -1; 00690 } 00691 00692 size_t match_pos = 0; 00693 00694 consume_char('\"'); 00695 00696 if (_last_err) { 00697 return -1; 00698 } 00699 00700 size_t read_idx = 0; 00701 size_t buf_idx = 0; 00702 char hexbuf[2]; 00703 00704 bool debug_on = _debug_on; 00705 bool disabled_debug = false; 00706 if (size > DEBUG_MAXLEN) { 00707 _debug_on = false; 00708 disabled_debug = true; 00709 } 00710 00711 for (; read_idx < size * 2 + match_pos; read_idx++) { 00712 int c = get_char(); 00713 00714 if (match_pos) { 00715 buf_idx++; 00716 } else { 00717 buf_idx = read_idx / 2; 00718 } 00719 00720 if (c == -1) { 00721 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00722 return -1; 00723 } 00724 if (c == _delimiter) { 00725 break; 00726 } else if (c == '\"') { 00727 match_pos = 0; 00728 read_idx--; 00729 continue; 00730 } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { 00731 match_pos++; 00732 if (match_pos == _stop_tag->len) { 00733 _stop_tag->found = true; 00734 // remove tag from string if it was matched 00735 buf_idx -= (_stop_tag->len - 1); 00736 break; 00737 } 00738 } else if (match_pos) { 00739 match_pos = 0; 00740 if (c == _stop_tag->tag[match_pos]) { 00741 match_pos++; 00742 } 00743 } 00744 00745 if (match_pos) { 00746 buf[buf_idx] = c; 00747 } else { 00748 hexbuf[read_idx % 2] = c; 00749 if (read_idx % 2 == 1) { 00750 hex_to_char(hexbuf, *(buf + buf_idx)); 00751 } 00752 } 00753 } 00754 00755 if (read_idx && (read_idx == size * 2 + match_pos)) { 00756 buf_idx++; 00757 } 00758 00759 #if MBED_CONF_CELLULAR_DEBUG_AT 00760 if (debug_on && disabled_debug) { 00761 tr_info("read_hex_string trace suppressed (total length %d)", buf_idx); 00762 } 00763 #else 00764 (void)disabled_debug; // Remove compiler warning 00765 #endif 00766 00767 _debug_on = debug_on; 00768 00769 return buf_idx; 00770 } 00771 00772 int32_t ATHandler::read_int() 00773 { 00774 if (!ok_to_proceed() || !_stop_tag || _stop_tag->found) { 00775 return -1; 00776 } 00777 00778 char buff[BUFF_SIZE]; 00779 if (read_string(buff, sizeof(buff)) == 0) { 00780 return -1; 00781 } 00782 00783 errno = 0; 00784 long result = std::strtol(buff, NULL, 10); 00785 if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE) { 00786 return -1; // overflow/underflow 00787 } 00788 if (result < 0) { 00789 return -1; // negative values are unsupported 00790 } 00791 if (*buff == '\0') { 00792 return -1; // empty string 00793 } 00794 return (int32_t) result; 00795 } 00796 00797 void ATHandler::set_delimiter(char delimiter) 00798 { 00799 _delimiter = delimiter; 00800 } 00801 00802 void ATHandler::set_default_delimiter() 00803 { 00804 _delimiter = DEFAULT_DELIMITER; 00805 } 00806 00807 void ATHandler::use_delimiter(bool use_delimiter) 00808 { 00809 _use_delimiter = use_delimiter; 00810 } 00811 00812 void ATHandler::set_tag(tag_t *tag_dst, const char *tag_seq) 00813 { 00814 if (tag_seq) { 00815 size_t tag_len = strlen(tag_seq); 00816 memcpy(tag_dst->tag, tag_seq, tag_len); 00817 tag_dst->tag[tag_len] = '\0'; 00818 tag_dst->len = tag_len; 00819 tag_dst->found = false; 00820 } else { 00821 _stop_tag = NULL; 00822 } 00823 } 00824 00825 void ATHandler::set_stop_tag(const char *stop_tag_seq) 00826 { 00827 if (_last_err || !_stop_tag) { 00828 return; 00829 } 00830 00831 set_tag(_stop_tag, stop_tag_seq); 00832 } 00833 00834 void ATHandler::set_scope(ScopeType scope_type) 00835 { 00836 if (_current_scope != scope_type) { 00837 _current_scope = scope_type; 00838 switch (_current_scope) { 00839 case RespType: 00840 _stop_tag = &_resp_stop; 00841 _stop_tag->found = false; 00842 break; 00843 case InfoType: 00844 _stop_tag = &_info_stop; 00845 _stop_tag->found = false; 00846 consume_char(' '); 00847 break; 00848 case ElemType: 00849 _stop_tag = &_elem_stop; 00850 _stop_tag->found = false; 00851 break; 00852 case NotSet: 00853 _stop_tag = NULL; 00854 return; 00855 default: 00856 break; 00857 } 00858 } 00859 } 00860 00861 // should match from recv_pos? 00862 bool ATHandler::match(const char *str, size_t size) 00863 { 00864 rewind_buffer(); 00865 00866 if ((_recv_len - _recv_pos) < size) { 00867 return false; 00868 } 00869 00870 if (str && memcmp(_recv_buff + _recv_pos, str, size) == 0) { 00871 // consume matching part 00872 _recv_pos += size; 00873 return true; 00874 } 00875 return false; 00876 } 00877 00878 bool ATHandler::match_urc() 00879 { 00880 rewind_buffer(); 00881 size_t prefix_len = 0; 00882 for (struct oob_t *oob = _oobs; oob; oob = oob->next) { 00883 prefix_len = oob->prefix_len; 00884 if (_recv_len >= prefix_len) { 00885 if (match(oob->prefix, prefix_len)) { 00886 set_scope(InfoType); 00887 if (oob->cb) { 00888 oob->cb(); 00889 } 00890 information_response_stop(); 00891 return true; 00892 } 00893 } 00894 } 00895 return false; 00896 } 00897 00898 bool ATHandler::match_error() 00899 { 00900 if (match(CME_ERROR, CME_ERROR_LENGTH)) { 00901 at_error(true, DeviceErrorTypeErrorCME); 00902 return true; 00903 } else if (match(CMS_ERROR, CMS_ERROR_LENGTH)) { 00904 at_error(true, DeviceErrorTypeErrorCMS); 00905 return true; 00906 } else if (match(ERROR_, ERROR_LENGTH)) { 00907 at_error(false, DeviceErrorTypeNoError); 00908 return true; 00909 } 00910 00911 return false; 00912 } 00913 00914 void ATHandler::clear_error() 00915 { 00916 _last_err = NSAPI_ERROR_OK ; 00917 _last_at_err.errCode = 0; 00918 _last_at_err.errType = DeviceErrorTypeNoError; 00919 _last_3gpp_error = 0; 00920 } 00921 00922 nsapi_error_t ATHandler::get_last_error() const 00923 { 00924 return _last_err; 00925 } 00926 00927 device_err_t ATHandler::get_last_device_error() const 00928 { 00929 return _last_at_err; 00930 } 00931 00932 void ATHandler::set_error(nsapi_error_t err) 00933 { 00934 if (err != NSAPI_ERROR_OK ) { 00935 tr_debug("AT error %d", err); 00936 } 00937 if (_last_err == NSAPI_ERROR_OK ) { 00938 _last_err = err; 00939 } 00940 00941 } 00942 00943 int ATHandler::get_3gpp_error() 00944 { 00945 return _last_3gpp_error; 00946 } 00947 00948 void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type) 00949 { 00950 if (_last_3gpp_error) { // don't overwrite likely root cause error 00951 return; 00952 } 00953 00954 if (error_type == DeviceErrorTypeErrorCMS && err < 128) { 00955 // CMS errors 0-127 maps straight to 3GPP errors 00956 _last_3gpp_error = err; 00957 } else { 00958 for (size_t i = 0; i < sizeof(map_3gpp_errors) / sizeof(map_3gpp_errors[0]); i++) { 00959 if (map_3gpp_errors[i][0] == err) { 00960 _last_3gpp_error = map_3gpp_errors[i][1]; 00961 tr_error("AT3GPP error code %d", get_3gpp_error()); 00962 break; 00963 } 00964 } 00965 } 00966 } 00967 00968 void ATHandler::at_error(bool error_code_expected, DeviceErrorType error_type) 00969 { 00970 if (error_code_expected && (error_type == DeviceErrorTypeErrorCMS || error_type == DeviceErrorTypeErrorCME)) { 00971 set_scope(InfoType); 00972 int32_t err = read_int(); 00973 00974 if (err != -1) { 00975 set_3gpp_error(err, error_type); 00976 _last_at_err.errCode = err; 00977 _last_at_err.errType = error_type; 00978 tr_warn("AT error code %ld", err); 00979 } else { 00980 tr_warn("ATHandler ERROR reading failed"); 00981 } 00982 } 00983 00984 set_error(NSAPI_ERROR_DEVICE_ERROR ); 00985 } 00986 00987 void ATHandler::resp(const char *prefix, bool check_urc) 00988 { 00989 _prefix_matched = false; 00990 _urc_matched = false; 00991 _error_found = false; 00992 00993 while (!get_last_error()) { 00994 00995 (void)match(CRLF, CRLF_LENGTH); 00996 00997 if (match(OK, OK_LENGTH)) { 00998 set_scope(RespType); 00999 _stop_tag->found = true; 01000 return; 01001 } 01002 01003 if (match_error()) { 01004 _error_found = true; 01005 return; 01006 } 01007 01008 if (prefix && strlen(prefix) && match(prefix, strlen(prefix))) { 01009 _prefix_matched = true; 01010 return; 01011 } 01012 01013 if (check_urc && match_urc()) { 01014 _urc_matched = true; 01015 clear_error(); 01016 continue; 01017 } 01018 01019 // If no match found, look for CRLF and consume everything up to and including CRLF 01020 if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { 01021 // If no prefix, return on CRLF - means data to read 01022 if (!prefix || (prefix && !strlen(prefix))) { 01023 return; 01024 } 01025 consume_to_tag(CRLF, true); 01026 } else { 01027 // If no prefix, no CRLF and no more chance to match for OK, ERROR or URC(since max resp length is already in buffer) 01028 // return so data could be read 01029 if ((!prefix || (prefix && !strlen(prefix))) && ((_recv_len - _recv_pos) >= _max_resp_length)) { 01030 return; 01031 } 01032 if (!fill_buffer()) { 01033 // if we don't get any match and no data within timeout, set an error to indicate need for recovery 01034 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01035 } 01036 } 01037 } 01038 01039 return; 01040 // something went wrong so application need to recover and retry 01041 } 01042 01043 void ATHandler::resp_start(const char *prefix, bool stop) 01044 { 01045 if (!ok_to_proceed()) { 01046 return; 01047 } 01048 01049 set_scope(NotSet); 01050 // Try get as much data as possible 01051 rewind_buffer(); 01052 (void)fill_buffer(false); 01053 01054 if (prefix) { 01055 MBED_ASSERT(strlen(prefix) < BUFF_SIZE); 01056 strcpy(_info_resp_prefix, prefix); // copy prefix so we can later use it without having to provide again for info_resp 01057 } 01058 01059 set_scope(RespType); 01060 01061 resp(prefix, true); 01062 01063 if (!stop && prefix && _prefix_matched) { 01064 set_scope(InfoType); 01065 } 01066 } 01067 01068 // check urc because of error as urc 01069 bool ATHandler::info_resp() 01070 { 01071 if (!ok_to_proceed() || _resp_stop.found) { 01072 return false; 01073 } 01074 01075 if (_prefix_matched) { 01076 _prefix_matched = false; 01077 return true; 01078 } 01079 01080 // If coming here after another info response was started(looping), stop the previous one. 01081 // Trying to handle stopping in this level instead of doing it in upper level. 01082 if (get_scope() == InfoType) { 01083 information_response_stop(); 01084 } 01085 01086 resp(_info_resp_prefix, false); 01087 01088 if (_prefix_matched) { 01089 set_scope(InfoType); 01090 _prefix_matched = false; 01091 return true; 01092 } 01093 01094 // On mismatch go to response scope 01095 set_scope(RespType); 01096 return false; 01097 } 01098 01099 bool ATHandler::info_elem(char start_tag) 01100 { 01101 if (!ok_to_proceed()) { 01102 return false; 01103 } 01104 01105 // If coming here after another info response element was started(looping), stop the previous one. 01106 // Trying to handle stopping in this level instead of doing it in upper level. 01107 if (get_scope() == ElemType) { 01108 information_response_element_stop(); 01109 } 01110 01111 consume_char(_delimiter); 01112 01113 if (consume_char(start_tag)) { 01114 _prefix_matched = true; 01115 set_scope(ElemType); 01116 return true; 01117 } 01118 01119 // On mismatch go to information response scope 01120 set_scope(InfoType); 01121 return false; 01122 } 01123 01124 bool ATHandler::consume_char(char ch) 01125 { 01126 int read_char = get_char(); 01127 if (read_char == -1) { 01128 return false; 01129 } 01130 // If we read something else than ch, recover it 01131 if (read_char != ch) { 01132 _recv_pos--; 01133 return false; 01134 } 01135 return true; 01136 } 01137 01138 bool ATHandler::consume_to_tag(const char *tag, bool consume_tag) 01139 { 01140 size_t match_pos = 0; 01141 size_t tag_length = strlen(tag); 01142 01143 while (true) { 01144 int c = get_char(); 01145 if (c == -1) { 01146 tr_debug("consume_to_tag not found"); 01147 return false; 01148 } 01149 if (c == tag[match_pos]) { 01150 match_pos++; 01151 } else if (match_pos != 0) { 01152 match_pos = 0; 01153 if (c == tag[match_pos]) { 01154 match_pos++; 01155 } 01156 } 01157 if (match_pos == tag_length) { 01158 break; 01159 } 01160 } 01161 01162 if (!consume_tag) { 01163 _recv_pos -= tag_length; 01164 } 01165 return true; 01166 } 01167 01168 bool ATHandler::consume_to_stop_tag() 01169 { 01170 if (!_stop_tag || (_stop_tag && _stop_tag->found) || _error_found) { 01171 return true; 01172 } 01173 01174 if (!_is_fh_usable) { 01175 _last_err = NSAPI_ERROR_BUSY ; 01176 return true; 01177 } 01178 01179 if (consume_to_tag((const char *)_stop_tag->tag, true)) { 01180 return true; 01181 } 01182 01183 tr_debug("AT stop tag not found"); 01184 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01185 return false; 01186 } 01187 01188 // consume by size needed? 01189 01190 void ATHandler::resp_stop() 01191 { 01192 if (_is_fh_usable) { 01193 // Do not return on error so that we can consume whatever there is in the buffer 01194 01195 if (_current_scope == ElemType) { 01196 information_response_element_stop(); 01197 set_scope(InfoType); 01198 } 01199 01200 if (_current_scope == InfoType) { 01201 information_response_stop(); 01202 } 01203 01204 // Go for response stop_tag 01205 if (_stop_tag && !_stop_tag->found && !_error_found) { 01206 // Check for URC for every new line 01207 while (!get_last_error()) { 01208 01209 if (match(_stop_tag->tag, _stop_tag->len)) { 01210 break; 01211 } 01212 01213 if (match_urc()) { 01214 continue; 01215 } 01216 01217 // If no URC nor stop_tag found, look for CRLF and consume everything up to and including CRLF 01218 if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { 01219 consume_to_tag(CRLF, true); 01220 // If stop tag is CRLF we have to stop reading/consuming the buffer 01221 if (!strncmp(CRLF, _stop_tag->tag, _stop_tag->len)) { 01222 break; 01223 } 01224 // If no URC nor CRLF nor stop_tag -> fill buffer 01225 } else { 01226 if (!fill_buffer()) { 01227 // if we don't get any match and no data within timeout, set an error to indicate need for recovery 01228 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01229 } 01230 } 01231 } 01232 } 01233 } else { 01234 _last_err = NSAPI_ERROR_BUSY ; 01235 } 01236 01237 set_scope(NotSet); 01238 01239 // Restore stop tag to OK 01240 set_tag(&_resp_stop, OK); 01241 // Reset info resp prefix 01242 memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); 01243 01244 _last_response_stop = rtos::Kernel::get_ms_count(); 01245 } 01246 01247 void ATHandler::information_response_stop() 01248 { 01249 if (consume_to_stop_tag()) { 01250 set_scope(RespType); 01251 } 01252 } 01253 01254 void ATHandler::information_response_element_stop() 01255 { 01256 if (consume_to_stop_tag()) { 01257 set_scope(InfoType); 01258 } 01259 } 01260 01261 ATHandler::ScopeType ATHandler::get_scope() 01262 { 01263 return _current_scope; 01264 } 01265 01266 const char *ATHandler::mem_str(const char *dest, size_t dest_len, const char *src, size_t src_len) 01267 { 01268 if (dest_len >= src_len) { 01269 for (size_t i = 0; i < dest_len - src_len + 1; ++i) { 01270 if (memcmp(dest + i, src, src_len) == 0) { 01271 return dest + i; 01272 } 01273 } 01274 } 01275 return NULL; 01276 } 01277 01278 void ATHandler::cmd_start(const char *cmd) 01279 { 01280 if (!ok_to_proceed()) { 01281 return; 01282 } 01283 01284 if (_at_send_delay) { 01285 rtos::ThisThread::sleep_until(_last_response_stop + _at_send_delay); 01286 } 01287 01288 (void)write(cmd, strlen(cmd)); 01289 01290 _cmd_start = true; 01291 } 01292 01293 void ATHandler::handle_args(const char *format, std::va_list list) 01294 { 01295 while (*format != '\0') { 01296 if (*format == 'd') { 01297 int32_t i = va_arg(list, int32_t); 01298 write_int(i); 01299 } else if (*format == 's') { 01300 char *str = (char *)va_arg(list, char *); 01301 write_string(str); 01302 } else if (*format == 'b') { 01303 uint8_t *bytes = va_arg(list, uint8_t *); 01304 int size = va_arg(list, int); 01305 write_bytes(bytes, size); 01306 } 01307 ++format; 01308 } 01309 } 01310 01311 void ATHandler::handle_start(const char *cmd, const char *cmd_chr) 01312 { 01313 int len = 0; 01314 memcpy(_cmd_buffer, "AT", 2); 01315 len += 2; 01316 int cmd_char_len = 0; 01317 if (cmd_chr) { 01318 cmd_char_len = strlen(cmd_chr); 01319 } 01320 MBED_ASSERT((3 + strlen(cmd) + cmd_char_len) < BUFF_SIZE); 01321 01322 memcpy(_cmd_buffer + len, cmd, strlen(cmd)); 01323 len += strlen(cmd); 01324 01325 if (cmd_char_len) { 01326 memcpy(_cmd_buffer + len, cmd_chr, cmd_char_len); 01327 len += cmd_char_len; 01328 } 01329 _cmd_buffer[len] = '\0'; 01330 01331 const bool temp_state = get_debug(); 01332 set_debug(true); 01333 01334 cmd_start(_cmd_buffer); 01335 01336 set_debug(temp_state); 01337 } 01338 01339 void ATHandler::cmd_start_stop(const char *cmd, const char *cmd_chr, const char *format, ...) 01340 { 01341 handle_start(cmd, cmd_chr); 01342 01343 va_list list; 01344 va_start(list, format); 01345 handle_args(format, list); 01346 va_end(list); 01347 01348 cmd_stop(); 01349 } 01350 01351 nsapi_error_t ATHandler::at_cmd_str(const char *cmd, const char *cmd_chr, char *resp_buf, size_t buf_size, const char *format, ...) 01352 { 01353 MBED_ASSERT(strlen(cmd) < BUFF_SIZE); 01354 lock(); 01355 01356 handle_start(cmd, cmd_chr); 01357 01358 va_list list; 01359 va_start(list, format); 01360 handle_args(format, list); 01361 va_end(list); 01362 01363 cmd_stop(); 01364 01365 if (strlen(cmd) > 0) { 01366 memcpy(_cmd_buffer, cmd, strlen(cmd)); 01367 _cmd_buffer[strlen(cmd)] = ':'; 01368 _cmd_buffer[strlen(cmd) + 1] = '\0'; 01369 resp_start(_cmd_buffer); 01370 } else { 01371 resp_start(); 01372 } 01373 01374 resp_buf[0] = '\0'; 01375 read_string(resp_buf, buf_size); 01376 resp_stop(); 01377 return unlock_return_error(); 01378 } 01379 01380 nsapi_error_t ATHandler::at_cmd_int(const char *cmd, const char *cmd_chr, int &resp, const char *format, ...) 01381 { 01382 lock(); 01383 01384 handle_start(cmd, cmd_chr); 01385 01386 va_list list; 01387 va_start(list, format); 01388 handle_args(format, list); 01389 va_end(list); 01390 01391 cmd_stop(); 01392 char temp[16]; 01393 size_t len = strlen(cmd); 01394 memcpy(temp, cmd, len); 01395 temp[len] = ':'; 01396 temp[len + 1] = '\0'; 01397 resp_start(temp); 01398 01399 resp = read_int(); 01400 resp_stop(); 01401 return unlock_return_error(); 01402 } 01403 01404 nsapi_error_t ATHandler::at_cmd_discard(const char *cmd, const char *cmd_chr, const char *format, ...) 01405 { 01406 lock(); 01407 01408 handle_start(cmd, cmd_chr); 01409 01410 va_list list; 01411 va_start(list, format); 01412 handle_args(format, list); 01413 va_end(list); 01414 01415 cmd_stop_read_resp(); 01416 return unlock_return_error(); 01417 } 01418 01419 void ATHandler::write_int(int32_t param) 01420 { 01421 // do common checks before sending subparameter 01422 if (check_cmd_send() == false) { 01423 return; 01424 } 01425 01426 // write the integer subparameter 01427 const int32_t str_len = 12; 01428 char number_string[str_len]; 01429 int32_t result = sprintf(number_string, "%" PRIi32, param); 01430 if (result > 0 && result < str_len) { 01431 (void)write(number_string, strlen(number_string)); 01432 } 01433 } 01434 01435 void ATHandler::write_string(const char *param, bool useQuotations) 01436 { 01437 // do common checks before sending subparameter 01438 if (check_cmd_send() == false) { 01439 return; 01440 } 01441 01442 // we are writing string, surround it with quotes 01443 if (useQuotations && write("\"", 1) != 1) { 01444 return; 01445 } 01446 01447 (void)write(param, strlen(param)); 01448 01449 if (useQuotations) { 01450 // we are writing string, surround it with quotes 01451 (void)write("\"", 1); 01452 } 01453 } 01454 01455 void ATHandler::cmd_stop() 01456 { 01457 if (!ok_to_proceed()) { 01458 return; 01459 } 01460 // Finish with CR 01461 (void)write(_output_delimiter, strlen(_output_delimiter)); 01462 } 01463 01464 void ATHandler::cmd_stop_read_resp() 01465 { 01466 cmd_stop(); 01467 resp_start(); 01468 resp_stop(); 01469 } 01470 01471 size_t ATHandler::write_bytes(const uint8_t *data, size_t len) 01472 { 01473 if (!ok_to_proceed()) { 01474 return 0; 01475 } 01476 01477 return write(data, len); 01478 } 01479 01480 size_t ATHandler::write(const void *data, size_t len) 01481 { 01482 pollfh fhs; 01483 fhs.fh = _fileHandle; 01484 fhs.events = POLLOUT; 01485 size_t write_len = 0; 01486 01487 #if MBED_CONF_CELLULAR_DEBUG_AT 01488 bool suppress_traced = false; 01489 #endif 01490 01491 for (; write_len < len;) { 01492 int count = poll(&fhs, 1, poll_timeout()); 01493 if (count <= 0 || !(fhs.revents & POLLOUT)) { 01494 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01495 return 0; 01496 } 01497 ssize_t ret = _fileHandle->write((uint8_t *)data + write_len, len - write_len); 01498 if (ret < 0) { 01499 set_error(NSAPI_ERROR_DEVICE_ERROR ); 01500 return 0; 01501 } 01502 01503 #if MBED_CONF_CELLULAR_DEBUG_AT 01504 if (write_len + ret > DEBUG_MAXLEN) { 01505 if (_debug_on && !suppress_traced) { 01506 debug_print((char *)data + write_len, DEBUG_MAXLEN, AT_TX); 01507 tr_debug("write trace suppressed (total length %d)", len); 01508 } 01509 suppress_traced = true; 01510 } else { 01511 debug_print((char *)data + write_len, ret, AT_TX); 01512 } 01513 #endif 01514 01515 write_len += (size_t)ret; 01516 } 01517 01518 return write_len; 01519 } 01520 01521 // do common checks before sending subparameters 01522 bool ATHandler::check_cmd_send() 01523 { 01524 if (!ok_to_proceed()) { 01525 return false; 01526 } 01527 01528 01529 // Don't write delimiter if flag was set so 01530 01531 // Don't write delimiter if this is the first subparameter 01532 if (_cmd_start) { 01533 _cmd_start = false; 01534 } else { 01535 if (_use_delimiter && write(&_delimiter, 1) != 1) { 01536 // writing of delimiter failed, return. write() already have set the _last_err 01537 return false; 01538 } 01539 } 01540 01541 return true; 01542 } 01543 01544 void ATHandler::flush() 01545 { 01546 if (!_is_fh_usable) { 01547 _last_err = NSAPI_ERROR_BUSY ; 01548 return; 01549 } 01550 tr_debug("AT flush"); 01551 reset_buffer(); 01552 while (fill_buffer(false)) { 01553 reset_buffer(); 01554 } 01555 } 01556 01557 void ATHandler::debug_print(const char *p, int len, ATType type) 01558 { 01559 #if MBED_CONF_CELLULAR_DEBUG_AT 01560 if (_debug_on) { 01561 const int buf_size = len * 4 + 1; // x4 -> reserve space for extra characters, +1 -> terminating null 01562 char *buffer = new char [buf_size]; 01563 if (buffer) { 01564 memset(buffer, 0, buf_size); 01565 01566 char *pbuf = buffer; 01567 for (ssize_t i = 0; i < len; i++) { 01568 const char c = *p++; 01569 if (isprint(c)) { 01570 *pbuf++ = c; 01571 } else if (c == '\r') { 01572 sprintf(pbuf, "<cr>"); 01573 pbuf += 4; 01574 } else if (c == '\n') { 01575 sprintf(pbuf, "<ln>"); 01576 pbuf += 4; 01577 } else { 01578 sprintf(pbuf, "<%02X>", c); 01579 pbuf += 4; 01580 } 01581 } 01582 MBED_ASSERT((int)(pbuf - buffer) <= buf_size); // Check for buffer overflow 01583 01584 if (type == AT_RX) { 01585 tr_info("AT RX (%2d): %s", len, buffer); 01586 } else if (type == AT_TX) { 01587 tr_info("AT TX (%2d): %s", len, buffer); 01588 } else { 01589 tr_info("AT ERR (%2d): %s", len, buffer); 01590 } 01591 01592 delete [] buffer; 01593 } else { 01594 tr_error("AT trace unable to allocate buffer!"); 01595 } 01596 } 01597 #endif // MBED_CONF_CELLULAR_DEBUG_AT 01598 } 01599 01600 bool ATHandler::sync(int timeout_ms) 01601 { 01602 if (!_is_fh_usable) { 01603 _last_err = NSAPI_ERROR_BUSY ; 01604 return false; 01605 } 01606 tr_debug("AT sync"); 01607 lock(); 01608 uint32_t timeout = _at_timeout; 01609 _at_timeout = timeout_ms; 01610 // poll for 10 seconds 01611 for (int i = 0; i < 10; i++) { 01612 // For sync use an AT command that is supported by all modems and likely not used frequently, 01613 // especially a common response like OK could be response to previous request. 01614 clear_error(); 01615 _start_time = rtos::Kernel::get_ms_count(); 01616 cmd_start("AT+CMEE?"); 01617 cmd_stop(); 01618 resp_start(); 01619 set_stop_tag("+CMEE:"); 01620 consume_to_stop_tag(); 01621 set_stop_tag(OK); 01622 consume_to_stop_tag(); 01623 if (!_last_err) { 01624 _at_timeout = timeout; 01625 unlock(); 01626 return true; 01627 } 01628 } 01629 tr_error("AT sync failed"); 01630 _at_timeout = timeout; 01631 unlock(); 01632 return false; 01633 } 01634 01635 void ATHandler::set_send_delay(uint16_t send_delay) 01636 { 01637 _at_send_delay = send_delay; 01638 } 01639 01640 void ATHandler::write_hex_string(char *str, size_t size) 01641 { 01642 // do common checks before sending subparameter 01643 if (check_cmd_send() == false) { 01644 return; 01645 } 01646 01647 (void) write("\"", 1); 01648 char hexbuf[2]; 01649 for (size_t i = 0; i < size; i++) { 01650 hexbuf[0] = hex_values[((str[i]) >> 4) & 0x0F]; 01651 hexbuf[1] = hex_values[(str[i]) & 0x0F]; 01652 write(hexbuf, 2); 01653 } 01654 (void) write("\"", 1); 01655 } 01656 01657 void ATHandler::set_baud(int baud_rate) 01658 { 01659 static_cast<UARTSerial *>(_fileHandle)->set_baud(baud_rate); 01660 } 01661
Generated on Tue Jul 12 2022 13:54:02 by
