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.
mbed-os/features/cellular/easy_cellular/CellularConnectionFSM.cpp@0:8fdf9a60065b, 2018-10-10 (annotated)
- Committer:
- kadonotakashi
- Date:
- Wed Oct 10 00:33:53 2018 +0000
- Revision:
- 0:8fdf9a60065b
how to make mbed librry
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kadonotakashi | 0:8fdf9a60065b | 1 | /* |
kadonotakashi | 0:8fdf9a60065b | 2 | * Copyright (c) 2017, Arm Limited and affiliates. |
kadonotakashi | 0:8fdf9a60065b | 3 | * SPDX-License-Identifier: Apache-2.0 |
kadonotakashi | 0:8fdf9a60065b | 4 | * |
kadonotakashi | 0:8fdf9a60065b | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
kadonotakashi | 0:8fdf9a60065b | 6 | * you may not use this file except in compliance with the License. |
kadonotakashi | 0:8fdf9a60065b | 7 | * You may obtain a copy of the License at |
kadonotakashi | 0:8fdf9a60065b | 8 | * |
kadonotakashi | 0:8fdf9a60065b | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
kadonotakashi | 0:8fdf9a60065b | 10 | * |
kadonotakashi | 0:8fdf9a60065b | 11 | * Unless required by applicable law or agreed to in writing, software |
kadonotakashi | 0:8fdf9a60065b | 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
kadonotakashi | 0:8fdf9a60065b | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
kadonotakashi | 0:8fdf9a60065b | 14 | * See the License for the specific language governing permissions and |
kadonotakashi | 0:8fdf9a60065b | 15 | * limitations under the License. |
kadonotakashi | 0:8fdf9a60065b | 16 | */ |
kadonotakashi | 0:8fdf9a60065b | 17 | |
kadonotakashi | 0:8fdf9a60065b | 18 | #include "CellularConnectionFSM.h" |
kadonotakashi | 0:8fdf9a60065b | 19 | |
kadonotakashi | 0:8fdf9a60065b | 20 | #ifdef CELLULAR_DEVICE |
kadonotakashi | 0:8fdf9a60065b | 21 | |
kadonotakashi | 0:8fdf9a60065b | 22 | #ifndef MBED_TRACE_MAX_LEVEL |
kadonotakashi | 0:8fdf9a60065b | 23 | #define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO |
kadonotakashi | 0:8fdf9a60065b | 24 | #endif |
kadonotakashi | 0:8fdf9a60065b | 25 | #include "CellularLog.h" |
kadonotakashi | 0:8fdf9a60065b | 26 | #include "CellularCommon.h" |
kadonotakashi | 0:8fdf9a60065b | 27 | #include "CellularDevice.h" |
kadonotakashi | 0:8fdf9a60065b | 28 | #include "CellularUtil.h" |
kadonotakashi | 0:8fdf9a60065b | 29 | |
kadonotakashi | 0:8fdf9a60065b | 30 | // timeout to wait for AT responses |
kadonotakashi | 0:8fdf9a60065b | 31 | #define TIMEOUT_POWER_ON (1*1000) |
kadonotakashi | 0:8fdf9a60065b | 32 | #define TIMEOUT_SIM_PIN (1*1000) |
kadonotakashi | 0:8fdf9a60065b | 33 | #define TIMEOUT_NETWORK (10*1000) |
kadonotakashi | 0:8fdf9a60065b | 34 | #define TIMEOUT_CONNECT (60*1000) |
kadonotakashi | 0:8fdf9a60065b | 35 | #define TIMEOUT_REGISTRATION (180*1000) |
kadonotakashi | 0:8fdf9a60065b | 36 | |
kadonotakashi | 0:8fdf9a60065b | 37 | // maximum time when retrying network register, attach and connect in seconds ( 20minutes ) |
kadonotakashi | 0:8fdf9a60065b | 38 | #define TIMEOUT_NETWORK_MAX (20*60) |
kadonotakashi | 0:8fdf9a60065b | 39 | |
kadonotakashi | 0:8fdf9a60065b | 40 | #define RETRY_COUNT_DEFAULT 3 |
kadonotakashi | 0:8fdf9a60065b | 41 | |
kadonotakashi | 0:8fdf9a60065b | 42 | namespace mbed { |
kadonotakashi | 0:8fdf9a60065b | 43 | |
kadonotakashi | 0:8fdf9a60065b | 44 | CellularConnectionFSM::CellularConnectionFSM() : |
kadonotakashi | 0:8fdf9a60065b | 45 | _serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _event_status_cb(0), _network(0), _power(0), _sim(0), |
kadonotakashi | 0:8fdf9a60065b | 46 | _queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _cellularDevice(0), _retry_count(0), _event_timeout(-1), |
kadonotakashi | 0:8fdf9a60065b | 47 | _at_queue(0), _event_id(0), _plmn(0), _command_success(false), _plmn_network_found(false) |
kadonotakashi | 0:8fdf9a60065b | 48 | { |
kadonotakashi | 0:8fdf9a60065b | 49 | memset(_sim_pin, 0, sizeof(_sim_pin)); |
kadonotakashi | 0:8fdf9a60065b | 50 | #if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0 |
kadonotakashi | 0:8fdf9a60065b | 51 | _start_time = 0; |
kadonotakashi | 0:8fdf9a60065b | 52 | #else |
kadonotakashi | 0:8fdf9a60065b | 53 | // so that not every device don't start at the exact same time (for example after power outage) |
kadonotakashi | 0:8fdf9a60065b | 54 | _start_time = rand() % (MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY); |
kadonotakashi | 0:8fdf9a60065b | 55 | #endif // MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY |
kadonotakashi | 0:8fdf9a60065b | 56 | |
kadonotakashi | 0:8fdf9a60065b | 57 | // set initial retry values in seconds |
kadonotakashi | 0:8fdf9a60065b | 58 | _retry_timeout_array[0] = 1; // double time on each retry in order to keep network happy |
kadonotakashi | 0:8fdf9a60065b | 59 | _retry_timeout_array[1] = 2; |
kadonotakashi | 0:8fdf9a60065b | 60 | _retry_timeout_array[2] = 4; |
kadonotakashi | 0:8fdf9a60065b | 61 | _retry_timeout_array[3] = 8; |
kadonotakashi | 0:8fdf9a60065b | 62 | _retry_timeout_array[4] = 16; |
kadonotakashi | 0:8fdf9a60065b | 63 | _retry_timeout_array[5] = 32; |
kadonotakashi | 0:8fdf9a60065b | 64 | _retry_timeout_array[6] = 64; |
kadonotakashi | 0:8fdf9a60065b | 65 | _retry_timeout_array[7] = 128; // if around two minutes was not enough then let's wait much longer |
kadonotakashi | 0:8fdf9a60065b | 66 | _retry_timeout_array[8] = 600; |
kadonotakashi | 0:8fdf9a60065b | 67 | _retry_timeout_array[9] = TIMEOUT_NETWORK_MAX; |
kadonotakashi | 0:8fdf9a60065b | 68 | _retry_array_length = MAX_RETRY_ARRAY_SIZE; |
kadonotakashi | 0:8fdf9a60065b | 69 | } |
kadonotakashi | 0:8fdf9a60065b | 70 | |
kadonotakashi | 0:8fdf9a60065b | 71 | CellularConnectionFSM::~CellularConnectionFSM() |
kadonotakashi | 0:8fdf9a60065b | 72 | { |
kadonotakashi | 0:8fdf9a60065b | 73 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 74 | } |
kadonotakashi | 0:8fdf9a60065b | 75 | |
kadonotakashi | 0:8fdf9a60065b | 76 | void CellularConnectionFSM::stop() |
kadonotakashi | 0:8fdf9a60065b | 77 | { |
kadonotakashi | 0:8fdf9a60065b | 78 | _queue.cancel(_event_id); |
kadonotakashi | 0:8fdf9a60065b | 79 | _queue.break_dispatch(); |
kadonotakashi | 0:8fdf9a60065b | 80 | |
kadonotakashi | 0:8fdf9a60065b | 81 | if (_queue_thread) { |
kadonotakashi | 0:8fdf9a60065b | 82 | _queue_thread->terminate(); |
kadonotakashi | 0:8fdf9a60065b | 83 | delete _queue_thread; |
kadonotakashi | 0:8fdf9a60065b | 84 | _queue_thread = NULL; |
kadonotakashi | 0:8fdf9a60065b | 85 | } |
kadonotakashi | 0:8fdf9a60065b | 86 | |
kadonotakashi | 0:8fdf9a60065b | 87 | if (_power) { |
kadonotakashi | 0:8fdf9a60065b | 88 | _cellularDevice->close_power(); |
kadonotakashi | 0:8fdf9a60065b | 89 | _power = NULL; |
kadonotakashi | 0:8fdf9a60065b | 90 | } |
kadonotakashi | 0:8fdf9a60065b | 91 | |
kadonotakashi | 0:8fdf9a60065b | 92 | if (_network) { |
kadonotakashi | 0:8fdf9a60065b | 93 | _cellularDevice->close_network(); |
kadonotakashi | 0:8fdf9a60065b | 94 | _network = NULL; |
kadonotakashi | 0:8fdf9a60065b | 95 | } |
kadonotakashi | 0:8fdf9a60065b | 96 | |
kadonotakashi | 0:8fdf9a60065b | 97 | if (_sim) { |
kadonotakashi | 0:8fdf9a60065b | 98 | _cellularDevice->close_sim(); |
kadonotakashi | 0:8fdf9a60065b | 99 | _sim = NULL; |
kadonotakashi | 0:8fdf9a60065b | 100 | } |
kadonotakashi | 0:8fdf9a60065b | 101 | |
kadonotakashi | 0:8fdf9a60065b | 102 | _state = STATE_INIT; |
kadonotakashi | 0:8fdf9a60065b | 103 | _next_state = _state; |
kadonotakashi | 0:8fdf9a60065b | 104 | } |
kadonotakashi | 0:8fdf9a60065b | 105 | |
kadonotakashi | 0:8fdf9a60065b | 106 | nsapi_error_t CellularConnectionFSM::init() |
kadonotakashi | 0:8fdf9a60065b | 107 | { |
kadonotakashi | 0:8fdf9a60065b | 108 | tr_info("CELLULAR_DEVICE: %s", CELLULAR_STRINGIFY(CELLULAR_DEVICE)); |
kadonotakashi | 0:8fdf9a60065b | 109 | _cellularDevice = CellularDevice::get_default_instance(); |
kadonotakashi | 0:8fdf9a60065b | 110 | if (!_cellularDevice) { |
kadonotakashi | 0:8fdf9a60065b | 111 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 112 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 113 | } |
kadonotakashi | 0:8fdf9a60065b | 114 | |
kadonotakashi | 0:8fdf9a60065b | 115 | _power = _cellularDevice->open_power(_serial); |
kadonotakashi | 0:8fdf9a60065b | 116 | if (!_power) { |
kadonotakashi | 0:8fdf9a60065b | 117 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 118 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 119 | } |
kadonotakashi | 0:8fdf9a60065b | 120 | |
kadonotakashi | 0:8fdf9a60065b | 121 | _network = _cellularDevice->open_network(_serial); |
kadonotakashi | 0:8fdf9a60065b | 122 | if (!_network) { |
kadonotakashi | 0:8fdf9a60065b | 123 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 124 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 125 | } |
kadonotakashi | 0:8fdf9a60065b | 126 | |
kadonotakashi | 0:8fdf9a60065b | 127 | _sim = _cellularDevice->open_sim(_serial); |
kadonotakashi | 0:8fdf9a60065b | 128 | if (!_sim) { |
kadonotakashi | 0:8fdf9a60065b | 129 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 130 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 131 | } |
kadonotakashi | 0:8fdf9a60065b | 132 | |
kadonotakashi | 0:8fdf9a60065b | 133 | _at_queue = _cellularDevice->get_queue(); |
kadonotakashi | 0:8fdf9a60065b | 134 | _at_queue->chain(&_queue); |
kadonotakashi | 0:8fdf9a60065b | 135 | |
kadonotakashi | 0:8fdf9a60065b | 136 | _retry_count = 0; |
kadonotakashi | 0:8fdf9a60065b | 137 | _state = STATE_INIT; |
kadonotakashi | 0:8fdf9a60065b | 138 | _next_state = STATE_INIT; |
kadonotakashi | 0:8fdf9a60065b | 139 | |
kadonotakashi | 0:8fdf9a60065b | 140 | return _network->init(); |
kadonotakashi | 0:8fdf9a60065b | 141 | } |
kadonotakashi | 0:8fdf9a60065b | 142 | |
kadonotakashi | 0:8fdf9a60065b | 143 | bool CellularConnectionFSM::power_on() |
kadonotakashi | 0:8fdf9a60065b | 144 | { |
kadonotakashi | 0:8fdf9a60065b | 145 | nsapi_error_t err = _power->on(); |
kadonotakashi | 0:8fdf9a60065b | 146 | if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) { |
kadonotakashi | 0:8fdf9a60065b | 147 | tr_warn("Cellular start failed. Power off/on."); |
kadonotakashi | 0:8fdf9a60065b | 148 | err = _power->off(); |
kadonotakashi | 0:8fdf9a60065b | 149 | if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) { |
kadonotakashi | 0:8fdf9a60065b | 150 | tr_error("Cellular power down failing after failed power up attempt!"); |
kadonotakashi | 0:8fdf9a60065b | 151 | } |
kadonotakashi | 0:8fdf9a60065b | 152 | return false; |
kadonotakashi | 0:8fdf9a60065b | 153 | } |
kadonotakashi | 0:8fdf9a60065b | 154 | return true; |
kadonotakashi | 0:8fdf9a60065b | 155 | } |
kadonotakashi | 0:8fdf9a60065b | 156 | |
kadonotakashi | 0:8fdf9a60065b | 157 | void CellularConnectionFSM::set_sim_pin(const char *sim_pin) |
kadonotakashi | 0:8fdf9a60065b | 158 | { |
kadonotakashi | 0:8fdf9a60065b | 159 | strncpy(_sim_pin, sim_pin, sizeof(_sim_pin)); |
kadonotakashi | 0:8fdf9a60065b | 160 | _sim_pin[sizeof(_sim_pin) - 1] = '\0'; |
kadonotakashi | 0:8fdf9a60065b | 161 | } |
kadonotakashi | 0:8fdf9a60065b | 162 | |
kadonotakashi | 0:8fdf9a60065b | 163 | void CellularConnectionFSM::set_plmn(const char *plmn) |
kadonotakashi | 0:8fdf9a60065b | 164 | { |
kadonotakashi | 0:8fdf9a60065b | 165 | _plmn = plmn; |
kadonotakashi | 0:8fdf9a60065b | 166 | } |
kadonotakashi | 0:8fdf9a60065b | 167 | |
kadonotakashi | 0:8fdf9a60065b | 168 | bool CellularConnectionFSM::open_sim() |
kadonotakashi | 0:8fdf9a60065b | 169 | { |
kadonotakashi | 0:8fdf9a60065b | 170 | CellularSIM::SimState state = CellularSIM::SimStateUnknown; |
kadonotakashi | 0:8fdf9a60065b | 171 | // wait until SIM is readable |
kadonotakashi | 0:8fdf9a60065b | 172 | // here you could add wait(secs) if you know start delay of your SIM |
kadonotakashi | 0:8fdf9a60065b | 173 | if (_sim->get_sim_state(state) != NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 174 | tr_info("Waiting for SIM (err while reading)..."); |
kadonotakashi | 0:8fdf9a60065b | 175 | if (_event_status_cb) { |
kadonotakashi | 0:8fdf9a60065b | 176 | _event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state); |
kadonotakashi | 0:8fdf9a60065b | 177 | } |
kadonotakashi | 0:8fdf9a60065b | 178 | return false; |
kadonotakashi | 0:8fdf9a60065b | 179 | } |
kadonotakashi | 0:8fdf9a60065b | 180 | |
kadonotakashi | 0:8fdf9a60065b | 181 | // report current state so callback can set sim pin if needed |
kadonotakashi | 0:8fdf9a60065b | 182 | if (_event_status_cb) { |
kadonotakashi | 0:8fdf9a60065b | 183 | _event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state); |
kadonotakashi | 0:8fdf9a60065b | 184 | } |
kadonotakashi | 0:8fdf9a60065b | 185 | |
kadonotakashi | 0:8fdf9a60065b | 186 | if (state == CellularSIM::SimStatePinNeeded) { |
kadonotakashi | 0:8fdf9a60065b | 187 | if (strlen(_sim_pin)) { |
kadonotakashi | 0:8fdf9a60065b | 188 | tr_info("SIM pin required, entering pin"); |
kadonotakashi | 0:8fdf9a60065b | 189 | nsapi_error_t err = _sim->set_pin(_sim_pin); |
kadonotakashi | 0:8fdf9a60065b | 190 | if (err) { |
kadonotakashi | 0:8fdf9a60065b | 191 | tr_error("SIM pin set failed with: %d, bailing out...", err); |
kadonotakashi | 0:8fdf9a60065b | 192 | } |
kadonotakashi | 0:8fdf9a60065b | 193 | } else { |
kadonotakashi | 0:8fdf9a60065b | 194 | // No sim pin provided even it's needed, stop state machine |
kadonotakashi | 0:8fdf9a60065b | 195 | tr_error("PIN required but No SIM pin provided."); |
kadonotakashi | 0:8fdf9a60065b | 196 | _retry_count = MAX_RETRY_ARRAY_SIZE; |
kadonotakashi | 0:8fdf9a60065b | 197 | return false; |
kadonotakashi | 0:8fdf9a60065b | 198 | } |
kadonotakashi | 0:8fdf9a60065b | 199 | } |
kadonotakashi | 0:8fdf9a60065b | 200 | |
kadonotakashi | 0:8fdf9a60065b | 201 | return state == CellularSIM::SimStateReady; |
kadonotakashi | 0:8fdf9a60065b | 202 | } |
kadonotakashi | 0:8fdf9a60065b | 203 | |
kadonotakashi | 0:8fdf9a60065b | 204 | bool CellularConnectionFSM::is_registered() |
kadonotakashi | 0:8fdf9a60065b | 205 | { |
kadonotakashi | 0:8fdf9a60065b | 206 | CellularNetwork::RegistrationStatus status; |
kadonotakashi | 0:8fdf9a60065b | 207 | bool is_registered = false; |
kadonotakashi | 0:8fdf9a60065b | 208 | |
kadonotakashi | 0:8fdf9a60065b | 209 | for (int type = 0; type < CellularNetwork::C_MAX; type++) { |
kadonotakashi | 0:8fdf9a60065b | 210 | if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) { |
kadonotakashi | 0:8fdf9a60065b | 211 | tr_debug("get_network_registration: type=%d, status=%d", type, status); |
kadonotakashi | 0:8fdf9a60065b | 212 | if (is_registered) { |
kadonotakashi | 0:8fdf9a60065b | 213 | break; |
kadonotakashi | 0:8fdf9a60065b | 214 | } |
kadonotakashi | 0:8fdf9a60065b | 215 | } |
kadonotakashi | 0:8fdf9a60065b | 216 | } |
kadonotakashi | 0:8fdf9a60065b | 217 | |
kadonotakashi | 0:8fdf9a60065b | 218 | return is_registered; |
kadonotakashi | 0:8fdf9a60065b | 219 | } |
kadonotakashi | 0:8fdf9a60065b | 220 | |
kadonotakashi | 0:8fdf9a60065b | 221 | bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type, |
kadonotakashi | 0:8fdf9a60065b | 222 | CellularNetwork::RegistrationStatus &status, bool &is_registered) |
kadonotakashi | 0:8fdf9a60065b | 223 | { |
kadonotakashi | 0:8fdf9a60065b | 224 | is_registered = false; |
kadonotakashi | 0:8fdf9a60065b | 225 | bool is_roaming = false; |
kadonotakashi | 0:8fdf9a60065b | 226 | nsapi_error_t err = _network->get_registration_status(type, status); |
kadonotakashi | 0:8fdf9a60065b | 227 | if (err != NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 228 | if (err != NSAPI_ERROR_UNSUPPORTED) { |
kadonotakashi | 0:8fdf9a60065b | 229 | tr_warn("Get network registration failed (type %d)!", type); |
kadonotakashi | 0:8fdf9a60065b | 230 | } |
kadonotakashi | 0:8fdf9a60065b | 231 | return false; |
kadonotakashi | 0:8fdf9a60065b | 232 | } |
kadonotakashi | 0:8fdf9a60065b | 233 | switch (status) { |
kadonotakashi | 0:8fdf9a60065b | 234 | case CellularNetwork::RegisteredRoaming: |
kadonotakashi | 0:8fdf9a60065b | 235 | is_roaming = true; |
kadonotakashi | 0:8fdf9a60065b | 236 | // fall-through |
kadonotakashi | 0:8fdf9a60065b | 237 | case CellularNetwork::RegisteredHomeNetwork: |
kadonotakashi | 0:8fdf9a60065b | 238 | is_registered = true; |
kadonotakashi | 0:8fdf9a60065b | 239 | break; |
kadonotakashi | 0:8fdf9a60065b | 240 | case CellularNetwork::RegisteredSMSOnlyRoaming: |
kadonotakashi | 0:8fdf9a60065b | 241 | is_roaming = true; |
kadonotakashi | 0:8fdf9a60065b | 242 | // fall-through |
kadonotakashi | 0:8fdf9a60065b | 243 | case CellularNetwork::RegisteredSMSOnlyHome: |
kadonotakashi | 0:8fdf9a60065b | 244 | tr_warn("SMS only network registration!"); |
kadonotakashi | 0:8fdf9a60065b | 245 | break; |
kadonotakashi | 0:8fdf9a60065b | 246 | case CellularNetwork::RegisteredCSFBNotPreferredRoaming: |
kadonotakashi | 0:8fdf9a60065b | 247 | is_roaming = true; |
kadonotakashi | 0:8fdf9a60065b | 248 | // fall-through |
kadonotakashi | 0:8fdf9a60065b | 249 | case CellularNetwork::RegisteredCSFBNotPreferredHome: |
kadonotakashi | 0:8fdf9a60065b | 250 | tr_warn("Not preferred network registration!"); |
kadonotakashi | 0:8fdf9a60065b | 251 | break; |
kadonotakashi | 0:8fdf9a60065b | 252 | case CellularNetwork::AttachedEmergencyOnly: |
kadonotakashi | 0:8fdf9a60065b | 253 | tr_warn("Emergency only network registration!"); |
kadonotakashi | 0:8fdf9a60065b | 254 | break; |
kadonotakashi | 0:8fdf9a60065b | 255 | case CellularNetwork::RegistrationDenied: |
kadonotakashi | 0:8fdf9a60065b | 256 | case CellularNetwork::NotRegistered: |
kadonotakashi | 0:8fdf9a60065b | 257 | case CellularNetwork::Unknown: |
kadonotakashi | 0:8fdf9a60065b | 258 | case CellularNetwork::SearchingNetwork: |
kadonotakashi | 0:8fdf9a60065b | 259 | default: |
kadonotakashi | 0:8fdf9a60065b | 260 | break; |
kadonotakashi | 0:8fdf9a60065b | 261 | } |
kadonotakashi | 0:8fdf9a60065b | 262 | |
kadonotakashi | 0:8fdf9a60065b | 263 | if (is_roaming) { |
kadonotakashi | 0:8fdf9a60065b | 264 | tr_warn("Roaming cellular network!"); |
kadonotakashi | 0:8fdf9a60065b | 265 | } |
kadonotakashi | 0:8fdf9a60065b | 266 | |
kadonotakashi | 0:8fdf9a60065b | 267 | return true; |
kadonotakashi | 0:8fdf9a60065b | 268 | } |
kadonotakashi | 0:8fdf9a60065b | 269 | |
kadonotakashi | 0:8fdf9a60065b | 270 | void CellularConnectionFSM::report_failure(const char *msg) |
kadonotakashi | 0:8fdf9a60065b | 271 | { |
kadonotakashi | 0:8fdf9a60065b | 272 | tr_error("Cellular network failed: %s", msg); |
kadonotakashi | 0:8fdf9a60065b | 273 | if (_status_callback) { |
kadonotakashi | 0:8fdf9a60065b | 274 | _status_callback(_state, _next_state); |
kadonotakashi | 0:8fdf9a60065b | 275 | } |
kadonotakashi | 0:8fdf9a60065b | 276 | } |
kadonotakashi | 0:8fdf9a60065b | 277 | |
kadonotakashi | 0:8fdf9a60065b | 278 | const char *CellularConnectionFSM::get_state_string(CellularState state) |
kadonotakashi | 0:8fdf9a60065b | 279 | { |
kadonotakashi | 0:8fdf9a60065b | 280 | #if MBED_CONF_MBED_TRACE_ENABLE |
kadonotakashi | 0:8fdf9a60065b | 281 | static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"}; |
kadonotakashi | 0:8fdf9a60065b | 282 | return strings[state]; |
kadonotakashi | 0:8fdf9a60065b | 283 | #else |
kadonotakashi | 0:8fdf9a60065b | 284 | return NULL; |
kadonotakashi | 0:8fdf9a60065b | 285 | #endif // #if MBED_CONF_MBED_TRACE_ENABLE |
kadonotakashi | 0:8fdf9a60065b | 286 | } |
kadonotakashi | 0:8fdf9a60065b | 287 | |
kadonotakashi | 0:8fdf9a60065b | 288 | bool CellularConnectionFSM::is_registered_to_plmn() |
kadonotakashi | 0:8fdf9a60065b | 289 | { |
kadonotakashi | 0:8fdf9a60065b | 290 | int format; |
kadonotakashi | 0:8fdf9a60065b | 291 | CellularNetwork::operator_t op; |
kadonotakashi | 0:8fdf9a60065b | 292 | |
kadonotakashi | 0:8fdf9a60065b | 293 | nsapi_error_t err = _network->get_operator_params(format, op); |
kadonotakashi | 0:8fdf9a60065b | 294 | if (err == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 295 | if (format == 2) { |
kadonotakashi | 0:8fdf9a60065b | 296 | // great, numeric format we can do comparison for that |
kadonotakashi | 0:8fdf9a60065b | 297 | if (strcmp(op.op_num, _plmn) == 0) { |
kadonotakashi | 0:8fdf9a60065b | 298 | return true; |
kadonotakashi | 0:8fdf9a60065b | 299 | } |
kadonotakashi | 0:8fdf9a60065b | 300 | return false; |
kadonotakashi | 0:8fdf9a60065b | 301 | } |
kadonotakashi | 0:8fdf9a60065b | 302 | |
kadonotakashi | 0:8fdf9a60065b | 303 | // format was alpha, get operator names to do the comparing |
kadonotakashi | 0:8fdf9a60065b | 304 | CellularNetwork::operator_names_list names_list; |
kadonotakashi | 0:8fdf9a60065b | 305 | nsapi_error_t err = _network->get_operator_names(names_list); |
kadonotakashi | 0:8fdf9a60065b | 306 | if (err == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 307 | CellularNetwork::operator_names_t *op_names = names_list.get_head(); |
kadonotakashi | 0:8fdf9a60065b | 308 | bool found_match = false; |
kadonotakashi | 0:8fdf9a60065b | 309 | while (op_names) { |
kadonotakashi | 0:8fdf9a60065b | 310 | if (format == 0) { |
kadonotakashi | 0:8fdf9a60065b | 311 | if (strcmp(op.op_long, op_names->alpha) == 0) { |
kadonotakashi | 0:8fdf9a60065b | 312 | found_match = true; |
kadonotakashi | 0:8fdf9a60065b | 313 | } |
kadonotakashi | 0:8fdf9a60065b | 314 | } else if (format == 1) { |
kadonotakashi | 0:8fdf9a60065b | 315 | if (strcmp(op.op_short, op_names->alpha) == 0) { |
kadonotakashi | 0:8fdf9a60065b | 316 | found_match = true; |
kadonotakashi | 0:8fdf9a60065b | 317 | } |
kadonotakashi | 0:8fdf9a60065b | 318 | } |
kadonotakashi | 0:8fdf9a60065b | 319 | |
kadonotakashi | 0:8fdf9a60065b | 320 | if (found_match) { |
kadonotakashi | 0:8fdf9a60065b | 321 | if (strcmp(_plmn, op_names->numeric)) { |
kadonotakashi | 0:8fdf9a60065b | 322 | names_list.delete_all(); |
kadonotakashi | 0:8fdf9a60065b | 323 | return true; |
kadonotakashi | 0:8fdf9a60065b | 324 | } |
kadonotakashi | 0:8fdf9a60065b | 325 | names_list.delete_all(); |
kadonotakashi | 0:8fdf9a60065b | 326 | return false; |
kadonotakashi | 0:8fdf9a60065b | 327 | } |
kadonotakashi | 0:8fdf9a60065b | 328 | } |
kadonotakashi | 0:8fdf9a60065b | 329 | } |
kadonotakashi | 0:8fdf9a60065b | 330 | names_list.delete_all(); |
kadonotakashi | 0:8fdf9a60065b | 331 | } |
kadonotakashi | 0:8fdf9a60065b | 332 | |
kadonotakashi | 0:8fdf9a60065b | 333 | return false; |
kadonotakashi | 0:8fdf9a60065b | 334 | } |
kadonotakashi | 0:8fdf9a60065b | 335 | |
kadonotakashi | 0:8fdf9a60065b | 336 | nsapi_error_t CellularConnectionFSM::continue_from_state(CellularState state) |
kadonotakashi | 0:8fdf9a60065b | 337 | { |
kadonotakashi | 0:8fdf9a60065b | 338 | tr_info("Continue state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state), |
kadonotakashi | 0:8fdf9a60065b | 339 | get_state_string((CellularConnectionFSM::CellularState)state)); |
kadonotakashi | 0:8fdf9a60065b | 340 | _state = state; |
kadonotakashi | 0:8fdf9a60065b | 341 | _next_state = state; |
kadonotakashi | 0:8fdf9a60065b | 342 | _retry_count = 0; |
kadonotakashi | 0:8fdf9a60065b | 343 | if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) { |
kadonotakashi | 0:8fdf9a60065b | 344 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 345 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 346 | } |
kadonotakashi | 0:8fdf9a60065b | 347 | |
kadonotakashi | 0:8fdf9a60065b | 348 | return NSAPI_ERROR_OK; |
kadonotakashi | 0:8fdf9a60065b | 349 | } |
kadonotakashi | 0:8fdf9a60065b | 350 | |
kadonotakashi | 0:8fdf9a60065b | 351 | nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state) |
kadonotakashi | 0:8fdf9a60065b | 352 | { |
kadonotakashi | 0:8fdf9a60065b | 353 | MBED_ASSERT(_cellularDevice); |
kadonotakashi | 0:8fdf9a60065b | 354 | _retry_count = 0; |
kadonotakashi | 0:8fdf9a60065b | 355 | if (state < _state) { |
kadonotakashi | 0:8fdf9a60065b | 356 | _state = state; |
kadonotakashi | 0:8fdf9a60065b | 357 | } else { |
kadonotakashi | 0:8fdf9a60065b | 358 | // update next state so that we don't continue from previous state |
kadonotakashi | 0:8fdf9a60065b | 359 | _state = _next_state; |
kadonotakashi | 0:8fdf9a60065b | 360 | } |
kadonotakashi | 0:8fdf9a60065b | 361 | if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) { |
kadonotakashi | 0:8fdf9a60065b | 362 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 363 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 364 | } |
kadonotakashi | 0:8fdf9a60065b | 365 | |
kadonotakashi | 0:8fdf9a60065b | 366 | return NSAPI_ERROR_OK; |
kadonotakashi | 0:8fdf9a60065b | 367 | } |
kadonotakashi | 0:8fdf9a60065b | 368 | |
kadonotakashi | 0:8fdf9a60065b | 369 | void CellularConnectionFSM::enter_to_state(CellularState state) |
kadonotakashi | 0:8fdf9a60065b | 370 | { |
kadonotakashi | 0:8fdf9a60065b | 371 | _next_state = state; |
kadonotakashi | 0:8fdf9a60065b | 372 | _retry_count = 0; |
kadonotakashi | 0:8fdf9a60065b | 373 | _command_success = false; |
kadonotakashi | 0:8fdf9a60065b | 374 | } |
kadonotakashi | 0:8fdf9a60065b | 375 | |
kadonotakashi | 0:8fdf9a60065b | 376 | void CellularConnectionFSM::retry_state_or_fail() |
kadonotakashi | 0:8fdf9a60065b | 377 | { |
kadonotakashi | 0:8fdf9a60065b | 378 | if (++_retry_count < MAX_RETRY_ARRAY_SIZE) { |
kadonotakashi | 0:8fdf9a60065b | 379 | tr_debug("Retry State %s, retry %d/%d", get_state_string(_state), _retry_count, MAX_RETRY_ARRAY_SIZE); |
kadonotakashi | 0:8fdf9a60065b | 380 | _event_timeout = _retry_timeout_array[_retry_count]; |
kadonotakashi | 0:8fdf9a60065b | 381 | } else { |
kadonotakashi | 0:8fdf9a60065b | 382 | report_failure(get_state_string(_state)); |
kadonotakashi | 0:8fdf9a60065b | 383 | return; |
kadonotakashi | 0:8fdf9a60065b | 384 | } |
kadonotakashi | 0:8fdf9a60065b | 385 | } |
kadonotakashi | 0:8fdf9a60065b | 386 | |
kadonotakashi | 0:8fdf9a60065b | 387 | void CellularConnectionFSM::state_init() |
kadonotakashi | 0:8fdf9a60065b | 388 | { |
kadonotakashi | 0:8fdf9a60065b | 389 | // we should check that if power is already on then we can jump to device ready state |
kadonotakashi | 0:8fdf9a60065b | 390 | _cellularDevice->set_timeout(TIMEOUT_POWER_ON); |
kadonotakashi | 0:8fdf9a60065b | 391 | tr_info("Cellular state init (timeout %d ms)", TIMEOUT_POWER_ON); |
kadonotakashi | 0:8fdf9a60065b | 392 | nsapi_error_t err = _power->is_device_ready(); |
kadonotakashi | 0:8fdf9a60065b | 393 | if (err != NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 394 | _event_timeout = _start_time; |
kadonotakashi | 0:8fdf9a60065b | 395 | tr_info("Init state, waiting %d ms before POWER state)", _start_time); |
kadonotakashi | 0:8fdf9a60065b | 396 | enter_to_state(STATE_POWER_ON); |
kadonotakashi | 0:8fdf9a60065b | 397 | } else { |
kadonotakashi | 0:8fdf9a60065b | 398 | tr_info("Device was ready to accept commands, jump to device ready"); |
kadonotakashi | 0:8fdf9a60065b | 399 | enter_to_state(STATE_DEVICE_READY); |
kadonotakashi | 0:8fdf9a60065b | 400 | } |
kadonotakashi | 0:8fdf9a60065b | 401 | } |
kadonotakashi | 0:8fdf9a60065b | 402 | |
kadonotakashi | 0:8fdf9a60065b | 403 | void CellularConnectionFSM::state_power_on() |
kadonotakashi | 0:8fdf9a60065b | 404 | { |
kadonotakashi | 0:8fdf9a60065b | 405 | _cellularDevice->set_timeout(TIMEOUT_POWER_ON); |
kadonotakashi | 0:8fdf9a60065b | 406 | tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON); |
kadonotakashi | 0:8fdf9a60065b | 407 | if (power_on()) { |
kadonotakashi | 0:8fdf9a60065b | 408 | enter_to_state(STATE_DEVICE_READY); |
kadonotakashi | 0:8fdf9a60065b | 409 | } else { |
kadonotakashi | 0:8fdf9a60065b | 410 | // retry to power on device |
kadonotakashi | 0:8fdf9a60065b | 411 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 412 | } |
kadonotakashi | 0:8fdf9a60065b | 413 | } |
kadonotakashi | 0:8fdf9a60065b | 414 | |
kadonotakashi | 0:8fdf9a60065b | 415 | bool CellularConnectionFSM::device_ready() |
kadonotakashi | 0:8fdf9a60065b | 416 | { |
kadonotakashi | 0:8fdf9a60065b | 417 | if (_cellularDevice->init_module(_serial) != NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 418 | return false; |
kadonotakashi | 0:8fdf9a60065b | 419 | } |
kadonotakashi | 0:8fdf9a60065b | 420 | tr_info("Cellular device ready"); |
kadonotakashi | 0:8fdf9a60065b | 421 | if (_event_status_cb) { |
kadonotakashi | 0:8fdf9a60065b | 422 | _event_status_cb((nsapi_event_t)CellularDeviceReady, 0); |
kadonotakashi | 0:8fdf9a60065b | 423 | } |
kadonotakashi | 0:8fdf9a60065b | 424 | _power->remove_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb)); |
kadonotakashi | 0:8fdf9a60065b | 425 | _cellularDevice->close_power(); |
kadonotakashi | 0:8fdf9a60065b | 426 | _power = NULL; |
kadonotakashi | 0:8fdf9a60065b | 427 | return true; |
kadonotakashi | 0:8fdf9a60065b | 428 | } |
kadonotakashi | 0:8fdf9a60065b | 429 | |
kadonotakashi | 0:8fdf9a60065b | 430 | void CellularConnectionFSM::state_device_ready() |
kadonotakashi | 0:8fdf9a60065b | 431 | { |
kadonotakashi | 0:8fdf9a60065b | 432 | _cellularDevice->set_timeout(TIMEOUT_POWER_ON); |
kadonotakashi | 0:8fdf9a60065b | 433 | if (_power->set_at_mode() == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 434 | if (device_ready()) { |
kadonotakashi | 0:8fdf9a60065b | 435 | enter_to_state(STATE_SIM_PIN); |
kadonotakashi | 0:8fdf9a60065b | 436 | } |
kadonotakashi | 0:8fdf9a60065b | 437 | } else { |
kadonotakashi | 0:8fdf9a60065b | 438 | if (_retry_count == 0) { |
kadonotakashi | 0:8fdf9a60065b | 439 | (void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb)); |
kadonotakashi | 0:8fdf9a60065b | 440 | } |
kadonotakashi | 0:8fdf9a60065b | 441 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 442 | } |
kadonotakashi | 0:8fdf9a60065b | 443 | } |
kadonotakashi | 0:8fdf9a60065b | 444 | |
kadonotakashi | 0:8fdf9a60065b | 445 | void CellularConnectionFSM::state_sim_pin() |
kadonotakashi | 0:8fdf9a60065b | 446 | { |
kadonotakashi | 0:8fdf9a60065b | 447 | _cellularDevice->set_timeout(TIMEOUT_SIM_PIN); |
kadonotakashi | 0:8fdf9a60065b | 448 | tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN); |
kadonotakashi | 0:8fdf9a60065b | 449 | if (open_sim()) { |
kadonotakashi | 0:8fdf9a60065b | 450 | bool success = false; |
kadonotakashi | 0:8fdf9a60065b | 451 | for (int type = 0; type < CellularNetwork::C_MAX; type++) { |
kadonotakashi | 0:8fdf9a60065b | 452 | if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) { |
kadonotakashi | 0:8fdf9a60065b | 453 | success = true; |
kadonotakashi | 0:8fdf9a60065b | 454 | } |
kadonotakashi | 0:8fdf9a60065b | 455 | } |
kadonotakashi | 0:8fdf9a60065b | 456 | if (!success) { |
kadonotakashi | 0:8fdf9a60065b | 457 | tr_warn("Failed to set any URC's for registration"); |
kadonotakashi | 0:8fdf9a60065b | 458 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 459 | return; |
kadonotakashi | 0:8fdf9a60065b | 460 | } |
kadonotakashi | 0:8fdf9a60065b | 461 | if (_plmn) { |
kadonotakashi | 0:8fdf9a60065b | 462 | enter_to_state(STATE_MANUAL_REGISTERING_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 463 | } else { |
kadonotakashi | 0:8fdf9a60065b | 464 | enter_to_state(STATE_REGISTERING_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 465 | } |
kadonotakashi | 0:8fdf9a60065b | 466 | } else { |
kadonotakashi | 0:8fdf9a60065b | 467 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 468 | } |
kadonotakashi | 0:8fdf9a60065b | 469 | } |
kadonotakashi | 0:8fdf9a60065b | 470 | |
kadonotakashi | 0:8fdf9a60065b | 471 | void CellularConnectionFSM::state_registering() |
kadonotakashi | 0:8fdf9a60065b | 472 | { |
kadonotakashi | 0:8fdf9a60065b | 473 | _cellularDevice->set_timeout(TIMEOUT_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 474 | if (is_registered()) { |
kadonotakashi | 0:8fdf9a60065b | 475 | // we are already registered, go to attach |
kadonotakashi | 0:8fdf9a60065b | 476 | enter_to_state(STATE_ATTACHING_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 477 | } else { |
kadonotakashi | 0:8fdf9a60065b | 478 | _cellularDevice->set_timeout(TIMEOUT_REGISTRATION); |
kadonotakashi | 0:8fdf9a60065b | 479 | if (!_command_success) { |
kadonotakashi | 0:8fdf9a60065b | 480 | _command_success = (_network->set_registration() == NSAPI_ERROR_OK); |
kadonotakashi | 0:8fdf9a60065b | 481 | } |
kadonotakashi | 0:8fdf9a60065b | 482 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 483 | } |
kadonotakashi | 0:8fdf9a60065b | 484 | } |
kadonotakashi | 0:8fdf9a60065b | 485 | |
kadonotakashi | 0:8fdf9a60065b | 486 | // only used when _plmn is set |
kadonotakashi | 0:8fdf9a60065b | 487 | void CellularConnectionFSM::state_manual_registering_network() |
kadonotakashi | 0:8fdf9a60065b | 488 | { |
kadonotakashi | 0:8fdf9a60065b | 489 | _cellularDevice->set_timeout(TIMEOUT_REGISTRATION); |
kadonotakashi | 0:8fdf9a60065b | 490 | tr_info("state_manual_registering_network"); |
kadonotakashi | 0:8fdf9a60065b | 491 | if (!_plmn_network_found) { |
kadonotakashi | 0:8fdf9a60065b | 492 | if (is_registered() && is_registered_to_plmn()) { |
kadonotakashi | 0:8fdf9a60065b | 493 | _plmn_network_found = true; |
kadonotakashi | 0:8fdf9a60065b | 494 | enter_to_state(STATE_ATTACHING_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 495 | } else { |
kadonotakashi | 0:8fdf9a60065b | 496 | if (!_command_success) { |
kadonotakashi | 0:8fdf9a60065b | 497 | _command_success = (_network->set_registration(_plmn) == NSAPI_ERROR_OK); |
kadonotakashi | 0:8fdf9a60065b | 498 | } |
kadonotakashi | 0:8fdf9a60065b | 499 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 500 | } |
kadonotakashi | 0:8fdf9a60065b | 501 | } |
kadonotakashi | 0:8fdf9a60065b | 502 | } |
kadonotakashi | 0:8fdf9a60065b | 503 | |
kadonotakashi | 0:8fdf9a60065b | 504 | void CellularConnectionFSM::state_attaching() |
kadonotakashi | 0:8fdf9a60065b | 505 | { |
kadonotakashi | 0:8fdf9a60065b | 506 | _cellularDevice->set_timeout(TIMEOUT_CONNECT); |
kadonotakashi | 0:8fdf9a60065b | 507 | if (_network->set_attach() == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 508 | _cellularDevice->close_sim(); |
kadonotakashi | 0:8fdf9a60065b | 509 | _sim = NULL; |
kadonotakashi | 0:8fdf9a60065b | 510 | enter_to_state(STATE_ACTIVATING_PDP_CONTEXT); |
kadonotakashi | 0:8fdf9a60065b | 511 | } else { |
kadonotakashi | 0:8fdf9a60065b | 512 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 513 | } |
kadonotakashi | 0:8fdf9a60065b | 514 | } |
kadonotakashi | 0:8fdf9a60065b | 515 | |
kadonotakashi | 0:8fdf9a60065b | 516 | void CellularConnectionFSM::state_activating_pdp_context() |
kadonotakashi | 0:8fdf9a60065b | 517 | { |
kadonotakashi | 0:8fdf9a60065b | 518 | _cellularDevice->set_timeout(TIMEOUT_CONNECT); |
kadonotakashi | 0:8fdf9a60065b | 519 | tr_info("Activate PDP Context (timeout %d ms)", TIMEOUT_CONNECT); |
kadonotakashi | 0:8fdf9a60065b | 520 | if (_network->activate_context() == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 521 | // when using modems stack connect is synchronous |
kadonotakashi | 0:8fdf9a60065b | 522 | _next_state = STATE_CONNECTING_NETWORK; |
kadonotakashi | 0:8fdf9a60065b | 523 | } else { |
kadonotakashi | 0:8fdf9a60065b | 524 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 525 | } |
kadonotakashi | 0:8fdf9a60065b | 526 | } |
kadonotakashi | 0:8fdf9a60065b | 527 | |
kadonotakashi | 0:8fdf9a60065b | 528 | void CellularConnectionFSM::state_connect_to_network() |
kadonotakashi | 0:8fdf9a60065b | 529 | { |
kadonotakashi | 0:8fdf9a60065b | 530 | _cellularDevice->set_timeout(TIMEOUT_CONNECT); |
kadonotakashi | 0:8fdf9a60065b | 531 | tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_CONNECT); |
kadonotakashi | 0:8fdf9a60065b | 532 | if (_network->connect() == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 533 | _cellularDevice->set_timeout(TIMEOUT_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 534 | tr_debug("Connected to cellular network, set at timeout (timeout %d ms)", TIMEOUT_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 535 | // when using modems stack connect is synchronous |
kadonotakashi | 0:8fdf9a60065b | 536 | _next_state = STATE_CONNECTED; |
kadonotakashi | 0:8fdf9a60065b | 537 | } else { |
kadonotakashi | 0:8fdf9a60065b | 538 | retry_state_or_fail(); |
kadonotakashi | 0:8fdf9a60065b | 539 | } |
kadonotakashi | 0:8fdf9a60065b | 540 | } |
kadonotakashi | 0:8fdf9a60065b | 541 | |
kadonotakashi | 0:8fdf9a60065b | 542 | void CellularConnectionFSM::state_connected() |
kadonotakashi | 0:8fdf9a60065b | 543 | { |
kadonotakashi | 0:8fdf9a60065b | 544 | _cellularDevice->set_timeout(TIMEOUT_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 545 | tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 546 | if (_status_callback) { |
kadonotakashi | 0:8fdf9a60065b | 547 | _status_callback(_state, _next_state); |
kadonotakashi | 0:8fdf9a60065b | 548 | } |
kadonotakashi | 0:8fdf9a60065b | 549 | } |
kadonotakashi | 0:8fdf9a60065b | 550 | |
kadonotakashi | 0:8fdf9a60065b | 551 | void CellularConnectionFSM::event() |
kadonotakashi | 0:8fdf9a60065b | 552 | { |
kadonotakashi | 0:8fdf9a60065b | 553 | _event_timeout = -1; |
kadonotakashi | 0:8fdf9a60065b | 554 | switch (_state) { |
kadonotakashi | 0:8fdf9a60065b | 555 | case STATE_INIT: |
kadonotakashi | 0:8fdf9a60065b | 556 | state_init(); |
kadonotakashi | 0:8fdf9a60065b | 557 | break; |
kadonotakashi | 0:8fdf9a60065b | 558 | case STATE_POWER_ON: |
kadonotakashi | 0:8fdf9a60065b | 559 | state_power_on(); |
kadonotakashi | 0:8fdf9a60065b | 560 | break; |
kadonotakashi | 0:8fdf9a60065b | 561 | case STATE_DEVICE_READY: |
kadonotakashi | 0:8fdf9a60065b | 562 | state_device_ready(); |
kadonotakashi | 0:8fdf9a60065b | 563 | break; |
kadonotakashi | 0:8fdf9a60065b | 564 | case STATE_SIM_PIN: |
kadonotakashi | 0:8fdf9a60065b | 565 | state_sim_pin(); |
kadonotakashi | 0:8fdf9a60065b | 566 | break; |
kadonotakashi | 0:8fdf9a60065b | 567 | case STATE_REGISTERING_NETWORK: |
kadonotakashi | 0:8fdf9a60065b | 568 | state_registering(); |
kadonotakashi | 0:8fdf9a60065b | 569 | break; |
kadonotakashi | 0:8fdf9a60065b | 570 | case STATE_MANUAL_REGISTERING_NETWORK: |
kadonotakashi | 0:8fdf9a60065b | 571 | state_manual_registering_network(); |
kadonotakashi | 0:8fdf9a60065b | 572 | break; |
kadonotakashi | 0:8fdf9a60065b | 573 | case STATE_ATTACHING_NETWORK: |
kadonotakashi | 0:8fdf9a60065b | 574 | state_attaching(); |
kadonotakashi | 0:8fdf9a60065b | 575 | break; |
kadonotakashi | 0:8fdf9a60065b | 576 | case STATE_ACTIVATING_PDP_CONTEXT: |
kadonotakashi | 0:8fdf9a60065b | 577 | state_activating_pdp_context(); |
kadonotakashi | 0:8fdf9a60065b | 578 | break; |
kadonotakashi | 0:8fdf9a60065b | 579 | case STATE_CONNECTING_NETWORK: |
kadonotakashi | 0:8fdf9a60065b | 580 | state_connect_to_network(); |
kadonotakashi | 0:8fdf9a60065b | 581 | break; |
kadonotakashi | 0:8fdf9a60065b | 582 | case STATE_CONNECTED: |
kadonotakashi | 0:8fdf9a60065b | 583 | state_connected(); |
kadonotakashi | 0:8fdf9a60065b | 584 | break; |
kadonotakashi | 0:8fdf9a60065b | 585 | default: |
kadonotakashi | 0:8fdf9a60065b | 586 | MBED_ASSERT(0); |
kadonotakashi | 0:8fdf9a60065b | 587 | break; |
kadonotakashi | 0:8fdf9a60065b | 588 | } |
kadonotakashi | 0:8fdf9a60065b | 589 | |
kadonotakashi | 0:8fdf9a60065b | 590 | if (_next_state != _state || _event_timeout >= 0) { |
kadonotakashi | 0:8fdf9a60065b | 591 | if (_next_state != _state) { // state exit condition |
kadonotakashi | 0:8fdf9a60065b | 592 | tr_info("Cellular state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state), |
kadonotakashi | 0:8fdf9a60065b | 593 | get_state_string((CellularConnectionFSM::CellularState)_next_state)); |
kadonotakashi | 0:8fdf9a60065b | 594 | if (_status_callback) { |
kadonotakashi | 0:8fdf9a60065b | 595 | if (!_status_callback(_state, _next_state)) { |
kadonotakashi | 0:8fdf9a60065b | 596 | return; |
kadonotakashi | 0:8fdf9a60065b | 597 | } |
kadonotakashi | 0:8fdf9a60065b | 598 | } |
kadonotakashi | 0:8fdf9a60065b | 599 | } else { |
kadonotakashi | 0:8fdf9a60065b | 600 | tr_info("Cellular event in %d seconds", _event_timeout); |
kadonotakashi | 0:8fdf9a60065b | 601 | } |
kadonotakashi | 0:8fdf9a60065b | 602 | _state = _next_state; |
kadonotakashi | 0:8fdf9a60065b | 603 | if (_event_timeout == -1) { |
kadonotakashi | 0:8fdf9a60065b | 604 | _event_timeout = 0; |
kadonotakashi | 0:8fdf9a60065b | 605 | } |
kadonotakashi | 0:8fdf9a60065b | 606 | _event_id = _queue.call_in(_event_timeout * 1000, callback(this, &CellularConnectionFSM::event)); |
kadonotakashi | 0:8fdf9a60065b | 607 | if (!_event_id) { |
kadonotakashi | 0:8fdf9a60065b | 608 | report_failure("Cellular event failure!"); |
kadonotakashi | 0:8fdf9a60065b | 609 | return; |
kadonotakashi | 0:8fdf9a60065b | 610 | } |
kadonotakashi | 0:8fdf9a60065b | 611 | } |
kadonotakashi | 0:8fdf9a60065b | 612 | } |
kadonotakashi | 0:8fdf9a60065b | 613 | |
kadonotakashi | 0:8fdf9a60065b | 614 | nsapi_error_t CellularConnectionFSM::start_dispatch() |
kadonotakashi | 0:8fdf9a60065b | 615 | { |
kadonotakashi | 0:8fdf9a60065b | 616 | MBED_ASSERT(!_queue_thread); |
kadonotakashi | 0:8fdf9a60065b | 617 | |
kadonotakashi | 0:8fdf9a60065b | 618 | _queue_thread = new rtos::Thread(osPriorityNormal, 2048); |
kadonotakashi | 0:8fdf9a60065b | 619 | if (!_queue_thread) { |
kadonotakashi | 0:8fdf9a60065b | 620 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 621 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 622 | } |
kadonotakashi | 0:8fdf9a60065b | 623 | if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) { |
kadonotakashi | 0:8fdf9a60065b | 624 | stop(); |
kadonotakashi | 0:8fdf9a60065b | 625 | return NSAPI_ERROR_NO_MEMORY; |
kadonotakashi | 0:8fdf9a60065b | 626 | } |
kadonotakashi | 0:8fdf9a60065b | 627 | |
kadonotakashi | 0:8fdf9a60065b | 628 | return NSAPI_ERROR_OK; |
kadonotakashi | 0:8fdf9a60065b | 629 | } |
kadonotakashi | 0:8fdf9a60065b | 630 | |
kadonotakashi | 0:8fdf9a60065b | 631 | void CellularConnectionFSM::set_serial(UARTSerial *serial) |
kadonotakashi | 0:8fdf9a60065b | 632 | { |
kadonotakashi | 0:8fdf9a60065b | 633 | _serial = serial; |
kadonotakashi | 0:8fdf9a60065b | 634 | } |
kadonotakashi | 0:8fdf9a60065b | 635 | |
kadonotakashi | 0:8fdf9a60065b | 636 | void CellularConnectionFSM::set_callback(mbed::Callback<bool(int, int)> status_callback) |
kadonotakashi | 0:8fdf9a60065b | 637 | { |
kadonotakashi | 0:8fdf9a60065b | 638 | _status_callback = status_callback; |
kadonotakashi | 0:8fdf9a60065b | 639 | } |
kadonotakashi | 0:8fdf9a60065b | 640 | |
kadonotakashi | 0:8fdf9a60065b | 641 | void CellularConnectionFSM::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) |
kadonotakashi | 0:8fdf9a60065b | 642 | { |
kadonotakashi | 0:8fdf9a60065b | 643 | MBED_ASSERT(_network); |
kadonotakashi | 0:8fdf9a60065b | 644 | _event_status_cb = status_cb; |
kadonotakashi | 0:8fdf9a60065b | 645 | if (status_cb) { |
kadonotakashi | 0:8fdf9a60065b | 646 | _network->attach(callback(this, &CellularConnectionFSM::network_callback)); |
kadonotakashi | 0:8fdf9a60065b | 647 | } else { |
kadonotakashi | 0:8fdf9a60065b | 648 | _network->attach(NULL); |
kadonotakashi | 0:8fdf9a60065b | 649 | } |
kadonotakashi | 0:8fdf9a60065b | 650 | } |
kadonotakashi | 0:8fdf9a60065b | 651 | |
kadonotakashi | 0:8fdf9a60065b | 652 | void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr) |
kadonotakashi | 0:8fdf9a60065b | 653 | { |
kadonotakashi | 0:8fdf9a60065b | 654 | tr_info("FSM: network_callback called with event: %d, intptr: %d, _state: %s", ev, ptr, get_state_string(_state)); |
kadonotakashi | 0:8fdf9a60065b | 655 | if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && |
kadonotakashi | 0:8fdf9a60065b | 656 | (_state == STATE_REGISTERING_NETWORK || _state == STATE_MANUAL_REGISTERING_NETWORK)) { |
kadonotakashi | 0:8fdf9a60065b | 657 | // expect packet data so only these states are valid |
kadonotakashi | 0:8fdf9a60065b | 658 | if (ptr == CellularNetwork::RegisteredHomeNetwork || ptr == CellularNetwork::RegisteredRoaming) { |
kadonotakashi | 0:8fdf9a60065b | 659 | if (_plmn) { |
kadonotakashi | 0:8fdf9a60065b | 660 | if (is_registered_to_plmn()) { |
kadonotakashi | 0:8fdf9a60065b | 661 | if (!_plmn_network_found) { |
kadonotakashi | 0:8fdf9a60065b | 662 | _plmn_network_found = true; |
kadonotakashi | 0:8fdf9a60065b | 663 | _queue.cancel(_event_id); |
kadonotakashi | 0:8fdf9a60065b | 664 | continue_from_state(STATE_ATTACHING_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 665 | } |
kadonotakashi | 0:8fdf9a60065b | 666 | } |
kadonotakashi | 0:8fdf9a60065b | 667 | } else { |
kadonotakashi | 0:8fdf9a60065b | 668 | _queue.cancel(_event_id); |
kadonotakashi | 0:8fdf9a60065b | 669 | continue_from_state(STATE_ATTACHING_NETWORK); |
kadonotakashi | 0:8fdf9a60065b | 670 | } |
kadonotakashi | 0:8fdf9a60065b | 671 | } |
kadonotakashi | 0:8fdf9a60065b | 672 | } |
kadonotakashi | 0:8fdf9a60065b | 673 | |
kadonotakashi | 0:8fdf9a60065b | 674 | if (_event_status_cb) { |
kadonotakashi | 0:8fdf9a60065b | 675 | _event_status_cb(ev, ptr); |
kadonotakashi | 0:8fdf9a60065b | 676 | } |
kadonotakashi | 0:8fdf9a60065b | 677 | } |
kadonotakashi | 0:8fdf9a60065b | 678 | |
kadonotakashi | 0:8fdf9a60065b | 679 | void CellularConnectionFSM::ready_urc_cb() |
kadonotakashi | 0:8fdf9a60065b | 680 | { |
kadonotakashi | 0:8fdf9a60065b | 681 | tr_debug("Device ready URC func called"); |
kadonotakashi | 0:8fdf9a60065b | 682 | if (_state == STATE_DEVICE_READY && _power->set_at_mode() == NSAPI_ERROR_OK) { |
kadonotakashi | 0:8fdf9a60065b | 683 | tr_debug("State was STATE_DEVICE_READY and at mode ready, cancel state and move to next"); |
kadonotakashi | 0:8fdf9a60065b | 684 | if (device_ready()) { |
kadonotakashi | 0:8fdf9a60065b | 685 | _queue.cancel(_event_id); |
kadonotakashi | 0:8fdf9a60065b | 686 | continue_from_state(STATE_SIM_PIN); |
kadonotakashi | 0:8fdf9a60065b | 687 | } |
kadonotakashi | 0:8fdf9a60065b | 688 | } |
kadonotakashi | 0:8fdf9a60065b | 689 | } |
kadonotakashi | 0:8fdf9a60065b | 690 | |
kadonotakashi | 0:8fdf9a60065b | 691 | events::EventQueue *CellularConnectionFSM::get_queue() |
kadonotakashi | 0:8fdf9a60065b | 692 | { |
kadonotakashi | 0:8fdf9a60065b | 693 | return &_queue; |
kadonotakashi | 0:8fdf9a60065b | 694 | } |
kadonotakashi | 0:8fdf9a60065b | 695 | |
kadonotakashi | 0:8fdf9a60065b | 696 | CellularNetwork *CellularConnectionFSM::get_network() |
kadonotakashi | 0:8fdf9a60065b | 697 | { |
kadonotakashi | 0:8fdf9a60065b | 698 | return _network; |
kadonotakashi | 0:8fdf9a60065b | 699 | } |
kadonotakashi | 0:8fdf9a60065b | 700 | |
kadonotakashi | 0:8fdf9a60065b | 701 | CellularDevice *CellularConnectionFSM::get_device() |
kadonotakashi | 0:8fdf9a60065b | 702 | { |
kadonotakashi | 0:8fdf9a60065b | 703 | return _cellularDevice; |
kadonotakashi | 0:8fdf9a60065b | 704 | } |
kadonotakashi | 0:8fdf9a60065b | 705 | |
kadonotakashi | 0:8fdf9a60065b | 706 | CellularSIM *CellularConnectionFSM::get_sim() |
kadonotakashi | 0:8fdf9a60065b | 707 | { |
kadonotakashi | 0:8fdf9a60065b | 708 | return _sim; |
kadonotakashi | 0:8fdf9a60065b | 709 | } |
kadonotakashi | 0:8fdf9a60065b | 710 | |
kadonotakashi | 0:8fdf9a60065b | 711 | NetworkStack *CellularConnectionFSM::get_stack() |
kadonotakashi | 0:8fdf9a60065b | 712 | { |
kadonotakashi | 0:8fdf9a60065b | 713 | return _cellularDevice->get_stack(); |
kadonotakashi | 0:8fdf9a60065b | 714 | } |
kadonotakashi | 0:8fdf9a60065b | 715 | |
kadonotakashi | 0:8fdf9a60065b | 716 | void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len) |
kadonotakashi | 0:8fdf9a60065b | 717 | { |
kadonotakashi | 0:8fdf9a60065b | 718 | _retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len; |
kadonotakashi | 0:8fdf9a60065b | 719 | |
kadonotakashi | 0:8fdf9a60065b | 720 | for (int i = 0; i < _retry_array_length; i++) { |
kadonotakashi | 0:8fdf9a60065b | 721 | _retry_timeout_array[i] = timeout[i]; |
kadonotakashi | 0:8fdf9a60065b | 722 | } |
kadonotakashi | 0:8fdf9a60065b | 723 | } |
kadonotakashi | 0:8fdf9a60065b | 724 | |
kadonotakashi | 0:8fdf9a60065b | 725 | } // namespace |
kadonotakashi | 0:8fdf9a60065b | 726 | |
kadonotakashi | 0:8fdf9a60065b | 727 | #endif // CELLULAR_DEVICE |