BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
CellularConnectionFSM.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 "CellularConnectionFSM.h" 00019 00020 #ifdef CELLULAR_DEVICE 00021 00022 #ifndef MBED_TRACE_MAX_LEVEL 00023 #define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO 00024 #endif 00025 #include "CellularLog.h" 00026 00027 // timeout to wait for AT responses 00028 #define TIMEOUT_POWER_ON (1*1000) 00029 #define TIMEOUT_SIM_PIN (1*1000) 00030 #define TIMEOUT_NETWORK (10*1000) 00031 #define TIMEOUT_REGISTRATION (180*1000) 00032 00033 // maximum time when retrying network register, attach and connect in seconds ( 20minutes ) 00034 #define TIMEOUT_NETWORK_MAX (20*60) 00035 00036 #define RETRY_COUNT_DEFAULT 3 00037 00038 namespace mbed { 00039 00040 CellularConnectionFSM::CellularConnectionFSM() : 00041 _serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _network(0), _power(0), _sim(0), 00042 _queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _retry_count(0), _state_retry_count(0), _at_queue(8 * EVENTS_EVENT_SIZE) 00043 { 00044 memset(_sim_pin, 0, sizeof(_sim_pin)); 00045 #if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0 00046 _start_time = 0; 00047 #else 00048 _start_time = rand() % (MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY); 00049 #endif // MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY 00050 00051 // set initial retry values in seconds 00052 _retry_timeout_array[0] = 1; 00053 _retry_timeout_array[1] = 2; 00054 _retry_timeout_array[2] = 4; 00055 _retry_timeout_array[3] = 16; 00056 _retry_timeout_array[4] = 32; 00057 _retry_timeout_array[5] = 60; 00058 _retry_timeout_array[6] = 120; 00059 _retry_timeout_array[7] = 360; 00060 _retry_timeout_array[8] = 600; 00061 _retry_timeout_array[9] = TIMEOUT_NETWORK_MAX; 00062 _retry_array_length = MAX_RETRY_ARRAY_SIZE; 00063 00064 _cellularDevice = new CELLULAR_DEVICE(_at_queue); 00065 } 00066 00067 CellularConnectionFSM::~CellularConnectionFSM() 00068 { 00069 stop(); 00070 } 00071 00072 nsapi_error_t CellularConnectionFSM::init() 00073 { 00074 _power = _cellularDevice->open_power(_serial); 00075 if (!_power) { 00076 stop(); 00077 return NSAPI_ERROR_NO_MEMORY ; 00078 } 00079 _network = _cellularDevice->open_network(_serial); 00080 if (!_network) { 00081 stop(); 00082 return NSAPI_ERROR_NO_MEMORY ; 00083 } 00084 00085 _sim = _cellularDevice->open_sim(_serial); 00086 if (!_sim) { 00087 stop(); 00088 return NSAPI_ERROR_NO_MEMORY ; 00089 } 00090 00091 _at_queue.chain(&_queue); 00092 00093 tr_info("init done..."); 00094 return NSAPI_ERROR_OK ; 00095 } 00096 00097 bool CellularConnectionFSM::open_power(FileHandle *fh) 00098 { 00099 if (!_power) { 00100 _power = _cellularDevice->open_power(fh); 00101 if (!_power) { 00102 return false; 00103 } 00104 } 00105 nsapi_error_t err = _power->on(); 00106 if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED ) { 00107 tr_warn("Cellular start failed. Power off/on."); 00108 err = _power->off(); 00109 if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED ) { 00110 tr_error("Cellular power down failed!"); 00111 } 00112 return false; 00113 } 00114 return true; 00115 } 00116 00117 void CellularConnectionFSM::set_sim_pin(const char * sim_pin) 00118 { 00119 strncpy(_sim_pin, sim_pin, sizeof(_sim_pin)); 00120 } 00121 00122 bool CellularConnectionFSM::open_sim() 00123 { 00124 CellularSIM::SimState state = CellularSIM::SimStateUnknown; 00125 // wait until SIM is readable 00126 // here you could add wait(secs) if you know start delay of your SIM 00127 while (_sim->get_sim_state(state) != NSAPI_ERROR_OK || state == CellularSIM::SimStateUnknown) { 00128 tr_info("Waiting for SIM (state %d)...", state); 00129 return false; 00130 } 00131 tr_info("Initial SIM state: %d", state); 00132 00133 if (strlen(_sim_pin)) { 00134 nsapi_error_t err; 00135 if (state == CellularSIM::SimStatePinNeeded) { 00136 tr_info("SIM pin required, entering pin: %s", _sim_pin); 00137 err = _sim->set_pin(_sim_pin); 00138 if (err) { 00139 tr_error("SIM pin set failed with: %d, bailing out...", err); 00140 return false; 00141 } 00142 // here you could add wait(secs) if you know delay of changing PIN on your SIM 00143 for (int i = 0; i < MAX_SIM_READY_WAITING_TIME; i++) { 00144 if (_sim->get_sim_state(state) == NSAPI_ERROR_OK && state == CellularSIM::SimStateReady) { 00145 break; 00146 } 00147 tr_info("SIM state: %d", state); 00148 return false; 00149 } 00150 } 00151 } else { 00152 tr_info("No SIM pin provided."); 00153 } 00154 00155 return state == CellularSIM::SimStateReady; 00156 } 00157 00158 void CellularConnectionFSM::device_ready() 00159 { 00160 CellularInformation *info = _cellularDevice->open_information(_serial); 00161 char device_info_buf[2048]; // may be up to 2048 according to 3GPP 00162 00163 if (info->get_manufacturer(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK ) { 00164 tr_info("Cellular device manufacturer: %s", device_info_buf); 00165 } 00166 if (info->get_model(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK ) { 00167 tr_info("Cellular device model: %s", device_info_buf); 00168 } 00169 if (info->get_revision(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK ) { 00170 tr_info("Cellular device revision: %s", device_info_buf); 00171 } 00172 } 00173 00174 bool CellularConnectionFSM::set_network_registration(char *plmn) 00175 { 00176 if (_network->set_registration(plmn) != NSAPI_ERROR_OK ) { 00177 tr_error("Failed to set network registration."); 00178 return false; 00179 } 00180 return true; 00181 } 00182 00183 bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type, 00184 CellularNetwork::RegistrationStatus &status, bool &is_registered) 00185 { 00186 is_registered = false; 00187 bool is_roaming = false; 00188 nsapi_error_t err = _network->get_registration_status(type, status); 00189 if (err != NSAPI_ERROR_OK ) { 00190 if (err != NSAPI_ERROR_UNSUPPORTED ) { 00191 tr_warn("Get network registration failed (type %d)!", type); 00192 } 00193 return false; 00194 } 00195 switch (status) { 00196 case CellularNetwork::RegisteredRoaming: 00197 is_roaming = true; 00198 // fall-through 00199 case CellularNetwork::RegisteredHomeNetwork: 00200 is_registered = true; 00201 break; 00202 case CellularNetwork::RegisteredSMSOnlyRoaming: 00203 is_roaming = true; 00204 // fall-through 00205 case CellularNetwork::RegisteredSMSOnlyHome: 00206 tr_warn("SMS only network registration!"); 00207 break; 00208 case CellularNetwork::RegisteredCSFBNotPreferredRoaming: 00209 is_roaming = true; 00210 // fall-through 00211 case CellularNetwork::RegisteredCSFBNotPreferredHome: 00212 tr_warn("Not preferred network registration!"); 00213 break; 00214 case CellularNetwork::AttachedEmergencyOnly: 00215 tr_warn("Emergency only network registration!"); 00216 break; 00217 case CellularNetwork::RegistrationDenied: 00218 case CellularNetwork::NotRegistered: 00219 case CellularNetwork::Unknown: 00220 case CellularNetwork::SearchingNetwork: 00221 default: 00222 break; 00223 } 00224 00225 if (is_roaming) { 00226 tr_warn("Roaming cellular network!"); 00227 } 00228 00229 return true; 00230 } 00231 00232 bool CellularConnectionFSM::get_attach_network(CellularNetwork::AttachStatus &status) 00233 { 00234 nsapi_error_t err = _network->get_attach(status); 00235 if (err != NSAPI_ERROR_OK ) { 00236 return false; 00237 } 00238 return true; 00239 } 00240 00241 bool CellularConnectionFSM::set_attach_network() 00242 { 00243 nsapi_error_t attach_err = _network->set_attach(); 00244 if (attach_err != NSAPI_ERROR_OK ) { 00245 return false; 00246 } 00247 return true; 00248 } 00249 00250 void CellularConnectionFSM::report_failure(const char* msg) 00251 { 00252 tr_error("Cellular network failed: %s", msg); 00253 if (_status_callback) { 00254 _status_callback(_state, _next_state); 00255 } 00256 } 00257 00258 nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state) 00259 { 00260 if (state < _state) { 00261 _state = state; 00262 } 00263 if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) { 00264 stop(); 00265 return NSAPI_ERROR_NO_MEMORY ; 00266 } 00267 00268 return NSAPI_ERROR_OK ; 00269 } 00270 00271 void CellularConnectionFSM::event() 00272 { 00273 nsapi_error_t err; 00274 int event_timeout = -1; 00275 00276 switch (_state) { 00277 case STATE_INIT: 00278 event_timeout = _start_time; 00279 tr_info("INIT state, waiting %d ms before POWER state)", _start_time); 00280 _next_state = STATE_POWER_ON; 00281 break; 00282 case STATE_POWER_ON: 00283 _cellularDevice->set_timeout(TIMEOUT_POWER_ON); 00284 tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON); 00285 if (open_power(_serial)) { 00286 _next_state = STATE_DEVICE_READY; 00287 _retry_count = 0; 00288 } else { 00289 if (++_retry_count <= RETRY_COUNT_DEFAULT) { 00290 tr_warn("Power ON retry %d", _retry_count); 00291 event_timeout = 3 * 1000; 00292 } else { 00293 report_failure("Power"); 00294 return; 00295 } 00296 } 00297 break; 00298 case STATE_DEVICE_READY: 00299 _cellularDevice->set_timeout(TIMEOUT_POWER_ON); 00300 if (_power->set_at_mode() == NSAPI_ERROR_OK ) { 00301 tr_info("Cellular device ready"); 00302 _next_state = STATE_SIM_PIN; 00303 _retry_count = 0; 00304 device_ready(); 00305 } else { 00306 tr_info("Waiting for cellular device (retry %d/%d, timeout %d ms)", _retry_count, RETRY_COUNT_DEFAULT, 00307 TIMEOUT_POWER_ON); 00308 if (_retry_count++ <= RETRY_COUNT_DEFAULT) { 00309 event_timeout = 3 * 1000; 00310 } else { 00311 report_failure("Power"); 00312 return; 00313 } 00314 } 00315 break; 00316 case STATE_SIM_PIN: 00317 _cellularDevice->set_timeout(TIMEOUT_SIM_PIN); 00318 tr_info("Start cellular (timeout %d ms)", TIMEOUT_SIM_PIN); 00319 if (open_sim()) { 00320 _next_state = STATE_REGISTERING_NETWORK; 00321 _retry_count = 0; 00322 _state_retry_count = 0; 00323 tr_info("Check for network registration"); 00324 } else { 00325 if (_retry_count++ <= RETRY_COUNT_DEFAULT) { 00326 tr_warn("Waiting for SIM %d/%d", _retry_count, RETRY_COUNT_DEFAULT); 00327 event_timeout = 3 * 1000; 00328 } else { 00329 report_failure("Entering SIM PIN"); 00330 return; 00331 } 00332 } 00333 break; 00334 case STATE_REGISTERING_NETWORK: 00335 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00336 CellularNetwork::RegistrationStatus status; 00337 bool is_registered; 00338 _next_state = STATE_REGISTER_NETWORK; 00339 for (int type = 0; type < CellularNetwork::C_MAX; type++) { 00340 if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) { 00341 tr_debug("get_network_registration: type=%d, status=%d", type, status); 00342 if (is_registered) { 00343 tr_info("Registered to cellular network (type %d, status %d)", type, status); 00344 _next_state = STATE_ATTACHING_NETWORK; 00345 _retry_count = 0; 00346 _state_retry_count = 0; 00347 event_timeout = 0; 00348 tr_info("Check cellular network attach state"); 00349 break; 00350 } else { 00351 if (_retry_count < 180) { 00352 event_timeout = 1000; 00353 _next_state = STATE_REGISTERING_NETWORK; 00354 tr_info("Waiting for registration %d/180 (type %d, status %d)", _retry_count, type, status); 00355 } else { 00356 tr_info("Start cellular registration"); 00357 _next_state = STATE_REGISTER_NETWORK; 00358 _retry_count = 0; 00359 break; 00360 } 00361 } 00362 } 00363 } 00364 00365 if (_next_state == STATE_REGISTERING_NETWORK) { 00366 _retry_count++; 00367 } 00368 break; 00369 case STATE_REGISTER_NETWORK: 00370 _cellularDevice->set_timeout(TIMEOUT_REGISTRATION); 00371 tr_info("Register to cellular network (timeout %d ms)", TIMEOUT_REGISTRATION); 00372 if (set_network_registration()) { 00373 _next_state = STATE_REGISTERING_NETWORK; 00374 _retry_count = 0; 00375 if (_state_retry_count > RETRY_COUNT_DEFAULT) { 00376 report_failure("Registration retry"); 00377 return; 00378 } 00379 _state_retry_count++; 00380 } else { 00381 if (_retry_count < _retry_array_length) { 00382 event_timeout = _retry_timeout_array[_retry_count] * 1000; 00383 _retry_count++; 00384 } else { 00385 report_failure("Registration"); 00386 return; 00387 } 00388 } 00389 break; 00390 case STATE_ATTACHING_NETWORK: 00391 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00392 CellularNetwork::AttachStatus attach_status; 00393 if (get_attach_network(attach_status)) { 00394 if (attach_status == CellularNetwork::Attached) { 00395 _next_state = STATE_CONNECT_NETWORK; 00396 _retry_count = 0; 00397 } else { 00398 _next_state = STATE_ATTACH_NETWORK; 00399 _retry_count = 0; 00400 } 00401 } else { 00402 if (_retry_count++ <= RETRY_COUNT_DEFAULT) { 00403 event_timeout = 1 * 1000; 00404 } else { 00405 report_failure("Attaching"); 00406 return; 00407 } 00408 } 00409 break; 00410 case STATE_ATTACH_NETWORK: 00411 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00412 tr_info("Attach to cellular network (timeout %d ms)", TIMEOUT_NETWORK); 00413 if (set_attach_network()) { 00414 _next_state = STATE_ATTACHING_NETWORK; 00415 _retry_count = 0; 00416 if (_state_retry_count >= RETRY_COUNT_DEFAULT) { 00417 report_failure("Attach retry"); 00418 return; 00419 } 00420 _state_retry_count++; 00421 tr_info("Cellular network attaching"); 00422 } else { 00423 if (_retry_count < _retry_array_length) { 00424 event_timeout = _retry_timeout_array[_retry_count] * 1000; 00425 _retry_count++; 00426 } else { 00427 report_failure("Attach"); 00428 return; 00429 } 00430 } 00431 break; 00432 case STATE_CONNECT_NETWORK: 00433 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00434 tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_NETWORK); 00435 err = _network->connect(); 00436 if (!err) { 00437 _next_state = STATE_CONNECTED; 00438 } else { 00439 if (_retry_count < _retry_array_length) { 00440 event_timeout = _retry_timeout_array[_retry_count] * 1000; 00441 _retry_count++; 00442 } else { 00443 report_failure("Network Connect"); 00444 return; 00445 } 00446 } 00447 break; 00448 case STATE_CONNECTED: 00449 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00450 tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK); 00451 if (_status_callback) { 00452 if (!_status_callback(_state, _next_state)) { 00453 return; 00454 } 00455 } 00456 break; 00457 default: 00458 MBED_ASSERT(0); 00459 break; 00460 } 00461 00462 if (_next_state != _state || event_timeout >= 0) { 00463 if (_next_state != _state) { // state exit condition 00464 tr_info("Cellular state from %d to %d", _state, _next_state); 00465 if (_status_callback) { 00466 if (!_status_callback(_state, _next_state)) { 00467 return; 00468 } 00469 } 00470 } else { 00471 if (event_timeout == 0) { 00472 static int retry_count = 0; 00473 if (++retry_count <= 3) { 00474 tr_info("Cellular event retry %d", retry_count); 00475 } else { 00476 report_failure("Cellular connection failed!"); 00477 return; 00478 } 00479 } else { 00480 tr_info("Cellular event in %d milliseconds", event_timeout); 00481 } 00482 } 00483 _state = _next_state; 00484 if (event_timeout == -1) { 00485 event_timeout = 0; 00486 } 00487 if (!_queue.call_in(event_timeout, callback(this, &CellularConnectionFSM::event))) { 00488 report_failure("Cellular event failure!"); 00489 return; 00490 } 00491 } 00492 } 00493 00494 nsapi_error_t CellularConnectionFSM::start_dispatch() 00495 { 00496 tr_info("CellularConnectionUtil::start"); 00497 tr_info("Create cellular thread"); 00498 00499 MBED_ASSERT(!_queue_thread); 00500 00501 _queue_thread = new rtos::Thread; 00502 if (!_queue_thread) { 00503 stop(); 00504 return NSAPI_ERROR_NO_MEMORY ; 00505 } 00506 if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) { 00507 stop(); 00508 return NSAPI_ERROR_NO_MEMORY ; 00509 } 00510 00511 tr_info("CellularConnectionUtil::started"); 00512 return NSAPI_ERROR_OK ; 00513 } 00514 00515 void CellularConnectionFSM::stop() 00516 { 00517 tr_info("CellularConnectionUtil::stop"); 00518 _cellularDevice->close_power(); 00519 _cellularDevice->close_network(); 00520 if (_queue_thread) { 00521 _queue_thread->terminate(); 00522 _queue_thread = NULL; 00523 } 00524 } 00525 00526 void CellularConnectionFSM::set_serial(UARTSerial *serial) 00527 { 00528 _serial = serial; 00529 } 00530 00531 void CellularConnectionFSM::set_callback(mbed::Callback<bool(int, int)> status_callback) 00532 { 00533 _status_callback = status_callback; 00534 } 00535 00536 events::EventQueue *CellularConnectionFSM::get_queue() 00537 { 00538 return &_queue; 00539 } 00540 00541 CellularNetwork* CellularConnectionFSM::get_network() 00542 { 00543 return _network; 00544 } 00545 00546 CellularDevice* CellularConnectionFSM::get_device() 00547 { 00548 return _cellularDevice; 00549 } 00550 00551 CellularSIM* CellularConnectionFSM::get_sim() 00552 { 00553 return _sim; 00554 } 00555 00556 NetworkStack *CellularConnectionFSM::get_stack() 00557 { 00558 return _cellularDevice->get_stack(); 00559 } 00560 00561 void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len) 00562 { 00563 _retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len; 00564 00565 for (int i = 0; i < _retry_array_length; i++) { 00566 _retry_timeout_array[i] = timeout[i]; 00567 } 00568 } 00569 00570 } // namespace 00571 00572 #endif // CELLULAR_DEVICE
Generated on Tue Jul 12 2022 12:21:45 by
