From 5a7482667e86f231c51efad959e7bbed228fdd2e Mon Sep 17 00:00:00 2001 From: Teemu Kultala Date: Mon, 6 Nov 2017 14:18:03 +0200 Subject: [PATCH] NSAPI status callback changes This is the original content of feature-status-callbacks, reviewed in https://github.com/ARMmbed/mbed-os/pull/5457 --- .../lwip-interface/EthernetInterface.cpp | 39 +++- .../lwip-interface/EthernetInterface.h | 25 +++ .../FEATURE_LWIP/lwip-interface/lwip_stack.c | 201 ++++++++++++++---- .../FEATURE_LWIP/lwip-interface/lwip_stack.h | 9 +- .../FEATURE_LWIP/lwip-interface/ppp_lwip.cpp | 18 +- .../mbed-mesh-api/MeshInterfaceNanostack.h | 23 ++ .../source/MeshInterfaceNanostack.cpp | 41 +++- .../mbed-mesh-api/source/ThreadInterface.cpp | 18 +- features/netsocket/NetworkInterface.cpp | 14 ++ features/netsocket/NetworkInterface.h | 24 +++ .../PPPCellularInterface.cpp | 89 +++++--- .../PPPCellularInterface.h | 33 ++- features/netsocket/nsapi_ppp.h | 9 +- features/netsocket/nsapi_types.h | 27 +++ 14 files changed, 477 insertions(+), 93 deletions(-) diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp b/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp index 7c69b48a4c..24c9af734b 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp +++ b/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp @@ -19,11 +19,17 @@ /* Interface implementation */ -EthernetInterface::EthernetInterface() - : _dhcp(true), _ip_address(), _netmask(), _gateway() +EthernetInterface::EthernetInterface() : + _dhcp(true), + _ip_address(), + _netmask(), + _gateway(), + _connection_status_cb(NULL), + _connect_status(NSAPI_STATUS_DISCONNECTED) { } + nsapi_error_t EthernetInterface::set_network(const char *ip_address, const char *netmask, const char *gateway) { _dhcp = false; @@ -94,3 +100,32 @@ NetworkStack *EthernetInterface::get_stack() { return nsapi_create_stack(&lwip_stack); } + +void EthernetInterface::attach( + Callback status_cb) +{ + _connection_status_cb = status_cb; + mbed_lwip_attach(netif_status_cb, this); +} + +nsapi_connection_status_t EthernetInterface::get_connection_status() const +{ + return _connect_status; +} + +void EthernetInterface::netif_status_cb(void *ethernet_if_ptr, + nsapi_event_t reason, intptr_t parameter) +{ + EthernetInterface *eth_ptr = static_cast(ethernet_if_ptr); + eth_ptr->_connect_status = (nsapi_connection_status_t)parameter; + if (eth_ptr->_connection_status_cb) + { + eth_ptr->_connection_status_cb(reason, parameter); + } +} + +nsapi_error_t EthernetInterface::set_blocking(bool blocking) +{ + mbed_lwip_set_blocking(blocking); + return NSAPI_ERROR_OK; +} diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h b/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h index f92f70e4eb..61fba64cd2 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h +++ b/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h @@ -100,6 +100,26 @@ public: */ virtual const char *get_gateway(); + /** Register callback for status reporting + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback status_cb); + + /** Get the connection status + * + * @return The connection status according to nsapi_connection_status_t + */ + virtual nsapi_connection_status_t get_connection_status() const; + + /** Set blocking status of connect() which by default should be blocking + * + * @param blocking true if connect is blocking + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_blocking(bool blocking); + + protected: /** Provide access to the underlying stack * @@ -111,6 +131,11 @@ protected: char _ip_address[IPADDR_STRLEN_MAX]; char _netmask[NSAPI_IPv4_SIZE]; char _gateway[NSAPI_IPv4_SIZE]; + + + Callback _connection_status_cb; + nsapi_connection_status_t _connect_status; + static void netif_status_cb(void *, nsapi_event_t, intptr_t); }; diff --git a/features/FEATURE_LWIP/lwip-interface/lwip_stack.c b/features/FEATURE_LWIP/lwip-interface/lwip_stack.c index 23ffbc5317..f23767e7e1 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip_stack.c +++ b/features/FEATURE_LWIP/lwip-interface/lwip_stack.c @@ -71,7 +71,7 @@ static struct lwip_socket { } lwip_arena[MEMP_NUM_NETCONN]; static bool lwip_inited = false; -static bool lwip_connected = false; +static nsapi_connection_status_t lwip_connected = NSAPI_STATUS_DISCONNECTED; static bool netif_inited = false; static bool netif_is_ppp = false; @@ -155,6 +155,7 @@ static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u static struct netif lwip_netif; #if LWIP_DHCP static bool lwip_dhcp = false; +static bool lwip_dhcp_has_to_be_set = false; #endif static char lwip_mac_address[NSAPI_MAC_SIZE]; @@ -428,17 +429,65 @@ static void mbed_lwip_tcpip_init_irq(void *eh) sys_sem_signal(&lwip_tcpip_inited); } +/** This is a pointer to an Ethernet IF, whose callback will be called in case + * of network connection status changes + */ +static void *lwip_status_cb_handle = NULL; +/** This function is called when the netif state is set to up or down + */ +static mbed_lwip_client_callback lwip_client_callback = NULL; +/** The blocking status of the if + */ +static bool lwip_blocking = true; +static bool lwip_ppp = false; + + +static nsapi_error_t mbed_set_dhcp(struct netif *lwip_netif) +{ + if (!lwip_ppp) { + netif_set_up(lwip_netif); + } + +#if LWIP_DHCP + if (lwip_dhcp && lwip_dhcp_has_to_be_set) { + err_t err = dhcp_start(lwip_netif); + lwip_dhcp_has_to_be_set = false; + if (err) { + lwip_connected = NSAPI_STATUS_DISCONNECTED; + if (lwip_client_callback) { + lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } + return NSAPI_ERROR_DHCP_FAILURE; + } + } +#endif + + return NSAPI_ERROR_OK; +} + static sys_sem_t lwip_netif_linked; static sys_sem_t lwip_netif_unlinked; static void mbed_lwip_netif_link_irq(struct netif *lwip_netif) { if (netif_is_link_up(lwip_netif)) { - sys_sem_signal(&lwip_netif_linked); + + nsapi_error_t dhcp_status = mbed_set_dhcp(lwip_netif); + + if (lwip_blocking && dhcp_status == NSAPI_ERROR_OK) { + sys_sem_signal(&lwip_netif_linked); + } else if (dhcp_status != NSAPI_ERROR_OK) { + netif_set_down(lwip_netif); + } + + } else { sys_sem_signal(&lwip_netif_unlinked); } } + + + static char lwip_has_addr_state = 0; #define HAS_ANY_ADDR 1 @@ -452,28 +501,71 @@ static sys_sem_t lwip_netif_has_pref_addr; static sys_sem_t lwip_netif_has_both_addr; #endif + static void mbed_lwip_netif_status_irq(struct netif *lwip_netif) { if (netif_is_up(lwip_netif)) { + bool dns_addr_has_to_be_added = false; if (!(lwip_has_addr_state & HAS_ANY_ADDR) && mbed_lwip_get_ip_addr(true, lwip_netif)) { - sys_sem_signal(&lwip_netif_has_any_addr); + if (lwip_blocking) { + sys_sem_signal(&lwip_netif_has_any_addr); + } lwip_has_addr_state |= HAS_ANY_ADDR; + dns_addr_has_to_be_added = true; } #if PREF_ADDR_TIMEOUT if (!(lwip_has_addr_state & HAS_PREF_ADDR) && mbed_lwip_get_ip_addr(false, lwip_netif)) { - sys_sem_signal(&lwip_netif_has_pref_addr); + if (lwip_blocking) { + sys_sem_signal(&lwip_netif_has_pref_addr); + } lwip_has_addr_state |= HAS_PREF_ADDR; + dns_addr_has_to_be_added = true; } #endif #if BOTH_ADDR_TIMEOUT if (!(lwip_has_addr_state & HAS_BOTH_ADDR) && mbed_lwip_get_ipv4_addr(lwip_netif) && mbed_lwip_get_ipv6_addr(lwip_netif)) { - sys_sem_signal(&lwip_netif_has_both_addr); + if (lwip_blocking) { + sys_sem_signal(&lwip_netif_has_both_addr); + } lwip_has_addr_state |= HAS_BOTH_ADDR; + dns_addr_has_to_be_added = true; } #endif + + if (dns_addr_has_to_be_added && !lwip_blocking) { + add_dns_addr(lwip_netif); + } + + + if (lwip_has_addr_state & HAS_ANY_ADDR) { + lwip_connected = NSAPI_STATUS_GLOBAL_UP; + } + } else { + lwip_connected = NSAPI_STATUS_DISCONNECTED; + } + + if (lwip_client_callback) { + lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, lwip_connected); } } +void mbed_lwip_set_blocking(bool blocking) +{ + lwip_blocking = blocking; +} + +void mbed_lwip_attach(mbed_lwip_client_callback client_callback, void *status_cb_handle) +{ + lwip_client_callback = client_callback; + lwip_status_cb_handle = status_cb_handle; +} + +nsapi_connection_status_t mbed_lwip_netif_status_check(void) +{ + return lwip_connected; +} + + #if LWIP_ETHERNET static void mbed_lwip_set_mac_address(struct netif *netif) { @@ -599,7 +691,6 @@ nsapi_error_t mbed_lwip_emac_init(emac_interface_t *emac) #if LWIP_ETHERNET // Choose a MAC address - driver can override mbed_lwip_set_mac_address(&lwip_netif); - // Set up network if (!netif_add(&lwip_netif, #if LWIP_IPV4 @@ -608,10 +699,8 @@ nsapi_error_t mbed_lwip_emac_init(emac_interface_t *emac) emac, MBED_NETIF_INIT_FN, tcpip_input)) { return NSAPI_ERROR_DEVICE_ERROR; } - // Note the MAC address actually in use mbed_lwip_record_mac_address(&lwip_netif); - #if !DEVICE_EMAC eth_arch_enable_interrupts(); #endif @@ -634,19 +723,34 @@ nsapi_error_t mbed_lwip_init(emac_interface_t *emac) return ret; } + // Backwards compatibility with people using DEVICE_EMAC nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw) { return mbed_lwip_bringup_2(dhcp, false, ip, netmask, gw, DEFAULT_STACK); } -nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack) +nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, + const nsapi_ip_stack_t stack) { // Check if we've already connected - if (lwip_connected) { - return NSAPI_ERROR_PARAMETER; + + if (lwip_connected == NSAPI_STATUS_GLOBAL_UP) { + return NSAPI_ERROR_IS_CONNECTED; + } else if (lwip_connected == NSAPI_STATUS_CONNECTING) { + return NSAPI_ERROR_ALREADY; } + lwip_connected = NSAPI_STATUS_CONNECTING; + lwip_ppp = ppp; +#if LWIP_DHCP + lwip_dhcp_has_to_be_set = true; + if (stack != IPV6_STACK) { + lwip_dhcp = dhcp; + } else { + lwip_dhcp = false; + } +#endif mbed_lwip_core_init(); nsapi_error_t ret; @@ -666,9 +770,15 @@ nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const cha } if (ret != NSAPI_ERROR_OK) { + lwip_connected = NSAPI_STATUS_DISCONNECTED; return ret; } + + if (lwip_client_callback) { + lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING); + } + netif_inited = true; if (ppp) { netif_is_ppp = ppp; @@ -717,6 +827,10 @@ nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const cha if (!inet_aton(ip, &ip_addr) || !inet_aton(netmask, &netmask_addr) || !inet_aton(gw, &gw_addr)) { + lwip_connected = NSAPI_STATUS_DISCONNECTED; + if (lwip_client_callback) { + lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } return NSAPI_ERROR_PARAMETER; } @@ -728,45 +842,44 @@ nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const cha if (ppp) { err_t err = ppp_lwip_connect(); if (err) { + lwip_connected = NSAPI_STATUS_DISCONNECTED; + if (lwip_client_callback) { + lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } return mbed_lwip_err_remap(err); } } + + if (!netif_is_link_up(&lwip_netif)) { - if (sys_arch_sem_wait(&lwip_netif_linked, 15000) == SYS_ARCH_TIMEOUT) { - if (ppp) { - (void) ppp_lwip_disconnect(); + if (lwip_blocking) { + if (sys_arch_sem_wait(&lwip_netif_linked, 15000) == SYS_ARCH_TIMEOUT) { + if (ppp) { + ppp_lwip_disconnect(); + } + return NSAPI_ERROR_NO_CONNECTION; } - return NSAPI_ERROR_NO_CONNECTION; + } + } else { + ret = mbed_set_dhcp(&lwip_netif); + if (ret != NSAPI_ERROR_OK) { + return ret; } } - - if (!ppp) { - netif_set_up(&lwip_netif); - } - -#if LWIP_DHCP - if (stack != IPV6_STACK) { - // Connect to the network - lwip_dhcp = dhcp; - - if (lwip_dhcp) { - err_t err = dhcp_start(&lwip_netif); - if (err) { + + if (lwip_blocking) { + // If doesn't have address + if (!mbed_lwip_get_ip_addr(true, &lwip_netif)) { + if (sys_arch_sem_wait(&lwip_netif_has_any_addr, DHCP_TIMEOUT * 1000) == SYS_ARCH_TIMEOUT) { + if (ppp) { + ppp_lwip_disconnect(); + } return NSAPI_ERROR_DHCP_FAILURE; } } - } -#endif - - // If doesn't have address - if (!mbed_lwip_get_ip_addr(true, &lwip_netif)) { - if (sys_arch_sem_wait(&lwip_netif_has_any_addr, DHCP_TIMEOUT * 1000) == SYS_ARCH_TIMEOUT) { - if (ppp) { - (void) ppp_lwip_disconnect(); - } - return NSAPI_ERROR_DHCP_FAILURE; - } + } else { + return NSAPI_ERROR_OK; } #if PREF_ADDR_TIMEOUT @@ -790,8 +903,7 @@ nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const cha add_dns_addr(&lwip_netif); - lwip_connected = true; - return 0; + return NSAPI_ERROR_OK; } #if LWIP_IPV6 @@ -812,7 +924,7 @@ nsapi_error_t mbed_lwip_bringdown(void) nsapi_error_t mbed_lwip_bringdown_2(bool ppp) { // Check if we've connected - if (!lwip_connected) { + if (lwip_connected == NSAPI_STATUS_DISCONNECTED) { return NSAPI_ERROR_PARAMETER; } @@ -822,6 +934,7 @@ nsapi_error_t mbed_lwip_bringdown_2(bool ppp) dhcp_release(&lwip_netif); dhcp_stop(&lwip_netif); lwip_dhcp = false; + lwip_dhcp_has_to_be_set = false; } #endif @@ -856,7 +969,7 @@ nsapi_error_t mbed_lwip_bringdown_2(bool ppp) sys_sem_new(&lwip_netif_has_both_addr, 0); #endif lwip_has_addr_state = 0; - lwip_connected = false; + lwip_connected = NSAPI_STATUS_DISCONNECTED; return 0; } @@ -967,7 +1080,7 @@ static nsapi_error_t mbed_lwip_add_dns_server(nsapi_stack_t *stack, nsapi_addr_t static nsapi_error_t mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t *handle, nsapi_protocol_t proto) { // check if network is connected - if (!lwip_connected) { + if (lwip_connected == NSAPI_STATUS_DISCONNECTED) { return NSAPI_ERROR_NO_CONNECTION; } diff --git a/features/FEATURE_LWIP/lwip-interface/lwip_stack.h b/features/FEATURE_LWIP/lwip-interface/lwip_stack.h index 9fdb8ed7eb..16d82428d2 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip_stack.h +++ b/features/FEATURE_LWIP/lwip-interface/lwip_stack.h @@ -20,6 +20,7 @@ #include "nsapi.h" #include "emac_api.h" #include "lwip/opt.h" +#include "netif.h" #ifdef __cplusplus extern "C" { #endif @@ -28,11 +29,15 @@ extern "C" { // drivers attach through these. nsapi_error_t mbed_lwip_init(emac_interface_t *emac); nsapi_error_t mbed_lwip_emac_init(emac_interface_t *emac); +nsapi_connection_status_t mbed_lwip_netif_status_check(void); nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw); -nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack); +nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, + const nsapi_ip_stack_t stack); +typedef void (*mbed_lwip_client_callback)(void *ethernet_if_ptr, nsapi_event_t reason, intptr_t parameter); +void mbed_lwip_attach(mbed_lwip_client_callback status_cb, void *status_cb_handle); +void mbed_lwip_set_blocking(bool blocking); nsapi_error_t mbed_lwip_bringdown(void); nsapi_error_t mbed_lwip_bringdown_2(bool ppp); - const char *mbed_lwip_get_mac_address(void); char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen); char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen); diff --git a/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp b/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp index d1646540ba..8008ee556b 100644 --- a/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp +++ b/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp @@ -59,7 +59,7 @@ static bool ppp_active = false; static const char *login; static const char *pwd; static sys_sem_t ppp_close_sem; -static Callback connection_status_cb; +static Callback connection_status_cb; static EventQueue *prepare_event_queue() { @@ -207,8 +207,10 @@ static void ppp_link_status(ppp_pcb *pcb, int err_code, void *ctx) } if (err_code == PPPERR_NONE) { - /* suppress generating a callback event for connection up - * Because connect() call is blocking, why wait for a callback */ + /* status changes have to be reported */ + if (connection_status_cb) { + connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_GLOBAL_UP); + } return; } @@ -221,7 +223,7 @@ static void ppp_link_status(ppp_pcb *pcb, int err_code, void *ctx) /* Alright, PPP interface is down, we need to notify upper layer */ if (connection_status_cb) { - connection_status_cb(mapped_err_code); + connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); } } @@ -351,7 +353,13 @@ nsapi_error_t nsapi_ppp_error_code() return connect_error_code; } -nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback cb, const char *uname, const char *password, const nsapi_ip_stack_t stack) +nsapi_error_t nsapi_ppp_set_blocking(bool blocking) +{ + mbed_lwip_set_blocking(blocking); + return NSAPI_ERROR_OK; +} + +nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback cb, const char *uname, const char *password, const nsapi_ip_stack_t stack) { if (my_stream) { return NSAPI_ERROR_PARAMETER; diff --git a/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h b/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h index b79dabf633..bcf5c3e08a 100644 --- a/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h +++ b/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h @@ -62,6 +62,25 @@ public: * */ void mesh_network_handler(mesh_connection_status_t status); + /** Register callback for status reporting + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback status_cb); + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + virtual nsapi_connection_status_t get_connection_status() const; + + /** Set blocking status of connect() which by default should be blocking + * + * @param blocking true if connect is blocking + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_blocking(bool blocking); + protected: MeshInterfaceNanostack(); MeshInterfaceNanostack(NanostackPhy *phy); @@ -86,6 +105,10 @@ protected: char ip_addr_str[40]; char mac_addr_str[24]; Semaphore connect_semaphore; + + Callback _connection_status_cb; + nsapi_connection_status_t _connect_status; + bool _blocking; }; #endif /* MESHINTERFACENANOSTACK_H */ diff --git a/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/MeshInterfaceNanostack.cpp b/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/MeshInterfaceNanostack.cpp index 888568c9aa..b7e0d0b3bc 100644 --- a/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/MeshInterfaceNanostack.cpp +++ b/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/MeshInterfaceNanostack.cpp @@ -17,10 +17,14 @@ #include "MeshInterfaceNanostack.h" #include "NanostackInterface.h" #include "mesh_system.h" +#include "net_interface.h" + MeshInterfaceNanostack::MeshInterfaceNanostack() : phy(NULL), _network_interface_id(-1), _device_id(-1), _eui64(), - ip_addr_str(), mac_addr_str(), connect_semaphore(0) + ip_addr_str(), mac_addr_str(), connect_semaphore(0), + _connection_status_cb(NULL), _connect_status(NSAPI_STATUS_DISCONNECTED), + _blocking(true) { // Nothing to do } @@ -45,11 +49,27 @@ void MeshInterfaceNanostack::mesh_network_handler(mesh_connection_status_t statu { nanostack_lock(); - if (status == MESH_CONNECTED) { + if (status == MESH_CONNECTED && _blocking) { connect_semaphore.release(); } nanostack_unlock(); + + + if (status == MESH_CONNECTED) { + uint8_t temp_ipv6[16]; + if (!arm_net_address_get(_network_interface_id, ADDR_IPV6_GP, temp_ipv6)) { + _connect_status = NSAPI_STATUS_GLOBAL_UP; + } else { + _connect_status = NSAPI_STATUS_LOCAL_UP; + } + } else { + _connect_status = NSAPI_STATUS_DISCONNECTED; + } + + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status); + } } nsapi_error_t MeshInterfaceNanostack::register_phy() @@ -98,3 +118,20 @@ const char *MeshInterfaceNanostack::get_mac_address() { return mac_addr_str; } + +nsapi_connection_status_t MeshInterfaceNanostack::get_connection_status() const +{ + return _connect_status; +} + +void MeshInterfaceNanostack::attach( + Callback status_cb) +{ + _connection_status_cb = status_cb; +} + +nsapi_error_t MeshInterfaceNanostack::set_blocking(bool blocking) +{ + _blocking = blocking; + return NSAPI_ERROR_OK; +} diff --git a/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/ThreadInterface.cpp b/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/ThreadInterface.cpp index 5511653bb0..d27ffe6e49 100644 --- a/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/ThreadInterface.cpp +++ b/features/nanostack/FEATURE_NANOSTACK/mbed-mesh-api/source/ThreadInterface.cpp @@ -14,6 +14,12 @@ nsapi_error_t ThreadInterface::initialize(NanostackRfPhy *phy) int ThreadInterface::connect() { + if (_connect_status == NSAPI_STATUS_GLOBAL_UP || _connect_status == NSAPI_STATUS_LOCAL_UP) { + return NSAPI_ERROR_IS_CONNECTED; + } else if (_connect_status == NSAPI_STATUS_CONNECTING) { + return NSAPI_ERROR_ALREADY; + } + nanostack_lock(); if (register_phy() < 0) { @@ -42,10 +48,16 @@ int ThreadInterface::connect() // -routers will create new network and get local connectivity // -end devices will get connectivity once attached to existing network // -devices without network settings gets connectivity once commissioned and attached to network - int32_t count = connect_semaphore.wait(osWaitForever); + _connect_status = NSAPI_STATUS_CONNECTING; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING); + } + if (_blocking) { + int32_t count = connect_semaphore.wait(osWaitForever); - if (count <= 0) { - return NSAPI_ERROR_DHCP_FAILURE; // sort of... + if (count <= 0) { + return NSAPI_ERROR_DHCP_FAILURE; // sort of... + } } return 0; } diff --git a/features/netsocket/NetworkInterface.cpp b/features/netsocket/NetworkInterface.cpp index 5c058ea5b7..67ef5c8712 100644 --- a/features/netsocket/NetworkInterface.cpp +++ b/features/netsocket/NetworkInterface.cpp @@ -65,3 +65,17 @@ nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address) return get_stack()->add_dns_server(address); } +void NetworkInterface::attach(mbed::Callback status_cb) +{ +} + +nsapi_connection_status_t NetworkInterface::get_connection_status() const +{ + return NSAPI_STATUS_ERROR_UNSUPPORTED; +} + +nsapi_error_t NetworkInterface::set_blocking(bool blocking) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + diff --git a/features/netsocket/NetworkInterface.h b/features/netsocket/NetworkInterface.h index e7ecb8c0ac..eed1c81e9f 100644 --- a/features/netsocket/NetworkInterface.h +++ b/features/netsocket/NetworkInterface.h @@ -19,6 +19,7 @@ #include "netsocket/nsapi_types.h" #include "netsocket/SocketAddress.h" +#include "Callback.h" // Predeclared class class NetworkStack; @@ -31,6 +32,9 @@ class NetworkStack; */ class NetworkInterface { public: + + + virtual ~NetworkInterface() {}; /** Get the local MAC address @@ -126,6 +130,26 @@ public: */ virtual nsapi_error_t add_dns_server(const SocketAddress &address); + /** Register callback for status reporting + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback status_cb); + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + virtual nsapi_connection_status_t get_connection_status() const; + + /** Set blocking status of connect() which by default should be blocking + * + * @param blocking true if connect is blocking + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_blocking(bool blocking); + + protected: friend class Socket; friend class UDPSocket; diff --git a/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.cpp b/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.cpp index 22d9a19320..fe64baa819 100644 --- a/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.cpp +++ b/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.cpp @@ -263,9 +263,11 @@ PPPCellularInterface::PPPCellularInterface(FileHandle *fh, bool debug) _fh = fh; _debug_trace_on = debug; _stack = DEFAULT_STACK; + _connection_status_cb = NULL; + _connect_status = NSAPI_STATUS_DISCONNECTED; + _connect_is_blocking = true; dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; - dev_info.ppp_connection_up = false; } @@ -304,9 +306,13 @@ void PPPCellularInterface::modem_debug_on(bool on) _debug_trace_on = on; } -void PPPCellularInterface::connection_status_cb(Callback cb) +void PPPCellularInterface::ppp_status_cb(nsapi_event_t event, intptr_t parameter) { - _connection_status_cb = cb; + _connect_status = (nsapi_connection_status_t)parameter; + + if (_connection_status_cb) { + _connection_status_cb(event, parameter); + } } /** @@ -398,7 +404,7 @@ bool PPPCellularInterface::nwk_registration(uint8_t nwk_type) bool PPPCellularInterface::is_connected() { - return dev_info.ppp_connection_up; + return (_connect_status == NSAPI_STATUS_GLOBAL_UP || _connect_status == NSAPI_STATUS_LOCAL_UP); } // Get the SIM card going. @@ -560,13 +566,23 @@ nsapi_error_t PPPCellularInterface::connect() bool did_init = false; const char *apn_config = NULL; - if (dev_info.ppp_connection_up) { + if (is_connected()) { return NSAPI_ERROR_IS_CONNECTED; + } else if (_connect_status == NSAPI_STATUS_CONNECTING) { + return NSAPI_ERROR_ALREADY; + } + + _connect_status = NSAPI_STATUS_CONNECTING; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING); } do { retry_init: + + retcode = NSAPI_ERROR_OK; + /* setup AT parser */ setup_at_parser(); @@ -578,12 +594,13 @@ nsapi_error_t PPPCellularInterface::connect() enable_hup(false); if (!power_up()) { - return NSAPI_ERROR_DEVICE_ERROR; + retcode = NSAPI_ERROR_DEVICE_ERROR; + break; } retcode = initialize_sim_card(); if (retcode != NSAPI_ERROR_OK) { - return retcode; + break; } success = nwk_registration(PACKET_SWITCHED) //perform network registration @@ -595,7 +612,8 @@ nsapi_error_t PPPCellularInterface::connect() && set_CNMI(_at);//set new SMS indication if (!success) { - return NSAPI_ERROR_NO_CONNECTION; + retcode = NSAPI_ERROR_NO_CONNECTION; + break; } #if MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP @@ -608,7 +626,7 @@ nsapi_error_t PPPCellularInterface::connect() if (set_sim_pin_check_request) { retcode = do_sim_pin_check(_at, _pin); if (retcode != NSAPI_ERROR_OK) { - return retcode; + break; } /* set this request to false, as it is unnecessary to repeat in case of retry */ set_sim_pin_check_request = false; @@ -618,7 +636,7 @@ nsapi_error_t PPPCellularInterface::connect() if (change_pin) { retcode = do_change_sim_pin(_at, _pin, _new_pin); if (retcode != NSAPI_ERROR_OK) { - return retcode; + break; } /* set this request to false, as it is unnecessary to repeat in case of retry */ change_pin = false; @@ -636,12 +654,13 @@ nsapi_error_t PPPCellularInterface::connect() //sets up APN and IP protocol for external PDP context retcode = setup_context_and_credentials(); if (retcode != NSAPI_ERROR_OK) { - return retcode; + break; } if (!success) { shutdown_at_parser(); - return NSAPI_ERROR_NO_CONNECTION; + retcode = NSAPI_ERROR_NO_CONNECTION; + break; } initialized = true; @@ -668,7 +687,8 @@ nsapi_error_t PPPCellularInterface::connect() /* shutdown AT parser before notifying application of the failure */ shutdown_at_parser(); - return NSAPI_ERROR_NO_CONNECTION; + retcode = NSAPI_ERROR_NO_CONNECTION; + break; } /* This is the success case. @@ -681,12 +701,18 @@ nsapi_error_t PPPCellularInterface::connect() /* Initialize PPP * mbed_ppp_init() is a blocking call, it will block until * connected, or timeout after 30 seconds*/ - retcode = nsapi_ppp_connect(_fh, _connection_status_cb, _uname, _pwd, _stack); - if (retcode == NSAPI_ERROR_OK) { - dev_info.ppp_connection_up = true; - } + retcode = nsapi_ppp_connect(_fh, callback(this, &PPPCellularInterface::ppp_status_cb), _uname, _pwd, _stack); + } while ((_connect_status == NSAPI_STATUS_CONNECTING && _connect_is_blocking) && + apn_config && *apn_config); + + + if (retcode != NSAPI_ERROR_OK) { + _connect_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } + } - }while(!dev_info.ppp_connection_up && apn_config && *apn_config); return retcode; } @@ -699,13 +725,7 @@ nsapi_error_t PPPCellularInterface::connect() */ nsapi_error_t PPPCellularInterface::disconnect() { - nsapi_error_t ret = nsapi_ppp_disconnect(_fh); - if (ret == NSAPI_ERROR_OK) { - dev_info.ppp_connection_up = false; - return NSAPI_ERROR_OK; - } - - return ret; + return nsapi_ppp_disconnect(_fh); } const char *PPPCellularInterface::get_ip_address() @@ -797,4 +817,23 @@ NetworkStack *PPPCellularInterface::get_stack() return nsapi_ppp_get_stack(); } + +void PPPCellularInterface::attach( + Callback status_cb) +{ + _connection_status_cb = status_cb; +} + +nsapi_connection_status_t PPPCellularInterface::get_connection_status() const +{ + return _connect_status; +} + +nsapi_error_t PPPCellularInterface::set_blocking(bool blocking) +{ + return nsapi_ppp_set_blocking(blocking); +} + + + #endif // NSAPI_PPP_AVAILABLE diff --git a/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h b/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h index 8d33ebefe0..80cee234b3 100644 --- a/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h +++ b/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h @@ -85,7 +85,6 @@ typedef struct { char imei[15+1]; //!< International Mobile Equipment Identity char meid[18+1]; //!< Mobile Equipment IDentifier int flags; - bool ppp_connection_up; radio_access_nwk_type rat; nwk_registration_status_csd reg_status_csd; nwk_registration_status_psd reg_status_psd; @@ -166,7 +165,6 @@ public: * the lookup table then the driver tries to resort to default APN settings. * * Preferred method is to setup APN using 'set_credentials()' API. - * @return 0 on success, negative error code on failure */ virtual nsapi_error_t connect(); @@ -231,11 +229,6 @@ public: */ virtual const char *get_gateway(); - /** Get notified if the connection gets lost - * - * @param cb user defined callback - */ - void connection_status_cb(Callback cb); /** Turn modem debug traces on * @@ -243,6 +236,25 @@ public: */ void modem_debug_on(bool on); + /** Register callback for status reporting + * + * @param status_cb The callback for status changes + */ + virtual void attach(Callback status_cb); + + /** Get the connection status + * + * @return The connection status according to nsapi_connection_status_t + */ + virtual nsapi_connection_status_t get_connection_status() const; + + /** Set blocking status of connect() which by default should be blocking + * + * @param blocking true if connect is blocking + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_blocking(bool blocking); + private: FileHandle *_fh; ATCmdParser *_at; @@ -253,14 +265,17 @@ private: const char *_pwd; bool _debug_trace_on; nsapi_ip_stack_t _stack; - Callback _connection_status_cb; + Callback _connection_status_cb; + nsapi_connection_status_t _connect_status; + bool _connect_is_blocking; void base_initialization(); void setup_at_parser(); void shutdown_at_parser(); nsapi_error_t initialize_sim_card(); nsapi_error_t setup_context_and_credentials(); bool power_up(); - void power_down(); + void power_down(); + void ppp_status_cb(nsapi_event_t, intptr_t); protected: /** Enable or disable hang-up detection diff --git a/features/netsocket/nsapi_ppp.h b/features/netsocket/nsapi_ppp.h index 3041ba8a37..4e3a284c4d 100644 --- a/features/netsocket/nsapi_ppp.h +++ b/features/netsocket/nsapi_ppp.h @@ -29,6 +29,13 @@ namespace mbed { */ NetworkStack *nsapi_ppp_get_stack(); +/** Set connection blocking parameter + * + * @param blocking True if connection is blocking + * + * @return 0 on success, negative error code on failure + */ +nsapi_error_t nsapi_ppp_set_blocking(bool blocking); /** Connect to a PPP pipe * @@ -40,7 +47,7 @@ NetworkStack *nsapi_ppp_get_stack(); * * @return 0 on success, negative error code on failure */ -nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback status_cb=0, const char *uname=0, const char *pwd=0, const nsapi_ip_stack_t stack=DEFAULT_STACK); +nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback status_cb=0, const char *uname=0, const char *pwd=0, const nsapi_ip_stack_t stack=DEFAULT_STACK); /** Close a PPP connection * diff --git a/features/netsocket/nsapi_types.h b/features/netsocket/nsapi_types.h index 80663a80b3..b6b789d04c 100644 --- a/features/netsocket/nsapi_types.h +++ b/features/netsocket/nsapi_types.h @@ -56,6 +56,33 @@ enum nsapi_error { NSAPI_ERROR_ADDRESS_IN_USE = -3018, /*!< Address already in use */ }; + +/** Enum of connection status types + * + * Valid error codes have negative values. + * + * @enum nsapi_connection_status + */ + typedef enum nsapi_connection_status { + NSAPI_STATUS_LOCAL_UP = 0, /*!< local IP address set */ + NSAPI_STATUS_GLOBAL_UP = 1, /*!< global IP address set */ + NSAPI_STATUS_DISCONNECTED = 2, /*!< no connection to network */ + NSAPI_STATUS_CONNECTING = 3, /*!< connecting to network */ + NSAPI_STATUS_ERROR_UNSUPPORTED = NSAPI_ERROR_UNSUPPORTED +} nsapi_connection_status_t; + + +/** Enum of event types + * + * Event callbacks are accompanied with an event-dependent parameter passed as an intptr_t. + * + * @enum nsapi_event + */ + typedef enum nsapi_event { + NSAPI_EVENT_CONNECTION_STATUS_CHANGE = 0 /*!< network connection status has changed, the parameter = new status (nsapi_connection_status_t) */ +} nsapi_event_t; + + /** Type used to represent error codes * * This is a separate type from enum nsapi_error to avoid breaking