Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ATHandler.cpp Source File

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