mirror of https://github.com/ARMmbed/mbed-os.git
368 lines
12 KiB
C++
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 */
|