diff --git a/TESTS/netsocket/dns/main.cpp b/TESTS/netsocket/dns/main.cpp index 8761b1f7efa..ae2e3f5b820 100644 --- a/TESTS/netsocket/dns/main.cpp +++ b/TESTS/netsocket/dns/main.cpp @@ -160,7 +160,7 @@ static void net_bringup() net = NetworkInterface::get_default_instance(); nsapi_error_t err = net->connect(); TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err); - printf("MBED: IP address is '%s'\n", net->get_ip_address()); + printf("MBED: IP address is '%s'\n", net->get_ip_address() ? net->get_ip_address() : "null"); } static void net_bringdown() diff --git a/TESTS/netsocket/tcp/main.cpp b/TESTS/netsocket/tcp/main.cpp index 2f41109d863..019908cde2c 100644 --- a/TESTS/netsocket/tcp/main.cpp +++ b/TESTS/netsocket/tcp/main.cpp @@ -72,7 +72,7 @@ static void _ifup() NetworkInterface *net = NetworkInterface::get_default_instance(); nsapi_error_t err = net->connect(); TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err); - printf("MBED: TCPClient IP address is '%s'\n", net->get_ip_address()); + printf("MBED: TCPClient IP address is '%s'\n", net->get_ip_address() ? net->get_ip_address() : "null"); } static void _ifdown() diff --git a/TESTS/netsocket/tls/main.cpp b/TESTS/netsocket/tls/main.cpp index f7ae2253578..2a8fb9033a8 100644 --- a/TESTS/netsocket/tls/main.cpp +++ b/TESTS/netsocket/tls/main.cpp @@ -94,7 +94,7 @@ static void _ifup() NetworkInterface *net = NetworkInterface::get_default_instance(); nsapi_error_t err = net->connect(); TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err); - printf("MBED: TLSClient IP address is '%s'\n", net->get_ip_address()); + printf("MBED: TLSClient IP address is '%s'\n", net->get_ip_address() ? net->get_ip_address() : "null"); } static void _ifdown() diff --git a/TESTS/netsocket/udp/main.cpp b/TESTS/netsocket/udp/main.cpp index 38ae7a203f9..680b2cc92fd 100644 --- a/TESTS/netsocket/udp/main.cpp +++ b/TESTS/netsocket/udp/main.cpp @@ -59,7 +59,7 @@ static void _ifup() NetworkInterface *net = NetworkInterface::get_default_instance(); nsapi_error_t err = net->connect(); TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err); - printf("MBED: UDPClient IP address is '%s'\n", net->get_ip_address()); + printf("MBED: UDPClient IP address is '%s'\n", net->get_ip_address() ? net->get_ip_address() : "null"); } static void _ifdown() diff --git a/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/at_cellularcontexttest.cpp b/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/at_cellularcontexttest.cpp index a8acae727c3..451c3a571cc 100644 --- a/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/at_cellularcontexttest.cpp +++ b/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/at_cellularcontexttest.cpp @@ -537,7 +537,7 @@ TEST_F(TestAT_CellularContext, connect_disconnect_sync) ATHandler_stub::read_string_index = 2; ASSERT_EQ(ctx1.connect(), NSAPI_ERROR_OK); - ASSERT_EQ(network_cb_count, 5); + ASSERT_EQ(network_cb_count, 4); ASSERT_EQ(ctx1.disconnect(), NSAPI_ERROR_OK); ATHandler_stub::resp_info_true_counter = 1; @@ -704,7 +704,7 @@ TEST_F(TestAT_CellularContext, connect_disconnect_async) data.status_data = CellularNetwork::Attached; ctx1.cellular_callback((nsapi_event_t)CellularAttachNetwork, (intptr_t)&data); - ASSERT_EQ(network_cb_count, 5); + ASSERT_EQ(network_cb_count, 4); ASSERT_EQ(ctx1.connect(), NSAPI_ERROR_IS_CONNECTED); EXPECT_TRUE(ctx1.is_connected() == true); ASSERT_EQ(ctx1.disconnect(), NSAPI_ERROR_NO_MEMORY); diff --git a/UNITTESTS/features/cellular/framework/AT/at_cellularstack/at_cellularstacktest.cpp b/UNITTESTS/features/cellular/framework/AT/at_cellularstack/at_cellularstacktest.cpp index 214ab1c8928..57ad8519f52 100644 --- a/UNITTESTS/features/cellular/framework/AT/at_cellularstack/at_cellularstacktest.cpp +++ b/UNITTESTS/features/cellular/framework/AT/at_cellularstack/at_cellularstacktest.cpp @@ -175,7 +175,7 @@ TEST_F(TestAT_CellularStack, test_AT_CellularStack_get_ip_address) ATHandler at(&fh1, que, 0, ","); MyStack st(at, 0, IPV6_STACK); - EXPECT_EQ(strlen(st.get_ip_address()), 0); + EXPECT_TRUE(st.get_ip_address() == NULL); char table[] = "1.2.3.4.5.65.7.8.9.10.11\0"; ATHandler_stub::ssize_value = -1; diff --git a/UNITTESTS/features/cellular/framework/AT/at_cellularstack/unittest.cmake b/UNITTESTS/features/cellular/framework/AT/at_cellularstack/unittest.cmake index 2f1a243e02c..f0525045d70 100644 --- a/UNITTESTS/features/cellular/framework/AT/at_cellularstack/unittest.cmake +++ b/UNITTESTS/features/cellular/framework/AT/at_cellularstack/unittest.cmake @@ -28,4 +28,5 @@ set(unittest-test-sources stubs/NetworkStack_stub.cpp stubs/SocketAddress_stub.cpp stubs/mbed_assert_stub.c + stubs/ThisThread_stub.cpp ) diff --git a/UNITTESTS/stubs/AT_CellularContext_stub.cpp b/UNITTESTS/stubs/AT_CellularContext_stub.cpp index 4f89449efaa..32c0a4dd889 100644 --- a/UNITTESTS/stubs/AT_CellularContext_stub.cpp +++ b/UNITTESTS/stubs/AT_CellularContext_stub.cpp @@ -21,7 +21,7 @@ using namespace mbed; AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) : AT_CellularBase(at), _is_connected(false), - _current_op(OP_INVALID), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false) + _current_op(OP_INVALID), _fh(0), _cp_req(cp_req) { _stack = NULL; _pdp_type = DEFAULT_PDP_TYPE; @@ -43,6 +43,8 @@ AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, co _is_blocking = true; _device = device; _nw = NULL; + _nonip_req = nonip_req; + _cp_in_use = false; } AT_CellularContext::~AT_CellularContext() diff --git a/features/cellular/framework/API/CellularContext.h b/features/cellular/framework/API/CellularContext.h index 7f5c1ceb40b..f2fa19c2e26 100644 --- a/features/cellular/framework/API/CellularContext.h +++ b/features/cellular/framework/API/CellularContext.h @@ -344,6 +344,11 @@ class CellularContext : public CellularInterface { */ virtual void do_connect(); + /** After we have connected successfully we must check that we have a valid IP address. + * Some modems/networks don't give IP address right after connect so we must poll it for a while. + */ + void validate_ip_address(); + // member variables needed in target override methods NetworkStack *_stack; // must be pointer because of PPP pdp_type_t _pdp_type; @@ -368,6 +373,10 @@ class CellularContext : public CellularInterface { CellularDevice *_device; CellularNetwork *_nw; bool _is_blocking; + // flag indicating if Non-IP context was requested to be setup + bool _nonip_req; + // tells if CCIOTOPTI received green from network for CP optimization use + bool _cp_in_use; }; /** diff --git a/features/cellular/framework/AT/AT_CellularContext.cpp b/features/cellular/framework/AT/AT_CellularContext.cpp index 04dbe60cb56..5539a28230a 100644 --- a/features/cellular/framework/AT/AT_CellularContext.cpp +++ b/features/cellular/framework/AT/AT_CellularContext.cpp @@ -48,10 +48,10 @@ using namespace mbed; using namespace rtos; AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) : - AT_CellularBase(at), _is_connected(false), _current_op(OP_INVALID), _fh(0), _cp_req(cp_req), - _nonip_req(nonip_req), _cp_in_use(false) + AT_CellularBase(at), _is_connected(false), _current_op(OP_INVALID), _fh(0), _cp_req(cp_req) { tr_info("New CellularContext %s (%p)", apn ? apn : "", this); + _nonip_req = nonip_req; _apn = apn; _device = device; } @@ -587,7 +587,6 @@ void AT_CellularContext::do_connect() } #else _is_connected = true; - call_network_cb(NSAPI_STATUS_GLOBAL_UP); #endif } diff --git a/features/cellular/framework/AT/AT_CellularContext.h b/features/cellular/framework/AT/AT_CellularContext.h index 9831d9b9fab..7c3a527721c 100644 --- a/features/cellular/framework/AT/AT_CellularContext.h +++ b/features/cellular/framework/AT/AT_CellularContext.h @@ -131,10 +131,6 @@ class AT_CellularContext : public CellularContext, public AT_CellularBase { char _found_apn[MAX_APN_LENGTH]; // flag indicating if CP was requested to be setup bool _cp_req; - // flag indicating if Non-IP context was requested to be setup - bool _nonip_req; - // tells if CCIOTOPTI received green from network for CP optimization use - bool _cp_in_use; }; } // namespace mbed diff --git a/features/cellular/framework/AT/AT_CellularStack.cpp b/features/cellular/framework/AT/AT_CellularStack.cpp index 31417a98d82..a8aba5b578d 100644 --- a/features/cellular/framework/AT/AT_CellularStack.cpp +++ b/features/cellular/framework/AT/AT_CellularStack.cpp @@ -18,6 +18,7 @@ #include "AT_CellularStack.h" #include "CellularUtil.h" #include "CellularLog.h" +#include "ThisThread.h" using namespace mbed_cellular_util; using namespace mbed; @@ -54,41 +55,31 @@ int AT_CellularStack::find_socket_index(nsapi_socket_t handle) /** NetworkStack */ - const char *AT_CellularStack::get_ip_address() { _at.lock(); _at.cmd_start_stop("+CGPADDR", "=", "%d", _cid); - _at.resp_start("+CGPADDR:"); + int len = -1; if (_at.info_resp()) { - _at.skip_param(); - int len = _at.read_string(_ip, NSAPI_IPv4_SIZE); - if (len == -1) { - _ip[0] = '\0'; - _at.resp_stop(); - _at.unlock(); - // no IPV4 address, return - return NULL; - } + len = _at.read_string(_ip, PDP_IPV6_SIZE); - // in case stack type is not IPV4 only, try to look also for IPV6 address - if (_stack_type != IPV4_STACK) { + if (len != -1 && _stack_type != IPV4_STACK) { + // in case stack type is not IPV4 only, try to look also for IPV6 address (void)_at.read_string(_ip, PDP_IPV6_SIZE); } } - _at.resp_stop(); _at.unlock(); // we have at least IPV4 address convert_ipv6(_ip); - return _ip; + return len != -1 ? _ip : NULL; } nsapi_error_t AT_CellularStack::socket_stack_init() diff --git a/features/cellular/framework/device/CellularContext.cpp b/features/cellular/framework/device/CellularContext.cpp index 0b4ea68bd94..cf2746ecdbe 100644 --- a/features/cellular/framework/device/CellularContext.cpp +++ b/features/cellular/framework/device/CellularContext.cpp @@ -62,7 +62,7 @@ CellularContext::CellularContext() : _next(0), _stack(0), _pdp_type(DEFAULT_PDP_ _authentication_type(CellularContext::CHAP), _connect_status(NSAPI_STATUS_DISCONNECTED), _status_cb(0), _cid(-1), _new_context_set(false), _is_context_active(false), _is_context_activated(false), _apn(0), _uname(0), _pwd(0), _dcd_pin(NC), _active_high(false), _cp_netif(0), _retry_array_length(0), - _retry_count(0), _device(0), _nw(0), _is_blocking(true) + _retry_count(0), _device(0), _nw(0), _is_blocking(true), _nonip_req(false), _cp_in_use(false) { memset(_retry_timeout_array, 0, CELLULAR_RETRY_ARRAY_SIZE); } @@ -87,6 +87,28 @@ void CellularContext::set_authentication_type(AuthenticationType type) _authentication_type = type; } +void CellularContext::validate_ip_address() +{ + const int IP_MAX_TRIES = 10; // maximum of 2 seconds as we wait 200ms between tries + const int IP_WAIT_INTERVAL = 200; // 200 ms between retries + const char *ip = NULL; + int i = 0; + + while (1) { + ip = get_ip_address(); + if (ip || i >= IP_MAX_TRIES) { + if (ip == NULL) { + tr_warning("Connected but no local ip address"); + } else { + tr_info("Cellular local IP: %s", ip); + } + break; + } + rtos::ThisThread::sleep_for(IP_WAIT_INTERVAL); + i++; + } +} + void CellularContext::do_connect_with_retry() { if (_cb_data.final_try) { @@ -97,6 +119,12 @@ void CellularContext::do_connect_with_retry() } do_connect(); if (_cb_data.error == NSAPI_ERROR_OK) { + // Some modems don't get the ip address right after connect so we must + // validate it but even if we don't get ip we still send NSAPI_STATUS_GLOBAL_UP + if (!_nonip_req && !_cp_in_use) { // don't validate if non-ip case + validate_ip_address(); + } + call_network_cb(NSAPI_STATUS_GLOBAL_UP); return; }