From b654b76a3ce4302faaf28fae7482a22aad5f0e5e Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Sat, 7 Sep 2019 23:09:06 -0700 Subject: [PATCH] Add synchronization and switching between SoftAP/STA - A shared mutex is added for synchronization - ScopedMutexLock is used to to protect - SoftAP: start, stop - STA: scan, join, disconnect - Fix switching issue between SoftAP and STA mode for primary interface - Avoid reinit primary interface by getting mapping the current interface to the other one which is already on - In concurrent mode, STA is the default if it is up, otherwise SoftAP is default. - For non-concurrent mode, the most recent started interface is set as default. --- .../TARGET_WHD/interface/CyDhcpServer.cpp | 3 ++ .../TARGET_WHD/interface/WhdSTAInterface.cpp | 23 ++++++++- .../TARGET_WHD/interface/WhdSTAInterface.h | 5 +- .../interface/WhdSoftAPInterface.cpp | 26 ++++++++-- .../TARGET_WHD/interface/WhdSoftAPInterface.h | 5 +- .../TARGET_WHD/interface/whd_emac.cpp | 8 ++- ...t_wifi_interface.cpp => whd_interface.cpp} | 3 ++ .../TARGET_WHD/interface/whd_interface.h | 51 +++++++++++++++++++ 8 files changed, 114 insertions(+), 10 deletions(-) rename features/netsocket/emac-drivers/TARGET_WHD/interface/{default_wifi_interface.cpp => whd_interface.cpp} (92%) create mode 100644 features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.h diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/CyDhcpServer.cpp b/features/netsocket/emac-drivers/TARGET_WHD/interface/CyDhcpServer.cpp index 896a5c8886..89464bd0d2 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/CyDhcpServer.cpp +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/CyDhcpServer.cpp @@ -346,6 +346,9 @@ void CyDhcpServer::runServer(void) /* Create receive DHCP socket */ _socket.open(_nstack); + char iface_name[8] = {0}; + _niface->get_interface_name(iface_name); + _socket.setsockopt(NSAPI_SOCKET, NSAPI_BIND_TO_DEVICE, iface_name, strlen(iface_name)); _socket.bind((uint16_t)IP_PORT_DHCP_SERVER); /* Save the current netmask to be sent in DHCP packets as the 'subnet mask option' */ diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.cpp b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.cpp index 35f9c62ea0..ce5abcd4eb 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.cpp +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.cpp @@ -181,13 +181,14 @@ MBED_WEAK WhdSTAInterface::OlmInterface &WhdSTAInterface::OlmInterface::get_defa return olm; } -WhdSTAInterface::WhdSTAInterface(WHD_EMAC &emac, OnboardNetworkStack &stack, OlmInterface &olm) +WhdSTAInterface::WhdSTAInterface(WHD_EMAC &emac, OnboardNetworkStack &stack, OlmInterface &olm, whd_interface_shared_info_t &shared) : EMACInterface(emac, stack), _ssid("\0"), _pass("\0"), _security(NSAPI_SECURITY_NONE), _whd_emac(emac), - _olm(&olm) + _olm(&olm), + _iface_shared(shared) { } @@ -233,6 +234,7 @@ nsapi_error_t WhdSTAInterface::set_credentials(const char *ssid, const char *pas nsapi_error_t WhdSTAInterface::connect() { + ScopedMutexLock lock(_iface_shared.mutex); #define MAX_RETRY_COUNT ( 5 ) int i; @@ -249,6 +251,8 @@ nsapi_error_t WhdSTAInterface::connect() return whd_toerror(res); } + _iface_shared.if_status_flags |= IF_STATUS_STA_UP; + _iface_shared.default_if_cfg = DEFAULT_IF_STA; if (!_interface) { nsapi_error_t err = _stack.add_ethernet_interface(_emac, true, &_interface); if (err != NSAPI_ERROR_OK) { @@ -256,6 +260,9 @@ nsapi_error_t WhdSTAInterface::connect() return err; } _interface->attach(_connection_status_cb); + _iface_shared.iface_sta = _interface; + } else { + _stack.set_default_interface(_interface); } // Initialize the Offload Manager @@ -313,6 +320,8 @@ void WhdSTAInterface::wifi_on() nsapi_error_t WhdSTAInterface::disconnect() { + ScopedMutexLock lock(_iface_shared.mutex); + if (!_interface) { return NSAPI_STATUS_DISCONNECTED; } @@ -323,6 +332,14 @@ nsapi_error_t WhdSTAInterface::disconnect() return err; } + _iface_shared.if_status_flags &= ~IF_STATUS_STA_UP; + if (_iface_shared.if_status_flags & IF_STATUS_SOFT_AP_UP) { + _iface_shared.default_if_cfg = DEFAULT_IF_SOFT_AP; + _stack.set_default_interface(_iface_shared.iface_softap); + } else { + _iface_shared.default_if_cfg = DEFAULT_IF_NOT_SET; + } + // leave network whd_result_t res = whd_wifi_leave(_whd_emac.ifp); if (res != WHD_SUCCESS) { @@ -425,6 +442,8 @@ static void whd_scan_handler(whd_scan_result_t **result_ptr, int WhdSTAInterface::internal_scan(WiFiAccessPoint *aps, unsigned count, scan_result_type sres_type) { + ScopedMutexLock lock(_iface_shared.mutex); + // initialize wiced, this is noop if already init if (!_whd_emac.powered_up) { _whd_emac.power_up(); diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.h b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.h index 66b074a48d..2bda49d1ee 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.h +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSTAInterface.h @@ -23,6 +23,7 @@ #include "netsocket/OnboardNetworkStack.h" #include "WhdAccessPoint.h" #include "whd_emac.h" +#include "whd_interface.h" #include "whd_types_int.h" struct ol_desc; @@ -58,7 +59,8 @@ public: WhdSTAInterface( WHD_EMAC &emac = WHD_EMAC::get_instance(), OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance(), - OlmInterface &olm = OlmInterface::get_default_instance()); + OlmInterface &olm = OlmInterface::get_default_instance(), + whd_interface_shared_info_t &shared = whd_iface_shared); static WhdSTAInterface *get_default_instance(); @@ -246,6 +248,7 @@ private: nsapi_security_t _security; WHD_EMAC &_whd_emac; OlmInterface *_olm; + whd_interface_shared_info_t &_iface_shared; }; #endif diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.cpp b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.cpp index a13aff0b72..6a764750ee 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.cpp +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.cpp @@ -15,7 +15,6 @@ * limitations under the License. */ - #include "nsapi.h" #include "lwipopts.h" #include "WhdSoftAPInterface.h" @@ -27,6 +26,7 @@ #include "whd_emac.h" #include "whd_wifi_api.h" + extern int whd_toerror(whd_result_t res); extern nsapi_security_t whd_tosecurity(whd_security_t sec); extern whd_security_t whd_fromsecurity(nsapi_security_t sec); @@ -58,9 +58,10 @@ static void *whd_default_handle_softap_events(whd_interface_t ifp, const whd_eve } -WhdSoftAPInterface::WhdSoftAPInterface(WHD_EMAC &emac, OnboardNetworkStack &stack) +WhdSoftAPInterface::WhdSoftAPInterface(WHD_EMAC &emac, OnboardNetworkStack &stack, whd_interface_shared_info_t &shared) : EMACInterface(emac, stack), - _whd_emac(emac) + _whd_emac(emac), + _iface_shared(shared) { } @@ -69,8 +70,9 @@ WhdSoftAPInterface::WhdSoftAPInterface(WHD_EMAC &emac, OnboardNetworkStack &stac int WhdSoftAPInterface::start(const char *ssid, const char *pass, nsapi_security_t security, uint8_t channel, bool start_dhcp_server, const whd_custom_ie_info_t *ie_info, bool ap_sta_concur) { - nsapi_error_t err; + ScopedMutexLock lock(_iface_shared.mutex); + nsapi_error_t err; // power up primary emac interface first if (ap_sta_concur) { WHD_EMAC &emac_prime = WHD_EMAC::get_instance(WHD_STA_ROLE); @@ -116,13 +118,20 @@ int WhdSoftAPInterface::start(const char *ssid, const char *pass, nsapi_security return err; } + _iface_shared.if_status_flags |= IF_STATUS_SOFT_AP_UP; + if (!ap_sta_concur || (_iface_shared.default_if_cfg == DEFAULT_IF_NOT_SET)) { + _iface_shared.default_if_cfg = DEFAULT_IF_SOFT_AP; + } if (!_interface) { - nsapi_error_t err = _stack.add_ethernet_interface(_whd_emac, true, &_interface); + nsapi_error_t err = _stack.add_ethernet_interface(_whd_emac, _iface_shared.default_if_cfg == DEFAULT_IF_SOFT_AP, &_interface); if (err != NSAPI_ERROR_OK) { _interface = NULL; return err; } _interface->attach(_connection_status_cb); + _iface_shared.iface_softap = _interface; + } else if (_iface_shared.default_if_cfg == DEFAULT_IF_SOFT_AP) { + _stack.set_default_interface(_interface); } if (ie_info) { @@ -169,6 +178,8 @@ int WhdSoftAPInterface::start(const char *ssid, const char *pass, nsapi_security int WhdSoftAPInterface::stop(void) { + ScopedMutexLock lock(_iface_shared.mutex); + if (_dhcp_server && CY_RSLT_SUCCESS != _dhcp_server->stop()) { return NSAPI_ERROR_DHCP_FAILURE; } @@ -180,6 +191,11 @@ int WhdSoftAPInterface::stop(void) return err; } + _iface_shared.if_status_flags &= ~IF_STATUS_SOFT_AP_UP; + if ((_iface_shared.if_status_flags & IF_STATUS_STA_UP) == 0) { + _iface_shared.default_if_cfg = DEFAULT_IF_NOT_SET; + } + // stop softap whd_result_t res = whd_wifi_stop_ap(_whd_emac.ifp); if (res != WHD_SUCCESS) { diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.h b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.h index a4a0e1385c..ced7c04f25 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.h +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/WhdSoftAPInterface.h @@ -23,6 +23,7 @@ #include "netsocket/OnboardNetworkStack.h" #include "whd_emac.h" #include "CyDhcpServer.h" +#include "whd_interface.h" #include /** @@ -47,7 +48,8 @@ public: * @return pointer to default WhdSoftAPInterface instance */ WhdSoftAPInterface(WHD_EMAC &emac = WHD_EMAC::get_instance(WHD_AP_ROLE), - OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()); + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance(), + whd_interface_shared_info_t &shared = whd_iface_shared); /** Get the default WhdSoftAPInterface instance. * @return pointer to default WhdSoftAPInterface instance @@ -150,6 +152,7 @@ public: protected: WHD_EMAC &_whd_emac; std::unique_ptr _dhcp_server; + whd_interface_shared_info_t &_iface_shared; }; #endif diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_emac.cpp b/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_emac.cpp index 78c19a97f6..2c29536bed 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_emac.cpp +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_emac.cpp @@ -109,7 +109,13 @@ bool WHD_EMAC::power_up() // wifi driver and turns on the wifi chip. res = cybsp_wifi_init_secondary(&ifp /* Out */, &unicast_addr); } else { - res = cybsp_wifi_init_primary(&ifp /* OUT */); + WHD_EMAC &emac_other = WHD_EMAC::get_instance(interface_type == WHD_STA_ROLE ? WHD_AP_ROLE : + WHD_STA_ROLE); + if (!emac_other.powered_up) { + res = cybsp_wifi_init_primary(&ifp /* OUT */); + } else { + ifp = emac_other.ifp; + } } if (CY_RSLT_SUCCESS == res) { diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/default_wifi_interface.cpp b/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.cpp similarity index 92% rename from features/netsocket/emac-drivers/TARGET_WHD/interface/default_wifi_interface.cpp rename to features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.cpp index 69250ce889..6798817727 100644 --- a/features/netsocket/emac-drivers/TARGET_WHD/interface/default_wifi_interface.cpp +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.cpp @@ -17,6 +17,9 @@ #include "WhdSTAInterface.h" #include "WhdSoftAPInterface.h" +#include "whd_interface.h" + +whd_interface_shared_info_t whd_iface_shared; WiFiInterface *WiFiInterface::get_target_default_instance() { diff --git a/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.h b/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.h new file mode 100644 index 0000000000..73dbe3018f --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_WHD/interface/whd_interface.h @@ -0,0 +1,51 @@ +/* WHD implementation of NetworkInterfaceAPI + * Copyright (c) 2017-2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WHD_INTERFACE_H +#define WHD_INTERFACE_H + +#include "rtos/Mutex.h" +#include "OnboardNetworkStack.h" + +/** WhdSTAInterface class + * Shared information + */ +#define IF_STATUS_ALL_IF_DOWN 0x0 +#define IF_STATUS_STA_UP 0x1 +#define IF_STATUS_SOFT_AP_UP 0x2 + +enum whd_default_interface_config +{ + DEFAULT_IF_NOT_SET, + DEFAULT_IF_STA, + DEFAULT_IF_SOFT_AP +}; + +struct whd_interface_shared_info_t { + rtos::Mutex mutex; + whd_default_interface_config default_if_cfg; + uint32_t if_status_flags; + OnboardNetworkStack::Interface *iface_sta; + OnboardNetworkStack::Interface *iface_softap; + whd_interface_shared_info_t() : default_if_cfg(DEFAULT_IF_NOT_SET), if_status_flags(IF_STATUS_ALL_IF_DOWN), + iface_sta(NULL), iface_softap(NULL) + {} +}; + +extern whd_interface_shared_info_t whd_iface_shared; + +#endif