Merge pull request #6928 from jarvte/fix_cellular_connect_disconnect

Cellular: Fixed con-disc sequence can now be called multiple times.
pull/6752/merge
Cruz Monrreal 2018-05-29 10:36:11 -05:00 committed by GitHub
commit 917fe08752
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 167 additions and 142 deletions

View File

@ -144,13 +144,13 @@ bool CellularConnectionFSM::power_on()
return true;
}
void CellularConnectionFSM::set_sim_pin(const char * sim_pin)
void CellularConnectionFSM::set_sim_pin(const char *sim_pin)
{
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
_sim_pin[sizeof(_sim_pin)-1] = '\0';
}
void CellularConnectionFSM::set_plmn(const char* plmn)
void CellularConnectionFSM::set_plmn(const char *plmn)
{
_plmn = plmn;
}
@ -184,15 +184,6 @@ bool CellularConnectionFSM::open_sim()
return state == CellularSIM::SimStateReady;
}
bool CellularConnectionFSM::set_network_registration()
{
if (_network->set_registration(_plmn) != NSAPI_ERROR_OK) {
tr_error("Failed to set network registration.");
return false;
}
return true;
}
bool CellularConnectionFSM::is_registered()
{
CellularNetwork::RegistrationStatus status;
@ -259,25 +250,7 @@ bool CellularConnectionFSM::get_network_registration(CellularNetwork::Registrati
return true;
}
bool CellularConnectionFSM::get_attach_network(CellularNetwork::AttachStatus &status)
{
nsapi_error_t err = _network->get_attach(status);
if (err != NSAPI_ERROR_OK) {
return false;
}
return true;
}
bool CellularConnectionFSM::set_attach_network()
{
nsapi_error_t attach_err = _network->set_attach();
if (attach_err != NSAPI_ERROR_OK) {
return false;
}
return true;
}
void CellularConnectionFSM::report_failure(const char* msg)
void CellularConnectionFSM::report_failure(const char *msg)
{
tr_error("Cellular network failed: %s", msg);
if (_status_callback) {
@ -285,7 +258,7 @@ void CellularConnectionFSM::report_failure(const char* msg)
}
}
const char* CellularConnectionFSM::get_state_string(CellularState state)
const char *CellularConnectionFSM::get_state_string(CellularState state)
{
#if MBED_CONF_MBED_TRACE_ENABLE
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"};
@ -295,17 +268,6 @@ const char* CellularConnectionFSM::get_state_string(CellularState state)
#endif // #if MBED_CONF_MBED_TRACE_ENABLE
}
nsapi_error_t CellularConnectionFSM::is_automatic_registering(bool& auto_reg)
{
CellularNetwork::NWRegisteringMode mode;
nsapi_error_t err = _network->get_network_registering_mode(mode);
if (err == NSAPI_ERROR_OK) {
tr_debug("automatic registering mode: %d", mode);
auto_reg = (mode == CellularNetwork::NWModeAutomatic);
}
return err;
}
bool CellularConnectionFSM::is_registered_to_plmn()
{
int format;
@ -325,7 +287,7 @@ bool CellularConnectionFSM::is_registered_to_plmn()
CellularNetwork::operator_names_list names_list;
nsapi_error_t err = _network->get_operator_names(names_list);
if (err == NSAPI_ERROR_OK) {
CellularNetwork::operator_names_t* op_names = names_list.get_head();
CellularNetwork::operator_names_t *op_names = names_list.get_head();
bool found_match = false;
while (op_names) {
if (format == 0) {
@ -407,9 +369,18 @@ void CellularConnectionFSM::retry_state_or_fail()
void CellularConnectionFSM::state_init()
{
_event_timeout = _start_time;
tr_info("Init state, waiting %d ms before POWER state)", _start_time);
enter_to_state(STATE_POWER_ON);
// we should check that if power is already on then we can jump to device ready state
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
tr_info("Cellular state init (timeout %d ms)", TIMEOUT_POWER_ON);
nsapi_error_t err = _power->is_device_ready();
if (err != NSAPI_ERROR_OK) {
_event_timeout = _start_time;
tr_info("Init state, waiting %d ms before POWER state)", _start_time);
enter_to_state(STATE_POWER_ON);
} else {
tr_info("Device was ready to accept commands, jump to device ready");
enter_to_state(STATE_DEVICE_READY);
}
}
void CellularConnectionFSM::state_power_on()
@ -424,37 +395,21 @@ void CellularConnectionFSM::state_power_on()
}
}
bool CellularConnectionFSM::device_ready()
void CellularConnectionFSM::device_ready()
{
tr_info("Cellular device ready");
if (_event_status_cb) {
_event_status_cb((nsapi_event_t)CellularDeviceReady, 0);
}
_power->remove_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
bool success = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) {
success = true;
}
}
if (!success) {
tr_error("Failed to set any URC's for registration");
report_failure(get_state_string(_state));
return false;
}
return true;
}
void CellularConnectionFSM::state_device_ready()
{
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
if (_power->set_at_mode() == NSAPI_ERROR_OK) {
if (device_ready()) {
enter_to_state(STATE_SIM_PIN);
}
device_ready();
enter_to_state(STATE_SIM_PIN);
} else {
if (_retry_count == 0) {
(void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
@ -468,6 +423,18 @@ void CellularConnectionFSM::state_sim_pin()
_cellularDevice->set_timeout(TIMEOUT_SIM_PIN);
tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
bool success = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) {
success = true;
}
}
if (!success) {
tr_warn("Failed to set any URC's for registration");
retry_state_or_fail();
return;
}
if (_plmn) {
enter_to_state(STATE_MANUAL_REGISTERING_NETWORK);
} else {
@ -485,12 +452,9 @@ void CellularConnectionFSM::state_registering()
// we are already registered, go to attach
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
bool auto_reg = false;
nsapi_error_t err = is_automatic_registering(auto_reg);
if (err == NSAPI_ERROR_OK && !auto_reg) {
// automatic registering is not on, set registration and retry
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
set_network_registration();
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
if (!_command_success) {
_command_success = (_network->set_registration() == NSAPI_ERROR_OK);
}
retry_state_or_fail();
}
@ -507,7 +471,7 @@ void CellularConnectionFSM::state_manual_registering_network()
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
if (!_command_success) {
_command_success = set_network_registration();
_command_success = (_network->set_registration(_plmn) == NSAPI_ERROR_OK);
}
retry_state_or_fail();
}
@ -517,16 +481,8 @@ void CellularConnectionFSM::state_manual_registering_network()
void CellularConnectionFSM::state_attaching()
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
CellularNetwork::AttachStatus attach_status;
if (get_attach_network(attach_status)) {
if (attach_status == CellularNetwork::Attached) {
enter_to_state(STATE_ACTIVATING_PDP_CONTEXT);
} else {
if (!_command_success) {
_command_success = set_attach_network();
}
retry_state_or_fail();
}
if (_network->set_attach() == NSAPI_ERROR_OK) {
enter_to_state(STATE_ACTIVATING_PDP_CONTEXT);
} else {
retry_state_or_fail();
}
@ -701,9 +657,8 @@ void CellularConnectionFSM::ready_urc_cb()
if (_state == STATE_DEVICE_READY && _power->set_at_mode() == NSAPI_ERROR_OK) {
tr_debug("State was STATE_DEVICE_READY and at mode ready, cancel state and move to next");
_queue.cancel(_event_id);
if (device_ready()) {
continue_from_state(STATE_SIM_PIN);
}
device_ready();
continue_from_state(STATE_SIM_PIN);
}
}
@ -712,17 +667,17 @@ events::EventQueue *CellularConnectionFSM::get_queue()
return &_queue;
}
CellularNetwork* CellularConnectionFSM::get_network()
CellularNetwork *CellularConnectionFSM::get_network()
{
return _network;
}
CellularDevice* CellularConnectionFSM::get_device()
CellularDevice *CellularConnectionFSM::get_device()
{
return _cellularDevice;
}
CellularSIM* CellularConnectionFSM::get_sim()
CellularSIM *CellularConnectionFSM::get_sim()
{
return _sim;
}

View File

@ -95,7 +95,7 @@ public:
/** Get event queue that can be chained to main event queue (or use start_dispatch)
* @return event queue
*/
events::EventQueue* get_queue();
events::EventQueue *get_queue();
/** Start event queue dispatching
* @return see nsapi_error_t, 0 on success
@ -110,17 +110,17 @@ public:
/** Get cellular network interface
* @return network interface, NULL on failure
*/
CellularNetwork* get_network();
CellularNetwork *get_network();
/** Get cellular device interface
* @return device interface, NULL on failure
*/
CellularDevice* get_device();
CellularDevice *get_device();
/** Get cellular sim interface
* @return sim interface, NULL on failure
*/
CellularSIM* get_sim();
CellularSIM *get_sim();
/** Change cellular connection to the target state
* @param state to continue. Default is to connect.
@ -153,18 +153,14 @@ public:
* @param state state which is returned in string format
* @return string format of the given state
*/
const char* get_state_string(CellularState state);
const char *get_state_string(CellularState state);
private:
bool power_on();
bool open_sim();
bool get_network_registration(CellularNetwork::RegistrationType type, CellularNetwork::RegistrationStatus &status, bool &is_registered);
bool set_network_registration();
bool get_attach_network(CellularNetwork::AttachStatus &status);
bool set_attach_network();
bool is_registered();
bool device_ready();
nsapi_error_t is_automatic_registering(bool& auto_reg);
void device_ready();
// state functions to keep state machine simple
void state_init();
@ -215,7 +211,7 @@ private:
events::EventQueue _at_queue;
char _st_string[20];
int _event_id;
const char* _plmn;
const char *_plmn;
bool _command_success;
bool _plmn_network_found;
};

View File

@ -37,11 +37,11 @@ namespace mbed {
bool EasyCellularConnection::cellular_status(int state, int next_state)
{
tr_info("cellular_status: %s ==> %s", _cellularConnectionFSM.get_state_string((CellularConnectionFSM::CellularState)state),
_cellularConnectionFSM.get_state_string((CellularConnectionFSM::CellularState)next_state));
tr_info("cellular_status: %s ==> %s", _cellularConnectionFSM->get_state_string((CellularConnectionFSM::CellularState)state),
_cellularConnectionFSM->get_state_string((CellularConnectionFSM::CellularState)next_state));
if (_target_state == state) {
tr_info("Target state reached: %s", _cellularConnectionFSM.get_state_string(_target_state));
tr_info("Target state reached: %s", _cellularConnectionFSM->get_state_string(_target_state));
MBED_ASSERT(_cellularSemaphore.release() == osOK);
return false; // return false -> state machine is halted
}
@ -64,7 +64,7 @@ void EasyCellularConnection::network_callback(nsapi_event_t ev, intptr_t ptr)
EasyCellularConnection::EasyCellularConnection(bool debug) :
_is_connected(false), _is_initialized(false), _target_state(CellularConnectionFSM::STATE_POWER_ON), _cellularSerial(
MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0), _cellularConnectionFSM(), _credentials_err(
MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0), _cellularConnectionFSM(0), _credentials_err(
NSAPI_ERROR_OK), _status_cb(0)
{
tr_info("EasyCellularConnection()");
@ -76,8 +76,11 @@ EasyCellularConnection::EasyCellularConnection(bool debug) :
EasyCellularConnection::~EasyCellularConnection()
{
_cellularConnectionFSM.set_callback(NULL);
_cellularConnectionFSM.attach(NULL);
if (_cellularConnectionFSM) {
_cellularConnectionFSM->set_callback(NULL);
_cellularConnectionFSM->attach(NULL);
delete _cellularConnectionFSM;
}
}
nsapi_error_t EasyCellularConnection::init()
@ -87,14 +90,15 @@ nsapi_error_t EasyCellularConnection::init()
#if defined (MDMRTS) && defined (MDMCTS)
_cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
_cellularConnectionFSM.set_serial(&_cellularSerial);
_cellularConnectionFSM.set_callback(callback(this, &EasyCellularConnection::cellular_status));
_cellularConnectionFSM = new CellularConnectionFSM();
_cellularConnectionFSM->set_serial(&_cellularSerial);
_cellularConnectionFSM->set_callback(callback(this, &EasyCellularConnection::cellular_status));
err = _cellularConnectionFSM.init();
err = _cellularConnectionFSM->init();
if (err == NSAPI_ERROR_OK) {
err = _cellularConnectionFSM.start_dispatch();
_cellularConnectionFSM.attach(callback(this, &EasyCellularConnection::network_callback));
err = _cellularConnectionFSM->start_dispatch();
_cellularConnectionFSM->attach(callback(this, &EasyCellularConnection::network_callback));
}
_is_initialized = true;
}
@ -110,7 +114,7 @@ void EasyCellularConnection::set_credentials(const char *apn, const char *uname,
if (_credentials_err) {
return;
}
CellularNetwork * network = _cellularConnectionFSM.get_network();
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (network) {
_credentials_err = network->set_credentials(apn, uname, pwd);
#if USE_APN_LOOKUP
@ -128,8 +132,15 @@ void EasyCellularConnection::set_credentials(const char *apn, const char *uname,
void EasyCellularConnection::set_sim_pin(const char *sim_pin)
{
if (sim_pin) {
_cellularConnectionFSM.set_sim_pin(sim_pin);
if (sim_pin && strlen(sim_pin) > 0) {
if (!_cellularConnectionFSM) {
_credentials_err = init();
if (_credentials_err) {
return;
}
}
_cellularConnectionFSM->set_sim_pin(sim_pin);
}
}
@ -145,7 +156,7 @@ nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *a
}
if (sim_pin) {
_cellularConnectionFSM.set_sim_pin(sim_pin);
_cellularConnectionFSM->set_sim_pin(sim_pin);
}
return connect();
@ -179,16 +190,16 @@ nsapi_error_t EasyCellularConnection::connect()
#if USE_APN_LOOKUP
if (!_credentials_set) {
_target_state = CellularConnectionFSM::STATE_SIM_PIN;
err = _cellularConnectionFSM.continue_to_state(_target_state);
err = _cellularConnectionFSM->continue_to_state(_target_state);
if (err == NSAPI_ERROR_OK) {
int sim_wait = _cellularSemaphore.wait(60*1000); // reserve 60 seconds to access to SIM
int sim_wait = _cellularSemaphore.wait(60 * 1000); // reserve 60 seconds to access to SIM
if (sim_wait != 1) {
tr_error("NO SIM ACCESS");
err = NSAPI_ERROR_NO_CONNECTION;
} else {
char imsi[MAX_IMSI_LENGTH+1];
char imsi[MAX_IMSI_LENGTH + 1];
wait(1); // need to wait to access SIM in some modems
err = _cellularConnectionFSM.get_sim()->get_imsi(imsi);
err = _cellularConnectionFSM->get_sim()->get_imsi(imsi);
if (err == NSAPI_ERROR_OK) {
const char *apn_config = apnconfig(imsi);
if (apn_config) {
@ -196,7 +207,7 @@ nsapi_error_t EasyCellularConnection::connect()
const char* uname = _APN_GET(apn_config);
const char* pwd = _APN_GET(apn_config);
tr_info("Looked up APN %s", apn);
err = _cellularConnectionFSM.get_network()->set_credentials(apn, uname, pwd);
err = _cellularConnectionFSM->get_network()->set_credentials(apn, uname, pwd);
}
}
}
@ -209,7 +220,7 @@ nsapi_error_t EasyCellularConnection::connect()
#endif // USE_APN_LOOKUP
_target_state = CellularConnectionFSM::STATE_CONNECTED;
err = _cellularConnectionFSM.continue_to_state(_target_state);
err = _cellularConnectionFSM->continue_to_state(_target_state);
if (err == NSAPI_ERROR_OK) {
int ret_wait = _cellularSemaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes
if (ret_wait != 1) {
@ -231,11 +242,14 @@ nsapi_error_t EasyCellularConnection::disconnect()
#endif // #if USE_APN_LOOKUP
nsapi_error_t err = NSAPI_ERROR_OK;
if (_cellularConnectionFSM.get_network()) {
err = _cellularConnectionFSM.get_network()->disconnect();
if (_cellularConnectionFSM && _cellularConnectionFSM->get_network()) {
err = _cellularConnectionFSM->get_network()->disconnect();
}
_cellularConnectionFSM.stop();
if (err == NSAPI_ERROR_OK) {
delete _cellularConnectionFSM;
_cellularConnectionFSM = NULL;
}
return err;
}
@ -247,31 +261,41 @@ bool EasyCellularConnection::is_connected()
const char *EasyCellularConnection::get_ip_address()
{
CellularNetwork *network = _cellularConnectionFSM.get_network();
if (!network) {
if (_cellularConnectionFSM) {
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (!network) {
return NULL;
}
return _cellularConnectionFSM->get_network()->get_ip_address();
} else {
return NULL;
}
return _cellularConnectionFSM.get_network()->get_ip_address();
}
const char *EasyCellularConnection::get_netmask()
{
CellularNetwork *network = _cellularConnectionFSM.get_network();
if (!network) {
if (_cellularConnectionFSM) {
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (!network) {
return NULL;
}
return network->get_netmask();
} else {
return NULL;
}
return network->get_netmask();
}
const char *EasyCellularConnection::get_gateway()
{
CellularNetwork *network = _cellularConnectionFSM.get_network();
if (!network) {
if (_cellularConnectionFSM) {
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (!network) {
return NULL;
}
return network->get_gateway();
} else {
return NULL;
}
return network->get_gateway();
}
void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
@ -281,20 +305,35 @@ void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)
void EasyCellularConnection::modem_debug_on(bool on)
{
CellularDevice *dev = _cellularConnectionFSM.get_device();
if (dev) {
dev->modem_debug_on(on);
if (_cellularConnectionFSM) {
CellularDevice *dev = _cellularConnectionFSM->get_device();
if (dev) {
dev->modem_debug_on(on);
}
}
}
void EasyCellularConnection::set_plmn(const char* plmn)
void EasyCellularConnection::set_plmn(const char *plmn)
{
_cellularConnectionFSM.set_plmn(plmn);
if (plmn && strlen(plmn) > 0) {
if (!_cellularConnectionFSM) {
_credentials_err = init();
if (_credentials_err) {
return;
}
}
_cellularConnectionFSM->set_plmn(plmn);
}
}
NetworkStack *EasyCellularConnection::get_stack()
{
return _cellularConnectionFSM.get_stack();
if (_cellularConnectionFSM) {
return _cellularConnectionFSM->get_stack();
} else {
return NULL;
}
}
} // namespace

View File

@ -164,7 +164,7 @@ private:
UARTSerial _cellularSerial;
rtos::Semaphore _cellularSemaphore;
CellularConnectionFSM _cellularConnectionFSM;
CellularConnectionFSM *_cellularConnectionFSM;
nsapi_error_t _credentials_err;
Callback<void(nsapi_event_t, intptr_t)> _status_cb;
};

View File

@ -121,6 +121,12 @@ public:
*/
virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value) = 0;
/** Check whether the device is ready to accept commands.
*
* @return zero on success
*/
virtual nsapi_error_t is_device_ready() = 0;
/** Set URC callback function for device specific ready urc. URC is defined in device specific
* power API. Used in startup sequence to listen when device is ready
* for using at commands and possible sim.

View File

@ -371,7 +371,15 @@ nsapi_error_t AT_CellularNetwork::open_data_channel()
nsapi_error_t AT_CellularNetwork::disconnect()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_disconnect(_at.get_file_handle());
nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle());
// after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it
// will set the correct sigio and nonblocking
if (err == NSAPI_ERROR_OK) {
_at.lock();
_at.set_file_handle(_at.get_file_handle());
_at.unlock();
}
return err;
#else
_at.lock();
_at.cmd_start("AT+CGACT=0,");

View File

@ -233,6 +233,25 @@ nsapi_error_t AT_CellularPower::opt_receive_period(int mode, EDRXAccessTechnolog
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::is_device_ready()
{
_at.lock();
_at.cmd_start("AT");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
// we need to do this twice because for example after data mode the first 'AT' command will give modem a
// stimulus that we are back to command mode.
_at.clear_error();
_at.cmd_start("AT");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::set_device_ready_urc_cb(mbed::Callback<void()> callback)
{
return NSAPI_ERROR_UNSUPPORTED;

View File

@ -49,6 +49,8 @@ public:
virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value);
virtual nsapi_error_t is_device_ready();
virtual nsapi_error_t set_device_ready_urc_cb(mbed::Callback<void()> callback);
virtual void remove_device_ready_urc_cb(mbed::Callback<void()> callback);