mbed-os/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.cpp

368 lines
12 KiB
C++

/*
* 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 */