diff --git a/features/cellular/framework/API/CellularNetwork.h b/features/cellular/framework/API/CellularNetwork.h index c3f3855e04..8f81e66110 100644 --- a/features/cellular/framework/API/CellularNetwork.h +++ b/features/cellular/framework/API/CellularNetwork.h @@ -228,7 +228,7 @@ public: */ virtual nsapi_error_t get_attach(AttachStatus &status) = 0; - /** Request detach from a network. + /** Request detach and deregister from a network. * * @return NSAPI_ERROR_OK on success * NSAPI_ERROR_DEVICE_ERROR on failure diff --git a/features/cellular/framework/AT/ATHandler.cpp b/features/cellular/framework/AT/ATHandler.cpp index 840bf5cfff..d12a46ab44 100644 --- a/features/cellular/framework/AT/ATHandler.cpp +++ b/features/cellular/framework/AT/ATHandler.cpp @@ -69,7 +69,6 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char _previous_at_timeout(timeout), _at_send_delay(send_delay), _last_response_stop(0), - _fh_sigio_set(false), _processing(false), _ref_count(1), _is_fh_usable(true), @@ -106,9 +105,7 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char set_tag(&_info_stop, CRLF); set_tag(&_elem_stop, ")"); - _fileHandle->set_blocking(false); - - set_filehandle_sigio(); + set_file_handle(fh); } void ATHandler::set_debug(bool debug_on) @@ -151,6 +148,8 @@ FileHandle *ATHandler::get_file_handle() void ATHandler::set_file_handle(FileHandle *fh) { _fileHandle = fh; + _fileHandle->set_blocking(false); + set_filehandle_sigio(); } void ATHandler::set_is_filehandle_usable(bool usable) @@ -309,11 +308,7 @@ void ATHandler::process_oob() void ATHandler::set_filehandle_sigio() { - if (_fh_sigio_set) { - return; - } _fileHandle->sigio(mbed::Callback(this, &ATHandler::event)); - _fh_sigio_set = true; } void ATHandler::reset_buffer() @@ -1207,3 +1202,26 @@ void ATHandler::debug_print(char *p, int len) } #endif // MBED_CONF_CELLULAR_DEBUG_AT } + +bool ATHandler::sync(int timeout_ms) +{ + tr_debug("AT sync"); + // poll for 10 seconds + for (int i = 0; i < 10; i++) { + lock(); + set_at_timeout(timeout_ms, false); + // For sync use an AT command that is supported by all modems and likely not used frequently, + // especially a common response like OK could be response to previous request. + cmd_start("AT+CMEE?"); + cmd_stop(); + resp_start("+CMEE:"); + resp_stop(); + restore_at_timeout(); + unlock(); + if (!_last_err) { + return true; + } + } + tr_error("AT sync failed"); + return false; +} diff --git a/features/cellular/framework/AT/ATHandler.h b/features/cellular/framework/AT/ATHandler.h index 1e9952a4f7..3fbcdc8e10 100644 --- a/features/cellular/framework/AT/ATHandler.h +++ b/features/cellular/framework/AT/ATHandler.h @@ -181,6 +181,13 @@ public: */ void set_is_filehandle_usable(bool usable); + /** Synchronize AT command and response handling to modem. + * + * @param timeout_ms ATHandler timeout when trying to sync. Will be restored when function returns. + * @return true is synchronization was successful, false in case of failure + */ + bool sync(int timeout_ms); + protected: void event(); #ifdef AT_HANDLER_MUTEX @@ -211,8 +218,6 @@ private: uint16_t _at_send_delay; uint64_t _last_response_stop; - bool _fh_sigio_set; - bool _processing; int32_t _ref_count; bool _is_fh_usable; diff --git a/features/cellular/framework/AT/AT_CellularContext.cpp b/features/cellular/framework/AT/AT_CellularContext.cpp index cd201ced17..7ac30d13ba 100644 --- a/features/cellular/framework/AT/AT_CellularContext.cpp +++ b/features/cellular/framework/AT/AT_CellularContext.cpp @@ -28,6 +28,7 @@ #define DEVICE_TIMEOUT 5 * 60 * 1000 // 5 minutes #if NSAPI_PPP_AVAILABLE +#define AT_SYNC_TIMEOUT 1000 // 1 second timeout #include "nsapi_ppp.h" #endif @@ -555,6 +556,8 @@ void AT_CellularContext::do_connect() tr_error("Failed to open data channel!"); call_network_cb(NSAPI_STATUS_DISCONNECTED); _is_connected = false; + } else { + _is_context_activated = true; } } #else @@ -627,13 +630,17 @@ nsapi_error_t AT_CellularContext::disconnect() _at.lock(); _at.set_file_handle(_at.get_file_handle()); _at.set_is_filehandle_usable(true); - //_at.sync(); // consume extra characters after ppp disconnect, also it may take a while until modem listens AT commands + if (!_at.sync(AT_SYNC_TIMEOUT)) { // consume extra characters after ppp disconnect, also it may take a while until modem listens AT commands + tr_error("AT sync failed after PPP Disconnect"); + } _at.unlock(); #endif // NSAPI_PPP_AVAILABLE _at.lock(); // deactivate a context only if we have activated if (_is_context_activated) { + // CGACT and CGATT commands might take up to 3 minutes to respond. + _at.set_at_timeout(180 * 1000); _is_context_active = false; size_t active_contexts_count = 0; _at.cmd_start("AT+CGACT?"); @@ -659,16 +666,26 @@ nsapi_error_t AT_CellularContext::disconnect() // 3GPP TS 27.007: // For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR if (_is_context_active && (rat < CellularNetwork::RAT_E_UTRAN || active_contexts_count > 1)) { + _at.clear_error(); _at.cmd_start("AT+CGACT=0,"); _at.write_int(_cid); _at.cmd_stop_read_resp(); } + + if (_new_context_set) { + _at.clear_error(); + _at.cmd_start("AT+CGDCONT="); + _at.write_int(_cid); + _at.cmd_stop_read_resp(); + } + _at.clear_error(); + _at.cmd_start("AT+CGATT=0"); + _at.cmd_stop_read_resp(); + _at.restore_at_timeout(); } - if (!_at.get_last_error()) { - _is_connected = false; - call_network_cb(NSAPI_STATUS_DISCONNECTED); - } + _is_connected = false; + call_network_cb(NSAPI_STATUS_DISCONNECTED); return _at.unlock_return_error(); } diff --git a/features/cellular/framework/AT/AT_CellularNetwork.cpp b/features/cellular/framework/AT/AT_CellularNetwork.cpp index dcb1480482..9a421e3f46 100644 --- a/features/cellular/framework/AT/AT_CellularNetwork.cpp +++ b/features/cellular/framework/AT/AT_CellularNetwork.cpp @@ -350,6 +350,9 @@ nsapi_error_t AT_CellularNetwork::detach() _at.cmd_start("AT+CGATT=0"); _at.cmd_stop_read_resp(); + _at.cmd_start("AT+COPS=2"); + _at.cmd_stop_read_resp(); + call_network_cb(NSAPI_STATUS_DISCONNECTED); return _at.unlock_return_error();