takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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