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.
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 #include "CellularCommon.h" 00027 00028 // timeout to wait for AT responses 00029 #define TIMEOUT_POWER_ON (1*1000) 00030 #define TIMEOUT_SIM_PIN (1*1000) 00031 #define TIMEOUT_NETWORK (10*1000) 00032 #define TIMEOUT_CONNECT (60*1000) 00033 #define TIMEOUT_REGISTRATION (180*1000) 00034 00035 // maximum time when retrying network register, attach and connect in seconds ( 20minutes ) 00036 #define TIMEOUT_NETWORK_MAX (20*60) 00037 00038 #define RETRY_COUNT_DEFAULT 3 00039 00040 namespace mbed 00041 { 00042 00043 CellularConnectionFSM::CellularConnectionFSM() : 00044 _serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _event_status_cb(0), _network(0), _power(0), _sim(0), 00045 _queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _cellularDevice(0), _retry_count(0), _event_timeout(-1), 00046 _at_queue(8 * EVENTS_EVENT_SIZE), _event_id(0) 00047 { 00048 memset(_sim_pin, 0, sizeof(_sim_pin)); 00049 #if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0 00050 _start_time = 0; 00051 #else 00052 // so that not every device don't start at the exact same time (for example after power outage) 00053 _start_time = rand() % (MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY); 00054 #endif // MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY 00055 00056 // set initial retry values in seconds 00057 _retry_timeout_array[0] = 1; // double time on each retry in order to keep network happy 00058 _retry_timeout_array[1] = 2; 00059 _retry_timeout_array[2] = 4; 00060 _retry_timeout_array[3] = 8; 00061 _retry_timeout_array[4] = 16; 00062 _retry_timeout_array[5] = 32; 00063 _retry_timeout_array[6] = 64; 00064 _retry_timeout_array[7] = 128; // if around two minutes was not enough then let's wait much longer 00065 _retry_timeout_array[8] = 600; 00066 _retry_timeout_array[9] = TIMEOUT_NETWORK_MAX; 00067 _retry_array_length = MAX_RETRY_ARRAY_SIZE; 00068 } 00069 00070 CellularConnectionFSM::~CellularConnectionFSM() 00071 { 00072 stop(); 00073 delete _cellularDevice; 00074 } 00075 00076 void CellularConnectionFSM::stop() 00077 { 00078 tr_info("CellularConnectionUtil::stop"); 00079 if (_cellularDevice) { 00080 _cellularDevice->close_power(); 00081 _cellularDevice->close_network(); 00082 _cellularDevice->close_sim(); 00083 _power = NULL; 00084 _network = NULL; 00085 _sim = NULL; 00086 } 00087 if (_queue_thread) { 00088 _queue_thread->terminate(); 00089 delete _queue_thread; 00090 _queue_thread = NULL; 00091 } 00092 } 00093 00094 nsapi_error_t CellularConnectionFSM::init() 00095 { 00096 tr_info("CELLULAR_DEVICE: %s", CELLULAR_STRINGIFY(CELLULAR_DEVICE)); 00097 _cellularDevice = new CELLULAR_DEVICE(_at_queue); 00098 if (!_cellularDevice) { 00099 stop(); 00100 return NSAPI_ERROR_NO_MEMORY ; 00101 } 00102 00103 _power = _cellularDevice->open_power(_serial); 00104 if (!_power) { 00105 stop(); 00106 return NSAPI_ERROR_NO_MEMORY ; 00107 } 00108 _network = _cellularDevice->open_network(_serial); 00109 if (!_network) { 00110 stop(); 00111 return NSAPI_ERROR_NO_MEMORY ; 00112 } 00113 00114 _sim = _cellularDevice->open_sim(_serial); 00115 if (!_sim) { 00116 stop(); 00117 return NSAPI_ERROR_NO_MEMORY ; 00118 } 00119 00120 _at_queue.chain(&_queue); 00121 00122 _retry_count = 0; 00123 _state = STATE_INIT; 00124 _next_state = STATE_INIT; 00125 00126 return _network->init(); 00127 } 00128 00129 bool CellularConnectionFSM::power_on() 00130 { 00131 nsapi_error_t err = _power->on(); 00132 if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED ) { 00133 tr_warn("Cellular start failed. Power off/on."); 00134 err = _power->off(); 00135 if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED ) { 00136 tr_error("Cellular power down failed!"); 00137 } 00138 return false; 00139 } 00140 return true; 00141 } 00142 00143 void CellularConnectionFSM::set_sim_pin(const char * sim_pin) 00144 { 00145 strncpy(_sim_pin, sim_pin, sizeof(_sim_pin)); 00146 _sim_pin[sizeof(_sim_pin)-1] = '\0'; 00147 } 00148 00149 bool CellularConnectionFSM::open_sim() 00150 { 00151 CellularSIM::SimState state = CellularSIM::SimStateUnknown; 00152 // wait until SIM is readable 00153 // here you could add wait(secs) if you know start delay of your SIM 00154 if (_sim->get_sim_state(state) != NSAPI_ERROR_OK ) { 00155 tr_info("Waiting for SIM (err while reading)..."); 00156 return false; 00157 } 00158 00159 switch (state) { 00160 case CellularSIM::SimStateReady: 00161 tr_info("SIM Ready"); 00162 break; 00163 case CellularSIM::SimStatePinNeeded: { 00164 if (strlen(_sim_pin)) { 00165 tr_info("SIM pin required, entering pin: %s", _sim_pin); 00166 nsapi_error_t err = _sim->set_pin(_sim_pin); 00167 if (err) { 00168 tr_error("SIM pin set failed with: %d, bailing out...", err); 00169 } 00170 } else { 00171 tr_warn("PIN required but No SIM pin provided."); 00172 } 00173 } 00174 break; 00175 case CellularSIM::SimStatePukNeeded: 00176 tr_info("SIM PUK code needed..."); 00177 break; 00178 case CellularSIM::SimStateUnknown: 00179 tr_info("SIM, unknown state..."); 00180 break; 00181 default: 00182 MBED_ASSERT(1); 00183 break; 00184 } 00185 00186 if (_event_status_cb) { 00187 _event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state); 00188 } 00189 00190 return state == CellularSIM::SimStateReady; 00191 } 00192 00193 bool CellularConnectionFSM::set_network_registration(char *plmn) 00194 { 00195 if (_network->set_registration(plmn) != NSAPI_ERROR_OK ) { 00196 tr_error("Failed to set network registration."); 00197 return false; 00198 } 00199 return true; 00200 } 00201 00202 bool CellularConnectionFSM::is_registered() 00203 { 00204 CellularNetwork::RegistrationStatus status; 00205 bool is_registered = false; 00206 00207 for (int type = 0; type < CellularNetwork::C_MAX; type++) { 00208 if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) { 00209 tr_debug("get_network_registration: type=%d, status=%d", type, status); 00210 if (is_registered) { 00211 break; 00212 } 00213 } 00214 } 00215 00216 return is_registered; 00217 } 00218 00219 bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type, 00220 CellularNetwork::RegistrationStatus &status, bool &is_registered) 00221 { 00222 is_registered = false; 00223 bool is_roaming = false; 00224 nsapi_error_t err = _network->get_registration_status(type, status); 00225 if (err != NSAPI_ERROR_OK ) { 00226 if (err != NSAPI_ERROR_UNSUPPORTED ) { 00227 tr_warn("Get network registration failed (type %d)!", type); 00228 } 00229 return false; 00230 } 00231 switch (status) { 00232 case CellularNetwork::RegisteredRoaming: 00233 is_roaming = true; 00234 // fall-through 00235 case CellularNetwork::RegisteredHomeNetwork: 00236 is_registered = true; 00237 break; 00238 case CellularNetwork::RegisteredSMSOnlyRoaming: 00239 is_roaming = true; 00240 // fall-through 00241 case CellularNetwork::RegisteredSMSOnlyHome: 00242 tr_warn("SMS only network registration!"); 00243 break; 00244 case CellularNetwork::RegisteredCSFBNotPreferredRoaming: 00245 is_roaming = true; 00246 // fall-through 00247 case CellularNetwork::RegisteredCSFBNotPreferredHome: 00248 tr_warn("Not preferred network registration!"); 00249 break; 00250 case CellularNetwork::AttachedEmergencyOnly: 00251 tr_warn("Emergency only network registration!"); 00252 break; 00253 case CellularNetwork::RegistrationDenied: 00254 case CellularNetwork::NotRegistered: 00255 case CellularNetwork::Unknown: 00256 case CellularNetwork::SearchingNetwork: 00257 default: 00258 break; 00259 } 00260 00261 if (is_roaming) { 00262 tr_warn("Roaming cellular network!"); 00263 } 00264 00265 return true; 00266 } 00267 00268 bool CellularConnectionFSM::get_attach_network(CellularNetwork::AttachStatus &status) 00269 { 00270 nsapi_error_t err = _network->get_attach(status); 00271 if (err != NSAPI_ERROR_OK ) { 00272 return false; 00273 } 00274 return true; 00275 } 00276 00277 bool CellularConnectionFSM::set_attach_network() 00278 { 00279 nsapi_error_t attach_err = _network->set_attach(); 00280 if (attach_err != NSAPI_ERROR_OK ) { 00281 return false; 00282 } 00283 return true; 00284 } 00285 00286 void CellularConnectionFSM::report_failure(const char* msg) 00287 { 00288 tr_error("Cellular network failed: %s", msg); 00289 if (_status_callback) { 00290 _status_callback(_state, _next_state); 00291 } 00292 } 00293 00294 const char* CellularConnectionFSM::get_state_string(CellularState state) 00295 { 00296 static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"}; 00297 return strings[state]; 00298 } 00299 00300 nsapi_error_t CellularConnectionFSM::is_automatic_registering(bool& auto_reg) 00301 { 00302 CellularNetwork::NWRegisteringMode mode; 00303 nsapi_error_t err = _network->get_network_registering_mode(mode); 00304 if (err == NSAPI_ERROR_OK ) { 00305 tr_debug("automatic registering mode: %d", mode); 00306 auto_reg = (mode == CellularNetwork::NWModeAutomatic); 00307 } 00308 return err; 00309 } 00310 00311 nsapi_error_t CellularConnectionFSM::continue_from_state(CellularState state) 00312 { 00313 tr_info("Continue state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state), 00314 get_state_string((CellularConnectionFSM::CellularState)state)); 00315 _state = state; 00316 _next_state = state; 00317 _retry_count = 0; 00318 if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) { 00319 stop(); 00320 return NSAPI_ERROR_NO_MEMORY ; 00321 } 00322 00323 return NSAPI_ERROR_OK ; 00324 } 00325 00326 nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state) 00327 { 00328 _retry_count = 0; 00329 if (state < _state) { 00330 _state = state; 00331 } else { 00332 // update next state so that we don't continue from previous state 00333 _state = _next_state; 00334 } 00335 if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) { 00336 stop(); 00337 return NSAPI_ERROR_NO_MEMORY ; 00338 } 00339 00340 return NSAPI_ERROR_OK ; 00341 } 00342 00343 void CellularConnectionFSM::enter_to_state(CellularState state) 00344 { 00345 _next_state = state; 00346 _retry_count = 0; 00347 } 00348 00349 void CellularConnectionFSM::retry_state_or_fail() 00350 { 00351 if (++_retry_count < MAX_RETRY_ARRAY_SIZE) { 00352 tr_debug("Retry State %s, retry %d/%d", get_state_string(_state), _retry_count, MAX_RETRY_ARRAY_SIZE); 00353 _event_timeout = _retry_timeout_array[_retry_count]; 00354 } else { 00355 report_failure(get_state_string(_state)); 00356 return; 00357 } 00358 } 00359 00360 void CellularConnectionFSM::state_init() 00361 { 00362 _event_timeout = _start_time; 00363 tr_info("Init state, waiting %d ms before POWER state)", _start_time); 00364 enter_to_state(STATE_POWER_ON); 00365 } 00366 00367 void CellularConnectionFSM::state_power_on() 00368 { 00369 _cellularDevice->set_timeout(TIMEOUT_POWER_ON); 00370 tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON); 00371 if (power_on()) { 00372 enter_to_state(STATE_DEVICE_READY); 00373 } else { 00374 // retry to power on device 00375 retry_state_or_fail(); 00376 } 00377 } 00378 00379 bool CellularConnectionFSM::device_ready() 00380 { 00381 tr_info("Cellular device ready"); 00382 if (_event_status_cb) { 00383 _event_status_cb((nsapi_event_t)CellularDeviceReady, 0); 00384 } 00385 00386 _power->remove_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb)); 00387 00388 bool success = false; 00389 for (int type = 0; type < CellularNetwork::C_MAX; type++) { 00390 if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) { 00391 success = true; 00392 } 00393 } 00394 if (!success) { 00395 tr_error("Failed to set any URC's for registration"); 00396 report_failure(get_state_string(_state)); 00397 return false; 00398 } 00399 00400 return true; 00401 } 00402 00403 void CellularConnectionFSM::state_device_ready() 00404 { 00405 _cellularDevice->set_timeout(TIMEOUT_POWER_ON); 00406 if (_power->set_at_mode() == NSAPI_ERROR_OK ) { 00407 if (device_ready()) { 00408 enter_to_state(STATE_SIM_PIN); 00409 } 00410 } else { 00411 if (_retry_count == 0) { 00412 (void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb)); 00413 } 00414 retry_state_or_fail(); 00415 } 00416 } 00417 00418 void CellularConnectionFSM::state_sim_pin() 00419 { 00420 _cellularDevice->set_timeout(TIMEOUT_SIM_PIN); 00421 tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN); 00422 if (open_sim()) { 00423 enter_to_state(STATE_REGISTERING_NETWORK); 00424 } else { 00425 retry_state_or_fail(); 00426 } 00427 } 00428 00429 void CellularConnectionFSM::state_registering() 00430 { 00431 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00432 if (is_registered()) { 00433 // we are already registered, go to attach 00434 enter_to_state(STATE_ATTACHING_NETWORK); 00435 } else { 00436 bool auto_reg = false; 00437 nsapi_error_t err = is_automatic_registering(auto_reg); 00438 if (err == NSAPI_ERROR_OK && !auto_reg) { // when we support plmn add this : || plmn 00439 // automatic registering is not on, set registration and retry 00440 _cellularDevice->set_timeout(TIMEOUT_REGISTRATION); 00441 set_network_registration(); 00442 } 00443 retry_state_or_fail(); 00444 } 00445 } 00446 00447 void CellularConnectionFSM::state_attaching() 00448 { 00449 _cellularDevice->set_timeout(TIMEOUT_CONNECT); 00450 CellularNetwork::AttachStatus attach_status; 00451 if (get_attach_network(attach_status)) { 00452 if (attach_status == CellularNetwork::Attached) { 00453 enter_to_state(STATE_ACTIVATING_PDP_CONTEXT); 00454 } else { 00455 set_attach_network(); 00456 retry_state_or_fail(); 00457 } 00458 } else { 00459 retry_state_or_fail(); 00460 } 00461 } 00462 00463 void CellularConnectionFSM::state_activating_pdp_context() 00464 { 00465 _cellularDevice->set_timeout(TIMEOUT_CONNECT); 00466 tr_info("Activate PDP Context (timeout %d ms)", TIMEOUT_CONNECT); 00467 if (_network->activate_context() == NSAPI_ERROR_OK ) { 00468 // when using modems stack connect is synchronous 00469 _next_state = STATE_CONNECTING_NETWORK; 00470 } else { 00471 retry_state_or_fail(); 00472 } 00473 } 00474 00475 void CellularConnectionFSM::state_connect_to_network() 00476 { 00477 _cellularDevice->set_timeout(TIMEOUT_CONNECT); 00478 tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_CONNECT); 00479 if (_network->connect() == NSAPI_ERROR_OK ) { 00480 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00481 tr_debug("Connected to cellular network, set at timeout (timeout %d ms)", TIMEOUT_NETWORK); 00482 // when using modems stack connect is synchronous 00483 _next_state = STATE_CONNECTED; 00484 } else { 00485 retry_state_or_fail(); 00486 } 00487 } 00488 00489 void CellularConnectionFSM::state_connected() 00490 { 00491 _cellularDevice->set_timeout(TIMEOUT_NETWORK); 00492 tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK); 00493 if (_status_callback) { 00494 _status_callback(_state, _next_state); 00495 } 00496 } 00497 00498 void CellularConnectionFSM::event() 00499 { 00500 _event_timeout = -1; 00501 switch (_state) { 00502 case STATE_INIT: 00503 state_init(); 00504 break; 00505 case STATE_POWER_ON: 00506 state_power_on(); 00507 break; 00508 case STATE_DEVICE_READY: 00509 state_device_ready(); 00510 break; 00511 case STATE_SIM_PIN: 00512 state_sim_pin(); 00513 break; 00514 case STATE_REGISTERING_NETWORK: 00515 state_registering(); 00516 break; 00517 case STATE_ATTACHING_NETWORK: 00518 state_attaching(); 00519 break; 00520 case STATE_ACTIVATING_PDP_CONTEXT: 00521 state_activating_pdp_context(); 00522 break; 00523 case STATE_CONNECTING_NETWORK: 00524 state_connect_to_network(); 00525 break; 00526 case STATE_CONNECTED: 00527 state_connected(); 00528 break; 00529 default: 00530 MBED_ASSERT(0); 00531 break; 00532 } 00533 00534 if (_next_state != _state || _event_timeout >= 0) { 00535 if (_next_state != _state) { // state exit condition 00536 tr_info("Cellular state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state), 00537 get_state_string((CellularConnectionFSM::CellularState)_next_state)); 00538 if (_status_callback) { 00539 if (!_status_callback(_state, _next_state)) { 00540 return; 00541 } 00542 } 00543 } else { 00544 tr_info("Cellular event in %d seconds", _event_timeout); 00545 } 00546 _state = _next_state; 00547 if (_event_timeout == -1) { 00548 _event_timeout = 0; 00549 } 00550 _event_id = _queue.call_in(_event_timeout*1000, callback(this, &CellularConnectionFSM::event)); 00551 if (!_event_id) { 00552 report_failure("Cellular event failure!"); 00553 return; 00554 } 00555 } 00556 } 00557 00558 nsapi_error_t CellularConnectionFSM::start_dispatch() 00559 { 00560 MBED_ASSERT(!_queue_thread); 00561 00562 _queue_thread = new rtos::Thread(osPriorityNormal, 2048); 00563 if (!_queue_thread) { 00564 stop(); 00565 return NSAPI_ERROR_NO_MEMORY ; 00566 } 00567 if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) { 00568 stop(); 00569 return NSAPI_ERROR_NO_MEMORY ; 00570 } 00571 00572 return NSAPI_ERROR_OK ; 00573 } 00574 00575 void CellularConnectionFSM::set_serial(UARTSerial *serial) 00576 { 00577 _serial = serial; 00578 } 00579 00580 void CellularConnectionFSM::set_callback(mbed::Callback<bool(int, int)> status_callback) 00581 { 00582 _status_callback = status_callback; 00583 } 00584 00585 void CellularConnectionFSM::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) 00586 { 00587 _event_status_cb = status_cb; 00588 _network->attach(callback(this, &CellularConnectionFSM::network_callback)); 00589 } 00590 00591 void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr) 00592 { 00593 00594 tr_info("FSM: network_callback called with event: %d, intptr: %d", ev, ptr); 00595 if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && _state == STATE_REGISTERING_NETWORK) { 00596 // expect packet data so only these states are valid 00597 if (ptr == CellularNetwork::RegisteredHomeNetwork && CellularNetwork::RegisteredRoaming) { 00598 _queue.cancel(_event_id); 00599 continue_from_state(STATE_ATTACHING_NETWORK); 00600 } 00601 } 00602 00603 if (_event_status_cb) { 00604 _event_status_cb(ev, ptr); 00605 } 00606 } 00607 00608 void CellularConnectionFSM::ready_urc_cb() 00609 { 00610 tr_debug("Device ready URC func called"); 00611 if (_state == STATE_DEVICE_READY && _power->set_at_mode() == NSAPI_ERROR_OK ) { 00612 tr_debug("State was STATE_DEVICE_READY and at mode ready, cancel state and move to next"); 00613 _queue.cancel(_event_id); 00614 if (device_ready()) { 00615 continue_from_state(STATE_SIM_PIN); 00616 } 00617 } 00618 } 00619 00620 events::EventQueue *CellularConnectionFSM::get_queue() 00621 { 00622 return &_queue; 00623 } 00624 00625 CellularNetwork* CellularConnectionFSM::get_network() 00626 { 00627 return _network; 00628 } 00629 00630 CellularDevice* CellularConnectionFSM::get_device() 00631 { 00632 return _cellularDevice; 00633 } 00634 00635 CellularSIM* CellularConnectionFSM::get_sim() 00636 { 00637 return _sim; 00638 } 00639 00640 NetworkStack *CellularConnectionFSM::get_stack() 00641 { 00642 return _cellularDevice->get_stack(); 00643 } 00644 00645 void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len) 00646 { 00647 _retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len; 00648 00649 for (int i = 0; i < _retry_array_length; i++) { 00650 _retry_timeout_array[i] = timeout[i]; 00651 } 00652 } 00653 00654 } // namespace 00655 00656 #endif // CELLULAR_DEVICE
Generated on Tue Jul 12 2022 15:17:17 by
1.7.2