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.
features/cellular/framework/AT/ATHandler.cpp@2:7aab896b1a3b, 2019-03-13 (annotated)
- Committer:
- kevman
- Date:
- Wed Mar 13 11:03:24 2019 +0000
- Revision:
- 2:7aab896b1a3b
- Parent:
- 0:38ceb79fef03
2019-03-13
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| kevman | 0:38ceb79fef03 | 1 | /* |
| kevman | 0:38ceb79fef03 | 2 | * Copyright (c) 2017, Arm Limited and affiliates. |
| kevman | 0:38ceb79fef03 | 3 | * SPDX-License-Identifier: Apache-2.0 |
| kevman | 0:38ceb79fef03 | 4 | * |
| kevman | 0:38ceb79fef03 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| kevman | 0:38ceb79fef03 | 6 | * you may not use this file except in compliance with the License. |
| kevman | 0:38ceb79fef03 | 7 | * You may obtain a copy of the License at |
| kevman | 0:38ceb79fef03 | 8 | * |
| kevman | 0:38ceb79fef03 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| kevman | 0:38ceb79fef03 | 10 | * |
| kevman | 0:38ceb79fef03 | 11 | * Unless required by applicable law or agreed to in writing, software |
| kevman | 0:38ceb79fef03 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| kevman | 0:38ceb79fef03 | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| kevman | 0:38ceb79fef03 | 14 | * See the License for the specific language governing permissions and |
| kevman | 0:38ceb79fef03 | 15 | * limitations under the License. |
| kevman | 0:38ceb79fef03 | 16 | */ |
| kevman | 0:38ceb79fef03 | 17 | |
| kevman | 0:38ceb79fef03 | 18 | #include <ctype.h> |
| kevman | 0:38ceb79fef03 | 19 | #include <stdio.h> |
| kevman | 0:38ceb79fef03 | 20 | #include <limits.h> |
| kevman | 0:38ceb79fef03 | 21 | #include "ATHandler.h" |
| kevman | 0:38ceb79fef03 | 22 | #include "mbed_poll.h" |
| kevman | 0:38ceb79fef03 | 23 | #include "FileHandle.h" |
| kevman | 0:38ceb79fef03 | 24 | #include "mbed_wait_api.h" |
| kevman | 0:38ceb79fef03 | 25 | #include "mbed_debug.h" |
| kevman | 0:38ceb79fef03 | 26 | #include "rtos/Thread.h" |
| kevman | 0:38ceb79fef03 | 27 | #include "Kernel.h" |
| kevman | 0:38ceb79fef03 | 28 | #include "CellularUtil.h" |
| kevman | 0:38ceb79fef03 | 29 | |
| kevman | 0:38ceb79fef03 | 30 | using namespace mbed; |
| kevman | 0:38ceb79fef03 | 31 | using namespace events; |
| kevman | 0:38ceb79fef03 | 32 | using namespace mbed_cellular_util; |
| kevman | 0:38ceb79fef03 | 33 | |
| kevman | 0:38ceb79fef03 | 34 | #include "CellularLog.h" |
| kevman | 0:38ceb79fef03 | 35 | |
| kevman | 0:38ceb79fef03 | 36 | // URCs should be handled fast, if you add debug traces within URC processing then you also need to increase this time |
| kevman | 0:38ceb79fef03 | 37 | #define PROCESS_URC_TIME 20 |
| kevman | 0:38ceb79fef03 | 38 | |
| kevman | 0:38ceb79fef03 | 39 | const char *mbed::OK = "OK\r\n"; |
| kevman | 0:38ceb79fef03 | 40 | const uint8_t OK_LENGTH = 4; |
| kevman | 0:38ceb79fef03 | 41 | const char *mbed::CRLF = "\r\n"; |
| kevman | 0:38ceb79fef03 | 42 | const uint8_t CRLF_LENGTH = 2; |
| kevman | 0:38ceb79fef03 | 43 | const char *CME_ERROR = "+CME ERROR:"; |
| kevman | 0:38ceb79fef03 | 44 | const uint8_t CME_ERROR_LENGTH = 11; |
| kevman | 0:38ceb79fef03 | 45 | const char *CMS_ERROR = "+CMS ERROR:"; |
| kevman | 0:38ceb79fef03 | 46 | const uint8_t CMS_ERROR_LENGTH = 11; |
| kevman | 0:38ceb79fef03 | 47 | const char *ERROR_ = "ERROR\r\n"; |
| kevman | 0:38ceb79fef03 | 48 | const uint8_t ERROR_LENGTH = 7; |
| kevman | 0:38ceb79fef03 | 49 | const uint8_t MAX_RESP_LENGTH = CMS_ERROR_LENGTH; |
| kevman | 0:38ceb79fef03 | 50 | const char DEFAULT_DELIMITER = ','; |
| kevman | 0:38ceb79fef03 | 51 | |
| kevman | 0:38ceb79fef03 | 52 | static const uint8_t map_3gpp_errors[][2] = { |
| kevman | 0:38ceb79fef03 | 53 | { 103, 3 }, { 106, 6 }, { 107, 7 }, { 108, 8 }, { 111, 11 }, { 112, 12 }, { 113, 13 }, { 114, 14 }, |
| kevman | 0:38ceb79fef03 | 54 | { 115, 15 }, { 122, 22 }, { 125, 25 }, { 172, 95 }, { 173, 96 }, { 174, 97 }, { 175, 99 }, { 176, 111 }, |
| kevman | 0:38ceb79fef03 | 55 | { 177, 8 }, { 126, 26 }, { 127, 27 }, { 128, 28 }, { 129, 29 }, { 130, 30 }, { 131, 31 }, { 132, 32 }, |
| kevman | 0:38ceb79fef03 | 56 | { 133, 33 }, { 134, 34 }, { 140, 40 }, { 141, 41 }, { 142, 42 }, { 143, 43 }, { 144, 44 }, { 145, 45 }, |
| kevman | 0:38ceb79fef03 | 57 | { 146, 46 }, { 178, 65 }, { 179, 66 }, { 180, 48 }, { 181, 83 }, { 171, 49 }, |
| kevman | 0:38ceb79fef03 | 58 | }; |
| kevman | 0:38ceb79fef03 | 59 | |
| kevman | 0:38ceb79fef03 | 60 | ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char *output_delimiter, uint16_t send_delay) : |
| kevman | 0:38ceb79fef03 | 61 | _nextATHandler(0), |
| kevman | 0:38ceb79fef03 | 62 | _fileHandle(fh), |
| kevman | 0:38ceb79fef03 | 63 | _queue(queue), |
| kevman | 0:38ceb79fef03 | 64 | _last_err(NSAPI_ERROR_OK), |
| kevman | 0:38ceb79fef03 | 65 | _last_3gpp_error(0), |
| kevman | 0:38ceb79fef03 | 66 | _oob_string_max_length(0), |
| kevman | 0:38ceb79fef03 | 67 | _oobs(NULL), |
| kevman | 0:38ceb79fef03 | 68 | _at_timeout(timeout), |
| kevman | 0:38ceb79fef03 | 69 | _previous_at_timeout(timeout), |
| kevman | 0:38ceb79fef03 | 70 | _at_send_delay(send_delay), |
| kevman | 0:38ceb79fef03 | 71 | _last_response_stop(0), |
| kevman | 0:38ceb79fef03 | 72 | _fh_sigio_set(false), |
| kevman | 0:38ceb79fef03 | 73 | _processing(false), |
| kevman | 0:38ceb79fef03 | 74 | _ref_count(1), |
| kevman | 0:38ceb79fef03 | 75 | _is_fh_usable(true), |
| kevman | 0:38ceb79fef03 | 76 | _stop_tag(NULL), |
| kevman | 0:38ceb79fef03 | 77 | _delimiter(DEFAULT_DELIMITER), |
| kevman | 0:38ceb79fef03 | 78 | _prefix_matched(false), |
| kevman | 0:38ceb79fef03 | 79 | _urc_matched(false), |
| kevman | 0:38ceb79fef03 | 80 | _error_found(false), |
| kevman | 0:38ceb79fef03 | 81 | _max_resp_length(MAX_RESP_LENGTH), |
| kevman | 0:38ceb79fef03 | 82 | _debug_on(MBED_CONF_CELLULAR_DEBUG_AT), |
| kevman | 0:38ceb79fef03 | 83 | _cmd_start(false), |
| kevman | 0:38ceb79fef03 | 84 | _start_time(0) |
| kevman | 0:38ceb79fef03 | 85 | { |
| kevman | 0:38ceb79fef03 | 86 | clear_error(); |
| kevman | 0:38ceb79fef03 | 87 | |
| kevman | 0:38ceb79fef03 | 88 | if (output_delimiter) { |
| kevman | 0:38ceb79fef03 | 89 | _output_delimiter = new char[strlen(output_delimiter) + 1]; |
| kevman | 0:38ceb79fef03 | 90 | if (!_output_delimiter) { |
| kevman | 0:38ceb79fef03 | 91 | MBED_ASSERT(0); |
| kevman | 0:38ceb79fef03 | 92 | } else { |
| kevman | 0:38ceb79fef03 | 93 | memcpy(_output_delimiter, output_delimiter, strlen(output_delimiter) + 1); |
| kevman | 0:38ceb79fef03 | 94 | } |
| kevman | 0:38ceb79fef03 | 95 | } else { |
| kevman | 0:38ceb79fef03 | 96 | _output_delimiter = NULL; |
| kevman | 0:38ceb79fef03 | 97 | } |
| kevman | 0:38ceb79fef03 | 98 | |
| kevman | 0:38ceb79fef03 | 99 | reset_buffer(); |
| kevman | 0:38ceb79fef03 | 100 | memset(_recv_buff, 0, sizeof(_recv_buff)); |
| kevman | 0:38ceb79fef03 | 101 | memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); |
| kevman | 0:38ceb79fef03 | 102 | |
| kevman | 0:38ceb79fef03 | 103 | _current_scope = NotSet; |
| kevman | 0:38ceb79fef03 | 104 | set_tag(&_resp_stop, OK); |
| kevman | 0:38ceb79fef03 | 105 | set_tag(&_info_stop, CRLF); |
| kevman | 0:38ceb79fef03 | 106 | set_tag(&_elem_stop, ")"); |
| kevman | 0:38ceb79fef03 | 107 | |
| kevman | 0:38ceb79fef03 | 108 | _fileHandle->set_blocking(false); |
| kevman | 0:38ceb79fef03 | 109 | |
| kevman | 0:38ceb79fef03 | 110 | set_filehandle_sigio(); |
| kevman | 0:38ceb79fef03 | 111 | } |
| kevman | 0:38ceb79fef03 | 112 | |
| kevman | 0:38ceb79fef03 | 113 | void ATHandler::set_debug(bool debug_on) |
| kevman | 0:38ceb79fef03 | 114 | { |
| kevman | 0:38ceb79fef03 | 115 | _debug_on = debug_on; |
| kevman | 0:38ceb79fef03 | 116 | } |
| kevman | 0:38ceb79fef03 | 117 | |
| kevman | 0:38ceb79fef03 | 118 | ATHandler::~ATHandler() |
| kevman | 0:38ceb79fef03 | 119 | { |
| kevman | 0:38ceb79fef03 | 120 | while (_oobs) { |
| kevman | 0:38ceb79fef03 | 121 | struct oob_t *oob = _oobs; |
| kevman | 0:38ceb79fef03 | 122 | _oobs = oob->next; |
| kevman | 0:38ceb79fef03 | 123 | delete oob; |
| kevman | 0:38ceb79fef03 | 124 | } |
| kevman | 0:38ceb79fef03 | 125 | if (_output_delimiter) { |
| kevman | 0:38ceb79fef03 | 126 | delete [] _output_delimiter; |
| kevman | 0:38ceb79fef03 | 127 | } |
| kevman | 0:38ceb79fef03 | 128 | } |
| kevman | 0:38ceb79fef03 | 129 | |
| kevman | 0:38ceb79fef03 | 130 | void ATHandler::inc_ref_count() |
| kevman | 0:38ceb79fef03 | 131 | { |
| kevman | 0:38ceb79fef03 | 132 | _ref_count++; |
| kevman | 0:38ceb79fef03 | 133 | } |
| kevman | 0:38ceb79fef03 | 134 | |
| kevman | 0:38ceb79fef03 | 135 | void ATHandler::dec_ref_count() |
| kevman | 0:38ceb79fef03 | 136 | { |
| kevman | 0:38ceb79fef03 | 137 | _ref_count--; |
| kevman | 0:38ceb79fef03 | 138 | } |
| kevman | 0:38ceb79fef03 | 139 | |
| kevman | 0:38ceb79fef03 | 140 | int ATHandler::get_ref_count() |
| kevman | 0:38ceb79fef03 | 141 | { |
| kevman | 0:38ceb79fef03 | 142 | return _ref_count; |
| kevman | 0:38ceb79fef03 | 143 | } |
| kevman | 0:38ceb79fef03 | 144 | |
| kevman | 0:38ceb79fef03 | 145 | FileHandle *ATHandler::get_file_handle() |
| kevman | 0:38ceb79fef03 | 146 | { |
| kevman | 0:38ceb79fef03 | 147 | return _fileHandle; |
| kevman | 0:38ceb79fef03 | 148 | } |
| kevman | 0:38ceb79fef03 | 149 | |
| kevman | 0:38ceb79fef03 | 150 | void ATHandler::set_file_handle(FileHandle *fh) |
| kevman | 0:38ceb79fef03 | 151 | { |
| kevman | 0:38ceb79fef03 | 152 | _fileHandle = fh; |
| kevman | 0:38ceb79fef03 | 153 | } |
| kevman | 0:38ceb79fef03 | 154 | |
| kevman | 0:38ceb79fef03 | 155 | void ATHandler::set_is_filehandle_usable(bool usable) |
| kevman | 0:38ceb79fef03 | 156 | { |
| kevman | 0:38ceb79fef03 | 157 | _is_fh_usable = usable; |
| kevman | 0:38ceb79fef03 | 158 | } |
| kevman | 0:38ceb79fef03 | 159 | |
| kevman | 0:38ceb79fef03 | 160 | nsapi_error_t ATHandler::set_urc_handler(const char *prefix, mbed::Callback<void()> callback) |
| kevman | 0:38ceb79fef03 | 161 | { |
| kevman | 0:38ceb79fef03 | 162 | if (find_urc_handler(prefix, &callback)) { |
| kevman | 0:38ceb79fef03 | 163 | tr_warn("URC already added with prefix: %s", prefix); |
| kevman | 0:38ceb79fef03 | 164 | return NSAPI_ERROR_OK; |
| kevman | 0:38ceb79fef03 | 165 | } |
| kevman | 0:38ceb79fef03 | 166 | |
| kevman | 0:38ceb79fef03 | 167 | struct oob_t *oob = new struct oob_t; |
| kevman | 0:38ceb79fef03 | 168 | if (!oob) { |
| kevman | 0:38ceb79fef03 | 169 | return NSAPI_ERROR_NO_MEMORY; |
| kevman | 0:38ceb79fef03 | 170 | } else { |
| kevman | 0:38ceb79fef03 | 171 | size_t prefix_len = strlen(prefix); |
| kevman | 0:38ceb79fef03 | 172 | if (prefix_len > _oob_string_max_length) { |
| kevman | 0:38ceb79fef03 | 173 | _oob_string_max_length = prefix_len; |
| kevman | 0:38ceb79fef03 | 174 | if (_oob_string_max_length > _max_resp_length) { |
| kevman | 0:38ceb79fef03 | 175 | _max_resp_length = _oob_string_max_length; |
| kevman | 0:38ceb79fef03 | 176 | } |
| kevman | 0:38ceb79fef03 | 177 | } |
| kevman | 0:38ceb79fef03 | 178 | |
| kevman | 0:38ceb79fef03 | 179 | oob->prefix = prefix; |
| kevman | 0:38ceb79fef03 | 180 | oob->prefix_len = prefix_len; |
| kevman | 0:38ceb79fef03 | 181 | oob->cb = callback; |
| kevman | 0:38ceb79fef03 | 182 | oob->next = _oobs; |
| kevman | 0:38ceb79fef03 | 183 | _oobs = oob; |
| kevman | 0:38ceb79fef03 | 184 | } |
| kevman | 0:38ceb79fef03 | 185 | |
| kevman | 0:38ceb79fef03 | 186 | return NSAPI_ERROR_OK; |
| kevman | 0:38ceb79fef03 | 187 | } |
| kevman | 0:38ceb79fef03 | 188 | |
| kevman | 0:38ceb79fef03 | 189 | void ATHandler::remove_urc_handler(const char *prefix, mbed::Callback<void()> callback) |
| kevman | 0:38ceb79fef03 | 190 | { |
| kevman | 0:38ceb79fef03 | 191 | struct oob_t *current = _oobs; |
| kevman | 0:38ceb79fef03 | 192 | struct oob_t *prev = NULL; |
| kevman | 0:38ceb79fef03 | 193 | while (current) { |
| kevman | 0:38ceb79fef03 | 194 | if (strcmp(prefix, current->prefix) == 0 && current->cb == callback) { |
| kevman | 0:38ceb79fef03 | 195 | if (prev) { |
| kevman | 0:38ceb79fef03 | 196 | prev->next = current->next; |
| kevman | 0:38ceb79fef03 | 197 | } else { |
| kevman | 0:38ceb79fef03 | 198 | _oobs = current->next; |
| kevman | 0:38ceb79fef03 | 199 | } |
| kevman | 0:38ceb79fef03 | 200 | delete current; |
| kevman | 0:38ceb79fef03 | 201 | break; |
| kevman | 0:38ceb79fef03 | 202 | } |
| kevman | 0:38ceb79fef03 | 203 | prev = current; |
| kevman | 0:38ceb79fef03 | 204 | current = prev->next; |
| kevman | 0:38ceb79fef03 | 205 | } |
| kevman | 0:38ceb79fef03 | 206 | } |
| kevman | 0:38ceb79fef03 | 207 | |
| kevman | 0:38ceb79fef03 | 208 | bool ATHandler::find_urc_handler(const char *prefix, mbed::Callback<void()> *callback) |
| kevman | 0:38ceb79fef03 | 209 | { |
| kevman | 0:38ceb79fef03 | 210 | struct oob_t *oob = _oobs; |
| kevman | 0:38ceb79fef03 | 211 | while (oob) { |
| kevman | 0:38ceb79fef03 | 212 | if (strcmp(prefix, oob->prefix) == 0 && oob->cb == *callback) { |
| kevman | 0:38ceb79fef03 | 213 | return true; |
| kevman | 0:38ceb79fef03 | 214 | } |
| kevman | 0:38ceb79fef03 | 215 | oob = oob->next; |
| kevman | 0:38ceb79fef03 | 216 | } |
| kevman | 0:38ceb79fef03 | 217 | |
| kevman | 0:38ceb79fef03 | 218 | return false; |
| kevman | 0:38ceb79fef03 | 219 | } |
| kevman | 0:38ceb79fef03 | 220 | |
| kevman | 0:38ceb79fef03 | 221 | void ATHandler::event() |
| kevman | 0:38ceb79fef03 | 222 | { |
| kevman | 0:38ceb79fef03 | 223 | // _processing must be set before filehandle write/read to avoid repetitive sigio events |
| kevman | 0:38ceb79fef03 | 224 | if (!_processing) { |
| kevman | 0:38ceb79fef03 | 225 | _processing = true; |
| kevman | 0:38ceb79fef03 | 226 | (void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob)); |
| kevman | 0:38ceb79fef03 | 227 | } |
| kevman | 0:38ceb79fef03 | 228 | } |
| kevman | 0:38ceb79fef03 | 229 | |
| kevman | 0:38ceb79fef03 | 230 | void ATHandler::lock() |
| kevman | 0:38ceb79fef03 | 231 | { |
| kevman | 0:38ceb79fef03 | 232 | #ifdef AT_HANDLER_MUTEX |
| kevman | 0:38ceb79fef03 | 233 | _fileHandleMutex.lock(); |
| kevman | 0:38ceb79fef03 | 234 | #endif |
| kevman | 0:38ceb79fef03 | 235 | _processing = true; |
| kevman | 0:38ceb79fef03 | 236 | clear_error(); |
| kevman | 0:38ceb79fef03 | 237 | _start_time = rtos::Kernel::get_ms_count(); |
| kevman | 0:38ceb79fef03 | 238 | } |
| kevman | 0:38ceb79fef03 | 239 | |
| kevman | 0:38ceb79fef03 | 240 | void ATHandler::unlock() |
| kevman | 0:38ceb79fef03 | 241 | { |
| kevman | 0:38ceb79fef03 | 242 | _processing = false; |
| kevman | 0:38ceb79fef03 | 243 | #ifdef AT_HANDLER_MUTEX |
| kevman | 0:38ceb79fef03 | 244 | _fileHandleMutex.unlock(); |
| kevman | 0:38ceb79fef03 | 245 | #endif |
| kevman | 0:38ceb79fef03 | 246 | if (_fileHandle->readable() || (_recv_pos < _recv_len)) { |
| kevman | 0:38ceb79fef03 | 247 | (void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob)); |
| kevman | 0:38ceb79fef03 | 248 | } |
| kevman | 0:38ceb79fef03 | 249 | } |
| kevman | 0:38ceb79fef03 | 250 | |
| kevman | 0:38ceb79fef03 | 251 | nsapi_error_t ATHandler::unlock_return_error() |
| kevman | 0:38ceb79fef03 | 252 | { |
| kevman | 0:38ceb79fef03 | 253 | nsapi_error_t err = _last_err; |
| kevman | 0:38ceb79fef03 | 254 | unlock(); |
| kevman | 0:38ceb79fef03 | 255 | return err; |
| kevman | 0:38ceb79fef03 | 256 | } |
| kevman | 0:38ceb79fef03 | 257 | |
| kevman | 0:38ceb79fef03 | 258 | void ATHandler::set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout) |
| kevman | 0:38ceb79fef03 | 259 | { |
| kevman | 0:38ceb79fef03 | 260 | if (default_timeout) { |
| kevman | 0:38ceb79fef03 | 261 | _previous_at_timeout = timeout_milliseconds; |
| kevman | 0:38ceb79fef03 | 262 | _at_timeout = timeout_milliseconds; |
| kevman | 0:38ceb79fef03 | 263 | } else if (timeout_milliseconds != _at_timeout) { |
| kevman | 0:38ceb79fef03 | 264 | _previous_at_timeout = _at_timeout; |
| kevman | 0:38ceb79fef03 | 265 | _at_timeout = timeout_milliseconds; |
| kevman | 0:38ceb79fef03 | 266 | } |
| kevman | 0:38ceb79fef03 | 267 | } |
| kevman | 0:38ceb79fef03 | 268 | |
| kevman | 0:38ceb79fef03 | 269 | void ATHandler::restore_at_timeout() |
| kevman | 0:38ceb79fef03 | 270 | { |
| kevman | 0:38ceb79fef03 | 271 | if (_previous_at_timeout != _at_timeout) { |
| kevman | 0:38ceb79fef03 | 272 | _at_timeout = _previous_at_timeout; |
| kevman | 0:38ceb79fef03 | 273 | } |
| kevman | 0:38ceb79fef03 | 274 | } |
| kevman | 0:38ceb79fef03 | 275 | |
| kevman | 0:38ceb79fef03 | 276 | void ATHandler::process_oob() |
| kevman | 0:38ceb79fef03 | 277 | { |
| kevman | 0:38ceb79fef03 | 278 | if (!_is_fh_usable) { |
| kevman | 0:38ceb79fef03 | 279 | tr_debug("process_oob, filehandle is not usable, return..."); |
| kevman | 0:38ceb79fef03 | 280 | return; |
| kevman | 0:38ceb79fef03 | 281 | } |
| kevman | 0:38ceb79fef03 | 282 | lock(); |
| kevman | 0:38ceb79fef03 | 283 | tr_debug("process_oob readable=%d, pos=%u, len=%u", _fileHandle->readable(), _recv_pos, _recv_len); |
| kevman | 0:38ceb79fef03 | 284 | if (_fileHandle->readable() || (_recv_pos < _recv_len)) { |
| kevman | 0:38ceb79fef03 | 285 | _current_scope = NotSet; |
| kevman | 0:38ceb79fef03 | 286 | uint32_t timeout = _at_timeout; |
| kevman | 0:38ceb79fef03 | 287 | _at_timeout = PROCESS_URC_TIME; |
| kevman | 0:38ceb79fef03 | 288 | while (true) { |
| kevman | 0:38ceb79fef03 | 289 | if (match_urc()) { |
| kevman | 0:38ceb79fef03 | 290 | if (!(_fileHandle->readable() || (_recv_pos < _recv_len))) { |
| kevman | 0:38ceb79fef03 | 291 | break; // we have nothing to read anymore |
| kevman | 0:38ceb79fef03 | 292 | } |
| kevman | 0:38ceb79fef03 | 293 | } else if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { // If no match found, look for CRLF and consume everything up to CRLF |
| kevman | 0:38ceb79fef03 | 294 | consume_to_tag(CRLF, true); |
| kevman | 0:38ceb79fef03 | 295 | } else { |
| kevman | 0:38ceb79fef03 | 296 | if (!fill_buffer()) { |
| kevman | 0:38ceb79fef03 | 297 | reset_buffer(); // consume anything that could not be handled |
| kevman | 0:38ceb79fef03 | 298 | break; |
| kevman | 0:38ceb79fef03 | 299 | } |
| kevman | 0:38ceb79fef03 | 300 | _start_time = rtos::Kernel::get_ms_count(); |
| kevman | 0:38ceb79fef03 | 301 | } |
| kevman | 0:38ceb79fef03 | 302 | } |
| kevman | 0:38ceb79fef03 | 303 | _at_timeout = timeout; |
| kevman | 0:38ceb79fef03 | 304 | } |
| kevman | 0:38ceb79fef03 | 305 | tr_debug("process_oob exit"); |
| kevman | 0:38ceb79fef03 | 306 | unlock(); |
| kevman | 0:38ceb79fef03 | 307 | } |
| kevman | 0:38ceb79fef03 | 308 | |
| kevman | 0:38ceb79fef03 | 309 | void ATHandler::set_filehandle_sigio() |
| kevman | 0:38ceb79fef03 | 310 | { |
| kevman | 0:38ceb79fef03 | 311 | if (_fh_sigio_set) { |
| kevman | 0:38ceb79fef03 | 312 | return; |
| kevman | 0:38ceb79fef03 | 313 | } |
| kevman | 0:38ceb79fef03 | 314 | _fileHandle->sigio(mbed::Callback<void()>(this, &ATHandler::event)); |
| kevman | 0:38ceb79fef03 | 315 | _fh_sigio_set = true; |
| kevman | 0:38ceb79fef03 | 316 | } |
| kevman | 0:38ceb79fef03 | 317 | |
| kevman | 0:38ceb79fef03 | 318 | void ATHandler::reset_buffer() |
| kevman | 0:38ceb79fef03 | 319 | { |
| kevman | 0:38ceb79fef03 | 320 | _recv_pos = 0; |
| kevman | 0:38ceb79fef03 | 321 | _recv_len = 0; |
| kevman | 0:38ceb79fef03 | 322 | } |
| kevman | 0:38ceb79fef03 | 323 | |
| kevman | 0:38ceb79fef03 | 324 | void ATHandler::rewind_buffer() |
| kevman | 0:38ceb79fef03 | 325 | { |
| kevman | 0:38ceb79fef03 | 326 | if (_recv_pos > 0 && _recv_len >= _recv_pos) { |
| kevman | 0:38ceb79fef03 | 327 | _recv_len -= _recv_pos; |
| kevman | 0:38ceb79fef03 | 328 | // move what is not read to beginning of buffer |
| kevman | 0:38ceb79fef03 | 329 | memmove(_recv_buff, _recv_buff + _recv_pos, _recv_len); |
| kevman | 0:38ceb79fef03 | 330 | _recv_pos = 0; |
| kevman | 0:38ceb79fef03 | 331 | } |
| kevman | 0:38ceb79fef03 | 332 | } |
| kevman | 0:38ceb79fef03 | 333 | |
| kevman | 0:38ceb79fef03 | 334 | int ATHandler::poll_timeout(bool wait_for_timeout) |
| kevman | 0:38ceb79fef03 | 335 | { |
| kevman | 0:38ceb79fef03 | 336 | int timeout; |
| kevman | 0:38ceb79fef03 | 337 | if (wait_for_timeout) { |
| kevman | 0:38ceb79fef03 | 338 | uint64_t now = rtos::Kernel::get_ms_count(); |
| kevman | 0:38ceb79fef03 | 339 | if (now >= _start_time + _at_timeout) { |
| kevman | 0:38ceb79fef03 | 340 | timeout = 0; |
| kevman | 0:38ceb79fef03 | 341 | } else if (_start_time + _at_timeout - now > INT_MAX) { |
| kevman | 0:38ceb79fef03 | 342 | timeout = INT_MAX; |
| kevman | 0:38ceb79fef03 | 343 | } else { |
| kevman | 0:38ceb79fef03 | 344 | timeout = _start_time + _at_timeout - now; |
| kevman | 0:38ceb79fef03 | 345 | } |
| kevman | 0:38ceb79fef03 | 346 | } else { |
| kevman | 0:38ceb79fef03 | 347 | timeout = 0; |
| kevman | 0:38ceb79fef03 | 348 | } |
| kevman | 0:38ceb79fef03 | 349 | return timeout; |
| kevman | 0:38ceb79fef03 | 350 | } |
| kevman | 0:38ceb79fef03 | 351 | |
| kevman | 0:38ceb79fef03 | 352 | bool ATHandler::fill_buffer(bool wait_for_timeout) |
| kevman | 0:38ceb79fef03 | 353 | { |
| kevman | 0:38ceb79fef03 | 354 | // Reset buffer when full |
| kevman | 0:38ceb79fef03 | 355 | if (sizeof(_recv_buff) == _recv_len) { |
| kevman | 0:38ceb79fef03 | 356 | tr_error("AT overflow"); |
| kevman | 0:38ceb79fef03 | 357 | reset_buffer(); |
| kevman | 0:38ceb79fef03 | 358 | } |
| kevman | 0:38ceb79fef03 | 359 | |
| kevman | 0:38ceb79fef03 | 360 | pollfh fhs; |
| kevman | 0:38ceb79fef03 | 361 | fhs.fh = _fileHandle; |
| kevman | 0:38ceb79fef03 | 362 | fhs.events = POLLIN; |
| kevman | 0:38ceb79fef03 | 363 | int count = poll(&fhs, 1, poll_timeout(wait_for_timeout)); |
| kevman | 0:38ceb79fef03 | 364 | if (count > 0 && (fhs.revents & POLLIN)) { |
| kevman | 0:38ceb79fef03 | 365 | ssize_t len = _fileHandle->read(_recv_buff + _recv_len, sizeof(_recv_buff) - _recv_len); |
| kevman | 0:38ceb79fef03 | 366 | if (len > 0) { |
| kevman | 0:38ceb79fef03 | 367 | debug_print(_recv_buff + _recv_len, len); |
| kevman | 0:38ceb79fef03 | 368 | _recv_len += len; |
| kevman | 0:38ceb79fef03 | 369 | return true; |
| kevman | 0:38ceb79fef03 | 370 | } |
| kevman | 0:38ceb79fef03 | 371 | } |
| kevman | 0:38ceb79fef03 | 372 | |
| kevman | 0:38ceb79fef03 | 373 | return false; |
| kevman | 0:38ceb79fef03 | 374 | } |
| kevman | 0:38ceb79fef03 | 375 | |
| kevman | 0:38ceb79fef03 | 376 | int ATHandler::get_char() |
| kevman | 0:38ceb79fef03 | 377 | { |
| kevman | 0:38ceb79fef03 | 378 | if (_recv_pos == _recv_len) { |
| kevman | 0:38ceb79fef03 | 379 | reset_buffer(); // try to read as much as possible |
| kevman | 0:38ceb79fef03 | 380 | if (!fill_buffer()) { |
| kevman | 0:38ceb79fef03 | 381 | tr_warn("AT timeout"); |
| kevman | 0:38ceb79fef03 | 382 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 383 | return -1; // timeout to read |
| kevman | 0:38ceb79fef03 | 384 | } |
| kevman | 0:38ceb79fef03 | 385 | } |
| kevman | 0:38ceb79fef03 | 386 | |
| kevman | 0:38ceb79fef03 | 387 | return _recv_buff[_recv_pos++]; |
| kevman | 0:38ceb79fef03 | 388 | } |
| kevman | 0:38ceb79fef03 | 389 | |
| kevman | 0:38ceb79fef03 | 390 | void ATHandler::skip_param(uint32_t count) |
| kevman | 0:38ceb79fef03 | 391 | { |
| kevman | 0:38ceb79fef03 | 392 | if (_last_err || !_stop_tag || _stop_tag->found) { |
| kevman | 0:38ceb79fef03 | 393 | return; |
| kevman | 0:38ceb79fef03 | 394 | } |
| kevman | 0:38ceb79fef03 | 395 | |
| kevman | 0:38ceb79fef03 | 396 | for (uint32_t i = 0; (i < count && !_stop_tag->found); i++) { |
| kevman | 0:38ceb79fef03 | 397 | size_t match_pos = 0; |
| kevman | 0:38ceb79fef03 | 398 | while (true) { |
| kevman | 0:38ceb79fef03 | 399 | int c = get_char(); |
| kevman | 0:38ceb79fef03 | 400 | if (c == -1) { |
| kevman | 0:38ceb79fef03 | 401 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 402 | return; |
| kevman | 0:38ceb79fef03 | 403 | } else if (c == _delimiter) { |
| kevman | 0:38ceb79fef03 | 404 | break; |
| kevman | 0:38ceb79fef03 | 405 | } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { |
| kevman | 0:38ceb79fef03 | 406 | match_pos++; |
| kevman | 0:38ceb79fef03 | 407 | if (match_pos == _stop_tag->len) { |
| kevman | 0:38ceb79fef03 | 408 | _stop_tag->found = true; |
| kevman | 0:38ceb79fef03 | 409 | break; |
| kevman | 0:38ceb79fef03 | 410 | } |
| kevman | 0:38ceb79fef03 | 411 | } else if (match_pos) { |
| kevman | 0:38ceb79fef03 | 412 | match_pos = 0; |
| kevman | 0:38ceb79fef03 | 413 | } |
| kevman | 0:38ceb79fef03 | 414 | } |
| kevman | 0:38ceb79fef03 | 415 | } |
| kevman | 0:38ceb79fef03 | 416 | return; |
| kevman | 0:38ceb79fef03 | 417 | } |
| kevman | 0:38ceb79fef03 | 418 | |
| kevman | 0:38ceb79fef03 | 419 | void ATHandler::skip_param(ssize_t len, uint32_t count) |
| kevman | 0:38ceb79fef03 | 420 | { |
| kevman | 0:38ceb79fef03 | 421 | if (_last_err || !_stop_tag || _stop_tag->found) { |
| kevman | 0:38ceb79fef03 | 422 | return; |
| kevman | 0:38ceb79fef03 | 423 | } |
| kevman | 0:38ceb79fef03 | 424 | |
| kevman | 0:38ceb79fef03 | 425 | for (uint32_t i = 0; i < count; i++) { |
| kevman | 0:38ceb79fef03 | 426 | ssize_t read_len = 0; |
| kevman | 0:38ceb79fef03 | 427 | while (read_len < len) { |
| kevman | 0:38ceb79fef03 | 428 | int c = get_char(); |
| kevman | 0:38ceb79fef03 | 429 | if (c == -1) { |
| kevman | 0:38ceb79fef03 | 430 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 431 | return; |
| kevman | 0:38ceb79fef03 | 432 | } |
| kevman | 0:38ceb79fef03 | 433 | read_len++; |
| kevman | 0:38ceb79fef03 | 434 | } |
| kevman | 0:38ceb79fef03 | 435 | } |
| kevman | 0:38ceb79fef03 | 436 | return; |
| kevman | 0:38ceb79fef03 | 437 | } |
| kevman | 0:38ceb79fef03 | 438 | |
| kevman | 0:38ceb79fef03 | 439 | ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len) |
| kevman | 0:38ceb79fef03 | 440 | { |
| kevman | 0:38ceb79fef03 | 441 | if (_last_err) { |
| kevman | 0:38ceb79fef03 | 442 | return -1; |
| kevman | 0:38ceb79fef03 | 443 | } |
| kevman | 0:38ceb79fef03 | 444 | |
| kevman | 0:38ceb79fef03 | 445 | size_t read_len = 0; |
| kevman | 0:38ceb79fef03 | 446 | for (; read_len < len; read_len++) { |
| kevman | 0:38ceb79fef03 | 447 | int c = get_char(); |
| kevman | 0:38ceb79fef03 | 448 | if (c == -1) { |
| kevman | 0:38ceb79fef03 | 449 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 450 | return -1; |
| kevman | 0:38ceb79fef03 | 451 | } |
| kevman | 0:38ceb79fef03 | 452 | buf[read_len] = c; |
| kevman | 0:38ceb79fef03 | 453 | } |
| kevman | 0:38ceb79fef03 | 454 | return read_len; |
| kevman | 0:38ceb79fef03 | 455 | } |
| kevman | 0:38ceb79fef03 | 456 | |
| kevman | 0:38ceb79fef03 | 457 | ssize_t ATHandler::read_string(char *buf, size_t size, bool read_even_stop_tag) |
| kevman | 0:38ceb79fef03 | 458 | { |
| kevman | 0:38ceb79fef03 | 459 | if (_last_err || !_stop_tag || (_stop_tag->found && read_even_stop_tag == false)) { |
| kevman | 0:38ceb79fef03 | 460 | return -1; |
| kevman | 0:38ceb79fef03 | 461 | } |
| kevman | 0:38ceb79fef03 | 462 | |
| kevman | 0:38ceb79fef03 | 463 | consume_char('\"'); |
| kevman | 0:38ceb79fef03 | 464 | |
| kevman | 0:38ceb79fef03 | 465 | if (_last_err) { |
| kevman | 0:38ceb79fef03 | 466 | return -1; |
| kevman | 0:38ceb79fef03 | 467 | } |
| kevman | 0:38ceb79fef03 | 468 | |
| kevman | 0:38ceb79fef03 | 469 | size_t len = 0; |
| kevman | 0:38ceb79fef03 | 470 | size_t match_pos = 0; |
| kevman | 0:38ceb79fef03 | 471 | |
| kevman | 0:38ceb79fef03 | 472 | for (; len < (size - 1 + match_pos); len++) { |
| kevman | 0:38ceb79fef03 | 473 | int c = get_char(); |
| kevman | 0:38ceb79fef03 | 474 | if (c == -1) { |
| kevman | 0:38ceb79fef03 | 475 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 476 | return -1; |
| kevman | 0:38ceb79fef03 | 477 | } else if (c == _delimiter) { |
| kevman | 0:38ceb79fef03 | 478 | buf[len] = '\0'; |
| kevman | 0:38ceb79fef03 | 479 | break; |
| kevman | 0:38ceb79fef03 | 480 | } else if (c == '\"') { |
| kevman | 0:38ceb79fef03 | 481 | match_pos = 0; |
| kevman | 0:38ceb79fef03 | 482 | len--; |
| kevman | 0:38ceb79fef03 | 483 | continue; |
| kevman | 0:38ceb79fef03 | 484 | } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { |
| kevman | 0:38ceb79fef03 | 485 | match_pos++; |
| kevman | 0:38ceb79fef03 | 486 | if (match_pos == _stop_tag->len) { |
| kevman | 0:38ceb79fef03 | 487 | _stop_tag->found = true; |
| kevman | 0:38ceb79fef03 | 488 | // remove tag from string if it was matched |
| kevman | 0:38ceb79fef03 | 489 | len -= (_stop_tag->len - 1); |
| kevman | 0:38ceb79fef03 | 490 | buf[len] = '\0'; |
| kevman | 0:38ceb79fef03 | 491 | break; |
| kevman | 0:38ceb79fef03 | 492 | } |
| kevman | 0:38ceb79fef03 | 493 | } else if (match_pos) { |
| kevman | 0:38ceb79fef03 | 494 | match_pos = 0; |
| kevman | 0:38ceb79fef03 | 495 | } |
| kevman | 0:38ceb79fef03 | 496 | |
| kevman | 0:38ceb79fef03 | 497 | buf[len] = c; |
| kevman | 0:38ceb79fef03 | 498 | } |
| kevman | 0:38ceb79fef03 | 499 | |
| kevman | 0:38ceb79fef03 | 500 | if (len && (len == size - 1 + match_pos)) { |
| kevman | 0:38ceb79fef03 | 501 | buf[len] = '\0'; |
| kevman | 0:38ceb79fef03 | 502 | } |
| kevman | 0:38ceb79fef03 | 503 | |
| kevman | 0:38ceb79fef03 | 504 | return len; |
| kevman | 0:38ceb79fef03 | 505 | } |
| kevman | 0:38ceb79fef03 | 506 | |
| kevman | 0:38ceb79fef03 | 507 | ssize_t ATHandler::read_hex_string(char *buf, size_t size) |
| kevman | 0:38ceb79fef03 | 508 | { |
| kevman | 0:38ceb79fef03 | 509 | if (_last_err || !_stop_tag || _stop_tag->found) { |
| kevman | 0:38ceb79fef03 | 510 | return -1; |
| kevman | 0:38ceb79fef03 | 511 | } |
| kevman | 0:38ceb79fef03 | 512 | |
| kevman | 0:38ceb79fef03 | 513 | size_t match_pos = 0; |
| kevman | 0:38ceb79fef03 | 514 | |
| kevman | 0:38ceb79fef03 | 515 | consume_char('\"'); |
| kevman | 0:38ceb79fef03 | 516 | |
| kevman | 0:38ceb79fef03 | 517 | if (_last_err) { |
| kevman | 0:38ceb79fef03 | 518 | return -1; |
| kevman | 0:38ceb79fef03 | 519 | } |
| kevman | 0:38ceb79fef03 | 520 | |
| kevman | 0:38ceb79fef03 | 521 | size_t read_idx = 0; |
| kevman | 0:38ceb79fef03 | 522 | size_t buf_idx = 0; |
| kevman | 0:38ceb79fef03 | 523 | char hexbuf[2]; |
| kevman | 0:38ceb79fef03 | 524 | |
| kevman | 0:38ceb79fef03 | 525 | for (; read_idx < size * 2 + match_pos; read_idx++) { |
| kevman | 0:38ceb79fef03 | 526 | int c = get_char(); |
| kevman | 0:38ceb79fef03 | 527 | |
| kevman | 0:38ceb79fef03 | 528 | if (match_pos) { |
| kevman | 0:38ceb79fef03 | 529 | buf_idx++; |
| kevman | 0:38ceb79fef03 | 530 | } else { |
| kevman | 0:38ceb79fef03 | 531 | buf_idx = read_idx / 2; |
| kevman | 0:38ceb79fef03 | 532 | } |
| kevman | 0:38ceb79fef03 | 533 | |
| kevman | 0:38ceb79fef03 | 534 | if (c == -1) { |
| kevman | 0:38ceb79fef03 | 535 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 536 | return -1; |
| kevman | 0:38ceb79fef03 | 537 | } |
| kevman | 0:38ceb79fef03 | 538 | if (c == _delimiter) { |
| kevman | 0:38ceb79fef03 | 539 | break; |
| kevman | 0:38ceb79fef03 | 540 | } else if (c == '\"') { |
| kevman | 0:38ceb79fef03 | 541 | match_pos = 0; |
| kevman | 0:38ceb79fef03 | 542 | read_idx--; |
| kevman | 0:38ceb79fef03 | 543 | continue; |
| kevman | 0:38ceb79fef03 | 544 | } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { |
| kevman | 0:38ceb79fef03 | 545 | match_pos++; |
| kevman | 0:38ceb79fef03 | 546 | if (match_pos == _stop_tag->len) { |
| kevman | 0:38ceb79fef03 | 547 | _stop_tag->found = true; |
| kevman | 0:38ceb79fef03 | 548 | // remove tag from string if it was matched |
| kevman | 0:38ceb79fef03 | 549 | buf_idx -= (_stop_tag->len - 1); |
| kevman | 0:38ceb79fef03 | 550 | break; |
| kevman | 0:38ceb79fef03 | 551 | } |
| kevman | 0:38ceb79fef03 | 552 | } else if (match_pos) { |
| kevman | 0:38ceb79fef03 | 553 | match_pos = 0; |
| kevman | 0:38ceb79fef03 | 554 | } |
| kevman | 0:38ceb79fef03 | 555 | |
| kevman | 0:38ceb79fef03 | 556 | if (match_pos) { |
| kevman | 0:38ceb79fef03 | 557 | buf[buf_idx] = c; |
| kevman | 0:38ceb79fef03 | 558 | } else { |
| kevman | 0:38ceb79fef03 | 559 | hexbuf[read_idx % 2] = c; |
| kevman | 0:38ceb79fef03 | 560 | if (read_idx % 2 == 1) { |
| kevman | 0:38ceb79fef03 | 561 | hex_str_to_char_str(hexbuf, 2, buf + buf_idx); |
| kevman | 0:38ceb79fef03 | 562 | } |
| kevman | 0:38ceb79fef03 | 563 | } |
| kevman | 0:38ceb79fef03 | 564 | } |
| kevman | 0:38ceb79fef03 | 565 | |
| kevman | 0:38ceb79fef03 | 566 | if (read_idx && (read_idx == size * 2 + match_pos)) { |
| kevman | 0:38ceb79fef03 | 567 | buf_idx++; |
| kevman | 0:38ceb79fef03 | 568 | } |
| kevman | 0:38ceb79fef03 | 569 | |
| kevman | 0:38ceb79fef03 | 570 | return buf_idx; |
| kevman | 0:38ceb79fef03 | 571 | } |
| kevman | 0:38ceb79fef03 | 572 | |
| kevman | 0:38ceb79fef03 | 573 | int32_t ATHandler::read_int() |
| kevman | 0:38ceb79fef03 | 574 | { |
| kevman | 0:38ceb79fef03 | 575 | if (_last_err || !_stop_tag || _stop_tag->found) { |
| kevman | 0:38ceb79fef03 | 576 | return -1; |
| kevman | 0:38ceb79fef03 | 577 | } |
| kevman | 0:38ceb79fef03 | 578 | |
| kevman | 0:38ceb79fef03 | 579 | char buff[BUFF_SIZE]; |
| kevman | 0:38ceb79fef03 | 580 | char *first_no_digit; |
| kevman | 0:38ceb79fef03 | 581 | |
| kevman | 0:38ceb79fef03 | 582 | if (read_string(buff, (size_t)sizeof(buff)) == 0) { |
| kevman | 0:38ceb79fef03 | 583 | return -1; |
| kevman | 0:38ceb79fef03 | 584 | } |
| kevman | 0:38ceb79fef03 | 585 | |
| kevman | 0:38ceb79fef03 | 586 | return std::strtol(buff, &first_no_digit, 10); |
| kevman | 0:38ceb79fef03 | 587 | } |
| kevman | 0:38ceb79fef03 | 588 | |
| kevman | 0:38ceb79fef03 | 589 | void ATHandler::set_delimiter(char delimiter) |
| kevman | 0:38ceb79fef03 | 590 | { |
| kevman | 0:38ceb79fef03 | 591 | _delimiter = delimiter; |
| kevman | 0:38ceb79fef03 | 592 | } |
| kevman | 0:38ceb79fef03 | 593 | |
| kevman | 0:38ceb79fef03 | 594 | void ATHandler::set_default_delimiter() |
| kevman | 0:38ceb79fef03 | 595 | { |
| kevman | 0:38ceb79fef03 | 596 | _delimiter = DEFAULT_DELIMITER; |
| kevman | 0:38ceb79fef03 | 597 | } |
| kevman | 0:38ceb79fef03 | 598 | |
| kevman | 0:38ceb79fef03 | 599 | void ATHandler::set_tag(tag_t *tag_dst, const char *tag_seq) |
| kevman | 0:38ceb79fef03 | 600 | { |
| kevman | 0:38ceb79fef03 | 601 | if (tag_seq) { |
| kevman | 0:38ceb79fef03 | 602 | size_t tag_len = strlen(tag_seq); |
| kevman | 0:38ceb79fef03 | 603 | set_string(tag_dst->tag, tag_seq, tag_len); |
| kevman | 0:38ceb79fef03 | 604 | tag_dst->len = tag_len; |
| kevman | 0:38ceb79fef03 | 605 | tag_dst->found = false; |
| kevman | 0:38ceb79fef03 | 606 | } else { |
| kevman | 0:38ceb79fef03 | 607 | _stop_tag = NULL; |
| kevman | 0:38ceb79fef03 | 608 | } |
| kevman | 0:38ceb79fef03 | 609 | } |
| kevman | 0:38ceb79fef03 | 610 | |
| kevman | 0:38ceb79fef03 | 611 | void ATHandler::set_stop_tag(const char *stop_tag_seq) |
| kevman | 0:38ceb79fef03 | 612 | { |
| kevman | 0:38ceb79fef03 | 613 | if (_last_err || !_stop_tag) { |
| kevman | 0:38ceb79fef03 | 614 | return; |
| kevman | 0:38ceb79fef03 | 615 | } |
| kevman | 0:38ceb79fef03 | 616 | |
| kevman | 0:38ceb79fef03 | 617 | set_tag(_stop_tag, stop_tag_seq); |
| kevman | 0:38ceb79fef03 | 618 | } |
| kevman | 0:38ceb79fef03 | 619 | |
| kevman | 0:38ceb79fef03 | 620 | void ATHandler::set_scope(ScopeType scope_type) |
| kevman | 0:38ceb79fef03 | 621 | { |
| kevman | 0:38ceb79fef03 | 622 | if (_current_scope != scope_type) { |
| kevman | 0:38ceb79fef03 | 623 | _current_scope = scope_type; |
| kevman | 0:38ceb79fef03 | 624 | switch (_current_scope) { |
| kevman | 0:38ceb79fef03 | 625 | case RespType: |
| kevman | 0:38ceb79fef03 | 626 | _stop_tag = &_resp_stop; |
| kevman | 0:38ceb79fef03 | 627 | _stop_tag->found = false; |
| kevman | 0:38ceb79fef03 | 628 | break; |
| kevman | 0:38ceb79fef03 | 629 | case InfoType: |
| kevman | 0:38ceb79fef03 | 630 | _stop_tag = &_info_stop; |
| kevman | 0:38ceb79fef03 | 631 | _stop_tag->found = false; |
| kevman | 0:38ceb79fef03 | 632 | consume_char(' '); |
| kevman | 0:38ceb79fef03 | 633 | break; |
| kevman | 0:38ceb79fef03 | 634 | case ElemType: |
| kevman | 0:38ceb79fef03 | 635 | _stop_tag = &_elem_stop; |
| kevman | 0:38ceb79fef03 | 636 | _stop_tag->found = false; |
| kevman | 0:38ceb79fef03 | 637 | break; |
| kevman | 0:38ceb79fef03 | 638 | case NotSet: |
| kevman | 0:38ceb79fef03 | 639 | _stop_tag = NULL; |
| kevman | 0:38ceb79fef03 | 640 | return; |
| kevman | 0:38ceb79fef03 | 641 | default: |
| kevman | 0:38ceb79fef03 | 642 | break; |
| kevman | 0:38ceb79fef03 | 643 | } |
| kevman | 0:38ceb79fef03 | 644 | } |
| kevman | 0:38ceb79fef03 | 645 | } |
| kevman | 0:38ceb79fef03 | 646 | |
| kevman | 0:38ceb79fef03 | 647 | // should match from recv_pos? |
| kevman | 0:38ceb79fef03 | 648 | bool ATHandler::match(const char *str, size_t size) |
| kevman | 0:38ceb79fef03 | 649 | { |
| kevman | 0:38ceb79fef03 | 650 | rewind_buffer(); |
| kevman | 0:38ceb79fef03 | 651 | |
| kevman | 0:38ceb79fef03 | 652 | if ((_recv_len - _recv_pos) < size) { |
| kevman | 0:38ceb79fef03 | 653 | return false; |
| kevman | 0:38ceb79fef03 | 654 | } |
| kevman | 0:38ceb79fef03 | 655 | |
| kevman | 0:38ceb79fef03 | 656 | if (str && memcmp(_recv_buff + _recv_pos, str, size) == 0) { |
| kevman | 0:38ceb79fef03 | 657 | // consume matching part |
| kevman | 0:38ceb79fef03 | 658 | _recv_pos += size; |
| kevman | 0:38ceb79fef03 | 659 | return true; |
| kevman | 0:38ceb79fef03 | 660 | } |
| kevman | 0:38ceb79fef03 | 661 | return false; |
| kevman | 0:38ceb79fef03 | 662 | } |
| kevman | 0:38ceb79fef03 | 663 | |
| kevman | 0:38ceb79fef03 | 664 | bool ATHandler::match_urc() |
| kevman | 0:38ceb79fef03 | 665 | { |
| kevman | 0:38ceb79fef03 | 666 | rewind_buffer(); |
| kevman | 0:38ceb79fef03 | 667 | size_t prefix_len = 0; |
| kevman | 0:38ceb79fef03 | 668 | for (struct oob_t *oob = _oobs; oob; oob = oob->next) { |
| kevman | 0:38ceb79fef03 | 669 | prefix_len = oob->prefix_len; |
| kevman | 0:38ceb79fef03 | 670 | if (_recv_len >= prefix_len) { |
| kevman | 0:38ceb79fef03 | 671 | if (match(oob->prefix, prefix_len)) { |
| kevman | 0:38ceb79fef03 | 672 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 673 | if (oob->cb) { |
| kevman | 0:38ceb79fef03 | 674 | oob->cb(); |
| kevman | 0:38ceb79fef03 | 675 | } |
| kevman | 0:38ceb79fef03 | 676 | information_response_stop(); |
| kevman | 0:38ceb79fef03 | 677 | return true; |
| kevman | 0:38ceb79fef03 | 678 | } |
| kevman | 0:38ceb79fef03 | 679 | } |
| kevman | 0:38ceb79fef03 | 680 | } |
| kevman | 0:38ceb79fef03 | 681 | return false; |
| kevman | 0:38ceb79fef03 | 682 | } |
| kevman | 0:38ceb79fef03 | 683 | |
| kevman | 0:38ceb79fef03 | 684 | bool ATHandler::match_error() |
| kevman | 0:38ceb79fef03 | 685 | { |
| kevman | 0:38ceb79fef03 | 686 | if (match(CME_ERROR, CME_ERROR_LENGTH)) { |
| kevman | 0:38ceb79fef03 | 687 | at_error(true, DeviceErrorTypeErrorCME); |
| kevman | 0:38ceb79fef03 | 688 | return true; |
| kevman | 0:38ceb79fef03 | 689 | } else if (match(CMS_ERROR, CMS_ERROR_LENGTH)) { |
| kevman | 0:38ceb79fef03 | 690 | at_error(true, DeviceErrorTypeErrorCMS); |
| kevman | 0:38ceb79fef03 | 691 | return true; |
| kevman | 0:38ceb79fef03 | 692 | } else if (match(ERROR_, ERROR_LENGTH)) { |
| kevman | 0:38ceb79fef03 | 693 | at_error(false, DeviceErrorTypeNoError); |
| kevman | 0:38ceb79fef03 | 694 | return true; |
| kevman | 0:38ceb79fef03 | 695 | } |
| kevman | 0:38ceb79fef03 | 696 | |
| kevman | 0:38ceb79fef03 | 697 | return false; |
| kevman | 0:38ceb79fef03 | 698 | } |
| kevman | 0:38ceb79fef03 | 699 | |
| kevman | 0:38ceb79fef03 | 700 | void ATHandler::clear_error() |
| kevman | 0:38ceb79fef03 | 701 | { |
| kevman | 0:38ceb79fef03 | 702 | _last_err = NSAPI_ERROR_OK; |
| kevman | 0:38ceb79fef03 | 703 | _last_at_err.errCode = 0; |
| kevman | 0:38ceb79fef03 | 704 | _last_at_err.errType = DeviceErrorTypeNoError; |
| kevman | 0:38ceb79fef03 | 705 | _last_3gpp_error = 0; |
| kevman | 0:38ceb79fef03 | 706 | } |
| kevman | 0:38ceb79fef03 | 707 | |
| kevman | 0:38ceb79fef03 | 708 | nsapi_error_t ATHandler::get_last_error() const |
| kevman | 0:38ceb79fef03 | 709 | { |
| kevman | 0:38ceb79fef03 | 710 | return _last_err; |
| kevman | 0:38ceb79fef03 | 711 | } |
| kevman | 0:38ceb79fef03 | 712 | |
| kevman | 0:38ceb79fef03 | 713 | device_err_t ATHandler::get_last_device_error() const |
| kevman | 0:38ceb79fef03 | 714 | { |
| kevman | 0:38ceb79fef03 | 715 | return _last_at_err; |
| kevman | 0:38ceb79fef03 | 716 | } |
| kevman | 0:38ceb79fef03 | 717 | |
| kevman | 0:38ceb79fef03 | 718 | void ATHandler::set_error(nsapi_error_t err) |
| kevman | 0:38ceb79fef03 | 719 | { |
| kevman | 0:38ceb79fef03 | 720 | if (_last_err == NSAPI_ERROR_OK) { |
| kevman | 0:38ceb79fef03 | 721 | _last_err = err; |
| kevman | 0:38ceb79fef03 | 722 | } |
| kevman | 0:38ceb79fef03 | 723 | |
| kevman | 0:38ceb79fef03 | 724 | if (_last_err != err) { |
| kevman | 0:38ceb79fef03 | 725 | tr_warn("AT error code changed from %d to %d!", _last_err, err); |
| kevman | 0:38ceb79fef03 | 726 | } |
| kevman | 0:38ceb79fef03 | 727 | } |
| kevman | 0:38ceb79fef03 | 728 | |
| kevman | 0:38ceb79fef03 | 729 | int ATHandler::get_3gpp_error() |
| kevman | 0:38ceb79fef03 | 730 | { |
| kevman | 0:38ceb79fef03 | 731 | return _last_3gpp_error; |
| kevman | 0:38ceb79fef03 | 732 | } |
| kevman | 0:38ceb79fef03 | 733 | |
| kevman | 0:38ceb79fef03 | 734 | void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type) |
| kevman | 0:38ceb79fef03 | 735 | { |
| kevman | 0:38ceb79fef03 | 736 | if (_last_3gpp_error) { // don't overwrite likely root cause error |
| kevman | 0:38ceb79fef03 | 737 | return; |
| kevman | 0:38ceb79fef03 | 738 | } |
| kevman | 0:38ceb79fef03 | 739 | |
| kevman | 0:38ceb79fef03 | 740 | if (error_type == DeviceErrorTypeErrorCMS && err < 128) { |
| kevman | 0:38ceb79fef03 | 741 | // CMS errors 0-127 maps straight to 3GPP errors |
| kevman | 0:38ceb79fef03 | 742 | _last_3gpp_error = err; |
| kevman | 0:38ceb79fef03 | 743 | } else { |
| kevman | 0:38ceb79fef03 | 744 | for (size_t i = 0; i < sizeof(map_3gpp_errors) / sizeof(map_3gpp_errors[0]); i++) { |
| kevman | 0:38ceb79fef03 | 745 | if (map_3gpp_errors[i][0] == err) { |
| kevman | 0:38ceb79fef03 | 746 | _last_3gpp_error = map_3gpp_errors[i][1]; |
| kevman | 0:38ceb79fef03 | 747 | tr_debug("AT3GPP error code %d", get_3gpp_error()); |
| kevman | 0:38ceb79fef03 | 748 | break; |
| kevman | 0:38ceb79fef03 | 749 | } |
| kevman | 0:38ceb79fef03 | 750 | } |
| kevman | 0:38ceb79fef03 | 751 | } |
| kevman | 0:38ceb79fef03 | 752 | } |
| kevman | 0:38ceb79fef03 | 753 | |
| kevman | 0:38ceb79fef03 | 754 | void ATHandler::at_error(bool error_code_expected, DeviceErrorType error_type) |
| kevman | 0:38ceb79fef03 | 755 | { |
| kevman | 0:38ceb79fef03 | 756 | if (error_code_expected && (error_type == DeviceErrorTypeErrorCMS || error_type == DeviceErrorTypeErrorCME)) { |
| kevman | 0:38ceb79fef03 | 757 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 758 | int32_t err = read_int(); |
| kevman | 0:38ceb79fef03 | 759 | |
| kevman | 0:38ceb79fef03 | 760 | if (err != -1) { |
| kevman | 0:38ceb79fef03 | 761 | set_3gpp_error(err, error_type); |
| kevman | 0:38ceb79fef03 | 762 | _last_at_err.errCode = err; |
| kevman | 0:38ceb79fef03 | 763 | _last_at_err.errType = error_type; |
| kevman | 0:38ceb79fef03 | 764 | tr_error("AT error code %ld", err); |
| kevman | 0:38ceb79fef03 | 765 | } else { |
| kevman | 0:38ceb79fef03 | 766 | tr_warn("ATHandler ERROR reading failed"); |
| kevman | 0:38ceb79fef03 | 767 | } |
| kevman | 0:38ceb79fef03 | 768 | } |
| kevman | 0:38ceb79fef03 | 769 | |
| kevman | 0:38ceb79fef03 | 770 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 771 | } |
| kevman | 0:38ceb79fef03 | 772 | |
| kevman | 0:38ceb79fef03 | 773 | void ATHandler::resp(const char *prefix, bool check_urc) |
| kevman | 0:38ceb79fef03 | 774 | { |
| kevman | 0:38ceb79fef03 | 775 | _prefix_matched = false; |
| kevman | 0:38ceb79fef03 | 776 | _urc_matched = false; |
| kevman | 0:38ceb79fef03 | 777 | _error_found = false; |
| kevman | 0:38ceb79fef03 | 778 | |
| kevman | 0:38ceb79fef03 | 779 | while (!get_last_error()) { |
| kevman | 0:38ceb79fef03 | 780 | |
| kevman | 0:38ceb79fef03 | 781 | match(CRLF, CRLF_LENGTH); |
| kevman | 0:38ceb79fef03 | 782 | |
| kevman | 0:38ceb79fef03 | 783 | if (match(OK, OK_LENGTH)) { |
| kevman | 0:38ceb79fef03 | 784 | set_scope(RespType); |
| kevman | 0:38ceb79fef03 | 785 | _stop_tag->found = true; |
| kevman | 0:38ceb79fef03 | 786 | return; |
| kevman | 0:38ceb79fef03 | 787 | } |
| kevman | 0:38ceb79fef03 | 788 | |
| kevman | 0:38ceb79fef03 | 789 | if (match_error()) { |
| kevman | 0:38ceb79fef03 | 790 | _error_found = true; |
| kevman | 0:38ceb79fef03 | 791 | return; |
| kevman | 0:38ceb79fef03 | 792 | } |
| kevman | 0:38ceb79fef03 | 793 | |
| kevman | 0:38ceb79fef03 | 794 | if (prefix && match(prefix, strlen(prefix))) { |
| kevman | 0:38ceb79fef03 | 795 | _prefix_matched = true; |
| kevman | 0:38ceb79fef03 | 796 | return; |
| kevman | 0:38ceb79fef03 | 797 | } |
| kevman | 0:38ceb79fef03 | 798 | |
| kevman | 0:38ceb79fef03 | 799 | if (check_urc && match_urc()) { |
| kevman | 0:38ceb79fef03 | 800 | _urc_matched = true; |
| kevman | 0:38ceb79fef03 | 801 | } |
| kevman | 0:38ceb79fef03 | 802 | |
| kevman | 0:38ceb79fef03 | 803 | // If no match found, look for CRLF and consume everything up to and including CRLF |
| kevman | 0:38ceb79fef03 | 804 | if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { |
| kevman | 0:38ceb79fef03 | 805 | // If no prefix, return on CRLF - means data to read |
| kevman | 0:38ceb79fef03 | 806 | if (!prefix) { |
| kevman | 0:38ceb79fef03 | 807 | return; |
| kevman | 0:38ceb79fef03 | 808 | } |
| kevman | 0:38ceb79fef03 | 809 | consume_to_tag(CRLF, true); |
| kevman | 0:38ceb79fef03 | 810 | } else { |
| kevman | 0:38ceb79fef03 | 811 | // If no prefix, no CRLF and no more chance to match for OK, ERROR or URC(since max resp length is already in buffer) |
| kevman | 0:38ceb79fef03 | 812 | // return so data could be read |
| kevman | 0:38ceb79fef03 | 813 | if (!prefix && ((_recv_len - _recv_pos) >= _max_resp_length)) { |
| kevman | 0:38ceb79fef03 | 814 | return; |
| kevman | 0:38ceb79fef03 | 815 | } |
| kevman | 0:38ceb79fef03 | 816 | if (!fill_buffer()) { |
| kevman | 0:38ceb79fef03 | 817 | // if we don't get any match and no data within timeout, set an error to indicate need for recovery |
| kevman | 0:38ceb79fef03 | 818 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 819 | } |
| kevman | 0:38ceb79fef03 | 820 | } |
| kevman | 0:38ceb79fef03 | 821 | } |
| kevman | 0:38ceb79fef03 | 822 | |
| kevman | 0:38ceb79fef03 | 823 | return; |
| kevman | 0:38ceb79fef03 | 824 | // something went wrong so application need to recover and retry |
| kevman | 0:38ceb79fef03 | 825 | } |
| kevman | 0:38ceb79fef03 | 826 | |
| kevman | 0:38ceb79fef03 | 827 | void ATHandler::resp_start(const char *prefix, bool stop) |
| kevman | 0:38ceb79fef03 | 828 | { |
| kevman | 0:38ceb79fef03 | 829 | if (_last_err) { |
| kevman | 0:38ceb79fef03 | 830 | return; |
| kevman | 0:38ceb79fef03 | 831 | } |
| kevman | 0:38ceb79fef03 | 832 | |
| kevman | 0:38ceb79fef03 | 833 | // Try get as much data as possible |
| kevman | 0:38ceb79fef03 | 834 | rewind_buffer(); |
| kevman | 0:38ceb79fef03 | 835 | (void)fill_buffer(false); |
| kevman | 0:38ceb79fef03 | 836 | |
| kevman | 0:38ceb79fef03 | 837 | if (prefix) { |
| kevman | 0:38ceb79fef03 | 838 | MBED_ASSERT(strlen(prefix) < BUFF_SIZE); |
| kevman | 0:38ceb79fef03 | 839 | strcpy(_info_resp_prefix, prefix); // copy prefix so we can later use it without having to provide again for info_resp |
| kevman | 0:38ceb79fef03 | 840 | } |
| kevman | 0:38ceb79fef03 | 841 | |
| kevman | 0:38ceb79fef03 | 842 | set_scope(RespType); |
| kevman | 0:38ceb79fef03 | 843 | |
| kevman | 0:38ceb79fef03 | 844 | resp(prefix, true); |
| kevman | 0:38ceb79fef03 | 845 | |
| kevman | 0:38ceb79fef03 | 846 | if (!stop && prefix && _prefix_matched) { |
| kevman | 0:38ceb79fef03 | 847 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 848 | } |
| kevman | 0:38ceb79fef03 | 849 | } |
| kevman | 0:38ceb79fef03 | 850 | |
| kevman | 0:38ceb79fef03 | 851 | // check urc because of error as urc |
| kevman | 0:38ceb79fef03 | 852 | bool ATHandler::info_resp() |
| kevman | 0:38ceb79fef03 | 853 | { |
| kevman | 0:38ceb79fef03 | 854 | if (_last_err || _resp_stop.found) { |
| kevman | 0:38ceb79fef03 | 855 | return false; |
| kevman | 0:38ceb79fef03 | 856 | } |
| kevman | 0:38ceb79fef03 | 857 | |
| kevman | 0:38ceb79fef03 | 858 | if (_prefix_matched) { |
| kevman | 0:38ceb79fef03 | 859 | _prefix_matched = false; |
| kevman | 0:38ceb79fef03 | 860 | return true; |
| kevman | 0:38ceb79fef03 | 861 | } |
| kevman | 0:38ceb79fef03 | 862 | |
| kevman | 0:38ceb79fef03 | 863 | // If coming here after another info response was started(looping), stop the previous one. |
| kevman | 0:38ceb79fef03 | 864 | // Trying to handle stopping in this level instead of doing it in upper level. |
| kevman | 0:38ceb79fef03 | 865 | if (get_scope() == InfoType) { |
| kevman | 0:38ceb79fef03 | 866 | information_response_stop(); |
| kevman | 0:38ceb79fef03 | 867 | } |
| kevman | 0:38ceb79fef03 | 868 | |
| kevman | 0:38ceb79fef03 | 869 | resp(_info_resp_prefix, false); |
| kevman | 0:38ceb79fef03 | 870 | |
| kevman | 0:38ceb79fef03 | 871 | if (_prefix_matched) { |
| kevman | 0:38ceb79fef03 | 872 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 873 | _prefix_matched = false; |
| kevman | 0:38ceb79fef03 | 874 | return true; |
| kevman | 0:38ceb79fef03 | 875 | } |
| kevman | 0:38ceb79fef03 | 876 | |
| kevman | 0:38ceb79fef03 | 877 | // On mismatch go to response scope |
| kevman | 0:38ceb79fef03 | 878 | set_scope(RespType); |
| kevman | 0:38ceb79fef03 | 879 | return false; |
| kevman | 0:38ceb79fef03 | 880 | } |
| kevman | 0:38ceb79fef03 | 881 | |
| kevman | 0:38ceb79fef03 | 882 | bool ATHandler::info_elem(char start_tag) |
| kevman | 0:38ceb79fef03 | 883 | { |
| kevman | 0:38ceb79fef03 | 884 | if (_last_err) { |
| kevman | 0:38ceb79fef03 | 885 | return false; |
| kevman | 0:38ceb79fef03 | 886 | } |
| kevman | 0:38ceb79fef03 | 887 | |
| kevman | 0:38ceb79fef03 | 888 | // If coming here after another info response element was started(looping), stop the previous one. |
| kevman | 0:38ceb79fef03 | 889 | // Trying to handle stopping in this level instead of doing it in upper level. |
| kevman | 0:38ceb79fef03 | 890 | if (get_scope() == ElemType) { |
| kevman | 0:38ceb79fef03 | 891 | information_response_element_stop(); |
| kevman | 0:38ceb79fef03 | 892 | } |
| kevman | 0:38ceb79fef03 | 893 | |
| kevman | 0:38ceb79fef03 | 894 | consume_char(_delimiter); |
| kevman | 0:38ceb79fef03 | 895 | |
| kevman | 0:38ceb79fef03 | 896 | if (consume_char(start_tag)) { |
| kevman | 0:38ceb79fef03 | 897 | _prefix_matched = true; |
| kevman | 0:38ceb79fef03 | 898 | set_scope(ElemType); |
| kevman | 0:38ceb79fef03 | 899 | return true; |
| kevman | 0:38ceb79fef03 | 900 | } |
| kevman | 0:38ceb79fef03 | 901 | |
| kevman | 0:38ceb79fef03 | 902 | // On mismatch go to information response scope |
| kevman | 0:38ceb79fef03 | 903 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 904 | return false; |
| kevman | 0:38ceb79fef03 | 905 | } |
| kevman | 0:38ceb79fef03 | 906 | |
| kevman | 0:38ceb79fef03 | 907 | bool ATHandler::consume_char(char ch) |
| kevman | 0:38ceb79fef03 | 908 | { |
| kevman | 0:38ceb79fef03 | 909 | int read_char = get_char(); |
| kevman | 0:38ceb79fef03 | 910 | if (read_char == -1) { |
| kevman | 0:38ceb79fef03 | 911 | return false; |
| kevman | 0:38ceb79fef03 | 912 | } |
| kevman | 0:38ceb79fef03 | 913 | // If we read something else than ch, recover it |
| kevman | 0:38ceb79fef03 | 914 | if (read_char != ch) { |
| kevman | 0:38ceb79fef03 | 915 | _recv_pos--; |
| kevman | 0:38ceb79fef03 | 916 | return false; |
| kevman | 0:38ceb79fef03 | 917 | } |
| kevman | 0:38ceb79fef03 | 918 | return true; |
| kevman | 0:38ceb79fef03 | 919 | } |
| kevman | 0:38ceb79fef03 | 920 | |
| kevman | 0:38ceb79fef03 | 921 | bool ATHandler::consume_to_tag(const char *tag, bool consume_tag) |
| kevman | 0:38ceb79fef03 | 922 | { |
| kevman | 0:38ceb79fef03 | 923 | size_t match_pos = 0; |
| kevman | 0:38ceb79fef03 | 924 | |
| kevman | 0:38ceb79fef03 | 925 | while (true) { |
| kevman | 0:38ceb79fef03 | 926 | int c = get_char(); |
| kevman | 0:38ceb79fef03 | 927 | if (c == -1) { |
| kevman | 0:38ceb79fef03 | 928 | break; |
| kevman | 0:38ceb79fef03 | 929 | // compares c against tag at current position and if this match fails |
| kevman | 0:38ceb79fef03 | 930 | // compares c against tag[0] and also resets match_pos to 0 |
| kevman | 0:38ceb79fef03 | 931 | } else if (c == tag[match_pos] || ((match_pos = 1) && (c == tag[--match_pos]))) { |
| kevman | 0:38ceb79fef03 | 932 | match_pos++; |
| kevman | 0:38ceb79fef03 | 933 | if (match_pos == strlen(tag)) { |
| kevman | 0:38ceb79fef03 | 934 | if (!consume_tag) { |
| kevman | 0:38ceb79fef03 | 935 | _recv_pos -= strlen(tag); |
| kevman | 0:38ceb79fef03 | 936 | } |
| kevman | 0:38ceb79fef03 | 937 | return true; |
| kevman | 0:38ceb79fef03 | 938 | } |
| kevman | 0:38ceb79fef03 | 939 | } |
| kevman | 0:38ceb79fef03 | 940 | } |
| kevman | 0:38ceb79fef03 | 941 | tr_debug("consume_to_tag not found"); |
| kevman | 0:38ceb79fef03 | 942 | return false; |
| kevman | 0:38ceb79fef03 | 943 | } |
| kevman | 0:38ceb79fef03 | 944 | |
| kevman | 0:38ceb79fef03 | 945 | bool ATHandler::consume_to_stop_tag() |
| kevman | 0:38ceb79fef03 | 946 | { |
| kevman | 0:38ceb79fef03 | 947 | if (!_stop_tag || (_stop_tag && _stop_tag->found) || _error_found) { |
| kevman | 0:38ceb79fef03 | 948 | return true; |
| kevman | 0:38ceb79fef03 | 949 | } |
| kevman | 0:38ceb79fef03 | 950 | |
| kevman | 0:38ceb79fef03 | 951 | if (consume_to_tag((const char *)_stop_tag->tag, true)) { |
| kevman | 0:38ceb79fef03 | 952 | return true; |
| kevman | 0:38ceb79fef03 | 953 | } |
| kevman | 0:38ceb79fef03 | 954 | |
| kevman | 0:38ceb79fef03 | 955 | tr_warn("AT stop tag not found"); |
| kevman | 0:38ceb79fef03 | 956 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 957 | return false; |
| kevman | 0:38ceb79fef03 | 958 | } |
| kevman | 0:38ceb79fef03 | 959 | |
| kevman | 0:38ceb79fef03 | 960 | // consume by size needed? |
| kevman | 0:38ceb79fef03 | 961 | |
| kevman | 0:38ceb79fef03 | 962 | void ATHandler::resp_stop() |
| kevman | 0:38ceb79fef03 | 963 | { |
| kevman | 0:38ceb79fef03 | 964 | // Do not return on error so that we can consume whatever there is in the buffer |
| kevman | 0:38ceb79fef03 | 965 | |
| kevman | 0:38ceb79fef03 | 966 | if (_current_scope == ElemType) { |
| kevman | 0:38ceb79fef03 | 967 | information_response_element_stop(); |
| kevman | 0:38ceb79fef03 | 968 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 969 | } |
| kevman | 0:38ceb79fef03 | 970 | |
| kevman | 0:38ceb79fef03 | 971 | if (_current_scope == InfoType) { |
| kevman | 0:38ceb79fef03 | 972 | information_response_stop(); |
| kevman | 0:38ceb79fef03 | 973 | } |
| kevman | 0:38ceb79fef03 | 974 | |
| kevman | 0:38ceb79fef03 | 975 | // Go for response stop_tag |
| kevman | 0:38ceb79fef03 | 976 | if (consume_to_stop_tag()) { |
| kevman | 0:38ceb79fef03 | 977 | set_scope(NotSet); |
| kevman | 0:38ceb79fef03 | 978 | } |
| kevman | 0:38ceb79fef03 | 979 | |
| kevman | 0:38ceb79fef03 | 980 | // Restore stop tag to OK |
| kevman | 0:38ceb79fef03 | 981 | set_tag(&_resp_stop, OK); |
| kevman | 0:38ceb79fef03 | 982 | // Reset info resp prefix |
| kevman | 0:38ceb79fef03 | 983 | memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); |
| kevman | 0:38ceb79fef03 | 984 | |
| kevman | 0:38ceb79fef03 | 985 | _last_response_stop = rtos::Kernel::get_ms_count(); |
| kevman | 0:38ceb79fef03 | 986 | } |
| kevman | 0:38ceb79fef03 | 987 | |
| kevman | 0:38ceb79fef03 | 988 | void ATHandler::information_response_stop() |
| kevman | 0:38ceb79fef03 | 989 | { |
| kevman | 0:38ceb79fef03 | 990 | if (consume_to_stop_tag()) { |
| kevman | 0:38ceb79fef03 | 991 | set_scope(RespType); |
| kevman | 0:38ceb79fef03 | 992 | } |
| kevman | 0:38ceb79fef03 | 993 | } |
| kevman | 0:38ceb79fef03 | 994 | |
| kevman | 0:38ceb79fef03 | 995 | void ATHandler::information_response_element_stop() |
| kevman | 0:38ceb79fef03 | 996 | { |
| kevman | 0:38ceb79fef03 | 997 | if (consume_to_stop_tag()) { |
| kevman | 0:38ceb79fef03 | 998 | set_scope(InfoType); |
| kevman | 0:38ceb79fef03 | 999 | } |
| kevman | 0:38ceb79fef03 | 1000 | } |
| kevman | 0:38ceb79fef03 | 1001 | |
| kevman | 0:38ceb79fef03 | 1002 | ATHandler::ScopeType ATHandler::get_scope() |
| kevman | 0:38ceb79fef03 | 1003 | { |
| kevman | 0:38ceb79fef03 | 1004 | return _current_scope; |
| kevman | 0:38ceb79fef03 | 1005 | } |
| kevman | 0:38ceb79fef03 | 1006 | |
| kevman | 0:38ceb79fef03 | 1007 | void ATHandler::set_string(char *dest, const char *src, size_t src_len) |
| kevman | 0:38ceb79fef03 | 1008 | { |
| kevman | 0:38ceb79fef03 | 1009 | memcpy(dest, src, src_len); |
| kevman | 0:38ceb79fef03 | 1010 | dest[src_len] = '\0'; |
| kevman | 0:38ceb79fef03 | 1011 | } |
| kevman | 0:38ceb79fef03 | 1012 | |
| kevman | 0:38ceb79fef03 | 1013 | const char *ATHandler::mem_str(const char *dest, size_t dest_len, const char *src, size_t src_len) |
| kevman | 0:38ceb79fef03 | 1014 | { |
| kevman | 0:38ceb79fef03 | 1015 | if (dest_len > src_len) { |
| kevman | 0:38ceb79fef03 | 1016 | for (size_t i = 0; i < dest_len - src_len + 1; ++i) { |
| kevman | 0:38ceb79fef03 | 1017 | if (memcmp(dest + i, src, src_len) == 0) { |
| kevman | 0:38ceb79fef03 | 1018 | return dest + i; |
| kevman | 0:38ceb79fef03 | 1019 | } |
| kevman | 0:38ceb79fef03 | 1020 | } |
| kevman | 0:38ceb79fef03 | 1021 | } |
| kevman | 0:38ceb79fef03 | 1022 | return NULL; |
| kevman | 0:38ceb79fef03 | 1023 | } |
| kevman | 0:38ceb79fef03 | 1024 | |
| kevman | 0:38ceb79fef03 | 1025 | void ATHandler::cmd_start(const char *cmd) |
| kevman | 0:38ceb79fef03 | 1026 | { |
| kevman | 0:38ceb79fef03 | 1027 | |
| kevman | 0:38ceb79fef03 | 1028 | if (_at_send_delay) { |
| kevman | 0:38ceb79fef03 | 1029 | rtos::Thread::wait_until(_last_response_stop + _at_send_delay); |
| kevman | 0:38ceb79fef03 | 1030 | } |
| kevman | 0:38ceb79fef03 | 1031 | |
| kevman | 0:38ceb79fef03 | 1032 | if (_last_err != NSAPI_ERROR_OK) { |
| kevman | 0:38ceb79fef03 | 1033 | return; |
| kevman | 0:38ceb79fef03 | 1034 | } |
| kevman | 0:38ceb79fef03 | 1035 | |
| kevman | 0:38ceb79fef03 | 1036 | (void)write(cmd, strlen(cmd)); |
| kevman | 0:38ceb79fef03 | 1037 | |
| kevman | 0:38ceb79fef03 | 1038 | _cmd_start = true; |
| kevman | 0:38ceb79fef03 | 1039 | } |
| kevman | 0:38ceb79fef03 | 1040 | |
| kevman | 0:38ceb79fef03 | 1041 | void ATHandler::write_int(int32_t param) |
| kevman | 0:38ceb79fef03 | 1042 | { |
| kevman | 0:38ceb79fef03 | 1043 | // do common checks before sending subparameter |
| kevman | 0:38ceb79fef03 | 1044 | if (check_cmd_send() == false) { |
| kevman | 0:38ceb79fef03 | 1045 | return; |
| kevman | 0:38ceb79fef03 | 1046 | } |
| kevman | 0:38ceb79fef03 | 1047 | |
| kevman | 0:38ceb79fef03 | 1048 | // write the integer subparameter |
| kevman | 0:38ceb79fef03 | 1049 | const int32_t str_len = 12; |
| kevman | 0:38ceb79fef03 | 1050 | char number_string[str_len]; |
| kevman | 0:38ceb79fef03 | 1051 | int32_t result = sprintf(number_string, "%ld", param); |
| kevman | 0:38ceb79fef03 | 1052 | if (result > 0 && result < str_len) { |
| kevman | 0:38ceb79fef03 | 1053 | (void)write(number_string, strlen(number_string)); |
| kevman | 0:38ceb79fef03 | 1054 | } |
| kevman | 0:38ceb79fef03 | 1055 | } |
| kevman | 0:38ceb79fef03 | 1056 | |
| kevman | 0:38ceb79fef03 | 1057 | void ATHandler::write_string(const char *param, bool useQuotations) |
| kevman | 0:38ceb79fef03 | 1058 | { |
| kevman | 0:38ceb79fef03 | 1059 | // do common checks before sending subparameter |
| kevman | 0:38ceb79fef03 | 1060 | if (check_cmd_send() == false) { |
| kevman | 0:38ceb79fef03 | 1061 | return; |
| kevman | 0:38ceb79fef03 | 1062 | } |
| kevman | 0:38ceb79fef03 | 1063 | |
| kevman | 0:38ceb79fef03 | 1064 | // we are writing string, surround it with quotes |
| kevman | 0:38ceb79fef03 | 1065 | if (useQuotations && write("\"", 1) != 1) { |
| kevman | 0:38ceb79fef03 | 1066 | return; |
| kevman | 0:38ceb79fef03 | 1067 | } |
| kevman | 0:38ceb79fef03 | 1068 | |
| kevman | 0:38ceb79fef03 | 1069 | (void)write(param, strlen(param)); |
| kevman | 0:38ceb79fef03 | 1070 | |
| kevman | 0:38ceb79fef03 | 1071 | if (useQuotations) { |
| kevman | 0:38ceb79fef03 | 1072 | // we are writing string, surround it with quotes |
| kevman | 0:38ceb79fef03 | 1073 | (void)write("\"", 1); |
| kevman | 0:38ceb79fef03 | 1074 | } |
| kevman | 0:38ceb79fef03 | 1075 | } |
| kevman | 0:38ceb79fef03 | 1076 | |
| kevman | 0:38ceb79fef03 | 1077 | void ATHandler::cmd_stop() |
| kevman | 0:38ceb79fef03 | 1078 | { |
| kevman | 0:38ceb79fef03 | 1079 | if (_last_err != NSAPI_ERROR_OK) { |
| kevman | 0:38ceb79fef03 | 1080 | return; |
| kevman | 0:38ceb79fef03 | 1081 | } |
| kevman | 0:38ceb79fef03 | 1082 | // Finish with CR |
| kevman | 0:38ceb79fef03 | 1083 | (void)write(_output_delimiter, strlen(_output_delimiter)); |
| kevman | 0:38ceb79fef03 | 1084 | } |
| kevman | 0:38ceb79fef03 | 1085 | |
| kevman | 0:38ceb79fef03 | 1086 | size_t ATHandler::write_bytes(const uint8_t *data, size_t len) |
| kevman | 0:38ceb79fef03 | 1087 | { |
| kevman | 0:38ceb79fef03 | 1088 | if (_last_err != NSAPI_ERROR_OK) { |
| kevman | 0:38ceb79fef03 | 1089 | return 0; |
| kevman | 0:38ceb79fef03 | 1090 | } |
| kevman | 0:38ceb79fef03 | 1091 | |
| kevman | 0:38ceb79fef03 | 1092 | return write(data, len); |
| kevman | 0:38ceb79fef03 | 1093 | } |
| kevman | 0:38ceb79fef03 | 1094 | |
| kevman | 0:38ceb79fef03 | 1095 | size_t ATHandler::write(const void *data, size_t len) |
| kevman | 0:38ceb79fef03 | 1096 | { |
| kevman | 0:38ceb79fef03 | 1097 | pollfh fhs; |
| kevman | 0:38ceb79fef03 | 1098 | fhs.fh = _fileHandle; |
| kevman | 0:38ceb79fef03 | 1099 | fhs.events = POLLOUT; |
| kevman | 0:38ceb79fef03 | 1100 | size_t write_len = 0; |
| kevman | 0:38ceb79fef03 | 1101 | for (; write_len < len;) { |
| kevman | 0:38ceb79fef03 | 1102 | int count = poll(&fhs, 1, poll_timeout()); |
| kevman | 0:38ceb79fef03 | 1103 | if (count <= 0 || !(fhs.revents & POLLOUT)) { |
| kevman | 0:38ceb79fef03 | 1104 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 1105 | return 0; |
| kevman | 0:38ceb79fef03 | 1106 | } |
| kevman | 0:38ceb79fef03 | 1107 | ssize_t ret = _fileHandle->write((uint8_t *)data + write_len, len - write_len); |
| kevman | 0:38ceb79fef03 | 1108 | if (ret < 0) { |
| kevman | 0:38ceb79fef03 | 1109 | set_error(NSAPI_ERROR_DEVICE_ERROR); |
| kevman | 0:38ceb79fef03 | 1110 | return 0; |
| kevman | 0:38ceb79fef03 | 1111 | } |
| kevman | 0:38ceb79fef03 | 1112 | debug_print((char *)data + write_len, ret); |
| kevman | 0:38ceb79fef03 | 1113 | write_len += (size_t)ret; |
| kevman | 0:38ceb79fef03 | 1114 | } |
| kevman | 0:38ceb79fef03 | 1115 | |
| kevman | 0:38ceb79fef03 | 1116 | return write_len; |
| kevman | 0:38ceb79fef03 | 1117 | } |
| kevman | 0:38ceb79fef03 | 1118 | |
| kevman | 0:38ceb79fef03 | 1119 | // do common checks before sending subparameters |
| kevman | 0:38ceb79fef03 | 1120 | bool ATHandler::check_cmd_send() |
| kevman | 0:38ceb79fef03 | 1121 | { |
| kevman | 0:38ceb79fef03 | 1122 | if (_last_err != NSAPI_ERROR_OK) { |
| kevman | 0:38ceb79fef03 | 1123 | return false; |
| kevman | 0:38ceb79fef03 | 1124 | } |
| kevman | 0:38ceb79fef03 | 1125 | |
| kevman | 0:38ceb79fef03 | 1126 | // Don't write delimiter if this is the first subparameter |
| kevman | 0:38ceb79fef03 | 1127 | if (_cmd_start) { |
| kevman | 0:38ceb79fef03 | 1128 | _cmd_start = false; |
| kevman | 0:38ceb79fef03 | 1129 | } else { |
| kevman | 0:38ceb79fef03 | 1130 | if (write(&_delimiter, 1) != 1) { |
| kevman | 0:38ceb79fef03 | 1131 | // writing of delimiter failed, return. write() already have set the _last_err |
| kevman | 0:38ceb79fef03 | 1132 | return false; |
| kevman | 0:38ceb79fef03 | 1133 | } |
| kevman | 0:38ceb79fef03 | 1134 | } |
| kevman | 0:38ceb79fef03 | 1135 | |
| kevman | 0:38ceb79fef03 | 1136 | return true; |
| kevman | 0:38ceb79fef03 | 1137 | } |
| kevman | 0:38ceb79fef03 | 1138 | |
| kevman | 0:38ceb79fef03 | 1139 | void ATHandler::flush() |
| kevman | 0:38ceb79fef03 | 1140 | { |
| kevman | 0:38ceb79fef03 | 1141 | reset_buffer(); |
| kevman | 0:38ceb79fef03 | 1142 | while (fill_buffer(false)) { |
| kevman | 0:38ceb79fef03 | 1143 | reset_buffer(); |
| kevman | 0:38ceb79fef03 | 1144 | } |
| kevman | 0:38ceb79fef03 | 1145 | } |
| kevman | 0:38ceb79fef03 | 1146 | |
| kevman | 0:38ceb79fef03 | 1147 | void ATHandler::debug_print(char *p, int len) |
| kevman | 0:38ceb79fef03 | 1148 | { |
| kevman | 0:38ceb79fef03 | 1149 | #if MBED_CONF_CELLULAR_DEBUG_AT |
| kevman | 0:38ceb79fef03 | 1150 | if (_debug_on) { |
| kevman | 0:38ceb79fef03 | 1151 | #if MBED_CONF_MBED_TRACE_ENABLE |
| kevman | 0:38ceb79fef03 | 1152 | mbed_cellular_trace::mutex_wait(); |
| kevman | 0:38ceb79fef03 | 1153 | #endif |
| kevman | 0:38ceb79fef03 | 1154 | for (ssize_t i = 0; i < len; i++) { |
| kevman | 0:38ceb79fef03 | 1155 | char c = *p++; |
| kevman | 0:38ceb79fef03 | 1156 | if (!isprint(c)) { |
| kevman | 0:38ceb79fef03 | 1157 | if (c == '\r') { |
| kevman | 0:38ceb79fef03 | 1158 | debug("\n"); |
| kevman | 0:38ceb79fef03 | 1159 | } else if (c == '\n') { |
| kevman | 0:38ceb79fef03 | 1160 | } else { |
| kevman | 0:38ceb79fef03 | 1161 | debug("[%d]", c); |
| kevman | 0:38ceb79fef03 | 1162 | } |
| kevman | 0:38ceb79fef03 | 1163 | } else { |
| kevman | 0:38ceb79fef03 | 1164 | debug("%c", c); |
| kevman | 0:38ceb79fef03 | 1165 | } |
| kevman | 0:38ceb79fef03 | 1166 | } |
| kevman | 0:38ceb79fef03 | 1167 | #if MBED_CONF_MBED_TRACE_ENABLE |
| kevman | 0:38ceb79fef03 | 1168 | mbed_cellular_trace::mutex_release(); |
| kevman | 0:38ceb79fef03 | 1169 | #endif |
| kevman | 0:38ceb79fef03 | 1170 | } |
| kevman | 0:38ceb79fef03 | 1171 | #endif // MBED_CONF_CELLULAR_DEBUG_AT |
| kevman | 0:38ceb79fef03 | 1172 | } |