Newer
Older
mbed-os / connectivity / drivers / wifi / TARGET_STM / COMPONENT_EMW3080B / EMW3080BInterface.cpp
@Jerome Coutant Jerome Coutant on 30 Sep 2021 11 KB STM32: new EMW3080B wifi driver
/*
 * Copyright (c) STMicroelectronics 2021
 * 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.
 */


/* Includes ------------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
#include "EMW3080BInterface.h"
#if MX_WIFI_USE_SPI
#include "EMW3080B_SPI.h"
#else
#include "EMW3080B_UART.h"
#endif

#define DEBUG_SILENT  0
#define DEBUG_WARNING 1
#define DEBUG_INFO    2
#define DEBUG_LOG     3
#define DEFAULT_DEBUG DEBUG_SILENT

static  EMW3080BInterface  *emw3080b_object;

#if MX_WIFI_USE_SPI
static  EMW3080B_SPI *emw3080b_protocol_context;
#else
static  EMW3080B_UART *emw3080b_protocol_context;
#endif

static bool deepsleep_locked = false;

EMW3080BInterface::EMW3080BInterface(bool    debug,
                                     PinName mosi,
                                     PinName miso,
                                     PinName sclk,
                                     PinName nss,
                                     PinName notify,
                                     PinName flow,
                                     PinName reset,
                                     PinName tx,
                                     PinName rx,
                                     EMAC   &emac,
                                     OnboardNetworkStack &stack
                                    ) : EMACInterface(emac, stack), _ssid(""), _isConnected(false)
{
    emw3080b_object = this;
#if MX_WIFI_USE_SPI
    emw3080b_protocol_context = new EMW3080B_SPI(debug, mosi, miso, sclk, nss, notify, flow, reset);
#else
    emw3080b_protocol_context = new EMW3080B_UART(debug, tx, rx, reset);
#endif

    if (debug) {
        _debug_level = DEBUG_LOG;
    } else {
        _debug_level = DEFAULT_DEBUG;
    }

    probe();
}




int8_t  IO_Init_static(uint16_t mode)
{
    return emw3080b_protocol_context->IO_Init(mode);
}

int8_t  IO_DeInit_static(void)
{
    return emw3080b_protocol_context->IO_DeInit();
}

void  IO_Delay_static(uint32_t delayms)
{
    return emw3080b_protocol_context->IO_Delay(delayms);
}

uint16_t  IO_Send_static(uint8_t *data, uint16_t len)
{
    return emw3080b_protocol_context->IO_Send(data, len);
}

uint16_t  IO_Receive_static(uint8_t *buffer, uint16_t buff_size)
{
    return emw3080b_protocol_context->IO_Receive(buffer, buff_size);
}



MX_WIFIObject_t *wifi_obj_get(void)
{
    if (emw3080b_object) {
        return   &emw3080b_object->MxWifiObj;
    } else {
        error("MxWifiObj is not initialized");
    }
}

void EMW3080BInterface::probe(void)
{

    if (MX_WIFI_RegisterBusIO(&MxWifiObj,
                              IO_Init_static,
                              IO_DeInit_static,
                              IO_Delay_static,
                              IO_Send_static,
                              IO_Receive_static) != 0) {
        debug_if(_debug_level >= DEBUG_LOG, "EMW3080BInterface : MX_WIFI_RegisterBusIO failed \n");
        return;
    }


    if (MX_WIFI_HardResetModule(&MxWifiObj)) {
        debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : MX_WIFI_HardResetModule failed \n");
        return ;
    }

    /* wait for mxchip wifi reboot */
    rtos::ThisThread::sleep_for(800ms);

    if (MX_WIFI_Init(&MxWifiObj)) {
        error("EMW3080BInterface : MX_WIFI_Init failed, you may have to update MXCHIP fimrware module to version 2.1.11\n");
    }

    debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : Product name: %s\n", MxWifiObj.SysInfo.Product_Name);
    debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : Product ID: %s\n", MxWifiObj.SysInfo.Product_ID);
    debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : FW revision: %s\n", MxWifiObj.SysInfo.FW_Rev);
    debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : MAC %02x.%02x.%02x.%02x.%02x.%02x\n\n", MxWifiObj.SysInfo.MAC[0], MxWifiObj.SysInfo.MAC[1], MxWifiObj.SysInfo.MAC[2], MxWifiObj.SysInfo.MAC[3], MxWifiObj.SysInfo.MAC[4], MxWifiObj.SysInfo.MAC[5]);
}

void EMW3080BInterface::release(void)
{
    return;
}


int EMW3080BInterface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
{
    if ((ssid == NULL) || (strlen(ssid) == 0) || (strlen(ssid) > 32)) {
        debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : bad credential\n");
        return NSAPI_ERROR_PARAMETER;
    }

    if (security != NSAPI_SECURITY_NONE) {
        if ((pass == NULL) || (strcmp(pass, "") == 0) || (strlen(pass) > 63)) {
            debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : bad security\n");
            return NSAPI_ERROR_PARAMETER;
        }
    }

    _mutex.lock();
    memset(_ssid, 0, sizeof(_ssid));
    strncpy(_ssid, ssid, sizeof(_ssid));

    memset(_pass, 0, sizeof(_pass));
    if (security != NSAPI_SECURITY_NONE) {
        strncpy(_pass, pass, sizeof(_pass));
    }
    _sec =  nsapi_sec2emw_sec(security);

    _mutex.unlock();
    debug_if(_debug_level >= DEBUG_LOG, "EMW3080BInterface : set credential OK %s %s \n", _ssid, _pass);
    return NSAPI_ERROR_OK;
}

nsapi_error_t EMW3080BInterface::connect(const char *ssid, const char *pass, nsapi_security_t security,
                                         uint8_t channel)
{
    nsapi_error_t ret;

    if (channel != 0) {
        debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : connect bad channel value, only 0 is supported\n");
        ret =  NSAPI_ERROR_UNSUPPORTED;
    } else {

        _mutex.lock();
        nsapi_error_t credentials_status = set_credentials(ssid, pass, security);
        _mutex.unlock();

        if (credentials_status) {
            debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : connect unable to set credential\n");
            ret = credentials_status;
        } else {
            ret = connect();
        }
    }
    return ret;
}


nsapi_error_t EMW3080BInterface::connect()
{
    nsapi_error_t ret ;
    _mutex.lock();

    /* Disable deepsleep as wakeup latency is too high */
    if (!deepsleep_locked) {
        deepsleep_locked = true;
        sleep_manager_lock_deep_sleep();
    }

    MxWifiObj.NetSettings.DHCP_IsEnabled = true;

    if (_ssid[0] == '\0') {
        debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : connect , ssid is missing\n");
        ret = NSAPI_ERROR_NO_SSID;
    } else if (_isConnected) {
        debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : connect is already connected\n");
        ret = NSAPI_ERROR_IS_CONNECTED;
    } else {

        debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : connecting MX_WIFI\n");
        if (MX_WIFI_Connect(
                    &MxWifiObj,
                    _ssid,
                    _pass,
                    _sec)) {
            debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : Connect failed; wrong parameter ?\n");
            ret = NSAPI_ERROR_PARAMETER ;
        } else {
            // FIXME :  MX_WIFI_Connect command needs to allocate a netbuffer to store the module answer (zero copy mechanism)
            // potential issue is that netbuffer allocation is not ready because part of the  EMAC class  connect phase

            debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : connecting EMAC\n");
            ret = EMACInterface::connect();
            /* EMAC is waiting for UP conection , UP means we join an hotspot and  IP services running */
            if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IS_CONNECTED) {
                debug_if(_debug_level >= DEBUG_LOG, "EMW3080BInterface : Connected to emac! (using ssid %s , passw %s  )\n", _ssid, _pass);
                _isConnected = true;
                ret = NSAPI_ERROR_OK;
            } else {

                debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : EMAC Fail to connect NSAPI_ERROR %d\n", ret);
                (void) MX_WIFI_Disconnect(&MxWifiObj);
                EMACInterface::disconnect();
                ret = NSAPI_ERROR_CONNECTION_TIMEOUT;
            }
        }
    }
    _mutex.unlock();

    return ret;
}

nsapi_error_t EMW3080BInterface::disconnect()
{
    nsapi_error_t ret ;
    _mutex.lock();

    if (_isConnected == false) {
        ret = NSAPI_ERROR_NO_CONNECTION;
    } else {
        debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : disconnecting MX_WIFI and EMAC\n");
        if (MX_WIFI_Disconnect(&MxWifiObj)) {
            debug_if(_debug_level >= DEBUG_WARNING, "MXWIFI disconnect command failed\n");
            ret = NSAPI_ERROR_DEVICE_ERROR;
        } else {
            ret = NSAPI_ERROR_OK;
        }
        _isConnected = false;
        EMACInterface::disconnect();
    }

    if (deepsleep_locked) {
        deepsleep_locked = false;
        sleep_manager_unlock_deep_sleep();
    }

    _mutex.unlock();
    return ret;
}


int8_t EMW3080BInterface::get_rssi()
{
    _mutex.lock();
    int8_t ret = 0;
    if (_isConnected) {
        uint32_t  count;
        debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : Perform a scan for RSSI\n");

        MX_WIFI_Scan(&MxWifiObj, MC_SCAN_ACTIVE, (char *)&_ssid[0], strlen(_ssid));
        count = MX_WIFI_Get_scan_result(&MxWifiObj, (uint8_t *) _ap_info, MAX_AP_COUNT);
        if (count == 0) {
            debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : Get RSSI , scan did not find HotSpot %s\n", _ssid);
        } else {
            if (count > 1) {
                debug_if(_debug_level >= DEBUG_WARNING, "EMW3080BInterface : Get RSSI , scan find several HotSpot named %s, return strenght of first one\n", _ssid);
            }
            ret =  _ap_info[0].rssi;
        }
    }

    _mutex.unlock();
    debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : Get RSSI return %d\n", ret);
    return ret;
}



int EMW3080BInterface::scan(WiFiAccessPoint *res, unsigned int count)
{
    _mutex.lock();
    if (count == 0) {
        return MAX_AP_COUNT;
    } else {
        if (count > MAX_AP_COUNT) {
            count = MAX_AP_COUNT;
        }

        MX_WIFI_Scan(&MxWifiObj, MC_SCAN_PASSIVE, NULL, 0);
        count = MX_WIFI_Get_scan_result(&MxWifiObj, (uint8_t *) _ap_info, count);
        debug_if(_debug_level >= DEBUG_INFO, "EMW3080BInterface : Scan find %d HotSpot\n", count);

        if (res != NULL) {
            for (uint32_t  i = 0; i < count ; i++) {
                nsapi_wifi_ap_t ap;
                debug_if(_debug_level >= DEBUG_LOG, "EMW3080BInterface : %" PRIu32 "  SSID %s rssi %" PRIu32 "\n", i, _ap_info[i].ssid, _ap_info[i].rssi);
                debug_if(_debug_level >= DEBUG_LOG, "EMW3080BInterface : BSSID %hhx:%hhx:%hhx:%hhx:%hhx:%hhx\n", _ap_info[i].bssid[0], _ap_info[i].bssid[1], _ap_info[i].bssid[2], _ap_info[i].bssid[3], _ap_info[i].bssid[4], _ap_info[i].bssid[5]);

                memcpy(ap.ssid, _ap_info[i].ssid, 33);
                memcpy(ap.bssid, _ap_info[i].bssid, 6);
                ap.security = emw_sec2nsapi_sec(_ap_info[i].security);
                ap.rssi = _ap_info[i].rssi;
                ap.channel = _ap_info[i].channel;
                res[i] = WiFiAccessPoint(ap);
            }
        }
    }
    _mutex.unlock();
    return (int) count;
}


#if MBED_CONF_EMW3080B_PROVIDE_DEFAULT
WiFiInterface *WiFiInterface::get_default_instance()
{
    static EMW3080BInterface emw;
    return &emw;
}
#endif /* MBED_CONF_EMW3080B_PROVIDE_DEFAULT */


#if defined(MBED_CONF_NSAPI_PRESENT)
WiFiInterface *WiFiInterface::get_target_default_instance()
{
#if (DEFAULT_DEBUG == DEBUG_LOG)
    printf("get_target_default_instance\n");
#endif /* MBED_CONF_NSAPI_PRESENT */
    static EMW3080BInterface wifi;
    return &wifi;
}
#endif /* MBED_CONF_NSAPI_PRESENT */