diff --git a/connectivity/drivers/wifi/CMakeLists.txt b/connectivity/drivers/wifi/CMakeLists.txt index 6ca3b2f092..32af767127 100644 --- a/connectivity/drivers/wifi/CMakeLists.txt +++ b/connectivity/drivers/wifi/CMakeLists.txt @@ -3,6 +3,8 @@ add_subdirectory(TARGET_WICED EXCLUDE_FROM_ALL) +add_subdirectory(TARGET_STM EXCLUDE_FROM_ALL) + add_subdirectory(COMPONENT_WHD EXCLUDE_FROM_ALL) add_subdirectory(esp8266-driver) diff --git a/connectivity/drivers/wifi/TARGET_STM/CMakeLists.txt b/connectivity/drivers/wifi/TARGET_STM/CMakeLists.txt new file mode 100644 index 0000000000..78d80df1a6 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2020-2021 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +if("EMW3080B" IN_LIST MBED_TARGET_LABELS) + add_subdirectory(COMPONENT_EMW3080B EXCLUDE_FROM_ALL) +endif() diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/CMakeLists.txt b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/CMakeLists.txt new file mode 100644 index 0000000000..830fdf088d --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +add_library(wifi-EMW3080B INTERFACE) + +target_include_directories(mbed-wifi + INTERFACE + . + mx_wifi + mx_wifi/core +) + +target_sources(mbed-wifi + INTERFACE + EMW3080BInterface.cpp + EMW3080B_EMAC.cpp + EMW3080B_UART.cpp + EMW3080B_SPI.cpp + mx_wifi_mbed_os.cpp + mx_wifi/mx_wifi.c + mx_wifi/core/checksumutils.c + mx_wifi/core/mx_wifi_hci.c + mx_wifi/core/mx_wifi_ipc.c + mx_wifi/core/mx_wifi_slip.c +) diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.cpp b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.cpp new file mode 100644 index 0000000000..c59407d7ff --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.cpp @@ -0,0 +1,367 @@ +/* + * 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 */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.h new file mode 100644 index 0000000000..91f3057aa4 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080BInterface.h @@ -0,0 +1,207 @@ +/* EMW3080B implementation of NetworkInterfaceAPI + * 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. + */ + +#ifndef EMW3080B_INTERFACE_H +#define EMW3080B_INTERFACE_H + +#if defined(MBED_CONF_NSAPI_PRESENT) + +#include + +#include "mbed.h" +#include "mbed_debug.h" +#include "mx_wifi.h" +#include "netsocket/WiFiInterface.h" +#include "netsocket/EMACInterface.h" +#include "netsocket/OnboardNetworkStack.h" +#include "EMW3080B_EMAC.h" + + +/** EMW3080BInterface class + * Implementation of the NetworkStack for the EMW3080B + */ +class EMW3080BInterface : public WiFiInterface, public EMACInterface { +public: + EMW3080BInterface(bool debug = MBED_CONF_EMW3080B_WIFI_DEBUG, + PinName mosi = MBED_CONF_EMW3080B_WIFI_MOSI, + PinName miso = MBED_CONF_EMW3080B_WIFI_MISO, + PinName sclk = MBED_CONF_EMW3080B_WIFI_SCLK, + PinName nss = MBED_CONF_EMW3080B_WIFI_NSS, + PinName notify = MBED_CONF_EMW3080B_WIFI_NOTIFY, + PinName flow = MBED_CONF_EMW3080B_WIFI_FLOW, + PinName reset = MBED_CONF_EMW3080B_WIFI_RESET, + PinName tx = MBED_CONF_EMW3080B_WIFI_TX, + PinName rx = MBED_CONF_EMW3080B_WIFI_RX, + EMAC &emac = EMW3080B_EMAC::get_instance(), + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance() + ); + + /** Start the interface + * + * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. + * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return 0 on success, negative error code on failure + */ + nsapi_error_t connect(); + + /** Start the interface + * + * Attempts to connect to a WiFi network. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE) + * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED + * @return 0 on success, or error code on failure + */ + nsapi_error_t connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, uint8_t channel = 0); + + /** Stop the interface + * @return 0 on success, negative on failure + */ + nsapi_error_t disconnect(); + + /** Set the WiFi network credentials + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * (defaults to NSAPI_SECURITY_NONE) + * @return 0 on success, or error code on failure + */ + nsapi_error_t set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); + + /** Set the WiFi network channel - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0) + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + nsapi_error_t set_channel(uint8_t channel) + { + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + return 0; + } + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + int8_t get_rssi(); + + /** Scan for available networks + * + * This function will block. + * + * @param ap Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0) + * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + int scan(WiFiAccessPoint *res, unsigned count); + + MX_WIFIObject_t MxWifiObj; + +private: + + nsapi_security_t emw_sec2nsapi_sec(mwifi_security_t sec) + { + nsapi_security_t sec_out; + + switch (sec) { + case MX_WIFI_SEC_NONE: + sec_out = NSAPI_SECURITY_NONE; + break; + case MX_WIFI_SEC_WEP: + sec_out = NSAPI_SECURITY_WEP; + break; + case MX_WIFI_SEC_WPA_AES: + case MX_WIFI_SEC_WPA_TKIP: + sec_out = NSAPI_SECURITY_WPA; + break; + case MX_WIFI_SEC_WPA2_AES: + case MX_WIFI_SEC_WPA2_TKIP: + case MX_WIFI_SEC_WPA2_MIXED: + sec_out = NSAPI_SECURITY_WPA2; + break; + case MX_WIFI_SEC_AUTO: + sec_out = NSAPI_SECURITY_WPA_WPA2; + break; + default: + sec_out = NSAPI_SECURITY_WPA_WPA2; + break; + + } + return sec_out; + } + + MX_WIFI_SecurityType_t nsapi_sec2emw_sec(nsapi_security_t sec) + { + MX_WIFI_SecurityType_t mx_sec; + + switch (sec) { + case NSAPI_SECURITY_NONE: + mx_sec = MX_WIFI_SEC_NONE; + break; + case NSAPI_SECURITY_WEP: + mx_sec = MX_WIFI_SEC_WEP; + break; + case NSAPI_SECURITY_WPA: + mx_sec = MX_WIFI_SEC_WPA_AES; + break; + case NSAPI_SECURITY_WPA2: + mx_sec = MX_WIFI_SEC_WPA2_AES; + break; + default: + mx_sec = MX_WIFI_SEC_AUTO; + break; + } + + return mx_sec; + } + + /* MXCHIP array size for SCAN is 2KB , so limits number of AP to 20 */ +#define MAX_AP_COUNT 20 + + + int8_t IO_Init(uint16_t mode); + int8_t IO_DeInit(void); + void IO_Delay(uint32_t delayms); + uint16_t IO_Send(uint8_t *data, uint16_t len); + uint16_t IO_Receive(uint8_t *buffer, uint16_t buff_size); + + void probe(void); + void release(void); + char _ssid[33]; /* The longest possible name (defined in 802.11) +1 for the \0 */ + char _pass[64]; /* The longest allowed passphrase + 1 */ + mwifi_ap_info_t _ap_info[MAX_AP_COUNT]; + MX_WIFI_SecurityType_t _sec; + volatile bool _isConnected; + Mutex _mutex; + + uint8_t _debug_level; +}; + +#endif /* MBED_CONF_NSAPI_PRESENT */ + +#endif /* EMW3080B_INTERFACE_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_EMAC.cpp b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_EMAC.cpp new file mode 100644 index 0000000000..4343351e0e --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_EMAC.cpp @@ -0,0 +1,336 @@ +/* + * 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. + */ + +#include "EMW3080B_EMAC.h" +#include "mx_wifi_ipc.h" + +#include "lwip/etharp.h" +#include "lwip/ethip6.h" + +#define DEBUG_SILENT 0 +#define DEBUG_WARNING 1 +#define DEBUG_INFO 2 +#define DEBUG_LOG 3 +#define DEFAULT_DEBUG DEBUG_SILENT + + +EMW3080B_EMAC::EMW3080B_EMAC() +{ + _debug_level = DEFAULT_DEBUG; +} + + +uint32_t EMW3080B_EMAC::get_mtu_size() const +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : get_mtu_size %d\n", MX_WIFI_MTU_SIZE); + return MX_WIFI_MTU_SIZE; +} + +uint32_t EMW3080B_EMAC::get_align_preference() const +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : get_align_preference 0\n"); + return 0; +} + +void EMW3080B_EMAC::add_multicast_group(const uint8_t *addr) +{ + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : add_multicast_group is not supported\n"); +} + +void EMW3080B_EMAC::remove_multicast_group(const uint8_t *addr) +{ + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : remove_multicast_group is not supported\n"); +} + +void EMW3080B_EMAC::set_all_multicast(bool all) +{ + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : set_all_multicast not supported\n"); + /* No-op at this stage */ +} + +void EMW3080B_EMAC::power_down() +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : power_down\n"); + +} + +bool EMW3080B_EMAC::power_up() +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : power_up\n"); + + return true; +} + + +bool EMW3080B_EMAC::get_hwaddr(uint8_t *addr) const +{ + bool ret; + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : get_hwaddr\n"); + + MX_WIFIObject_t *pMxWifiObj = wifi_obj_get(); + if (pMxWifiObj) { + addr[0] = pMxWifiObj->SysInfo.MAC[0]; + addr[1] = pMxWifiObj->SysInfo.MAC[1]; + addr[2] = pMxWifiObj->SysInfo.MAC[2]; + addr[3] = pMxWifiObj->SysInfo.MAC[3]; + addr[4] = pMxWifiObj->SysInfo.MAC[4]; + addr[5] = pMxWifiObj->SysInfo.MAC[5]; + ret = true; + } else { + ret = false; + } + return ret; +} + + +void EMW3080B_EMAC::set_hwaddr(const uint8_t *addr) +{ + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : set_hwaddr ignoring this command ,not possible to set MAC address for MXCHIP device\n"); +} + +uint8_t EMW3080B_EMAC::get_hwaddr_size() const +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : get_hwaddr_size %u\n", EMW3080B_HWADDR_SIZE); + return EMW3080B_HWADDR_SIZE; +} + + +static void emac_data_callback(mx_buf_t *buffer, void *user_args) +{ + /* to retrieve the C++ class */ + EMW3080B_EMAC emac = EMW3080B_EMAC::get_instance(); + emac.mx_wifi_netlink_input_callback(buffer); +} + +void EMW3080B_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : set_link_input_cb\n"); + if (MX_WIFI_STATUS_OK != MX_WIFI_Network_bypass_mode_set(wifi_obj_get(), 1, emac_data_callback, NULL)) { + error("EMW3080B_EMAC : can not set set_link_input_cb\n"); + } else { + _emac_input_data_cb = input_cb; + } +} + +extern "C" { + void emac_status_changed(uint8_t cate, uint8_t status, void *arg) + { + /* to retrieve the C++ class */ + EMW3080B_EMAC emac = EMW3080B_EMAC::get_instance(); + emac.mx_wifi_status_changed(cate, status, arg); + } +} + +void EMW3080B_EMAC::mx_wifi_status_changed(uint8_t cate, uint8_t status, void *arg) +{ + bool mx_wifi_driver_up; + if ((uint8_t)MC_STATION == cate) { + switch (status) { + case MWIFI_EVENT_STA_DOWN: + mx_wifi_driver_up = false; + break; + + case MWIFI_EVENT_STA_UP: + mx_wifi_driver_up = true; + break; + + default: + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : mx_wifi_status_changed get unknown Event from EMW3080B\n"); + mx_wifi_driver_up = false; + break; + } + + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : Interface is %s (calling)\n", mx_wifi_driver_up ? "UP" : "DOWN"); + if (_emac_link_state_cb) { + _emac_link_state_cb(mx_wifi_driver_up); + } + + } else if ((uint8_t)MC_SOFTAP == cate) { + switch (status) { + case MWIFI_EVENT_AP_DOWN: + break; + + case MWIFI_EVENT_AP_UP: + break; + + default: + break; + } + } else { + /* nothing */ + } +} + + + +void EMW3080B_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) +{ + _emac_link_state_cb = state_cb; + + + if (MX_WIFI_RegisterStatusCallback_if( + wifi_obj_get(), + emac_status_changed, + NULL /* void * arg */, + (mwifi_if_t)MC_STATION)) { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : Fail to register callback\n"); + return ; + } + + +} + +EMACMemoryManager *emac3080b_global_memory_manager = NULL; + +void EMW3080B_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : set_memory_manager\n"); + _memory_manager = &mem_mngr; + emac3080b_global_memory_manager = &mem_mngr; + +} +#define EMW_PROTOCOL_HEADROOM sizeof(wifi_bypass_out_cparams_t) + +bool EMW3080B_EMAC::link_out(emac_mem_buf_t *buf) +{ + bool ret = true; + + emac_mem_buf_t *q; + uint32_t m = 0; + uint32_t len = 0; + int32_t mx_ret; + +#if MX_WIFI_TX_BUFFER_NO_COPY + for (q = buf; q != NULL; q = _memory_manager->get_next(q)) { + len += _memory_manager->get_len(q); + } + + mx_buf_t *net = mx_buf_alloc(len + EMW_PROTOCOL_HEADROOM); + if (net != NULL) { + MX_NET_BUFFER_HIDE_HEADER(net, EMW_PROTOCOL_HEADROOM); + MX_NET_BUFFER_SET_PAYLOAD_SIZE(net, len); + + uint8_t *payload = MX_NET_BUFFER_PAYLOAD(net); + for (q = buf; q != NULL; q = _memory_manager->get_next(q)) { + memcpy(payload, _memory_manager->get_ptr(q), _memory_manager->get_len(q)); + payload += _memory_manager->get_len(q); + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_EMAC : TX seg %" PRIu32 " %" PRIu32 " bytes\n", m, _memory_manager->get_len(q)); + m++; + } + + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_EMAC : %" PRIu32 " TX %" PRIu32 "\n", m, MX_NET_BUFFER_GET_PAYLOAD_SIZE(net)); + mx_ret = MX_WIFI_Network_bypass_netlink_output( + wifi_obj_get(), + MX_NET_BUFFER_PAYLOAD(net), + MX_NET_BUFFER_GET_PAYLOAD_SIZE(net), + STATION_IDX + ); + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_EMAC : TX done lust e zero %" PRIu32 "\n", mx_ret); + MX_NET_BUFFER_FREE(net); + if (mx_ret != MX_WIFI_STATUS_OK) { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : link_out : failed to send buffer\n"); + ret = false; + } +#else + /* copy is managed internally */ + ret = MX_WIFI_Network_bypass_netlink_output( + wifi_obj_get(), + _memory_manager->get_ptr(q), + _memory_manager->get_len(q), + STATION_IDX + ); +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + } else + { + error("EMW3080B_EMAC : unable to allocate %" PRIu32 " bytes\n", len); + } + + _memory_manager->free(buf); + return ret; +} + +void EMW3080B_EMAC::get_ifname(char *name, uint8_t size) const +{ + debug_if(_debug_level >= DEBUG_INFO, "EMW3080B_EMAC : get_ifname\n"); + if (size > 0) { + strncpy(name, "st", size - 1); + name[size - 1] = '\0'; + } +} + +EMW3080B_EMAC &EMW3080B_EMAC::get_instance() +{ + static EMW3080B_EMAC emac; + return emac; +} + +void EMW3080B_EMAC::mx_wifi_netlink_input_callback(mx_buf_t *buffer) +{ + struct eth_hdr *ethernet_header; + uint16_t ethertype; + uint32_t len = 0U; + + if (buffer != NULL) { + len = MX_NET_BUFFER_GET_PAYLOAD_SIZE(buffer); + + if ((len > 0U) && (len <= (uint32_t) MX_WIFI_MTU_SIZE)) { + /* points to packet payload, which starts with an Ethernet header */ + ethernet_header = (struct eth_hdr *) MX_NET_BUFFER_PAYLOAD(buffer); + + ethertype = lwip_htons(ethernet_header->type); + switch (ethertype) { + case ETHTYPE_IP: + /* case ETHTYPE_IPV6: */ + case ETHTYPE_ARP: + /* PPPoE packet */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: { + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_EMAC : process input packet 0x%02x, len=%" PRIu32 "\n", ethertype, len); + emac_mem_buf_t *p, *q; + uint32_t index = 0; + p = _memory_manager->alloc_pool(len, 0); + if (p != NULL) { + uint8_t *src = (uint8_t *) ethernet_header; + uint32_t m = 0; + for (q = p; q != NULL; q = _memory_manager->get_next(q)) { + uint8_t *dest = (uint8_t *) _memory_manager->get_ptr(q); + memcpy(dest, &src[index], _memory_manager->get_len(q)); + index += _memory_manager->get_len(q); + + if (index >= len) { + break; + } + m++; + } + + + if (_emac_input_data_cb) { + _emac_input_data_cb(p); + } + } else { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_EMAC : fail to allocate emac_mem_buf_t %" PRIu32 " bytes\n", len); + } + } + break; + + default: + break; + } + } + MX_NET_BUFFER_FREE(buffer); + } +} diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_EMAC.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_EMAC.h new file mode 100644 index 0000000000..17f368366c --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_EMAC.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#ifndef EMW3080B_EMAC_H_ +#define EMW3080B_EMAC_H_ + +#include + +#include "mbed.h" +#include "mbed_debug.h" +#include "EMACInterface.h" +#include "WiFiInterface.h" +#include "mx_wifi.h" + +extern EMACMemoryManager *emac3080b_global_memory_manager ; + + +class EMW3080B_EMAC : public EMAC { +public: + EMW3080B_EMAC(); + + static EMW3080B_EMAC &get_instance(); + + /** + * Return maximum transmission unit + * + * @return MTU in bytes + */ + virtual uint32_t get_mtu_size() const; + + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not + * align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference() const; + + /** + * Return interface name + * + * @param name Pointer to where the name should be written + * @param size Maximum number of character to copy + */ + virtual void get_ifname(char *name, uint8_t size) const; + + /** + * Returns size of the underlying interface HW address size. + * + * @return HW address size in bytes + */ + virtual uint8_t get_hwaddr_size() const; + + /** + * Return interface-supplied HW address + * + * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size + * + * HW address need not be provided if this interface does not have its own HW + * address configuration; stack will choose address from central system + * configuration if the function returns false and does not write to addr. + * + * @param addr HW address for underlying interface + * @return true if HW address is available + */ + virtual bool get_hwaddr(uint8_t *addr) const; + + /** + * Set HW address for interface + * + * Provided address has to be of correct size, see @a get_hwaddr_size + * + * Called to set the MAC address to actually use - if @a get_hwaddr is provided + * the stack would normally use that, but it could be overridden, eg for test + * purposes. + * + * @param addr Address to be set + */ + virtual void set_hwaddr(const uint8_t *addr); + + /** + * Sends the packet over the link + * + * That can not be called from an interrupt context. + * + * @param buf Packet to be send + * @return True if the packet was send successfully, False otherwise + */ + virtual bool link_out(emac_mem_buf_t *buf); + + /** + * Initializes the HW + * + * @return True on success, False in case of an error. + */ + virtual bool power_up(); + + /** + * Deinitializes the HW + * + */ + virtual void power_down(); + + /** + * Sets a callback that needs to be called for packets received for that interface + * + * @param input_cb Function to be register as a callback + */ + virtual void set_link_input_cb(emac_link_input_cb_t input_cb); + + /** + * Sets a callback that needs to be called on link status changes for given interface + * + * @param state_cb Function to be register as a callback + */ + virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); + + /** Add device to a multicast group + * + * @param address A multicast group hardware address + */ + virtual void add_multicast_group(const uint8_t *address); + + /** Remove device from a multicast group + * + * @param address A multicast group hardware address + */ + virtual void remove_multicast_group(const uint8_t *address); + + /** Request reception of all multicast packets + * + * @param all True to receive all multicasts + * False to receive only multicasts addressed to specified groups + */ + virtual void set_all_multicast(bool all); + + /** Sets memory manager that is used to handle memory buffers + * + * @param mem_mngr Pointer to memory manager + */ + virtual void set_memory_manager(EMACMemoryManager &mem_mngr); + + void mx_wifi_status_changed(uint8_t cate, uint8_t status, void *arg); + void mx_wifi_netlink_input_callback(mx_buf_t *buffer); + +#define EMW3080B_HWADDR_SIZE 6 + + emac_link_input_cb_t _emac_link_input_cb; /**< Callback for incoming data */ + emac_link_state_change_cb_t _emac_link_state_cb; + emac_link_input_cb_t _emac_input_data_cb; + EMACMemoryManager *_memory_manager; + uint8_t _mac_addr[EMW3080B_HWADDR_SIZE]; + + uint8_t _debug_level; +}; + +#endif /* EMW3080B_EMAC_H_ */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_SPI.cpp b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_SPI.cpp new file mode 100644 index 0000000000..459bb928b7 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_SPI.cpp @@ -0,0 +1,409 @@ +/* + * 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 "EMW3080B_SPI.h" + +#define DEBUG_SILENT 0 +#define DEBUG_WARNING 1 +#define DEBUG_INFO 2 +#define DEBUG_LOG 3 +#define DEFAULT_DEBUG DEBUG_SILENT + +static EMW3080B_SPI *emw3080B_spi_object; + + +EMW3080B_SPI::EMW3080B_SPI(bool debug, + PinName mosi, + PinName miso, + PinName sclk, + PinName nss, + PinName notify, + PinName flow, + PinName reset + ): SPI(mosi, miso, sclk), _resetpin(reset), _nsspin(nss), _notifypin(notify), _flowpin(flow) +{ + if (debug) { + _debug_level = DEBUG_INFO; // too much real time impact with DEBUG_LOG + } else { + _debug_level = DEFAULT_DEBUG; + } + + _notify_irq = new InterruptIn(notify); + _flow_irq = new InterruptIn(flow); + + _notify_irq->rise(NULL); + _flow_irq->rise(NULL); + + emw3080B_spi_object = this; + /* MXWIFI supports 30 Mhz SPI clock but Mbed implementation is limitted to 5 Mhz */ + /* DMA implementation would be required to increase this supported frequency */ + SPI::frequency(5000000); + /* Phase 0 and One edge => mode 0 */ + SPI::format(8, 0); + + SPI::set_default_write_value(0); + + SEM_INIT(spi_transfer_done_sem, 1); +} + +int flow_rise_count = 0; +int notify_rise_count = 0; + +void EMW3080B_SPI::flow_rise() +{ + flow_rise_count++; + SEM_SIGNAL(spi_flow_rise_sem); +} + +void EMW3080B_SPI::notify_rise() +{ + notify_rise_count++; + if (SEM_SIGNAL(spi_txrx_sem) != SEM_OK) { + error("failed to signal spi_txrx_sem\n"); + } +} + + +#pragma pack(1) +typedef struct _spi_header { + uint8_t type; + uint16_t len; + uint16_t lenx; + uint8_t dummy[3]; +} spi_header_t; +#pragma pack() + + +/* Private define ------------------------------------------------------------*/ +/* SPI protocol */ +#define SPI_WRITE (0x0A) +#define SPI_READ (0x0B) +#define SPI_HEADER_SIZE (5) +#define SPI_DATA_SIZE (MX_WIFI_HCI_DATA_SIZE) + +#define SPI_WAITING_FLOW_HIGH_TIMEOUT (100) /* ms unit */ +#define SPI_MAX_TRANSMIT_DURATION (500) /* ms unit */ + + +/* SPI CS */ +#define MX_WIFI_SPI_CS_HIGH() _nsspin = 1 +#define MX_WIFI_SPI_CS_LOW() _nsspin = 0 + + + +/** + * @brief Initialize SPI + * @param None + * @retval None + */ +int8_t EMW3080B_SPI::IO_Init(uint16_t mode) +{ + int8_t ret = 0; + + if (MX_WIFI_RESET == mode) { + /* HW reset */ + MX_WIFI_SPI_CS_HIGH(); + + _resetpin = 0; + rtos::ThisThread::sleep_for(100ms); + _resetpin = 1; + rtos::ThisThread::sleep_for(1200ms); + } else { + ret = mx_wifi_spi_txrx_start(); + } + return ret; +} + + +/** + * @brief DeInitialize SPI + * @param None + * @retval None + */ +int8_t EMW3080B_SPI::IO_DeInit(void) +{ + mx_wifi_spi_txrx_stop(); + return 0; +} + +void EMW3080B_SPI::IO_Delay(uint32_t delayms) +{ + return; +} + +uint16_t EMW3080B_SPI::IO_Send(uint8_t *data, uint16_t len) +{ + if ((NULL == data) || (0 == len) || (len > SPI_DATA_SIZE)) { + return 0; + } + + spi_tx_data = data; + spi_tx_len = len; + + if (SEM_SIGNAL(spi_txrx_sem) != SEM_OK) { + /* Happen if received thread did not have a chance to run on time, need to increase priority */ + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : spi semaphore has been already notified\n"); + } + + return len; +} + + +uint16_t EMW3080B_SPI::IO_Receive(uint8_t *buffer, uint16_t buff_size) +{ + return 0U; +} + + +int8_t EMW3080B_SPI::wait_flow_high(uint32_t timeout) +{ + int8_t ret = 0; + + if (SEM_WAIT(spi_flow_rise_sem, timeout, NULL) != SEM_OK) { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : wait_flow_high semaphore failed, timeout\n"); + ret = -1; + } + + return ret; +} + +int spi_handler_count = 0; +int spi_handler_event_value = 0; + +void EMW3080B_SPI::spi_handler(int event) +{ + spi_handler_count++; + spi_handler_event_value = event; + + SEM_SIGNAL(spi_transfer_done_sem); +} + + +int32_t EMW3080B_SPI::TransmitReceive(uint8_t *txdata, uint8_t *rxdata, uint32_t datalen, + uint32_t timeout) +{ + int32_t ret = 0; + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_SPI : Spi Tx Rx %" PRIu32 "\n", datalen); + SPI::transfer((const uint8_t *) txdata, (int) datalen, rxdata, (int) datalen, callback(this, &EMW3080B_SPI::spi_handler), SPI_EVENT_COMPLETE); + if (SEM_WAIT(spi_transfer_done_sem, timeout, NULL) != SEM_OK) { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Timeout on TransmitReceive %d\n", spi_handler_count); + ret = -1; + } + + return ret; +} + + +int32_t EMW3080B_SPI::Transmit(uint8_t *txdata, uint32_t datalen, uint32_t timeout) +{ + int32_t ret = 0; + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_SPI : Spi Tx %" PRIu32 "\n", datalen); + SPI::transfer((const uint8_t *) txdata, (int) datalen, (uint8_t *)NULL, (int) datalen, callback(this, &EMW3080B_SPI::spi_handler), SPI_EVENT_COMPLETE); + if (SEM_WAIT(spi_transfer_done_sem, timeout, NULL) != SEM_OK) { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Timeout on Transmit\n"); + ret = -1; + } + return ret; +} + +int32_t EMW3080B_SPI::Receive(uint8_t *rxdata, uint32_t datalen, uint32_t timeout) +{ + int32_t ret = 0; + debug_if(_debug_level >= DEBUG_LOG, "EMW3080B_SPI : Spi Rx %" PRIu32 "\n", datalen); + SPI::transfer((const uint8_t *) NULL, (int) datalen, rxdata, (int) datalen, callback(this, &EMW3080B_SPI::spi_handler), SPI_EVENT_COMPLETE); + if (SEM_WAIT(spi_transfer_done_sem, timeout, NULL) != SEM_OK) { + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Timeout on Receive\n"); + ret = -1; + } + return ret; +} + + +void EMW3080B_SPI::process_txrx_poll(uint32_t timeout) +{ + + spi_header_t mheader, sheader; + int32_t ret; + uint8_t *txdata; + uint8_t *p = NULL; + uint16_t datalen; + static mx_buf_t *netb = NULL; + bool first_miss = true; + + MX_WIFI_SPI_CS_HIGH(); + + while (netb == NULL) { + netb = MX_NET_BUFFER_ALLOC(MX_WIFI_BUFFER_SIZE); + if (netb == NULL) { + rtos::ThisThread::sleep_for(1ms); + if (true == first_miss) { + first_miss = false; + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Running Out of buffer for RX\n"); + } + } + } + + /* waiting for data to be sent or to be received */ + if (SEM_WAIT(spi_txrx_sem, timeout, NULL) == SEM_OK) { + if (spi_tx_data == NULL) { + if (_notifypin == 0) { + /* tx data null means no data to send , _flowpin low means no data to received */ + error("EMW3080B_SPI : Nothing to process but wake UP!!!\n"); + } + txdata = NULL; + mheader.len = 0; + } else { + mheader.len = spi_tx_len; + txdata = spi_tx_data; + } + + mheader.type = SPI_WRITE; + mheader.lenx = ~mheader.len; + mheader.dummy[0] = 0; + mheader.dummy[1] = 0; + mheader.dummy[2] = 0; + + MX_WIFI_SPI_CS_LOW(); + + /* wait EMW to be ready */ + if (wait_flow_high(SPI_WAITING_FLOW_HIGH_TIMEOUT) != 0) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : wait flow high timeout, notify_rise_count %d flow_rise_count %d flow is %d\n", notify_rise_count, flow_rise_count, (int)_flowpin); + } + + /* transmit only header part */ + sheader.type = 0; + sheader.len = 0; + + if (TransmitReceive((uint8_t *)&mheader, (uint8_t *)&sheader, sizeof(mheader), SPI_MAX_TRANSMIT_DURATION)) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Send mheader error\r\n"); + } + if (sheader.type != SPI_READ) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Invalid SPI type %02x\r\n", sheader.type); + } + if ((sheader.len ^ sheader.lenx) != 0xFFFF) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Invalid len %04x-%04x\r\n", sheader.len, sheader.lenx); + } + + /* send or received header must be not null */ + if ((sheader.len == 0) && (mheader.len == 0)) { + MX_WIFI_SPI_CS_HIGH(); + return; + } + + if ((sheader.len > SPI_DATA_SIZE) || (mheader.len > SPI_DATA_SIZE)) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : SPI length invalid: %d-%d\r\n", sheader.len, mheader.len); + } + + /* keep max length */ + if (mheader.len > sheader.len) { + datalen = mheader.len; + } else { + datalen = sheader.len; + } + + /* allocate a buffer */ + if (sheader.len > 0) { + /* get payload */ + p = MX_NET_BUFFER_PAYLOAD(netb); + } else { + p = NULL; + } + + /* flow must be high */ + + if (wait_flow_high(SPI_WAITING_FLOW_HIGH_TIMEOUT) != 0) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : timeout waiting for flow high after transfer !\r\n"); + } + + /* transmit and received */ + if (NULL != txdata) { + spi_tx_data = NULL; + spi_tx_len = 0; + if (NULL != p) { + ret = TransmitReceive(txdata, p, datalen, SPI_MAX_TRANSMIT_DURATION); + } else { + ret = Transmit(txdata, datalen, SPI_MAX_TRANSMIT_DURATION); + } + } else { + ret = Receive(p, datalen, SPI_MAX_TRANSMIT_DURATION); + } + + if (ret) { + MX_WIFI_SPI_CS_HIGH(); + debug_if(_debug_level >= DEBUG_WARNING, "EMW3080B_SPI : Transmit/Receive data timeout\r\n"); + } + + /* resize the input buffer and sent it back to processing thread */ + if (sheader.len > 0) { + MX_NET_BUFFER_SET_PAYLOAD_SIZE(netb, sheader.len); + mx_wifi_hci_input(netb); + netb = NULL; + + } + MX_WIFI_SPI_CS_HIGH(); + + } +} + +void mx_wifi_spi_txrx_task(void) +{ + while (1) { + emw3080B_spi_object->process_txrx_poll(WAIT_FOREVER); + } +} + +int8_t EMW3080B_SPI::mx_wifi_spi_txrx_start(void) +{ + int8_t ret = 0; + + SEM_INIT(spi_txrx_sem, 2); + SEM_INIT(spi_flow_rise_sem, 1); + SEM_INIT(spi_transfer_done_sem, 1); + _notify_irq->rise(callback(this, &EMW3080B_SPI::notify_rise)); + _flow_irq->rise(callback(this, &EMW3080B_SPI::flow_rise)); + + if (THREAD_OK == THREAD_INIT(MX_WIFI_TxRxThreadId, + mx_wifi_spi_txrx_task, NULL, + MX_WIFI_SPI_THREAD_STACK_SIZE, + MX_WIFI_SPI_THREAD_PRIORITY)) { + ret = 0; + } else { + ret = -1; + } + + return ret; +} + +int8_t EMW3080B_SPI::mx_wifi_spi_txrx_stop(void) +{ + + THREAD_DEINIT(MX_WIFI_TxRxThreadId); + _notify_irq->rise(NULL); + _flow_irq->rise(NULL); + SEM_DEINIT(spi_txrx_sem); + SEM_DEINIT(spi_flow_rise_sem); + SEM_DEINIT(spi_transfer_done_sem); + return 0; +} diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_SPI.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_SPI.h new file mode 100644 index 0000000000..f7c00fe158 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_SPI.h @@ -0,0 +1,85 @@ +/* + * 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 ------------------------------------------------------------------*/ +#include + +/* Private includes ----------------------------------------------------------*/ +#include "mbed.h" +#include "mbed_debug.h" +#include "mbed_error.h" +#include "mx_wifi.h" +#include "core/mx_wifi_hci.h" + + + +class EMW3080B_SPI : public SPI { +public: + EMW3080B_SPI(bool debug = MBED_CONF_EMW3080B_WIFI_DEBUG, + PinName mosi = MBED_CONF_EMW3080B_WIFI_MOSI, + PinName miso = MBED_CONF_EMW3080B_WIFI_MISO, + PinName sclk = MBED_CONF_EMW3080B_WIFI_SCLK, + PinName nss = MBED_CONF_EMW3080B_WIFI_NSS, + PinName notify = MBED_CONF_EMW3080B_WIFI_NOTIFY, + PinName flow = MBED_CONF_EMW3080B_WIFI_FLOW, + PinName reset = MBED_CONF_EMW3080B_WIFI_RESET + ); + +private: + DigitalOut _resetpin; + DigitalOut _nsspin; + + DigitalIn _notifypin; + DigitalIn _flowpin; + + InterruptIn *_notify_irq; + InterruptIn *_flow_irq; + + void flow_rise(void); + void notify_rise(void); + int8_t wait_flow_high(uint32_t timeout); + + SEM_DECLARE(spi_txrx_sem); + SEM_DECLARE(spi_flow_rise_sem); + SEM_DECLARE(spi_transfer_done_sem); + + uint8_t *spi_tx_data = NULL; + uint16_t spi_tx_len = 0; + + int32_t TransmitReceive(uint8_t *txdata, uint8_t *rxdata, uint32_t datalen, uint32_t timeout); + int32_t Transmit(uint8_t *txdata, uint32_t datalen, uint32_t timeout); + int32_t Receive(uint8_t *rxdata, uint32_t datalen, uint32_t timeout); + void spi_handler(int event); + + int8_t mx_wifi_spi_txrx_start(void); + int8_t mx_wifi_spi_txrx_stop(void); + + THREAD_DECLARE(MX_WIFI_TxRxThreadId); + + +public: + + int8_t IO_Init(uint16_t mode); + int8_t IO_DeInit(void); + void IO_Delay(uint32_t delayms); + uint16_t IO_Send(uint8_t *data, uint16_t len); + uint16_t IO_Receive(uint8_t *buffer, uint16_t buff_size); + void process_txrx_poll(uint32_t timeout); + + uint8_t _debug_level; +}; diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_UART.cpp b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_UART.cpp new file mode 100644 index 0000000000..a91c30178a --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_UART.cpp @@ -0,0 +1,144 @@ +/* + * 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 "EMW3080B_UART.h" + +#define DEBUG_SILENT 0 +#define DEBUG_WARNING 1 +#define DEBUG_INFO 2 +#define DEBUG_LOG 3 +#define DEFAULT_DEBUG DEBUG_SILENT + +//#define DEBUG_UART_DATA 1 + +static EMW3080B_UART *emw3080b_uart_object; + + +EMW3080B_UART::EMW3080B_UART(bool debug, + PinName tx, + PinName rx, + PinName reset + ): BufferedSerial(tx, rx, 230400), _resetpin(reset) +{ + emw3080b_uart_object = this; + + if (debug) { + _debug_level = DEBUG_LOG; + } else { + _debug_level = DEFAULT_DEBUG; + } +} + +#if DEBUG_UART_DATA +void debug_print(char *prefix, uint8_t *data, uint16_t len); +void debug_print(char *prefix, uint8_t *data, uint16_t len) +{ + if (NULL != data) { + printf("%s[%d]:\n", prefix, len); + for (int32_t i = 0; i < len; i++) { + printf(" %02x", data[i]); + } + printf("\n"); + for (int32_t i = 0; i < len; i++) { + printf(" %c ", data[i]); + } + printf("\n"); + } +} +#else +#define debug_print(...) +#endif /* DEBUG_UART_DATA */ + + +void EMW3080B_UART::process_txrx_poll(void) +{ + uint8_t c; + ssize_t n; + mx_buf_t *nbuf = NULL; + + n = read(&c, 1); + if (n == 1) { + nbuf = slip_input_byte(c); + if (NULL != nbuf) { + debug_print("URX", MX_NET_BUFFER_PAYLOAD(nbuf), MX_NET_BUFFER_GET_PAYLOAD_SIZE(nbuf)); + mx_wifi_hci_input(nbuf); + } + } +} + + +void HWInterfaceReceivedPollTask(void) +{ + while (true) { + emw3080b_uart_object->process_txrx_poll(); + } +} + + + +int8_t EMW3080B_UART::IO_Init(uint16_t mode) +{ + int8_t rc = 0; + + if (MX_WIFI_RESET == mode) { + /* HW reset */ + _resetpin = 0; + rtos::ThisThread::sleep_for(100ms); + _resetpin = 1; + rtos::ThisThread::sleep_for(1200ms); + } else { + + if (THREAD_OK == THREAD_INIT(MX_WIFI_UARTRecvThreadId, + HWInterfaceReceivedPollTask, NULL, + MX_WIFI_UART_THREAD_STACK_SIZE, MX_WIFI_UART_THREAD_PRIORITY)) { + rc = MX_WIFI_STATUS_OK; + } else { + rc = MX_WIFI_STATUS_ERROR; + } + } + return rc; +} + + +int8_t EMW3080B_UART::IO_DeInit(void) +{ + int8_t rc = 0; + THREAD_DEINIT(MX_WIFI_UARTRecvThreadId); + return rc; +} + +void EMW3080B_UART::IO_Delay(uint32_t delayms) +{ + printf("%s %d\n", __FILE__, __LINE__); + return; +} + +uint16_t EMW3080B_UART::IO_Send(uint8_t *pdata, uint16_t len) +{ + uint16_t rc; + debug_print("UTX", pdata, len); + rc = write(pdata, len); + return rc; +} + +uint16_t EMW3080B_UART::IO_Receive(uint8_t *pdata, uint16_t request_len) +{ + return 0; +} diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_UART.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_UART.h new file mode 100644 index 0000000000..05d80f171a --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/EMW3080B_UART.h @@ -0,0 +1,53 @@ +/* + * 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 "mbed.h" +#include "mbed_debug.h" +#include "mbed_error.h" +#include "mx_wifi.h" +#include "core/mx_wifi_hci.h" +#include "core/mx_wifi_slip.h" + + + +class EMW3080B_UART : public BufferedSerial { +public: + EMW3080B_UART(bool debug, + PinName tx, + PinName rx, + PinName reset + ); + +private: + DigitalOut _resetpin; + THREAD_DECLARE(MX_WIFI_UARTRecvThreadId); + + +public: + void process_txrx_poll(void); + + int8_t IO_Init(uint16_t mode); + int8_t IO_DeInit(void); + void IO_Delay(uint32_t delayms); + uint16_t IO_Send(uint8_t *data, uint16_t len); + uint16_t IO_Receive(uint8_t *buffer, uint16_t buff_size); + + uint8_t _debug_level; +}; diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/README.md b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/README.md new file mode 100644 index 0000000000..0241ce9d02 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/README.md @@ -0,0 +1,146 @@ +# EMW3080B WiFi driver for STM32 + +## License + +This software is licensed under terms that can be found in the [license](mx_wifi/LICENSE.md) file + + +## Currently supported platforms + +EMW3080B module is available + +- with an [ARDUINO extension board](https://www.seeedstudio.com/IOT-AT3080-IoT-development-board-p-4021.html) + +- with a ST Discovery kit for IoT node : [B-U585I-IOT02A](https://os.mbed.com/platforms/ST-Discovery-B-U585I-IOT02A/) + + +## Configuration + +B_U585I_IOT02A default configuration is enabled in [mbed_lib.json](mbed_lib.json) + +For Arduino shield, the UART interface is used. +See in mbed_lib.json, B_U585I_IOT02A__ARDUINO_SHIELD configuration example you need to add in your local mbed_app.json. + +``` + "YOUR_TARGET": { + "emw3080b.wifi-spi-interface": false, + "emw3080b.wifi-tx": "ARDUINO_UNO_D1", + "emw3080b.wifi-rx": "ARDUINO_UNO_D0", + "emw3080b.wifi-reset": "ARDUINO_UNO_D13", + "emw3080b.provide-default": true + }, +``` + +## Code Structure + +The Mbed EMW3080B driver relies on the [STM32 EMW3080B BSP driver](https://github.com/STMicroelectronics/STM32CubeU5/tree/main/Drivers/BSP/Components/mx_wifi) + +- COMPONENT_emw3080b/EMW3080BInterface.cpp : WiFiInterface class implementation (derived from EMACInterface ) +- COMPONENT_emw3080b/EMW3080B_EMAC.cpp : EMAC interface +- COMPONENT_emw3080b/EMW3080B_SPI.cpp : SPI communication protocol implementation +- COMPONENT_emw3080b/EMW3080B_UART.cpp : UART communication protocol implementation +- COMPONENT_emw3080b/mx_wifi/* : [STM32 EMW3080B BSP driver](https://github.com/STMicroelectronics/STM32CubeU5/tree/main/Drivers/BSP/Components/mx_wifi) + + +## Debug + +Some debug print on console can help to debug if necessary. + +Either update your mbed_app.json: +``` + "YOUR_TARGET": { + "emw3080b.wifi-debug": true + }, +``` + +Either update manually the different .cpp source files to choose the appropriate level of VERBOSITY. + +`#define DEFAULT_DEBUG DEBUG_SILENT` ==> choose DEBUG_WARNING/DEBUG_INFO/DEBUG_LOG + +NB: in file "EMW3080B_SPI.cpp", DEBUG_LOG may have side effect due to real time issue. + + +## Validation + +- netsocket tests: https://github.com/ARMmbed/mbed-os/tree/master/connectivity/netsocket/tests/TESTS/netsocket + +- network-wifi tests: https://github.com/ARMmbed/mbed-os/tree/master/connectivity/netsocket/tests/TESTS/network/wifi + + +## Open point + + +TODO: netbuffer allocator feedback to choose appropriate memory mngt (copy or not) and fix concern regarding potential race when starting EMACinterface. + +## Limitations + +Performance of SPI limitted to 5Mhz. + + +## Firmware version & firmware update + +The recommended firmware version is V2.1.11 + +NB: with older FW version, you could get an assert: +``` +++ MbedOS Error Info ++ +Error Status: 0x80FF0100 Code: 256 Module: 255 +Error Message: Fatal Run-time error +Location: 0x801CB73 +Error Value: 0xFFFFFFFE +Current Thread: lwip_tcpip Id: 0x20006058 Entry: 0x802064D StackSize: 0x4B0 StackMem: 0x20006698 SP: 0x20006ACC +For more info, visit: https://mbed.com/s/error?error=0x8003010D&tgt=B_U585I_IOT02A +-- MbedOS Error Info -- +EMW3080BInterface : MX_WIFI_Init failed, you may have to update MXCHIP fimrware module to version 2.1.11 +``` + +### How to get FW version ? + +Enable DEBUG_INFO in EMW3080BInterface.cpp + +``` +EMW3080BInterface : Product name: MXCHIP-WIFI +EMW3080BInterface : Product ID: EMW3080B +EMW3080BInterface : FW revision: V2.1.11 +``` + + +### How to upgrade FW for B_U585I_IOT02A ? + +Latest FW binary is provided in: + +https://www.st.com/en/development-tools/x-wifi-emw3080b.html#get-software + +Start TeraTerm (115200) + +Drag and drop `EMW3080updateV2.1.11RevC.bin` into `NOD_U585AI`drive + +You should get: +``` +################### Welcome to EMW3080 firmware update utility 1.0.0 for board RevB or RevC ################### + +STM32>Configured for MXchip embedded FW ST-EMW3080B_V2.1.11_SPI.OTA.BIN 0x8000234 / 546080 bytes +STM32>Don't forget to connect EMW3080 Boot to GND thanks to switch SW2 , move it to position "0" (instead of NC) to have boot loader running ! +STM32>Push user button (Blue) to flash EMW3080 device or enter command +STM32>MCU system clock 160 MHz , Uart Baud rate 921600 , Software emulated UART bit duration 173 cycles + + +" help" print this message +" boot" Boot EMW3080 (needed before using mx command) +" mx" mx [cmd] : send command to mxchip device (can not use cmd which require ymodem protocol) +" flash" flash mxchip firmware (same as pushing blue button) +" check" check mxchip firmware +STM32> +``` + +- on switch SW2 (with 2 white switches), move BOOT one (Id 1) from NC to O position +- press blue button (User B3) + +Wait till: +``` +STM32>Flash successfull, move back switch to original position, reset the device to get back to prompt +``` + +So: +- move switch back to postion NC +- Reset diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mbed_lib.json b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mbed_lib.json new file mode 100644 index 0000000000..c6238780cd --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mbed_lib.json @@ -0,0 +1,73 @@ +{ + "name": "emw3080b", + "config": { + "wifi-spi-interface": { + "help": "SPI interface if true / UART interface if false", + "value": "NC" + }, + "wifi-miso": { + "help": "SPI-MISO connection to external device", + "value": "NC" + }, + "wifi-mosi": { + "help": "SPI-MOSI connection to external device", + "value": "NC" + }, + "wifi-sclk": { + "help": "SPI-CLOCK connection to external device", + "value": "NC" + }, + "wifi-nss": { + "help": "SPI chip select of external device", + "value": "NC" + }, + "wifi-notify": { + "help": "EMW3080B notify from externam device", + "value": "NC" + }, + "wifi-flow": { + "help": "EMW3080B flow from externam device", + "value": "NC" + }, + "wifi-reset": { + "help": "EMW3080B reset to external device", + "value": "NC" + }, + "wifi-tx": { + "help": "EMW3080B uart tx to external device", + "value": "NC" + }, + "wifi-rx": { + "help": "EMW3080B uart rx from external device", + "value": "NC" + }, + "wifi-debug": { + "help": "Defines whether logging is on or off", + "value": false + }, + "provide-default": { + "help": "Provide default WifiInterface. [true/false]", + "value": false + } + }, + "target_overrides": { + "B_U585I_IOT02A": { + "wifi-spi-interface": true, + "wifi-miso": "PD_3", + "wifi-mosi": "PD_4", + "wifi-sclk": "PD_1", + "wifi-nss": "PB_12", + "wifi-notify": "PD_14", + "wifi-flow": "PG_15", + "wifi-reset": "PF_15", + "provide-default": true + }, + "B_U585I_IOT02A__ARDUINO_SHIELD": { + "wifi-spi-interface": false, + "wifi-tx": "ARDUINO_UNO_D1", + "wifi-rx": "ARDUINO_UNO_D0", + "wifi-reset": "ARDUINO_UNO_D13", + "provide-default": true + } + } +} diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/LICENSE.md b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/LICENSE.md new file mode 100644 index 0000000000..1af5233078 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/LICENSE.md @@ -0,0 +1,80 @@ +SLA0044 Rev5/February 2018 + +## Software license agreement + +### __ULTIMATE LIBERTY SOFTWARE LICENSE AGREEMENT__ + +BY INSTALLING, COPYING, DOWNLOADING, ACCESSING OR OTHERWISE USING THIS SOFTWARE +OR ANY PART THEREOF (AND THE RELATED DOCUMENTATION) FROM STMICROELECTRONICS +INTERNATIONAL N.V, SWISS BRANCH AND/OR ITS AFFILIATED COMPANIES +(STMICROELECTRONICS), THE RECIPIENT, ON BEHALF OF HIMSELF OR HERSELF, OR ON +BEHALF OF ANY ENTITY BY WHICH SUCH RECIPIENT IS EMPLOYED AND/OR ENGAGED AGREES +TO BE BOUND BY THIS SOFTWARE LICENSE AGREEMENT. + +Under STMicroelectronics’ intellectual property rights, the redistribution, +reproduction and use in source and binary forms of the software or any part +thereof, with or without modification, are permitted provided that the following +conditions are met: + +1. Redistribution of source code (modified or not) must retain any copyright +notice, this list of conditions and the disclaimer set forth below as items 10 +and 11. + +2. Redistributions in binary form, except as embedded into microcontroller or +microprocessor device manufactured by or for STMicroelectronics or a software +update for such device, must reproduce any copyright notice provided with the +binary code, this list of conditions, and the disclaimer set forth below as +items 10 and 11, in documentation and/or other materials provided with the +distribution. + +3. Neither the name of STMicroelectronics nor the names of other contributors to +this software may be used to endorse or promote products derived from this +software or part thereof without specific written permission. + +4. This software or any part thereof, including modifications and/or derivative +works of this software, must be used and execute solely and exclusively on or in +combination with a microcontroller or microprocessor device manufactured by or +for STMicroelectronics. + +5. No use, reproduction or redistribution of this software partially or totally +may be done in any manner that would subject this software to any Open Source +Terms. “Open Source Terms” shall mean any open source license which requires as +part of distribution of software that the source code of such software is +distributed therewith or otherwise made available, or open source license that +substantially complies with the Open Source definition specified at +www.opensource.org and any other comparable open source license such as for +example GNU General Public License (GPL), Eclipse Public License (EPL), Apache +Software License, BSD license or MIT license. + +6. STMicroelectronics has no obligation to provide any maintenance, support or +updates for the software. + +7. The software is and will remain the exclusive property of STMicroelectronics +and its licensors. The recipient will not take any action that jeopardizes +STMicroelectronics and its licensors' proprietary rights or acquire any rights +in the software, except the limited rights specified hereunder. + +8. The recipient shall comply with all applicable laws and regulations affecting +the use of the software or any part thereof including any applicable export +control law or regulation. + +9. Redistribution and use of this software or any part thereof other than as +permitted under this license is void and will automatically terminate your +rights under this license. + +10. THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS, WHICH ARE +DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT SHALL +STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +11. EXCEPT AS EXPRESSLY PERMITTED HEREUNDER, NO LICENSE OR OTHER RIGHTS, WHETHER +EXPRESS OR IMPLIED, ARE GRANTED UNDER ANY PATENT OR OTHER INTELLECTUAL PROPERTY +RIGHTS OF STMICROELECTRONICS OR ANY THIRD PARTY. diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/checksumutils.c b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/checksumutils.c new file mode 100644 index 0000000000..4af620d084 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/checksumutils.c @@ -0,0 +1,266 @@ +/** + ****************************************************************************** + * @file checksum_utils.c + * @author MCD Application Team + * @brief Host driver checksum utils of MXCHIP Wi-Fi component. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include "stdio.h" +/*cstat +MISRAC2012-* */ + +#include "checksumutils.h" + +#ifdef CHECKSUM_DEBUG +#define DEBUG_LOG printf +#else +#define DEBUG_LOG +#endif /* CHECKSUM_DEBUG */ + +#ifdef USE_STM32L_CRC + +/* User-defined polynomial */ +#define CRC_POLYNOMIAL_16B 0x1021 /* X^16 + X^12 + X^5 + 1, CRC-CCITT generating polynomial */ + +/* User-defined CRC init value */ +/* As the CRC is 16-bit long, the init value is 16-bit long as well */ +#define CRC_INIT_VALUE 0x0000 /* 0x5AB */ + +#endif /* USE_STM32L_CRC */ + +static uint8_t UpdateCRC8(uint8_t crcIn, uint8_t byte); + +static uint8_t UpdateCRC8(uint8_t crcIn, uint8_t byte) +{ + uint8_t crc = crcIn; + uint8_t i; + + crc ^= byte; + + for (i = 0; i < (uint8_t)8; i++) + { + if ((crc & (uint8_t)0x01) > 0u) + { + crc = (crc >> 1) ^ (uint8_t)0x8C; + } + else + { + crc >>= 1; + } + } + return crc; +} + + +void CRC8_Init(CRC8_Context *inContext) +{ + inContext->crc = 0; +} + + +void CRC8_Update(CRC8_Context *inContext, const uint8_t *inSrc, size_t inLen) +{ + const uint8_t *src = (const uint8_t *) inSrc; + const uint8_t *srcEnd = &(src[inLen]); + while (src < srcEnd) + { + inContext->crc = UpdateCRC8(inContext->crc, *src); + src++; + } +} + + +void CRC8_Final(CRC8_Context *inContext, uint8_t *outResult) +{ + *outResult = inContext->crc & 0xffu; +} + + +/*************************************CRC16******************************************/ + +#ifdef USE_STM32L_CRC +/** + * @brief CRC16 init function + */ +int8_t HW_CRC16_Init(CRC_HandleTypeDef *CrcHandle) +{ + /****************************************************************************/ + /* */ + /* CRC peripheral initialization */ + /* */ + /****************************************************************************/ + + if (NULL == CrcHandle) + { + DEBUG_LOG("*** CRC16_Init: CrcHandle null error!\n"); + return -1; + } + + CrcHandle->Instance = CRC; + + /* The default polynomial is not used. The one to be used must be defined + in CrcHandle.Init.GeneratingPolynomial */ + CrcHandle->Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; + + /* Set the value of the generating polynomial. + The one used in that example is the 16-bit long CRC generating + polynomial X^16 + X^12 + X^5 + 1 */ + CrcHandle->Init.GeneratingPolynomial = CRC_POLYNOMIAL_16B; + + /* The user-defined generating polynomial yields a 16-bit long CRC */ + CrcHandle->Init.CRCLength = CRC_POLYLENGTH_16B; + + /* The default init value is not used */ + CrcHandle->Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE; + + /* User init value is used instead */ + CrcHandle->Init.InitValue = CRC_INIT_VALUE; + + /* The input data are inverted by word */ + CrcHandle->Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; + /* The bit reversal is done on a full word basis. + + The input stream yielded by CRC16_DATA8[] is the sequence of + bytes 0x4D, 0x3C, 0x2B, 0x1A, 0xBE, 0x71, ... + meaning that the first word written in the CRC DR register is + 0x4D3C2B1A. + + Bit reversal done by the hardware on the full word leads to the actual + CRC processing of + 0x58D43CB2. + + Similarly, the second word written in the peripheral is 0xBE71C98A, leading to + the processing of 0x51938E7D after hardware input data reversal. + + Note that when the software writes less than a word in the peripheral (to minimize the + number of write accesses for a given number of bytes), the bit-reversal operation + is carried out only on the inputted data. + Therefore, the last written data is the last byte 0x5E, processed as 0x7A + by the hardware after bit-reversal to wrap-up the CRC computation. + + This means that the field InputDataInversionMode set to CRC_INPUTDATA_INVERSION_WORD + applied to {0x4D, 0x3C, 0x2B, 0x1A, 0xBE, 0x71, 0xC9, 0x8A, 0x5E} + yields the same result as InputDataInversionMode set to CRC_INPUTDATA_INVERSION_NONE + applied to {0x58, 0xD4, 0x3C, 0xB2, 0x51, 0x93, 0x8E, 0x7D, 0x7A}. + + */ + + /* The output data are inverted */ + CrcHandle->Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; + /* Output data reversal can only be done at bit level. + The expected CRC is 0x5043 after output data reversal, meaning + that the CRC before the reversal operation is 0xC20A. */ + + /* The input data are bytes (8-bit long data) */ + CrcHandle->InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; + + /* De-initialize the CRC peripheral */ + if (HAL_CRC_DeInit(CrcHandle) != HAL_OK) + { + /* Initialization Error */ + DEBUG_LOG("*** CRC16_Init: HAL_CRC_DeInit error!\n"); + return -1; + } + + /* Then, initialize the CRC handle */ + if (HAL_CRC_Init(CrcHandle) != HAL_OK) + { + /* Initialization Error */ + DEBUG_LOG("*** CRC16_Init: HAL_CRC_Init error!\n"); + return -1; + } + + return 0; /* init success */ +} + +int8_t HW_CRC16_Update(CRC_HandleTypeDef *CrcHandle, uint8_t *input_data, uint32_t input_len, uint16_t *crc16_out) +{ + /****************************************************************************/ + /* */ + /* CRC computation */ + /* */ + /****************************************************************************/ + + /* Used for storing CRC Value */ + __IO uint32_t uwCRCValue = 0; + + if (NULL == CrcHandle) + { + DEBUG_LOG("*** CRC16_Update: CrcHandle null error!\n"); + return -1; + } + + /* The 16-bit long CRC of the 9-byte buffer is computed. After peripheral initialization, + the CRC calculator is initialized with the user-defined value that is 0x5ABE. + + The computed CRC is stored in uint32_t uwCRCValue. The 16-bit long CRC is made of + uwCRCValue 16 LSB bits. */ + + uwCRCValue = HAL_CRC_Accumulate(CrcHandle, (uint32_t *)input_data, input_len); + *crc16_out = (uint16_t)(uwCRCValue & 0x0000FFFF); + + return 0; +} + +#else /* SOFTWARE CRC16 */ + +static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte) +{ + uint32_t crc = crcIn; + uint32_t in = (uint32_t)byte | (uint32_t)0x100; + + do + { + crc <<= 1; + in <<= 1; + if ((in & (uint32_t)0x100) > 0u) + { + ++crc; + } + if ((crc & (uint32_t)0x10000) > 0u) + { + crc ^= (uint32_t)0x1021; + } + } while (!((in & (uint32_t)0x10000) > 0u)); + return (uint16_t)(crc & (uint32_t)0xffffu); +} + +void CRC16_Init(CRC16_Context *inContext) +{ + inContext->crc = 0; +} + + +void CRC16_Update(CRC16_Context *inContext, const uint8_t *inSrc, size_t inLen) +{ + const uint8_t *src = (const uint8_t *) inSrc; + const uint8_t *srcEnd = &(src[inLen]); + while (src < srcEnd) + { + inContext->crc = UpdateCRC16(inContext->crc, *src); + src++; + } +} + + +void CRC16_Final(CRC16_Context *inContext, uint16_t *outResult) +{ + inContext->crc = UpdateCRC16(inContext->crc, 0); + inContext->crc = UpdateCRC16(inContext->crc, 0); + *outResult = inContext->crc & 0xffffu; +} + +#endif /* USE_STM32L_CRC */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/checksumutils.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/checksumutils.h new file mode 100644 index 0000000000..62fc0ad6e3 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/checksumutils.h @@ -0,0 +1,142 @@ +/** + ****************************************************************************** + * @file checksumutils.h + * @author MCD Application Team + * @brief Header for checksumutils.c module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef CHECKSUM_UTILS_H +#define CHECKSUM_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include +#include +/*cstat +MISRAC2012-* */ + + +/* NOTE: MUST ENABLE STM32L HARDWARE CRC periph before use this API +#define USE_STM32L_CRC + */ + +#ifdef USE_STM32L_CRC +/*cstat -MISRAC2012-* */ +#include "stm32l4xx_hal.h" +/*cstat +MISRAC2012-* */ +#endif /* USE_STM32L_CRC */ + + +/********************* CRC8 MXOS Check ************************************** + ******************CRC-8 XMODEM x8+x5+x4+1****************************** + ****************************************************************************/ + +typedef struct +{ + uint8_t crc; +} CRC8_Context; + +/** + * @brief initialize the CRC8 Context + * + * @param inContext holds CRC8 result + * + * @retval none + */ +void CRC8_Init(CRC8_Context *inContext); + + +/** + * @brief Calculate the CRC8 result + * + * @param inContext holds CRC8 result during calculation process + * @param inSrc input data + * @param inLen length of input data + * + * @retval none + */ +void CRC8_Update(CRC8_Context *inContext, const uint8_t *inSrc, size_t inLen); + + +/** + * @brief output CRC8 result + * + * @param inContext holds CRC8 result + * @param outResutl holds CRC8 final result + * + * @retval none + */ +void CRC8_Final(CRC8_Context *inContext, uint8_t *outResult); + + +/********************* CRC16 MXOS Check ************************************** + ******************CRC-16/XMODEM x16+x12+x5+1****************************** + ******************************************************************************/ + +#ifdef USE_STM32L_CRC + +int8_t HW_CRC16_Init(CRC_HandleTypeDef *CrcHandle); +int8_t HW_CRC16_Update(CRC_HandleTypeDef *CrcHandle, uint8_t *input_data, uint32_t input_len, uint16_t *crc16_out); + +#else + +typedef struct +{ + uint16_t crc; +} CRC16_Context; + +/** + * @brief initialize the CRC16 Context + * + * @param inContext holds CRC16 result + * + * @retval none + */ +void CRC16_Init(CRC16_Context *inContext); + + +/** + * @brief Calculate the CRC16 result + * + * @param inContext holds CRC16 result during calculation process + * @param inSrc input data + * @param inLen length of input data + * + * @retval none + */ +void CRC16_Update(CRC16_Context *inContext, const uint8_t *inSrc, size_t inLen); + + +/** + * @brief output CRC16 result + * + * @param inContext holds CRC16 result + * @param outResutl holds CRC16 final result + * + * @retval none + */ +void CRC16_Final(CRC16_Context *inContext, uint16_t *outResult); + +#endif /* USE_STM32L_CRC */ + + +#ifdef __cplusplus +} +#endif + +#endif /* CHECKSUM_UTILS_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_rtos_abs.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_rtos_abs.h new file mode 100644 index 0000000000..3c68e209d7 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_rtos_abs.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * @file mx_rtos_abs.h + * @author MCD Application Team + * @brief Header for mx_wifi.c module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_RTOS_ABS_H +#define MX_RTOS_ABS_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Includes ------------------------------------------------------------------*/ +#include "mx_wifi_conf.h" +#include "stdlib.h" +#include "stddef.h" + + +#if MX_WIFI_USE_CMSIS_OS + +#else + + +#endif /* MX_WIFI_USE_CMSIS_OS */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MX_RTOS_ABS_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_hci.c b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_hci.c new file mode 100644 index 0000000000..69cbab1e0f --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_hci.c @@ -0,0 +1,182 @@ +/** + ****************************************************************************** + * @file mx_wifi_hci.c + * @author MCD Application Team + * @brief Host driver HCI protocol of MXCHIP Wi-Fi component. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include "stdlib.h" +/*cstat +MISRAC2012-* */ +#include + +#include "mx_wifi_conf.h" +#include "mx_wifi_hci.h" +#include "mx_wifi_slip.h" +#include "checksumutils.h" + +#ifdef MX_WIFI_HCI_DEBUG +#define DEBUG_LOG(M, ...) printf((M), ##__VA_ARGS__) +#else +#define DEBUG_LOG(M, ...) +#endif /* MX_WIFI_HCI_DEBUG */ + +#define DEBUG_ERROR(M, ...) printf((M), ##__VA_ARGS__) + +/* Private defines -----------------------------------------------------------*/ + +/* Private function prototypes -----------------------------------------------*/ + +/* HCI low level function */ +static hci_send_func_t tcl_output = NULL; +/* HCI recv data queue */ +static FIFO_DECLARE(hci_pkt_fifo); + +static bool mx_wifi_hci_pkt_verify(uint8_t *data, uint16_t len); + + +/* Private functions ---------------------------------------------------------*/ +static bool mx_wifi_hci_pkt_verify(uint8_t *data, uint16_t len) +{ + /* here each uart slip frame or spi frame as a hci packet */ + return true; +} + + +/* Global functions ----------------------------------------------------------*/ +int32_t mx_wifi_hci_init(hci_send_func_t low_level_send) +{ + int32_t ret = 0; + + tcl_output = low_level_send; + + if (0 == ret) + { + FIFO_INIT(hci_pkt_fifo, MX_WIFI_MAX_RX_BUFFER_COUNT); + } + + return ret; +} + +int32_t mx_wifi_hci_deinit(void) +{ + FIFO_DEINIT(hci_pkt_fifo); + return 0; +} + +int32_t mx_wifi_hci_send(uint8_t *payload, uint16_t len) +{ + int32_t ret = 0; + uint16_t sent = 0; + +#if MX_WIFI_USE_SPI + sent = tcl_output(payload, len); + if (len != sent) + { + DEBUG_ERROR("tcl_output(spi) error sent=%d !\n", sent); + ret = -1; + } + else + { + ret = 0; + } +#else + uint8_t *slip_frame = NULL; + uint16_t slip_len = 0; + + slip_frame = slip_transfer(payload, len, &slip_len); + if ((NULL != slip_frame) && (slip_len > 0)) + { + sent = tcl_output(slip_frame, slip_len); + if (slip_len == sent) + { + ret = 0; + } + else + { + DEBUG_ERROR("tcl_output(uart) error sent=%d !\r\n", sent); + ret = -1; + } + + MX_WIFI_FREE(slip_frame); + slip_frame = NULL; + } + else + { + DEBUG_ERROR("create slip frame error!\r\n"); + ret = -2; + } +#endif /* MX_WIFI_USE_SPI */ + + return ret; +} + +void process_txrx_poll(uint32_t timeout); + +mx_buf_t *mx_wifi_hci_recv(uint32_t timeout) +{ + mx_buf_t *nbuf; + nbuf = (mx_buf_t*) FIFO_POP(hci_pkt_fifo, timeout, process_txrx_poll); + if (nbuf != NULL) + { + MX_STAT(out_fifo); + } + return nbuf; +} + +void mx_wifi_hci_free(mx_buf_t *nbuf) +{ + if (NULL != nbuf) + { + (void) MX_NET_BUFFER_FREE(nbuf); + } +} + + +/** + * @brief LOW LEVEL INTERFACE + */ +void mx_wifi_hci_input(mx_buf_t *netbuf) +{ + if (NULL != netbuf) + { + uint8_t *data = MX_NET_BUFFER_PAYLOAD(netbuf); + uint32_t len = MX_NET_BUFFER_GET_PAYLOAD_SIZE(netbuf); + + if ((NULL != data) && (len > 0)) + { + if (mx_wifi_hci_pkt_verify(data, len)) + { + if (FIFO_OK != FIFO_PUSH(hci_pkt_fifo, netbuf, WAIT_FOREVER, NULL)) + { + DEBUG_ERROR("push tcl input queue err!\n"); + MX_NET_BUFFER_FREE(netbuf); + } + else + { + DEBUG_LOG("\nhci input len %"PRIu32" nbuf : %p\n", len, netbuf); + MX_STAT(in_fifo); + } + } + else + { + DEBUG_LOG("input bad tcl pkt!\n"); + MX_NET_BUFFER_FREE(netbuf); + } + } + } +} + diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_hci.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_hci.h new file mode 100644 index 0000000000..1744587f4e --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_hci.h @@ -0,0 +1,77 @@ +/** + ****************************************************************************** + * @file mx_wifi_hci.h + * @author MCD Application Team + * @brief Header for mx_wifi_hci.c module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_HCI_H +#define MX_WIFI_HCI_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include "stdint.h" +#include "string.h" +#include "stdbool.h" +#include "stdio.h" +/*cstat +MISRAC2012-* */ + +#include "mx_wifi_ipc.h" + +/** + * @brief CONFIGURATIONS + */ +/* #define MX_WIFI_HCI_DEBUG */ + +/** + * @brief HCI PACKET + */ +#define MX_WIFI_HCI_DATA_SIZE (MIPC_PKT_MAX_SIZE) + +/** + * @brief PROTOTYPES + */ +typedef struct _hci_pkt_s +{ + uint16_t len; + uint8_t *data; +} hci_pkt_t; + +typedef uint16_t (*hci_send_func_t)(uint8_t *data, uint16_t size); + +/** + * @brief API + */ +int32_t mx_wifi_hci_init(hci_send_func_t low_level_send); +int32_t mx_wifi_hci_send(uint8_t *payload, uint16_t len); +mx_buf_t *mx_wifi_hci_recv(uint32_t timeout); +void mx_wifi_hci_free(mx_buf_t *nbuf); +int32_t mx_wifi_hci_deinit(void); + +/** + * @brief LOW LEVEL INTERFACE + */ +void mx_wifi_hci_input(mx_buf_t *netbuf); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MX_WIFI_HCI_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_ipc.c b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_ipc.c new file mode 100644 index 0000000000..03841475aa --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_ipc.c @@ -0,0 +1,421 @@ +/** + ****************************************************************************** + * @file mx_wifi_ipc.c + * @author MCD Application Team + * @brief Host driver IPC protocol of MXCHIP Wi-Fi component. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include +#include +/*cstat +MISRAC2012-* */ + +#include + +#include "mx_wifi.h" +#include "mx_wifi_ipc.h" +#include "mx_wifi_hci.h" + + +#ifdef MX_WIFI_IPC_DEBUG +#define DEBUG_LOG(M, ...) printf((M), ##__VA_ARGS__) +#define DEBUG_ERROR(M, ...) printf((M), ##__VA_ARGS__) +#else +#define DEBUG_LOG(M, ...) +#define DEBUG_ERROR(M, ...) printf((M), ##__VA_ARGS__) +#endif /* MX_WIFI_IPC_DEBUG */ + +#define MIPC_REQ_LIST_SIZE (64) + +/** + * @brief IPC API event handlers + */ +typedef void (*event_callback_t)(mx_buf_t *mx_buff); +typedef struct _event_item_s +{ + uint16_t api_id; + void (*callback)(mx_buf_t *mx_buff); +} event_item_t; + +event_item_t event_table[3] = +{ + /* system */ + {MIPC_API_SYS_REBOOT_EVENT, mapi_reboot_event_callback}, + /* wifi */ + {MIPC_API_WIFI_STATUS_EVENT, mapi_wifi_status_event_callback}, + {MIPC_API_WIFI_BYPASS_INPUT_EVENT, mapi_wifi_netlink_input_callback}, +}; + +/** + * @brief IPC API request list + */ +typedef struct _mipc_req_s +{ + uint32_t req_id; + SEM_DECLARE(resp_flag); + uint16_t *rbuffer_size; /* in/out*/ + uint8_t *rbuffer; +} mipc_req_t; + + +static mipc_req_t pending_request; + +static uint32_t get_new_req_id(void); +static uint32_t mpic_get_req_id(uint8_t *buffer_in); +static uint16_t mpic_get_api_id(uint8_t *buffer_in); +static uint32_t mipc_event(mx_buf_t *netbuf); + +/* unique sequence number */ +static uint32_t get_new_req_id(void) +{ + static uint32_t id = 1; + return id++; +} + +static uint32_t mpic_get_req_id(uint8_t *buffer_in) +{ + return *((uint32_t *) & (buffer_in[MIPC_PKT_REQ_ID_OFFSET])); +} + +static uint16_t mpic_get_api_id(uint8_t *buffer_in) +{ + return *((uint16_t *) & (buffer_in[MIPC_PKT_API_ID_OFFSET])); +} + +static uint32_t mipc_event(mx_buf_t *netbuf) +{ + uint32_t req_id = MIPC_REQ_ID_NONE; + uint16_t api_id = MIPC_API_ID_NONE; + uint32_t i; + void (*callback)(mx_buf_t *mx_buff); + + if (NULL != netbuf) + { + uint8_t *buffer_in = MX_NET_BUFFER_PAYLOAD(netbuf); + uint32_t buffer_size = MX_NET_BUFFER_GET_PAYLOAD_SIZE(netbuf); + + if ((NULL != buffer_in) && (buffer_size >= MIPC_PKT_MIN_SIZE)) + { + req_id = mpic_get_req_id(buffer_in); + api_id = mpic_get_api_id(buffer_in); + DEBUG_LOG("req_id: 0x%08"PRIx32", api_id: 0x%04x\n", req_id, api_id); + if ((0 == (api_id & MIPC_API_EVENT_BASE)) && (MIPC_REQ_ID_NONE != req_id)) + { + /* cmd response must match pending req id */ + MX_ASSERT(pending_request.req_id == req_id); + { + + /* return params */ + if ((pending_request.rbuffer_size != NULL) && (*(pending_request.rbuffer_size) > 0) + && (NULL != pending_request.rbuffer)) + { + *(pending_request.rbuffer_size) = *(pending_request.rbuffer_size) < (buffer_size - MIPC_PKT_MIN_SIZE) ? \ + *(pending_request.rbuffer_size) : (buffer_size - MIPC_PKT_MIN_SIZE); + memcpy(pending_request.rbuffer, buffer_in + MIPC_PKT_PARAMS_OFFSET, *(pending_request.rbuffer_size)); + } + pending_request.req_id = 0xFFFFFFFF; + if (SEM_OK != SEM_SIGNAL(pending_request.resp_flag)) + { + DEBUG_ERROR("Failed to signal command response\n"); + while (1); + } + MX_STAT(cmd_get_answer); + mx_wifi_hci_free(netbuf); + } + } + else /* event callback */ + { + for (i = 0; i < sizeof(event_table) / sizeof(event_item_t); i++) + { + if (event_table[i].api_id == api_id) + { + callback = event_table[i].callback; + if (NULL != callback) + { + DEBUG_LOG("callback with %p\n", buffer_in); + callback(netbuf); + break; + } + } + } + if (i == sizeof(event_table) / sizeof(event_item_t)) + { + DEBUG_ERROR("unknown event: 0x%04x !\n", api_id); + mx_wifi_hci_free(netbuf); + } + } + } + else + { + DEBUG_LOG("unknown buffer content\n"); + mx_wifi_hci_free(netbuf); + } + } + return req_id; +} + +/******************************************************************************* + * IPC API implementations for mx_wifi over HCI + ******************************************************************************/ + +/** + * @brief mxchip ipc protocol init + * @param ipc_send low level send function + * @return int32_t status code + */ +int32_t mipc_init(mipc_send_func_t ipc_send) +{ + int32_t ret; + + pending_request.req_id = 0xFFFFFFFF; + SEM_INIT(pending_request.resp_flag, 1); + ret = mx_wifi_hci_init(ipc_send); + + return ret; +} + + +int32_t mipc_deinit(void) +{ + int32_t ret; + SEM_DEINIT(pending_request.resp_flag); + ret = mx_wifi_hci_deinit(); + + return ret; +} + + +int32_t mipc_request(uint16_t api_id, uint8_t *cparams, uint16_t cparams_size, + uint8_t *rbuffer, uint16_t *rbuffer_size, uint32_t timeout_ms) +{ + int32_t ret = MIPC_CODE_ERROR; + + uint8_t *cbuf; + uint8_t *pos; + uint16_t cbuf_size; + uint32_t req_id; + bool copy_buffer = true; + + LOCK(wifi_obj_get()->lockcmd); + if (cparams_size <= MX_WIFI_IPC_PAYLOAD_SIZE) + { + /* create cmd data */ + cbuf_size = sizeof(req_id) + sizeof(api_id) + cparams_size; + +#if MX_WIFI_TX_BUFFER_NO_COPY + if (api_id == MIPC_API_WIFI_BYPASS_OUT_CMD) + { + cbuf = cparams - sizeof(req_id) - sizeof(api_id); + copy_buffer = false; + } + else +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + { + cbuf = (uint8_t *)MX_WIFI_MALLOC(cbuf_size); + } + + if (NULL != cbuf) + { + /* get an uniq identifier */ + req_id = get_new_req_id(); + /* copy the protocol parameter to the head part of the buffer */ + pos = cbuf; + memcpy(pos, &req_id, sizeof(req_id)); + pos += sizeof(req_id); + memcpy(pos, &api_id, sizeof(api_id)); + pos += sizeof(api_id); + + if ((true == copy_buffer) && (cparams_size > 0)) + { + memcpy(pos, cparams, cparams_size); + } + + /* a single pending request due to LOCK usage on command */ + if (pending_request.req_id != 0xFFFFFFFF) + { + DEBUG_LOG("Error req_id must be 0xffffffff here %"PRIu32"\n", pending_request.req_id); + while (1); + } + pending_request.req_id = req_id; + pending_request.rbuffer = rbuffer; + pending_request.rbuffer_size = rbuffer_size; + /* static int iter=0; */ + /* printf("%d push %d\n",iter++,cbuf_size); */ + + /* send the command */ + DEBUG_LOG("cmd %"PRIu32"\n", req_id); + ret = mx_wifi_hci_send(cbuf, cbuf_size); + if (ret == 0) + { + /* wait for command answer */ + if (SEM_WAIT(pending_request.resp_flag, timeout_ms, mipc_poll) != SEM_OK) + { + DEBUG_ERROR("Error: command 0x%04x timeout(%"PRIu32" ms) waiting answer %"PRIu32"\n", + api_id, timeout_ms, pending_request.req_id); + pending_request.req_id = 0xFFFFFFFF; + ret = MIPC_CODE_ERROR; + } + + } + else + { + DEBUG_ERROR("Failed to send command to Hci\n"); + while (1); + } + DEBUG_LOG("done %"PRIu32"\n", req_id); + if (true == copy_buffer) + { + MX_WIFI_FREE(cbuf); + } + } + } + UNLOCK(wifi_obj_get()->lockcmd); + + return ret; +} + + +/** + * @brief mipc poll + * @param timeout_ms timeout in ms + * @return int32_t 0 if success, otherwise failed + */ +void mipc_poll(uint32_t timeout) +{ + mx_buf_t *nbuf; + + /* process the received data inside RX buffer */ + nbuf = mx_wifi_hci_recv(timeout); + if (NULL != nbuf) + { + uint32_t len = MX_NET_BUFFER_GET_PAYLOAD_SIZE(nbuf); + DEBUG_LOG("\nhci recv len %"PRIu32"\n", len); + if (len > 0) + { + mipc_event(nbuf); + } + else + { + MX_NET_BUFFER_FREE(nbuf); + } + } +} + + +int32_t mipc_echo(uint8_t *in, uint16_t in_len, uint8_t *out, uint16_t *out_len, + uint32_t timeout) +{ + int32_t ret = MIPC_CODE_ERROR; + + if ((NULL != in) && (NULL != out) && (NULL != out_len)) + { + ret = mipc_request(MIPC_API_SYS_ECHO_CMD, in, in_len, out, out_len, timeout); + if (MIPC_CODE_SUCCESS == ret) + { + ret = MIPC_CODE_SUCCESS; + } + else + { + *out_len = 0; + } + } + return ret; +} + +/******************************************************************************* + * IPC API event callbacks + ******************************************************************************/ + +/* system */ + +void mapi_reboot_event_callback(mx_buf_t *buff) +{ + if (buff != NULL) + { + mx_wifi_hci_free(buff); + } + DEBUG_LOG("\nEVENT: reboot done.\n"); +} + +/* wifi */ + +void mapi_wifi_status_event_callback(mx_buf_t *nbuf) +{ + uint8_t cate; + mwifi_status_t status; + mx_wifi_status_callback_t status_cb = NULL; + void *cb_args = NULL; + + if (NULL != nbuf) + { + uint8_t *payload = MX_NET_BUFFER_PAYLOAD(nbuf); + status = *((mwifi_status_t *)(payload + MIPC_PKT_PARAMS_OFFSET)); + DEBUG_LOG("\nEVENT: wifi status: %02x\r\n", status); + mx_wifi_hci_free(nbuf); + + switch (status) + { + case MWIFI_EVENT_STA_UP: + case MWIFI_EVENT_STA_DOWN: + case MWIFI_EVENT_STA_GOT_IP: + cate = MC_STATION; + status_cb = wifi_obj_get()->Runtime.status_cb[0]; + cb_args = wifi_obj_get()->Runtime.callback_arg[0]; + break; + + case MWIFI_EVENT_AP_UP: + case MWIFI_EVENT_AP_DOWN: + cate = MC_SOFTAP; + status_cb = wifi_obj_get()->Runtime.status_cb[0]; + cb_args = wifi_obj_get()->Runtime.callback_arg[0]; + break; + + default: + cate = MC_SOFTAP; + MX_ASSERT(false); + break; + } + + if (NULL != status_cb) + { + status_cb(cate, status, cb_args); + } + } +} + +void mapi_wifi_netlink_input_callback(mx_buf_t *nbuf) +{ + wifi_bypass_in_rparams_t *in_rprarams; + /* DEBUG_LOG("IP stack in %d\n",len); */ + if (NULL != nbuf) + { + uint8_t *buffer_in = MX_NET_BUFFER_PAYLOAD(nbuf); + MX_STAT(callback); + + in_rprarams = (wifi_bypass_in_rparams_t *)(buffer_in + MIPC_PKT_PARAMS_OFFSET); + MX_NET_BUFFER_HIDE_HEADER(nbuf, MIPC_PKT_PARAMS_OFFSET + sizeof(wifi_bypass_in_rparams_t)); + if ((NULL != wifi_obj_get()->Runtime.netlink_input_cb) && \ + (in_rprarams->tot_len > 0)) + { + wifi_obj_get()->Runtime.netlink_input_cb(nbuf, + wifi_obj_get()->Runtime.netlink_user_args); + } + else + { + MX_NET_BUFFER_FREE(nbuf); + } + } +} diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_ipc.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_ipc.h new file mode 100644 index 0000000000..310101a2c3 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_ipc.h @@ -0,0 +1,657 @@ +/** + ****************************************************************************** + * @file mx_wifi_ipc.h + * @author MCD Application Team + * @brief Header for mx_wifi_ipc.c module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_IPC_H +#define MX_WIFI_IPC_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include +#include +#include +#include +/*cstat +MISRAC2012-* */ + +#include "mx_wifi.h" + +/* Exported Constants --------------------------------------------------------*/ +/* #define MX_WIFI_IPC_DEBUG */ +#define MX_API_VERSION ("2.0.0") + +/** + * @brief IPC error code + */ +#define MIPC_CODE_SUCCESS (0) +#define MIPC_CODE_ERROR (-1) +#define MIPC_CODE_TIMEOUT (-2) +#define MIPC_CODE_NO_MEMORY (-3) + +/** + * @brief IPC packet + */ +/* + * |--------+--------+--------------------| + * | req_id | api_id | args (...) | + * |--------+--------+--------------------| + * | 4Bytes | 2Btyes | nBytes | + * |--------+--------+--------------------| + */ +#define MIPC_PKT_REQ_ID_OFFSET (0) +#define MIPC_PKT_REQ_ID_SIZE (4) +#define MIPC_PKT_API_ID_OFFSET (MIPC_PKT_REQ_ID_OFFSET + MIPC_PKT_REQ_ID_SIZE) +#define MIPC_PKT_API_ID_SIZE (2) +#define MIPC_PKT_PARAMS_OFFSET (MIPC_PKT_API_ID_OFFSET + MIPC_PKT_API_ID_SIZE) +#define MIPC_HEADER_SIZE (MIPC_PKT_REQ_ID_SIZE + MIPC_PKT_API_ID_SIZE) +#define MIPC_PKT_MIN_SIZE (MIPC_HEADER_SIZE) +#define MIPC_PKT_MAX_SIZE (MIPC_HEADER_SIZE + MX_WIFI_IPC_PAYLOAD_SIZE) + +/** + * @brief IPC api id + */ +#define MIPC_REQ_ID_NONE (0x00000000) +#define MIPC_API_ID_NONE (0x0000) +#define MIPC_API_CMD_BASE (MIPC_API_ID_NONE) +#define MIPC_API_EVENT_BASE (0x8000) + +/** + * API CMD + */ +/* system */ +#define MIPC_API_SYS_CMD_BASE (MIPC_API_CMD_BASE + 0x0000) +#define MIPC_API_SYS_ECHO_CMD (MIPC_API_SYS_CMD_BASE + 0x0001) +#define MIPC_API_SYS_REBOOT_CMD (MIPC_API_SYS_CMD_BASE + 0x0002) +#define MIPC_API_SYS_VERSION_CMD (MIPC_API_SYS_CMD_BASE + 0x0003) +#define MIPC_API_SYS_RESET_CMD (MIPC_API_SYS_CMD_BASE + 0x0004) + +/* wifi */ +#define MIPC_API_WIFI_CMD_BASE (MIPC_API_CMD_BASE + 0x0100) +#define MIPC_API_WIFI_GET_MAC_CMD (MIPC_API_WIFI_CMD_BASE + 0x0001) +#define MIPC_API_WIFI_SCAN_CMD (MIPC_API_WIFI_CMD_BASE + 0x0002) +#define MIPC_API_WIFI_CONNECT_CMD (MIPC_API_WIFI_CMD_BASE + 0x0003) +#define MIPC_API_WIFI_DISCONNECT_CMD (MIPC_API_WIFI_CMD_BASE + 0x0004) +#define MIPC_API_WIFI_SOFTAP_START_CMD (MIPC_API_WIFI_CMD_BASE + 0x0005) +#define MIPC_API_WIFI_SOFTAP_STOP_CMD (MIPC_API_WIFI_CMD_BASE + 0x0006) +#define MIPC_API_WIFI_GET_IP_CMD (MIPC_API_WIFI_CMD_BASE + 0x0007) +#define MIPC_API_WIFI_GET_LINKINFO_CMD (MIPC_API_WIFI_CMD_BASE + 0x0008) +#define MIPC_API_WIFI_PS_ON_CMD (MIPC_API_WIFI_CMD_BASE + 0x0009) +#define MIPC_API_WIFI_PS_OFF_CMD (MIPC_API_WIFI_CMD_BASE + 0x000a) +#define MIPC_API_WIFI_PING_CMD (MIPC_API_WIFI_CMD_BASE + 0x000b) +#define MIPC_API_WIFI_BYPASS_SET_CMD (MIPC_API_WIFI_CMD_BASE + 0x000c) +#define MIPC_API_WIFI_BYPASS_GET_CMD (MIPC_API_WIFI_CMD_BASE + 0x000d) +#define MIPC_API_WIFI_BYPASS_OUT_CMD (MIPC_API_WIFI_CMD_BASE + 0x000e) + +/* socket */ +#define MIPC_API_SOCKET_CMD_BASE (MIPC_API_CMD_BASE + 0x0200) +#define MIPC_API_SOCKET_CREATE_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0001) +#define MIPC_API_SOCKET_CONNECT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0002) +#define MIPC_API_SOCKET_SEND_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0003) +#define MIPC_API_SOCKET_SENDTO_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0004) +#define MIPC_API_SOCKET_RECV_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0005) +#define MIPC_API_SOCKET_RECVFROM_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0006) +#define MIPC_API_SOCKET_SHUTDOWN_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0007) +#define MIPC_API_SOCKET_CLOSE_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0008) +#define MIPC_API_SOCKET_GETSOCKOPT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0009) +#define MIPC_API_SOCKET_SETSOCKOPT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x000a) +#define MIPC_API_SOCKET_BIND_CMD (MIPC_API_SOCKET_CMD_BASE + 0x000b) +#define MIPC_API_SOCKET_LISTEN_CMD (MIPC_API_SOCKET_CMD_BASE + 0x000c) +#define MIPC_API_SOCKET_ACCEPT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x000d) +#define MIPC_API_SOCKET_SELECT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x000e) +#define MIPC_API_SOCKET_GETSOCKNAME_CMD (MIPC_API_SOCKET_CMD_BASE + 0x000f) +#define MIPC_API_SOCKET_GETPEERNAME_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0010) +#define MIPC_API_SOCKET_GETHOSTBYNAME_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0011) + +/* TLS cmd */ +#define MIPC_API_TLS_SET_VER_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0081) +#define MIPC_API_TLS_SET_CLIENT_CERT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0082) +#define MIPC_API_TLS_SET_SERVER_CERT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0083) +#define MIPC_API_TLS_ACCEPT_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0084) +#define MIPC_API_TLS_CONNECT_SNI_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0085) +#define MIPC_API_TLS_SEND_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0086) +#define MIPC_API_TLS_RECV_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0087) +#define MIPC_API_TLS_CLOSE_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0088) +#define MIPC_API_TLS_SET_NONBLOCK_CMD (MIPC_API_SOCKET_CMD_BASE + 0x0089) + +#define MIPC_API_MDNS_CMD_BASE (MIPC_API_CMD_BASE + 0x0300) +#define MIPC_API_MDNS_START_CMD (MIPC_API_MDNS_CMD_BASE + 0x0001) +#define MIPC_API_MDNS_STOP_CMD (MIPC_API_MDNS_CMD_BASE + 0x0002) +#define MIPC_API_MDNS_ANNOUNCE_CMD (MIPC_API_MDNS_CMD_BASE + 0x0003) +#define MIPC_API_MDNS_DEANNOUNCE_CMD (MIPC_API_MDNS_CMD_BASE + 0x0004) +#define MIPC_API_MDNS_DEANNOUNCE_ALL_CMD (MIPC_API_MDNS_CMD_BASE + 0x0005) +#define MIPC_API_MDNS_IFACE_STATE_CHANGE_CMD (MIPC_API_MDNS_CMD_BASE + 0x0006) +#define MIPC_API_MDNS_SET_HOSTNAME_CMD (MIPC_API_MDNS_CMD_BASE + 0x0007) +#define MIPC_API_MDNS_SET_TXT_REC_CMD (MIPC_API_MDNS_CMD_BASE + 0x0008) +/** + * API EVENT + */ +/* system */ +#define MIPC_API_SYS_EVENT_BASE (MIPC_API_EVENT_BASE + 0x0000) +#define MIPC_API_SYS_REBOOT_EVENT (MIPC_API_SYS_EVENT_BASE + 0x0001) + +/* wifi */ +#define MIPC_API_WIFI_EVENT_BASE (MIPC_API_EVENT_BASE + 0x0100) +#define MIPC_API_WIFI_STATUS_EVENT (MIPC_API_WIFI_EVENT_BASE + 0x0001) +#define MIPC_API_WIFI_BYPASS_INPUT_EVENT (MIPC_API_WIFI_EVENT_BASE + 0x0002) + +/* Exported macro-------------------------------------------------------------*/ + +/* Exported typedef ----------------------------------------------------------*/ +typedef uint16_t (*mipc_send_func_t)(uint8_t *data, uint16_t size); + +/* Exported functions --------------------------------------------------------*/ + +/* MX_IPC */ +int32_t mipc_init(mipc_send_func_t ipc_send); +int32_t mipc_deinit(void); + +/* ipc api request */ +int32_t mipc_request(uint16_t api_id, uint8_t *cparams, uint16_t cparams_size, + uint8_t *rbuffer, uint16_t *rbuffer_size, uint32_t timeout_ms); + +/* ipc handle response/event */ +void mipc_poll(uint32_t timeout); + +/* ipc echo test */ +int32_t mipc_echo(uint8_t *in, uint16_t in_len, uint8_t *out, uint16_t *out_len, + uint32_t timeout); + +/* Module API event callbacks ------------------------------------------------*/ +/* system */ +void mapi_reboot_event_callback(mx_buf_t *buff); + +/* wifi */ +#pragma pack(1) +typedef struct _wifi_scan_cparams_s +{ + int8_t ssid[33]; /* 32 + 1 '\0' string end */ +} wifi_scan_cparams_t; + +typedef struct _wifi_scan_rparams_s +{ + uint8_t num; + mwifi_ap_info_t ap[1]; /* ap info array memory */ +} wifi_scan_rparams_t; + +typedef struct +{ + uint8_t bssid[6]; /**< bssid of access-point */ + uint8_t channel; /**< channel of access-point */ + mwifi_security_t security; /**< security of access-point */ +} mwifi_connect_attr_t; + +typedef struct _wifi_connect_cparams_s +{ + int8_t ssid[33]; /* 32 + 1 '\0' string end */ + int8_t key[65]; /* 64 + 1 '\0' string end */ + int32_t key_len; + uint8_t use_attr; + uint8_t use_ip; + mwifi_connect_attr_t attr; + mwifi_ip_attr_t ip; +} wifi_connect_cparams_t; + +typedef struct +{ + int32_t is_connected; /**< The link to wlan is established or not, 0: disconnected, 1: connected. */ + int32_t rssi; /**< Signal strength of the current connected AP */ + int8_t ssid[33]; /**< SSID of the current connected wlan */ + uint8_t bssid[6]; /**< BSSID of the current connected wlan */ + int8_t key[65]; /**< The passphrase/PSK of the connected AP */ + int32_t channel; /**< Channel of the current connected wlan */ + mwifi_security_t security; /**< security of access-point */ +} mwifi_link_info_t; + +typedef struct _wifi_get_linkinof_rparams_s +{ + int32_t status; + mwifi_link_info_t info; +} wifi_get_linkinof_rparams_t; + +typedef struct _wifi_get_ip_rparams_s +{ + int32_t status; + mwifi_ip_attr_t ip; +} wifi_get_ip_rparams_t; + +typedef struct _wifi_softap_start_cparams_s +{ + int8_t ssid[32]; + int8_t key[64]; + int32_t channel; + mwifi_ip_attr_t ip; +} wifi_softap_start_cparams_t; + +/* ping */ +typedef struct wifi_ping_cparams_s +{ + char hostname[255]; + int32_t count; + int32_t delay_ms; +} wifi_ping_cparams_t; + +typedef struct wifi_ping_rparams_s +{ + int32_t num; + int32_t delay_ms[1]; +} wifi_ping_rparams_t; + +typedef struct wifi_bypass_set_cparams_s +{ + int32_t mode; +} wifi_bypass_set_cparams_t; + +typedef struct wifi_bypass_get_rparams_s +{ + int32_t mode; +} wifi_bypass_get_rparams_t; + +typedef struct wifi_bypass_out_cparams_s +{ + int32_t idx; + uint8_t useless[16]; + uint16_t data_len; +} wifi_bypass_out_cparams_t; + +typedef struct wifi_bypass_in_rparams_s +{ + int32_t idx; + uint8_t useless[16]; + uint16_t tot_len; +} wifi_bypass_in_rparams_t; +#pragma pack() + +void mapi_wifi_status_event_callback(mx_buf_t *nbuf); +void mapi_wifi_netlink_input_callback(mx_buf_t *nbuf); + + +#if MX_WIFI_NETWORK_BYPASS_MODE == 0 +/* socket */ +#pragma pack(1) +/* create */ +typedef struct _socket_create_cparams_s +{ + int32_t domain; + int32_t type; + int32_t protocol; +} socket_create_cparams_t; + +typedef struct _socket_create_rparams_s +{ + int32_t fd; +} socket_create_rparams_t; + +/* setsockopt */ +typedef struct _socket_setsockopt_cparams_s +{ + int32_t socket; + int32_t level; + int32_t optname; + socklen_t optlen; + uint8_t optval[16]; +} socket_setsockopt_cparams_t; + +typedef struct _socket_setsockopt_rparams_s +{ + int32_t status; +} socket_setsockopt_rparams_t; + +/* getsockopt */ +typedef struct _socket_getsockopt_cparams_s +{ + int32_t socket; + int32_t level; + int32_t optname; +} socket_getsockopt_cparams_t; + +typedef struct _socket_getsockopt_rparams_s +{ + int32_t status; + socklen_t optlen; + uint8_t optval[16]; +} socket_getsockopt_rparams_t; + +/* bind */ +typedef struct _socket_bind_cparams_s +{ + int32_t socket; + struct sockaddr addr; + socklen_t length; +} socket_bind_cparams_t; + +typedef struct _socket_bind_rparams_s +{ + int32_t status; +} socket_bind_rparams_t; + +/* connect */ +typedef struct _socket_connect_cparams_s +{ + int32_t socket; + struct sockaddr addr; + socklen_t length; +} socket_connect_cparams_t; + +typedef struct _socket_connect_rparams_s +{ + int32_t status; +} socket_connect_rparams_t; + +/* shutdown */ +typedef struct _socket_shutdown_cparams_s +{ + int32_t filedes; + int32_t how; +} socket_shutdown_cparams_t; + +typedef struct _socket_shutdown_rparams_s +{ + int32_t status; +} socket_shutdown_rparams_t; + +/* close */ +typedef struct _socket_close_cparams_s +{ + int32_t filedes; +} socket_close_cparams_t; + +typedef struct _socket_close_rparams_s +{ + int32_t status; +} socket_close_rparams_t; + +/* send */ +typedef struct _socket_send_cparams_s +{ + int32_t socket; + size_t size; + int32_t flags; + uint8_t buffer[1]; +} socket_send_cparams_t; + +typedef struct _socket_send_rparams_s +{ + int32_t sent; +} socket_send_rparams_t; + +/* sendto */ +typedef struct _socket_sendto_cparams_s +{ + int32_t socket; + size_t size; + int32_t flags; + struct sockaddr addr; + socklen_t length; + uint8_t buffer[1]; +} socket_sendto_cparams_t; + +typedef struct _socket_sendto_rparams_s +{ + int32_t sent; +} socket_sendto_rparams_t; + +/* recv */ +typedef struct _socket_recv_cparams_s +{ + int32_t socket; + size_t size; + int32_t flags; +} socket_recv_cparams_t; + +typedef struct _socket_recv_rparams_s +{ + int32_t received; + uint8_t buffer[1]; +} socket_recv_rparams_t; + +/* recvfrom */ +typedef struct _socket_recvfrom_cparams_s +{ + int32_t socket; + size_t size; + int32_t flags; +} socket_recvfrom_cparams_t; + +typedef struct _socket_recvfrom_rparams_s +{ + int32_t received; + struct sockaddr addr; + socklen_t length; + uint8_t buffer[1]; +} socket_recvfrom_rparams_t; + +/* gethostbyname */ +typedef struct _socket_gethostbyname_cparams_s +{ + char name[253]; +} socket_gethostbyname_cparams_t; + +typedef struct _socket_gethostbyname_rparams_s +{ + int32_t status; + uint32_t s_addr; +} socket_gethostbyname_rparams_t; + +/* getpeername */ +typedef struct _socket_getpeername_cparams_s +{ + int32_t s; +} socket_getpeername_cparams_t; + +typedef struct _socket_getpeername_rparams_s +{ + int32_t status; + struct sockaddr name; + socklen_t namelen; +} socket_getpeername_rparams_t; + +/* getsockname */ +typedef struct _socket_getsockname_cparams_s +{ + int32_t s; +} socket_getsockname_cparams_t; + +typedef struct _socket_getsockname_rparams_s +{ + int32_t status; + struct sockaddr name; + socklen_t namelen; +} socket_getsockname_rparams_t; + +/* listen */ +typedef struct _socket_listen_cparams_s +{ + int32_t socket; + int32_t n; +} socket_listen_cparams_t; + +typedef struct _socket_listen_rparams_s +{ + int32_t status; +} socket_listen_rparams_t; + +/* accept */ +typedef struct _socket_accept_cparams_s +{ + int32_t socket; +} socket_accept_cparams_t; + +typedef struct _socket_accept_rparams_s +{ + int32_t socket; + struct sockaddr addr; + socklen_t length; +} socket_accept_rparams_t; + +/* tls */ +/* tls set ver */ +typedef struct _tls_set_ver_cparams_s +{ + mtls_ver_t version; +} tls_set_ver_cparams_t; + +typedef struct _tls_set_ver_rparams_s +{ + int32_t ret; +} tls_set_ver_rparams_t; + +/* tls set client cert */ +typedef struct _tls_set_client_cert_cparams_s +{ + uint16_t cert_pem_size; + uint16_t private_key_pem_size; + char cert_data[1]; /* cert_pem + private_key_pem */ +} tls_set_client_cert_cparams_t; + +typedef struct _tls_set_client_cert_rparams_s +{ + int32_t ret; +} tls_set_client_cert_rparams_t; + +/* tls set server cert */ +typedef struct _tls_set_server_cert_cparams_s +{ + uint16_t cert_pem_size; + uint16_t private_key_pem_size; + uint16_t verify_ca_size; + char cert_data[1]; /* cert_pem + private_key_pem + verify_ca */ +} tls_set_server_cert_cparams_t; + +typedef struct _tls_set_server_cert_rparams_s +{ + int32_t ret; +} tls_set_server_cert_rparams_t; + +/* tls accept */ +typedef struct _tls_accept_cparams_s +{ + int32_t fd; +} tls_accept_cparams_t; + +typedef struct _tls_accept_rparams_s +{ + mtls_t tls; +} tls_accept_rparams_t; + +/* tls connect_sni */ +typedef struct _tls_connect_sni_cparams_s +{ + struct sockaddr addr; + socklen_t length; + char sni_servername[128]; + int32_t calen; + char ca[1]; +} tls_connect_sni_cparams_t; + +typedef struct _tls_connect_sni_rparams_s +{ + mtls_t tls; + int32_t errno; +} tls_connect_sni_rparams_t; + +/* tls send */ +typedef struct _tls_send_cparams_s +{ + mtls_t tls; + size_t size; + uint8_t buffer[1]; +} tls_send_cparams_t; + +typedef struct _tls_send_rparams_s +{ + int32_t sent; +} tls_send_rparams_t; + +/* tls recv */ +typedef struct _tls_recv_cparams_s +{ + mtls_t tls; + size_t size; +} tls_recv_cparams_t; + +typedef struct _tls_recv_rparams_s +{ + int32_t received; + uint8_t buffer[1]; +} tls_recv_rparams_t; + +/* tls close */ +typedef struct _tls_close_cparams_s +{ + mtls_t tls; +} tls_close_cparams_t; + +typedef struct _tls_close_rparams_s +{ + int32_t ret; +} tls_close_rparams_t; + +/* tls nonblock */ +typedef struct _tls_set_nonblock_cparams_s +{ + mtls_t tls; + int32_t nonblock; +} tls_set_nonblock_cparams_t; + +typedef struct _tls_set_nonblock_rparams_s +{ + int32_t ret; +} tls_set_nonblock_rparams_t; + +#pragma pack() + +#pragma pack(1) +typedef struct mdns_start_cparams_s +{ + char domain[MDNS_MAX_LABEL_LEN + 1]; + char hostname[MDNS_MAX_LABEL_LEN + 1]; +} mdns_start_cparams_t; +typedef struct mdns_announce_cparams_s +{ + uint8_t iface; + struct mc_mdns_service service_data; +} mdns_announce_cparams_t, mdns_deannounce_cparams_t; +typedef struct mdns_deannounce_all_cparams_s +{ + uint8_t iface; +} mdns_deannounce_all_cparams_t; +typedef struct mdns_iface_state_change_cparams_s +{ + uint8_t iface; + uint8_t state; +} mdns_iface_state_change_cparams_t; +typedef struct mdns_set_hostname_cparams_s +{ + char hostname[MDNS_MAX_LABEL_LEN + 1]; +} mdns_set_hostname_cparams_t; +typedef struct mdns_set_txt_rec_cparams_s +{ + struct mc_mdns_service service_data; + char keyvals[MDNS_MAX_KEYVAL_LEN + 1]; + char separator; +} mdns_set_txt_rec_cparams_t; +#pragma pack() +#endif /* MX_WIFI_NETWORK_BYPASS_MODE */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MX_WIFI_IPC_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_slip.c b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_slip.c new file mode 100644 index 0000000000..80e837c02a --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_slip.c @@ -0,0 +1,203 @@ +/** + ****************************************************************************** + * @file mx_wifi_slip.c + * @author MCD Application Team + * @brief Host driver SLIP protocol of MXCHIP Wi-Fi component. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +/*cstat -MISRAC2012-* */ +#include "stdio.h" +#include "stdlib.h" +/*cstat +MISRAC2012-* */ + +#include "mx_wifi_conf.h" +#include "mx_wifi_slip.h" +#include "mx_wifi_ipc.h" + +/* debug function */ +#ifdef MX_WIFI_SLIP_DEBUG +#define DEBUG_LOG(M, ...) printf((M), ##__VA_ARGS__) +#else +#define DEBUG_LOG(M, ...) +#endif /* MX_WIFI_SLIP_DEBUG */ + +#define DEBUG_WARNING(...) +/* slip buffer number */ +#define SLIP_BUFFER_SIZE (MIPC_PKT_MAX_SIZE + 100) + + +enum +{ + SLIP_STATE_IDLE, /* NOT START */ + SLIP_STATE_CONTINUE, /* receive data to buffer */ + SLIP_STATE_GOT_ESCAPE /* last byte is escape */ +}; + + +uint8_t *slip_transfer(uint8_t *data, uint16_t len, uint16_t *outlen) +{ + uint16_t i; + uint16_t j; + uint16_t inc = 2; + uint8_t *buff = NULL; + + for (i = 0; i < len; i++) + { + if ((data[i] == SLIP_START) || (data[i] == SLIP_END) || (data[i] == SLIP_ESCAPE)) + { + inc++; + } + } + + buff = (uint8_t *)MX_WIFI_MALLOC(len + inc); + if (buff == NULL) + { + return NULL; + } + + buff[0] = SLIP_START; + for (i = 0, j = 1; i < len; i++) + { + if (data[i] == SLIP_START) + { + buff[j++] = SLIP_ESCAPE; + buff[j++] = SLIP_ESCAPE_START; + } + else if (data[i] == SLIP_END) + { + buff[j++] = SLIP_ESCAPE; + buff[j++] = SLIP_ESCAPE_END; + } + else if (data[i] == SLIP_ESCAPE) + { + buff[j++] = SLIP_ESCAPE; + buff[j++] = SLIP_ESCAPE_ES; + } + else + { + buff[j++] = data[i]; + } + } + buff[j++] = SLIP_END; + *outlen = j; + + return buff; +} + + +mx_buf_t *slip_input_byte(uint8_t data) +{ + mx_buf_t *outgoing_nbuf = NULL; + static uint16_t slip_state = SLIP_STATE_IDLE; + static uint16_t slip_index = 0; + static uint8_t *slip_buffer = NULL; + static mx_buf_t *nbuf = NULL; + + if (slip_buffer == NULL) + { + bool first_miss = true; + do + { + nbuf = MX_NET_BUFFER_ALLOC(SLIP_BUFFER_SIZE); + if (nbuf == NULL) + { + DELAYms(1); + if (true == first_miss) + { + first_miss = false; + DEBUG_WARNING("Running Out of buffer for RX\n"); + } + } + } while (NULL == nbuf); + slip_buffer = MX_NET_BUFFER_PAYLOAD(nbuf); + } + + if (slip_index >= SLIP_BUFFER_SIZE) + { + slip_index = 0; + slip_state = SLIP_STATE_IDLE; + } + + switch (slip_state) + { + case SLIP_STATE_GOT_ESCAPE: + if (data == SLIP_START) + { + slip_index = 0; + } + else if (data == SLIP_ESCAPE_START) + { + slip_buffer[slip_index++] = SLIP_START; + } + else if (data == SLIP_ESCAPE_ES) + { + slip_buffer[slip_index++] = SLIP_ESCAPE; + } + else if (data == SLIP_ESCAPE_END) + { + slip_buffer[slip_index++] = SLIP_END; + } + else + { + goto RESET; + } + slip_state = SLIP_STATE_CONTINUE; + break; + + case SLIP_STATE_IDLE: + if (data == SLIP_START) + { + slip_index = 0; + slip_state = SLIP_STATE_CONTINUE; + } + break; + + case SLIP_STATE_CONTINUE: /* continue */ + if (data == SLIP_START) + { + slip_index = 0; + slip_state = SLIP_STATE_CONTINUE; + } + else if (data == SLIP_END) + { + outgoing_nbuf = nbuf; + slip_buffer = NULL; + MX_NET_BUFFER_SET_PAYLOAD_SIZE(nbuf, slip_index); + nbuf = NULL; + goto RESET; + } + else if (data == SLIP_ESCAPE) + { + slip_state = SLIP_STATE_GOT_ESCAPE; + } + else + { + slip_buffer[slip_index++] = data; + } + break; + + default: + break; + } + + return outgoing_nbuf; + +RESET: + slip_index = 0; + slip_state = SLIP_STATE_IDLE; + return outgoing_nbuf; +} + diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_slip.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_slip.h new file mode 100644 index 0000000000..4c35f089f0 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/core/mx_wifi_slip.h @@ -0,0 +1,74 @@ +/** + ****************************************************************************** + * @file mx_wifi_slip.h + * @author MCD Application Team + * @brief Header for mx_wifi_slip.c module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_SLIP_H +#define MX_WIFI_SLIP_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Includes ------------------------------------------------------------------*/ +#include "mx_wifi_conf.h" + +/* + * CONFIGURATIONS + */ +#define MX_WIFI_SLIP_DEBUG + + +/* SLIP_PACKET + * |--------+---------+--------| + * | START | PAYLOAD | END | + * |--------+---------+--------| + * | 1Bytes | nBytes | 1Bytes | + * |--------+---------+--------| + */ + +/* + * API + */ + +/* transfer HCI data to SLIP data, + * return the SLIP buffer */ +uint8_t *slip_transfer(uint8_t *data, uint16_t len, uint16_t *outlen); + +/* PHY receive one serial byte to SLIP, + * return SLIP frame + * NOTE: use slip_buf_free to free slip buffer if data process finished. */ +mx_buf_t *slip_input_byte(uint8_t data); + +/* free slip frame buffer returned by slip_input_byte */ +void slip_buf_free(uint8_t *buf); + +enum +{ + SLIP_START = 0xC0, + SLIP_END = 0xD0, + SLIP_ESCAPE = 0xDB, + SLIP_ESCAPE_START = 0xDC, + SLIP_ESCAPE_ES = 0xDD, + SLIP_ESCAPE_END = 0xDE +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MX_WIFI_SLIP_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi.c b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi.c new file mode 100644 index 0000000000..8db03dee1b --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi.c @@ -0,0 +1,3252 @@ +/** + ****************************************************************************** + * @file mx_wifi.c + * @author MCD Application Team + * @brief Host driver API of MXCHIP Wi-Fi component. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "mx_wifi.h" +#include "core/mx_wifi_ipc.h" + +/* Private defines -----------------------------------------------------------*/ +/* debug log function */ +#ifdef MX_WIFI_API_DEBUG +#define DEBUG_LOG(M, ...) (void) printf((M), ##__VA_ARGS__) +#else +#define DEBUG_LOG(M, ...) +#endif /* MX_WIFI_API_DEBUG */ + +#define MX_HTONL(A) ((((uint32_t)(A) & 0xff000000U) >> 24) | \ + (((uint32_t)(A) & 0x00ff0000U) >> 8) | \ + (((uint32_t)(A) & 0x0000ff00U) << 8) | \ + (((uint32_t)(A) & 0x000000ffU) << 24)) + +#define MX_NTOHL MX_HTONL + + +#define MX_IN_RANGE(c, lo, up) (((c) >= (lo)) && ((c) <= (up))) +#define MX_IS_PRINT(c) (MX_IN_RANGE((c), 0x20, 0x7f)) +#define MX_ISDIGIT(c) (MX_IN_RANGE((c), '0', '9')) +#define MX_ISXDIGIT(c) (MX_ISDIGIT(c) || MX_IN_RANGE((c), 'a', 'f') || MX_IN_RANGE((c), 'A', 'F')) +#define MX_ISLOWER(c) (MX_IN_RANGE((c), 'a', 'z')) +#define MX_ISSPACE(c) (((c) == ' ')\ + || ((c) == '\f') || ((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == '\v')) + +#if 0 +/* select function file descriptions */ +fd_set mc_select_rfds; +fd_set mc_select_wfds; +fd_set mc_select_efds; +int32_t mc_select_ret_value; +#endif /* 0 */ + +MX_STAT_DECLARE(); +void _MX_WIFI_RecvThread(void* ); + +/* Private data types -----------------------------------------------*/ +typedef struct mx_in_addr +{ + uint32_t s_addr; +} mx_in_addr_t; + +typedef struct +{ + uint32_t addr; +} mx_ip4_addr_t; + +typedef mx_ip4_addr_t mx_ip_addr_t; + + + +#define MX_SIN_ZERO_LEN 8 +typedef struct mx_sockaddr_in +{ + uint8_t sin_len; + uint8_t sin_family; + uint16_t sin_port; + mx_in_addr_t sin_addr; + int8_t sin_zero[MX_SIN_ZERO_LEN]; +} mx_sockaddr_in_t; + + +/* Private functions ---------------------------------------------------------*/ +static int32_t mx_aton(const int8_t *ptr, mx_ip_addr_t *addr); +static int32_t mx_aton_r(const int8_t *cp); +static int8_t *mx_ntoa(const mx_ip4_addr_t *addr); + +/** + * @brief Function description + * @param Params + * @retval socket status + */ + +static int32_t mx_aton(const int8_t *ptr, mx_ip_addr_t *addr) +{ + uint32_t val = 0; + uint32_t base; + int8_t c0; + const int8_t *cp = ptr; + uint32_t parts[4]; + uint32_t *pp = parts; + int32_t ret = 1; + int32_t done; + + c0 = *cp; + done = 0; + for (;;) + { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (done == 1) + { + break; + } + + if (!MX_ISDIGIT(c0)) + { + ret = 0; + done = 1; + } + else + { + val = 0; + base = 10; + if (c0 == '0') + { + ++cp; + c0 = (int8_t) * cp; + if ((c0 == (int8_t) 'x') || (c0 == (int8_t) 'X')) + { + base = 16; + ++cp; + c0 = (int8_t) * cp; + } + else + { + base = 8; + } + } + + for (;;) + { + if (MX_ISDIGIT(c0)) + { + val = (val * base) + (uint32_t)c0 - (uint32_t) '0'; + ++cp; + c0 = (int8_t) * cp; + } + else if ((base == 16U) && MX_ISXDIGIT(c0)) + { + val = (val << 4) | ((uint32_t)c0 + 10U - (uint32_t)(MX_ISLOWER(c0) ? 'a' : 'A')); + ++cp; + c0 = (int8_t) * cp; + } + else + { + break; + } + } + + if (c0 == '.') + { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= (parts + 3)) + { + ret = 0; + done = 1; + } + else + { + *pp = val; + pp++; + ++cp; + c0 = (int8_t) * cp; + } + } + else + { + done = 1; + } + } + } + /* + * Check for trailing characters. + */ + if ((c0 != (int8_t)'\0') && (MX_ISSPACE((c0)) == false)) + { + ret = 0; + } + else + + /* + * Concoct the address according to + * the number of parts specified. + */ + { + switch (pp - parts + 1) + { + case 0: + ret = 0; /* initial nondigit */ + break; + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) + { + ret = 0; + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffffU) + { + ret = 0; + break; + } + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xffU) + { + ret = 0; + break; + } + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + + default: + ret = 0; + break; + } + } + + if (ret == 1) + { + if (addr != NULL) + { + addr->addr = MX_HTONL(val); + } + } + return ret; +} + + + + +static int32_t mx_aton_r(const int8_t *cp) +{ + mx_ip_addr_t val; + int32_t ret; + val.addr = 0; + if (mx_aton(cp, &val) != 0) + { + ret = (int32_t) val.addr; + } + else + { + ret = 0; + } + return (ret); +} + + + +/** + * @brief Register physical interface IO operation function + * @param Obj mxchip wifi object + * @param IO_Init IO init function + * @param IO_DeInit IO deinit function + * @param IO_Delay IO delay function + * @param IO_Send IO send function + * @param IO_Receive IO recv function + * @return MX_WIFI_STATUS_T status code + */ +MX_WIFI_STATUS_T MX_WIFI_RegisterBusIO(MX_WIFIObject_t *Obj, + IO_Init_Func IO_Init, + IO_DeInit_Func IO_DeInit, + IO_Delay_Func IO_Delay, + IO_Send_Func IO_Send, + IO_Receive_Func IO_Receive) +{ + MX_WIFI_STATUS_T rc; + + if ((NULL == Obj) || (NULL == IO_Init) || (NULL == IO_DeInit) || (NULL == IO_Send) || \ + (NULL == IO_Receive) || (NULL == IO_Delay)) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + Obj->fops.IO_Init = IO_Init; + Obj->fops.IO_DeInit = IO_DeInit; + Obj->fops.IO_Send = IO_Send; + Obj->fops.IO_Receive = IO_Receive; + Obj->fops.IO_Delay = IO_Delay; + rc = MX_WIFI_STATUS_OK; + } + return rc; +} + +/** + * @brief reset wifi module by hardware + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_HardResetModule(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T rc; + int32_t ret; + + + MX_STAT_INIT(); + + if (NULL == Obj) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + /* reset Wi-Fi by reset pin */ + ret = Obj->fops.IO_Init(MX_WIFI_RESET); + if ((int32_t)0 == ret) + { + rc = MX_WIFI_STATUS_OK; + } + else + { + rc = MX_WIFI_STATUS_ERROR; + } + } + + return rc; +} + +/** + * @brief set timeout for mxchip wifi API + * @param Obj wifi object + * @param Timeout timeout in ms + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_SetTimeout(MX_WIFIObject_t *Obj, uint32_t Timeout) +{ + MX_WIFI_STATUS_T rc; + + if (NULL == Obj) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + Obj->Runtime.Timeout = Timeout; + rc = MX_WIFI_STATUS_OK; + } + return rc; +} + +/* + * run with RTOS + */ +THREAD_DECLARE(MX_WIFI_RecvThreadId); + + +/** + * @brief wifi stat recv thread for RTOS + * @param argument thread arguments + */ +void _MX_WIFI_RecvThread(void* arg) +{ + MX_WIFIObject_t *Obj = wifi_obj_get(); + + if (NULL != Obj) + { + while (true) + { + (void) mipc_poll(500); + + } + } + /* Delete the Thread */ + THREAD_TERMINATE(MX_WIFI_RecvThreadId); +} + + + +/** + * @brief wifi init + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_Init(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + uint16_t rparams_size; + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (Obj->Runtime.interfaces == 0u) + { + LOCK_INIT(Obj->lockcmd); + + /* 0. set cmd timeout */ + Obj->Runtime.Timeout = MX_WIFI_CMD_TIMEOUT; + + /* 1. init wifi low level IO(UART/SPI) */ + (void)(Obj->fops.IO_Init(MX_WIFI_INIT)); + { + /* 2. init wifi ipc */ + if (MIPC_CODE_SUCCESS == mipc_init(Obj->fops.IO_Send)) + { + + /* 2a start thread for RTOS implementation */ + + if (THREAD_OK != THREAD_INIT(MX_WIFI_RecvThreadId, _MX_WIFI_RecvThread, NULL, + MX_WIFI_RECEIVED_THREAD_STACK_SIZE, + MX_WIFI_RECEIVED_THREAD_PRIORITY)) + { + ret = MX_WIFI_STATUS_ERROR; + } + else + { + /* 3. get version */ + (void)memset(&(Obj->SysInfo.FW_Rev[0]), 0, MX_WIFI_FW_REV_SIZE); + rparams_size = MX_WIFI_FW_REV_SIZE; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SYS_VERSION_CMD, + NULL, 0, + &(Obj->SysInfo.FW_Rev[0]), + &rparams_size, + MX_WIFI_CMD_TIMEOUT)) + { + (void)strncpy((char *)(Obj->SysInfo.Product_Name), + MX_WIFI_PRODUCT_NAME, MX_WIFI_PRODUCT_NAME_SIZE); + (void)strncpy((char *)(Obj->SysInfo.Product_ID), + MX_WIFI_PRODUCT_ID, MX_WIFI_PRODUCT_ID_SIZE); + + /* 4. get MAC */ + (void)memset(&(Obj->SysInfo.MAC[0]), 0, MX_WIFI_MAC_SIZE); + rparams_size = MX_WIFI_MAC_SIZE; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_GET_MAC_CMD, + NULL, 0, + &(Obj->SysInfo.MAC[0]), + &rparams_size, + MX_WIFI_CMD_TIMEOUT)) + { + ret = MX_WIFI_STATUS_OK; + Obj->Runtime.interfaces++; + } /* get MAC */ + } /* get version */ + } + } + } + } + else + { + Obj->Runtime.interfaces++; + ret = MX_WIFI_STATUS_OK; + } + } + + return ret; +} + +/** + * @brief wifi deinit + * @param Obj wifi object + * @return MX_WIFI_STATUS_T + */ +MX_WIFI_STATUS_T MX_WIFI_DeInit(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (Obj->Runtime.interfaces == 1u) + { + (void) THREAD_DEINIT(MX_WIFI_RecvThreadId); + (void)mipc_deinit(); + Obj->fops.IO_DeInit(); + ret = MX_WIFI_STATUS_OK; + Obj->Runtime.interfaces--; + } + else + { + ret = MX_WIFI_STATUS_OK; + if (Obj->Runtime.interfaces > 0u) + { + Obj->Runtime.interfaces--; + } + } + } + + return ret; +} + +/** + * @brief wifi data yield + * @param Obj wifi object + * @param timeout timetou in ms + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_IO_YIELD(MX_WIFIObject_t *Obj, uint32_t timeout) +{ + + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_OK; + if (NULL != Obj) + { +#if MX_WIFI_BARE_OS + mipc_poll(timeout); +#endif + } + return ret; +} + +/** + * @brief wifi software reboot + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_ResetModule(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SYS_REBOOT_CMD, NULL, 0, + NULL, 0, MX_WIFI_CMD_TIMEOUT)) + { + ret = MX_WIFI_STATUS_OK; + } + } + return ret; +} + +/** + * @brief wifi factory reset + * @param Obj wifi object + * @return MX_WIFI_STATUS_T + */ +MX_WIFI_STATUS_T MX_WIFI_ResetToFactoryDefault(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SYS_RESET_CMD, NULL, 0, + NULL, 0, MX_WIFI_CMD_TIMEOUT)) + { + ret = MX_WIFI_STATUS_OK; + } + } + return ret; +} + +/** + * @brief wifi get firmware version + * @param Obj wifi object + * @param version buffer to get version + * @param size buffer size + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_GetVersion(MX_WIFIObject_t *Obj, uint8_t *version, uint32_t size) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + uint16_t rparams_size; + + if ((NULL == Obj) || (NULL == version) || (size > (uint32_t)MX_WIFI_FW_REV_SIZE) \ + || ((uint32_t)0 == size)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + (void)memset(&(Obj->SysInfo.FW_Rev[0]), 0, MX_WIFI_FW_REV_SIZE); + rparams_size = MX_WIFI_FW_REV_SIZE; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SYS_VERSION_CMD, NULL, 0, + &(Obj->SysInfo.FW_Rev[0]), + &rparams_size, MX_WIFI_CMD_TIMEOUT)) + { + (void)memcpy(version, &(Obj->SysInfo.FW_Rev[0]), MX_WIFI_FW_REV_SIZE); + ret = MX_WIFI_STATUS_OK; + } + + } + return ret; +} + +/** + * @brief wifi get MAC address + * @param Obj wifi object + * @param mac buffer to get MAC address (6 bytes) + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_GetMACAddress(MX_WIFIObject_t *Obj, uint8_t *mac) +{ + MX_WIFI_STATUS_T ret; + + if ((NULL == Obj) || (NULL == mac)) + { + ret = MX_WIFI_STATUS_ERROR; + } + else + { + (void)memcpy(mac, Obj->SysInfo.MAC, MX_WIFI_MAC_SIZE); + ret = MX_WIFI_STATUS_OK; + } + + return ret; +} + +/** + * @brief wifi scan start + * @param Obj wifi object + * @param scan_mode scan mode + * @param ssid ssid to scan + * @param len max number to scan + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_Scan(MX_WIFIObject_t *Obj, mc_wifi_scan_mode_t scan_mode, + char *ssid, int32_t len) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + wifi_scan_cparams_t cparams; + wifi_scan_rparams_t *rparams_p = (wifi_scan_rparams_t *)(&(Obj->Runtime.scan_result[0])); + uint16_t rparams_size; + + if ((NULL == Obj) || (((mc_wifi_scan_mode_t)MC_SCAN_ACTIVE == scan_mode) && + ((NULL == ssid) || (len <= 0) || (len > 32)))) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + memcpy(&(cparams.ssid[0]), ssid, len); + rparams_size = MX_WIFI_SCAN_BUF_SIZE; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_SCAN_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)rparams_p, &rparams_size, + MX_WIFI_SCAN_TIMEOUT)) + { + Obj->Runtime.scan_number = rparams_p->num; + memcpy(&(Obj->Runtime.scan_result[0]), &(rparams_p->ap[0]), + Obj->Runtime.scan_number * sizeof(mwifi_ap_info_t)); + ret = MX_WIFI_STATUS_OK; + } + } + return ret; +} + +/** + * @brief get wifi scan result + * @param Obj wifi object + * @param results buffer to get scan result + * @param number max ap number to get + * @return int8_t ap number got + */ +int8_t MX_WIFI_Get_scan_result(MX_WIFIObject_t *Obj, uint8_t *results, uint8_t number) +{ + int8_t copy_number; + + if ((NULL == Obj) || (NULL == results) || ((uint8_t)0 == number)) + { + copy_number = 0; + } + else + { + copy_number = (int8_t)(MIN(Obj->Runtime.scan_number, number)); + (void)memcpy(results, Obj->Runtime.scan_result, (size_t)copy_number * sizeof(mwifi_ap_info_t)); + } + return copy_number; +} + +/** + * @brief register wifi station status event callback + * @param Obj wifi object + * @param cb callback function + * @param arg callback argument + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_RegisterStatusCallback(MX_WIFIObject_t *Obj, + mx_wifi_status_callback_t cb, + void *arg) +{ + MX_WIFI_STATUS_T rc; + + if (NULL == Obj) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + Obj->Runtime.status_cb[0] = cb; + Obj->Runtime.callback_arg[0] = arg; + rc = MX_WIFI_STATUS_OK; + } + return rc; +} + +/** + * @brief unregister wifi station event callback function + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_UnRegisterStatusCallback(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T rc; + + if (NULL == Obj) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + Obj->Runtime.status_cb[0] = NULL; + Obj->Runtime.callback_arg[0] = NULL; + rc = MX_WIFI_STATUS_OK; + } + return rc; +} + +/** + * @brief register wifi event callback for station or AP mode + * @param Obj wifi object + * @param cb callback function + * @param arg callback argument + * @param interface wifi mode + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_RegisterStatusCallback_if(MX_WIFIObject_t *Obj, + mx_wifi_status_callback_t cb, + void *arg, + mwifi_if_t interface) +{ + MX_WIFI_STATUS_T rc; + + if (NULL == Obj) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + if ((mwifi_if_t)MC_SOFTAP == interface) + { + Obj->Runtime.status_cb[1] = cb; + Obj->Runtime.callback_arg[1] = arg; + } + else + { + Obj->Runtime.status_cb[0] = cb; + Obj->Runtime.callback_arg[0] = arg; + } + rc = MX_WIFI_STATUS_OK; + + } + return rc; +} + +/** + * @brief register wifi event callback for station or AP mode + * @param Obj wifi object + * @param interface wifi mode + * @return MX_WIFI_STATUS_T + */ +MX_WIFI_STATUS_T MX_WIFI_UnRegisterStatusCallback_if(MX_WIFIObject_t *Obj, mwifi_if_t interface) +{ + MX_WIFI_STATUS_T rc; + + if (NULL == Obj) + { + rc = MX_WIFI_STATUS_ERROR; + } + else + { + if ((mwifi_if_t)MC_SOFTAP == interface) + { + Obj->Runtime.status_cb[1] = NULL; + Obj->Runtime.callback_arg[1] = NULL; + } + else + { + Obj->Runtime.status_cb[0] = NULL; + Obj->Runtime.callback_arg[0] = NULL; + } + rc = MX_WIFI_STATUS_OK; + } + return rc; +} + + +static int8_t *mx_ntoa(const mx_ip4_addr_t *addr) +{ + uint32_t MX_S_ADDR; + uint8_t val; + int8_t inv[3]; + uint8_t *ap; + uint8_t rem; + uint8_t i; + int32_t len = 0; + int8_t *buf_ret; + static int8_t buf[16]; + + MX_S_ADDR = addr->addr; + + ap = (uint8_t *)&MX_S_ADDR; + for (uint8_t n = 0; n < (uint8_t) 4; n++) + { + i = 0; + val = ap[n]; + do + { + rem = val % 10U; + val /= 10U; + inv[i] = (int8_t)'0' + rem; + i++; + } while (val != 0U); + + while (i != 0U) + { + i--; + if (len < 16) + { + buf[len] = inv[i]; + len++; + } + } + + if ((n < 3U) && (len < 16)) + { + buf[len] = (int8_t) '.'; + len++; + } + } + + if (len < 16) + { + buf[len] = (int8_t) '\0'; + buf_ret = buf; + + } + else + { + buf_ret = (int8_t *) "000.000.000.000"; + } + + return buf_ret; +} + + +/** + * @brief wifi connect to an AP + * @param Obj wifi object + * @param SSID ssid of AP + * @param Password password of AP + * @param SecType security type (not used, auto) + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_Connect(MX_WIFIObject_t *Obj, const char *SSID, + const char *Password, MX_WIFI_SecurityType_t SecType) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + wifi_connect_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t rparams_size; + mwifi_ip_attr_t ip_attr; + mx_ip4_addr_t net_ipaddr; + + (void)SecType; + + if ((NULL == Obj) || (NULL == SSID) || (strlen(SSID) > (uint32_t)MX_MAX_SSID_LEN) + || (NULL == Password) || (strlen(Password) > (uint32_t)MX_MAX_KEY_LEN)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + strncpy((char *)cparams.ssid, SSID, MX_MAX_SSID_LEN); + strncpy((char *)cparams.key, Password, MX_MAX_KEY_LEN); + cparams.key_len = strlen(Password); + cparams.use_attr = 0; + cparams.use_ip = 0; + + if ((uint8_t)0 == Obj->NetSettings.DHCP_IsEnabled) + { + (void)memset(&ip_attr, 0, sizeof(mwifi_ip_attr_t)); + (void)memcpy(&net_ipaddr, Obj->NetSettings.IP_Addr, 4); + (void)memcpy(ip_attr.localip, mx_ntoa(&net_ipaddr), MX_MAX_IP_LEN); + (void)memcpy(&net_ipaddr, Obj->NetSettings.IP_Mask, 4); + (void)memcpy(ip_attr.netmask, mx_ntoa(&net_ipaddr), MX_MAX_IP_LEN); + (void)memcpy(&net_ipaddr, Obj->NetSettings.Gateway_Addr, 4); + (void)memcpy(ip_attr.gateway, mx_ntoa(&net_ipaddr), MX_MAX_IP_LEN); + (void)memcpy(&net_ipaddr, Obj->NetSettings.DNS1, 4); + (void)memcpy(ip_attr.dnserver, mx_ntoa(&net_ipaddr), MX_MAX_IP_LEN); + cparams.use_ip = 1; + memcpy(&(cparams.ip), &ip_attr, sizeof(cparams.ip)); + } + + rparams_size = sizeof(status); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_CONNECT_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &rparams_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + + } + return ret; +} + +/** + * @brief connect to an AP with WAP-E + * @param Obj wifi object + * @param SSID ssid of AP + * @param Identity identity of client + * @param Password password of client + * @param attr EAP attribute + * @param ip ip attribute + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_EAP_Connect(MX_WIFIObject_t *Obj, const char *SSID, + const char *Identity, const char *Password, + mwifi_eap_attr_t *attr, mwifi_ip_attr_t *ip) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_OK; + +#if 0 + lib_ipc_eap_attr_t ipc_eap_attr; + + if ((NULL == Obj) || (NULL == SSID) || (strlen(SSID) > (uint32_t)MX_MAX_SSID_LEN) || \ + (NULL == Identity) || (strlen(Identity) > (uint32_t)MX_MAX_IDENTITY_LEN) || \ + (NULL == Password) || (strlen(Password) > (uint32_t)MX_MAX_KEY_LEN)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (!MX_WIFI_LOCK((Obj))) + { + ret = MX_WIFI_STATUS_TIMEOUT; + } + else + { + (void)memset(&ipc_eap_attr, 0, sizeof(ipc_eap_attr)); + + if (NULL != attr) + { + /* just set eap type here, rootca/cert/key set by specifical API */ + if (((uint8_t)EAP_TYPE_TLS != attr->eap_type) && ((uint8_t)EAP_TYPE_TTLS != attr->eap_type) && + ((uint8_t)EAP_TYPE_PEAP != attr->eap_type)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + ipc_eap_attr.eap_type = attr->eap_type; + + if (NULL != attr->rootca) + { + if (MIPC_CODE_SUCCESS != wifi_eap_set_rootca_cmd(attr->rootca, strlen(attr->rootca))) + { + ret = MX_WIFI_STATUS_ERROR; + } + } + + if ((MX_WIFI_STATUS_OK == ret) && (NULL != attr->client_cert)) + { + if (MIPC_CODE_SUCCESS != wifi_eap_set_client_cert_cmd(attr->client_cert, strlen(attr->client_cert))) + { + ret = MX_WIFI_STATUS_ERROR; + } + } + + if ((MX_WIFI_STATUS_OK == ret) && (NULL != attr->client_key)) + { + if (MIPC_CODE_SUCCESS != wifi_eap_set_client_key_cmd(attr->client_key, strlen(attr->client_key))) + { + ret = MX_WIFI_STATUS_ERROR; + } + } + } + } + else + { + ipc_eap_attr.eap_type = (uint8_t)EAP_TYPE_PEAP; /* default eap type */ + } + + if (MX_WIFI_STATUS_OK == ret) + { + if (MIPC_CODE_SUCCESS != wifi_eap_connect_cmd(SSID, (int32_t)strlen(SSID), + Identity, (int32_t)strlen(Identity), + Password, (int32_t)strlen(Password), + &ipc_eap_attr, sizeof(ipc_eap_attr), + ip, (NULL != ip) ? sizeof(mwifi_ip_attr_t) : 0u)) + { + ret = MX_WIFI_STATUS_ERROR; + } + } + + (void)MX_WIFI_UNLOCK((Obj)); + } + } +#endif /* 0 */ + + return ret; +} + +/** + * @brief wifi station disconnect + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_Disconnect(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + int32_t status = MIPC_CODE_ERROR; + uint16_t rparams_size; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + rparams_size = sizeof(status); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_DISCONNECT_CMD, NULL, 0, + (uint8_t *)&status, &rparams_size, + 15000)) /* disconnect max timeout 15s */ + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief connect AP with WPS + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_WPS_Connect(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_val; + int32_t addr_ret_flag; + int32_t *p_addr_ret_val; + int32_t *p_addr_ret_flag; + + if (NULL != Obj) + { + p_addr_ret_val = &ret; + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_val, &p_addr_ret_val, sizeof(addr_ret_val)); + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == wifi_wps_connect_cmd(addr_ret_val, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, &ret, Obj->Runtime.Timeout)) + { + ret = MX_WIFI_STATUS_OK; + } + } + } +#endif /* 0 */ + + return ret; +} + +/** + * @brief stop connecting to an AP with WPS + * @param Obj wifi object + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_WPS_Stop(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_val; + int32_t addr_ret_flag; + int32_t *p_addr_ret_val; + int32_t *p_addr_ret_flag; + + if (NULL != Obj) + { + p_addr_ret_val = &ret; + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_val, &p_addr_ret_val, sizeof(addr_ret_val)); + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == wifi_wps_stop_cmd(addr_ret_val, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, &ret, Obj->Runtime.Timeout)) + { + ret = MX_WIFI_STATUS_OK; + } + } + } +#endif /* 0 */ + + return ret; +} + +/** + * @brief get wifi station connect status + * @param Obj wifi object + * @return int8_t 1 -- connected, 0 -- not connected + */ +int8_t MX_WIFI_IsConnected(MX_WIFIObject_t *Obj) +{ + int8_t ret = 0; + wifi_get_linkinof_rparams_t rparams; + uint16_t rparams_size = sizeof(rparams); + rparams.status = MIPC_CODE_ERROR; + if (NULL != Obj) + { + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_GET_LINKINFO_CMD, NULL, 0, + (uint8_t *)&rparams, &rparams_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == rparams.status) + { + Obj->NetSettings.IsConnected = rparams.info.is_connected; + ret = Obj->NetSettings.IsConnected; + } + } + } + return ret; +} + +/** + * @brief get wifi IPv4 address + * @param Obj wifi object + * @param ipaddr address buffer + * @param wifi_if wifi interface + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_GetIPAddress(MX_WIFIObject_t *Obj, uint8_t *ipaddr, mwifi_if_t wifi_if) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + wifi_get_ip_rparams_t rparams; + uint16_t rparams_size = sizeof(rparams); + int32_t ip; + int32_t netmask; + int32_t gw; + int32_t dns; + + rparams.status = MIPC_CODE_ERROR; + + if (NULL != Obj) + { + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_GET_IP_CMD, + (uint8_t *)&wifi_if, sizeof(wifi_if), + (uint8_t *)&rparams, &rparams_size, + 1000)) + { + if (MIPC_CODE_SUCCESS == rparams.status) + { + ip = mx_aton_r((int8_t const *) & (rparams.ip.localip[0])); + memcpy(&(Obj->NetSettings.IP_Addr[0]), &ip, 4); + + netmask = mx_aton_r((int8_t const *) & (rparams.ip.netmask[0])); + memcpy(&(Obj->NetSettings.IP_Mask[0]), &netmask, 4); + + gw = mx_aton_r((int8_t const *) & (rparams.ip.gateway[0])); + memcpy(&(Obj->NetSettings.Gateway_Addr[0]), &gw, 4); + + dns = mx_aton_r((int8_t const *) & (rparams.ip.dnserver[0])); + memcpy(&(Obj->NetSettings.DNS1[0]), &dns, 4); + + (void)memcpy(ipaddr, Obj->NetSettings.IP_Addr, 4); + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief get wifi IPv6 address info + * @param Obj wifi object + * @param ipaddr6 ipv6 address buffer + * @param addr_num ipv6 address index (0,1,2) + * @param wifi_if wifi interface + * @return MX_WIFI_STATUS_T status + */ +MX_WIFI_STATUS_T MX_WIFI_GetIP6Address(MX_WIFIObject_t *Obj, uint8_t *ipaddr6, int32_t addr_num, mwifi_if_t wifi_if) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_flag; + int32_t *p_addr_ret_flag; + + if ((NULL != Obj) && (NULL != ipaddr6) && (addr_num < 3) && (addr_num >= 0)) + { + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == wifi_get_ip6_addr_cmd((int32_t)addr_num, (int32_t)wifi_if, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, NULL, Obj->Runtime.Timeout)) + { + (void)memcpy(ipaddr6, Obj->NetSettings.IP6_Addr[addr_num], 16); + ret = MX_WIFI_STATUS_OK; + } + } + } +#endif /* 0 */ + + return ret; +} + +/** + * @brief Get the local IPv6 address state of the wifi module. + * @param Obj: pointer to module handle + * @param addr_num: index of the IPv6 address (index: 0/1/2). + * @param wifi_if: wifi mode(station or softap). + * @retval IPV6 address State, error if < 0 + */ +int32_t MX_WIFI_GetIP6AddressState(MX_WIFIObject_t *Obj, int32_t addr_num, mwifi_if_t wifi_if) +{ + int32_t state = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_flag; + int32_t *p_addr_ret_flag; + + if ((NULL != Obj) && (addr_num < 3) && (addr_num >= 0)) + { + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == wifi_get_ip6_state_cmd((int32_t)addr_num, (int32_t)wifi_if, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, NULL, Obj->Runtime.Timeout)) + { + state = Obj->NetSettings.IP6_state[addr_num]; + } + } + } +#endif /* 0 */ + + return state; +} + +/* +* SoftAP + */ + +/** + * @brief Start softAP(miniAP) mode + * @param Obj: pointer to module handle + * @param ap_settings: softAP settings. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_StartAP(MX_WIFIObject_t *Obj, MX_WIFI_APSettings_t *ap_settings) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + wifi_softap_start_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t rparams_size = sizeof(status); + + if ((NULL == Obj) || (NULL == ap_settings)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memcpy((char *)cparams.ssid, ap_settings->SSID, sizeof(cparams.ssid)); + memcpy((char *)cparams.key, ap_settings->pswd, sizeof(cparams.key)); + cparams.channel = ap_settings->channel; + memcpy(&(cparams.ip), &(ap_settings->ip), sizeof(cparams.ip)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_SOFTAP_START_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &rparams_size, + 3000)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Stop softAP(miniAP) mode + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_StopAP(MX_WIFIObject_t *Obj) +{ + MX_WIFI_STATUS_T ret = MX_WIFI_STATUS_ERROR; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL != Obj) + { + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_SOFTAP_STOP_CMD, NULL, 0, + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +#if MX_WIFI_NETWORK_BYPASS_MODE == 0 +/** + * @brief Create a socket. + * @param Obj: pointer to module handle + * @param domain: socket domain + * @param type: socket type + * @param protocol: socket protocol + * @retval Socket file descriptor, return < 1 if failed. + */ +int32_t MX_WIFI_Socket_create(MX_WIFIObject_t *Obj, int32_t domain, int32_t type, int32_t protocol) +{ + int32_t ret_fd = -1; + socket_create_cparams_t cp; + socket_create_rparams_t rp; + uint16_t out_size = sizeof(rp); + + if (NULL != Obj) + { + cp.domain = domain; + cp.type = type; + cp.protocol = protocol; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_CREATE_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + ret_fd = rp.fd; + } + } + + return ret_fd; +} + +/** + * @brief Set option for a socket + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param level: option level + * @param optname: option to set + * @param optvalue: value buffer for the option + * @param optlen: length of the option value + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_setsockopt(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t level, + int32_t optname, const void *optvalue, int32_t optlen) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_setsockopt_cparams_t cp; + socket_setsockopt_rparams_t rp; + uint16_t out_size = sizeof(rp); + + rp.status = MIPC_CODE_ERROR; + if ((NULL == Obj) || (sockfd < 0) || (NULL == optvalue) || (optlen <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.socket = sockfd; + cp.level = level; + cp.optname = optname; + cp.optlen = optlen > sizeof(cp.optval) ? sizeof(cp.optval) : optlen; + memcpy(&(cp.optval[0]), optvalue, cp.optlen); + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_SETSOCKOPT_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Get option of a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param level: option level + * @param optname: option to set + * @param optvalue: buffer pointer of value of the option + * @param optlen: buffer pointer of length of the option value + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_getsockopt(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t level, + int32_t optname, void *optvalue, uint32_t *optlen) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_getsockopt_cparams_t cp; + socket_getsockopt_rparams_t rp; + uint16_t out_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == optvalue) || (NULL == optlen)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.socket = sockfd; + cp.level = level; + cp.optname = optname; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_GETSOCKOPT_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + *optlen = (rp.optlen > (*optlen)) ? (*optlen) : rp.optlen; + memcpy(optvalue, &(rp.optval[0]), *optlen); + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Bind a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: socket address + * @param addrlen: address length + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_bind(MX_WIFIObject_t *Obj, int32_t sockfd, + const struct sockaddr *addr, int32_t addrlen) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_bind_cparams_t cp; + socket_bind_rparams_t rp; + uint16_t out_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == addr) || (addrlen <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.socket = sockfd; + memcpy(&(cp.addr), addr, sizeof(cp.addr)); + cp.length = addrlen; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_BIND_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Listen a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param backlog: max number to queued. + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_listen(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t backlog) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_listen_cparams_t cp; + socket_listen_rparams_t rp; + uint16_t rp_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.socket = sockfd; + cp.n = backlog; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_LISTEN_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Accept a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: client address + * @param addrlen: length of client address + * @retval Accepted client socket fd, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_accept(MX_WIFIObject_t *Obj, int32_t sockfd, + struct sockaddr *addr, uint32_t *addrlen) +{ + int32_t ret_fd = -1; + socket_accept_cparams_t cp; + socket_accept_rparams_t rp; + uint16_t rp_size = sizeof(rp); + rp.socket = -1; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == addr) || (NULL == addrlen)) + { + ret_fd = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.socket = sockfd; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_ACCEPT_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.socket >= 0) + { + memcpy(addr, &(rp.addr), sizeof(rp.addr)); + *addrlen = rp.length; + ret_fd = rp.socket; + } + } + } + return ret_fd; +} + +/** + * @brief Socket connect. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: client address + * @param addrlen: length of client address + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_connect(MX_WIFIObject_t *Obj, int32_t sockfd, + const struct sockaddr *addr, int32_t addrlen) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_connect_cparams_t cp; + socket_connect_rparams_t rp; + uint16_t out_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == addr) || (addrlen <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.socket = sockfd; + memcpy(&(cp.addr), addr, sizeof(cp.addr)); + cp.length = addrlen; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_CONNECT_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Socket shutdown. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param mode: shutdown mode: + * 0 Stop receiving data for this socket; + * 1 Stop trying to transmit data from this socket + * 2 Stop all transmit from this socket + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_shutdown(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t mode) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_shutdown_cparams_t cp; + socket_shutdown_rparams_t rp; + uint16_t out_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.filedes = sockfd; + cp.how = mode; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_SHUTDOWN_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Socket close. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_close(MX_WIFIObject_t *Obj, int32_t sockfd) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + socket_close_cparams_t cp; + socket_close_rparams_t rp; + uint16_t out_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.filedes = sockfd; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_CLOSE_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Socket send. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: send data buffer + * @param len: length of send data + * @param flags: zero for MXOS + * @retval Number of bytes sent, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_send(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, + int32_t len, int32_t flags) +{ + int32_t ret = -1; + socket_send_cparams_t *cp; + uint16_t cp_size; + socket_send_rparams_t rp; + uint16_t rp_size = sizeof(rp); + int32_t datalen; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == buf) || (len <= 0)) + { + ret = -1; + } + else + { + if ((len + sizeof(socket_send_cparams_t) - 1) > MX_WIFI_IPC_PAYLOAD_SIZE) + { + datalen = (MX_WIFI_IPC_PAYLOAD_SIZE - (sizeof(socket_send_cparams_t) - 1)); + } + else + { + datalen = len; + } + rp.sent = 0; + cp_size = (sizeof(socket_send_cparams_t) - 1 + datalen); + cp = (socket_send_cparams_t *)MX_WIFI_MALLOC(cp_size); + if (NULL != cp) + { + cp->socket = sockfd; + memcpy(&(cp->buffer[0]), buf, datalen); + cp->size = datalen; + cp->flags = flags; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_SEND_CMD, + (uint8_t *)cp, cp_size, + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + ret = rp.sent; + } + MX_WIFI_FREE(cp); + } + } + return ret; +} + +/** + * @brief Socket sendto. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: send data buffer + * @param len: length of send data + * @param flags: zero for MXOS + * @param toaddr: address to send + * @param toaddrlen: length of address to send + * @retval Number of bytes sent, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_sendto(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, + int32_t len, int32_t flags, + struct sockaddr *toaddr, int32_t toaddrlen) +{ + int32_t ret = -1; + socket_sendto_cparams_t *cp; + uint16_t cp_size; + socket_sendto_rparams_t rp; + uint16_t rp_size = sizeof(rp); + int32_t datalen; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == buf) || (len <= 0) || (NULL == toaddr) || (toaddrlen <= 0)) + { + ret = -1; + } + else + { + if ((len + sizeof(socket_sendto_cparams_t) - 1) > MX_WIFI_IPC_PAYLOAD_SIZE) + { + datalen = (MX_WIFI_IPC_PAYLOAD_SIZE - (sizeof(socket_sendto_cparams_t) - 1)); + } + else + { + datalen = len; + } + cp_size = (sizeof(socket_sendto_cparams_t) - 1 + datalen); + cp = (socket_sendto_cparams_t *)MX_WIFI_MALLOC(cp_size); + if (NULL != cp) + { + rp.sent = 0; + cp->socket = sockfd; + memcpy(&(cp->buffer[0]), buf, datalen); + cp->size = datalen; + cp->flags = flags; + memcpy(&(cp->addr), toaddr, sizeof(cp->addr)); + cp->length = toaddrlen; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_SENDTO_CMD, + (uint8_t *)cp, cp_size, + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + ret = rp.sent; + } + MX_WIFI_FREE(cp); + } + } + return ret; +} + +/** + * @brief Socket recv. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: recv buffer + * @param len: length of recv buffer + * @param flags: zero for MXOS + * @retval Number of bytes received, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_recv(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, + int32_t len, int32_t flags) +{ + int32_t ret = -1; + socket_recv_cparams_t cp; + socket_recv_rparams_t *rp; + uint16_t rp_size; + int32_t datalen; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == buf) || (len <= 0)) + { + ret = -1; + } + else + { + ret = 0; + if ((len + sizeof(socket_recv_rparams_t) - 1) > MX_WIFI_IPC_PAYLOAD_SIZE) + { + datalen = (MX_WIFI_IPC_PAYLOAD_SIZE - (sizeof(socket_recv_rparams_t) - 1)); + } + else + { + datalen = len; + } + rp_size = (sizeof(socket_recv_rparams_t) - 1 + datalen); + rp = (socket_recv_rparams_t *)MX_WIFI_MALLOC(rp_size); + if (NULL != rp) + { + rp->received = 0; + cp.socket = sockfd; + cp.size = datalen; + cp.flags = flags; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_RECV_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if ((rp->received <= datalen) && (rp->received > 0)) + { + memcpy(buf, &(rp->buffer[0]), rp->received); + } + ret = rp->received; + } + MX_WIFI_FREE(rp); + } + } + return ret; +} + +/** + * @brief Socket recvfrom. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: recv buffer + * @param len: length of recv buffer + * @param fromaddr: address of the data source + * @param fromaddrlen: length of address of the data source + * @param flags: zero for MXOS + * @retval Number of bytes received, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_recvfrom(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, + int32_t len, int32_t flags, + struct sockaddr *fromaddr, uint32_t *fromaddrlen) +{ + int32_t ret = -1; + socket_recvfrom_cparams_t cp; + socket_recvfrom_rparams_t *rp; + uint16_t rp_size; + int32_t datalen; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == buf) || (len <= 0) || (NULL == fromaddr) \ + || (NULL == fromaddrlen)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + ret = 0; + if ((len + sizeof(socket_recvfrom_rparams_t) - 1) > MX_WIFI_IPC_PAYLOAD_SIZE) + { + datalen = (MX_WIFI_IPC_PAYLOAD_SIZE - (sizeof(socket_recvfrom_rparams_t) - 1)); + } + else + { + datalen = len; + } + rp_size = (sizeof(socket_recvfrom_rparams_t) - 1 + datalen); + rp = (socket_recvfrom_rparams_t *)MX_WIFI_MALLOC(rp_size); + if (NULL != rp) + { + rp->received = 0; + cp.socket = sockfd; + cp.size = datalen; + cp.flags = flags; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_RECVFROM_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if ((rp->received <= datalen) && (rp->received > 0)) + { + memcpy(buf, &(rp->buffer[0]), rp->received); + ret = rp->received; + memcpy(fromaddr, &(rp->addr), sizeof(rp->addr)); + *fromaddrlen = rp->length; + } + } + MX_WIFI_FREE(rp); + } + } + return ret; +} + +/** + * @brief Gethostbyname, only for IPv4 address. + * @param Obj: pointer to module handle + * @param addr: address of the host + * @param name: hostname + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_gethostbyname(MX_WIFIObject_t *Obj, struct sockaddr *addr, char *name) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mx_sockaddr_in_t addr_in; + socket_gethostbyname_cparams_t cp; + socket_gethostbyname_rparams_t rp; + uint16_t rp_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (NULL == addr) || (NULL == name) || (strlen(name) > (uint32_t)MX_MAX_DNSNAME_LEN)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + uint32_t msize; + memset(&cp, 0, sizeof(cp)); + msize = MIN(sizeof(cp.name), strlen(name) + 1); + memcpy(&(cp.name[0]), name, msize); + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_GETHOSTBYNAME_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.status == MIPC_CODE_SUCCESS) + { + addr_in.sin_addr.s_addr = rp.s_addr; + addr_in.sin_family = AF_INET; + addr_in.sin_len = sizeof(addr_in); + memcpy(addr, &addr_in, sizeof(struct sockaddr)); + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Ping a host, only for IPv4 address. + * @param Obj: pointer to module handle + * @param addr: hostname + * @param count: ping max count + * @param delay: ping delay in millisecond + * @param response: response time array of ping result + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_ping(MX_WIFIObject_t *Obj, const char *hostname, + int32_t count, int32_t delay, int32_t response[]) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + wifi_ping_cparams_t cp; + int32_t ping_resp[1 + MX_WIFI_PING_MAX]; + wifi_ping_rparams_t *rp; + uint16_t rp_size = sizeof(ping_resp); + int32_t i = 0; + + if ((NULL == Obj) || (NULL == hostname) || (count <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + int32_t msize; + memset(&cp, 0, sizeof(cp)); + msize = MIN(sizeof(cp.hostname), strlen(hostname) + 1); + memcpy(&(cp.hostname[0]), hostname, msize); + cp.count = count; + cp.delay_ms = delay; + memset(ping_resp, 0, sizeof(ping_resp)); + rp = (wifi_ping_rparams_t *)&ping_resp; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_PING_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp->num > 0) + { + for (i = 0; i < rp->num; i++) + { + response[i] = rp->delay_ms[i]; + } + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +#if 0 +/** + * @brief Get IPv4/v6 address info by nodename. + * @param Obj: pointer to module handle + * @param nodename: descriptive name or address string of the host + * @param servname: not used, set NULL + * @param hints: structure containing input values that set socktype and protocol + * @param res: buf to store the result (set to NULL on failure) + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_getaddrinfo(MX_WIFIObject_t *Obj, const char *nodename, const char *servname, + const struct addrinfo *hints, struct mc_addrinfo *res) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_val; + int32_t addr_ret_flag; + int32_t *p_addr_ret_val; + int32_t *p_addr_ret_flag; + + if ((NULL == Obj) || (NULL == nodename) || (NULL == hints) || (NULL == res)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + p_addr_ret_val = &ret; + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_val, &p_addr_ret_val, sizeof(addr_ret_val)); + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == socket_getaddrinfo_cmd(nodename, (int32_t)strlen(nodename), + servname, (int32_t)strlen(servname), + (void *)hints, sizeof(struct addrinfo), (int)res, + addr_ret_val, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, NULL, Obj->Runtime.Timeout)) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Monitor multiple file descriptors for sockets + * @attention Never doing operations in different threads + * @param Obj: pointer to module handle + * @param nfds: is the highest-numbered file descriptor in any of the three + * sets, plus 1 + * @param readfds: A file descriptor sets will be watched to see if characters + * become available for reading + * @param writefds: A file descriptor sets will be watched to see if a write + * will not block. + * @param exceptfds: A file descriptor sets will be watched for exceptions. + * @param timeout: The timeout argument specifies the interval that select() + * should block waiting for a file descriptor to become ready. + * If timeout is NULL (no timeout), select() can block until API timeout. + * @retval On success, return the number of file descriptors contained in the + * three returned descriptor sets (that is, the total number of bits + * that are set in readfds, writefds, exceptfds) which may be zero if + * the timeout expires before anything interesting happens. On error, + * -1 is returned, the file descriptor sets are unmodified, and timeout + * becomes undefined. + */ +int32_t MX_WIFI_Socket_select(MX_WIFIObject_t *Obj, int32_t nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct mc_timeval *timeout) +{ + int32_t ret = -1; /* error */ + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t *p_ret_flag; + int32_t addr_ret_flag; + + if ((NULL != Obj) && (nfds > 0) && ((NULL != readfds) || (NULL != writefds) || (NULL != exceptfds))) + { + p_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_flag, &p_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == socket_select_cmd(nfds, readfds, sizeof(fd_set), + writefds, sizeof(fd_set), + exceptfds, sizeof(fd_set), + timeout, sizeof(struct mc_timeval), + addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, NULL, 200)) + { + ret = mc_select_ret_value; + if (ret > 0) + { + if (readfds) + { + (void)memcpy(readfds, &mc_select_rfds, sizeof(fd_set)); + } + if (writefds) + { + (void)memcpy(writefds, &mc_select_wfds, sizeof(fd_set)); + } + if (exceptfds) + { + (void)memcpy(exceptfds, &mc_select_efds, sizeof(fd_set)); + } + } + mc_select_ret_value = -1; + } + } + } + return ret; +} +#endif /* 0 */ + +/** + * @brief socket getpeername. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: address buffer + * @param addrlen: size of address buffer + * @retval get address of peer socket, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_getpeername(MX_WIFIObject_t *Obj, int32_t sockfd, struct sockaddr *addr, uint32_t *addrlen) +{ + int32_t ret = -1; + socket_getpeername_cparams_t cp; + socket_getpeername_rparams_t rp; + uint16_t rp_size = sizeof(rp); + + if ((NULL == Obj) || (sockfd < 0) || (NULL == addr) || (NULL == addrlen) || (*addrlen <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.s = sockfd; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_GETPEERNAME_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == rp.status) + { + memcpy(addr, &(rp.name), sizeof(rp.name)); + *addrlen = rp.namelen; + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief socket getsockname. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: address buffer + * @param addrlen: size of address buffer + * @retval get address of local socket, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_getsockname(MX_WIFIObject_t *Obj, int32_t sockfd, struct sockaddr *addr, uint32_t *addrlen) +{ + int32_t ret = -1; + socket_getsockname_cparams_t cp; + socket_getsockname_rparams_t rp; + uint16_t rp_size = sizeof(rp); + rp.status = MIPC_CODE_ERROR; + + if ((NULL == Obj) || (sockfd < 0) || (NULL == addr) || (NULL == addrlen) || (*addrlen <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.s = sockfd; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_SOCKET_GETSOCKNAME_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == rp.status) + { + memcpy(addr, &(rp.name), sizeof(rp.name)); + *addrlen = rp.namelen; + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/* mDNS */ + +/** + * @brief start mDNS service. + * @param Obj: pointer to module handle + * @param domain: domain of service + * @param name: hostname + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_start(MX_WIFIObject_t *Obj, const char *domain, char *hostname) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_start_cparams_t cparams; + int32_t status; + uint16_t out_size = sizeof(status); + status = MIPC_CODE_ERROR; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + memcpy(&(cparams.domain[0]), domain, sizeof(cparams.domain)); + memcpy(&(cparams.hostname[0]), hostname, sizeof(cparams.hostname)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_START_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + + return ret; +} + +/** + * @brief stop mDNS service. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_stop(MX_WIFIObject_t *Obj) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + int32_t status = MIPC_CODE_ERROR; + uint16_t rparams_size; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + rparams_size = sizeof(status); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_STOP_CMD, NULL, 0, + (uint8_t *)&status, &rparams_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief announce a service. + * @param Obj: pointer to module handle + * @param service: service to announce + * @param interface: wifi interface + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_announce_service(MX_WIFIObject_t *Obj, + struct mc_mdns_service *service, mwifi_if_t interface) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_announce_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if ((NULL == Obj) || (NULL == service)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + cparams.iface = interface; + memcpy(&(cparams.service_data), service, sizeof(cparams.service_data)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_ANNOUNCE_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + + return ret; +} + +/** + * @brief deannounce a service. + * @param Obj: pointer to module handle + * @param service: service to deannounce + * @param interface: wifi interface + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_deannounce_service(MX_WIFIObject_t *Obj, + struct mc_mdns_service *service, + mwifi_if_t interface) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_deannounce_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if ((NULL == Obj) || (NULL == service)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + cparams.iface = interface; + memcpy(&(cparams.service_data), service, sizeof(cparams.service_data)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_DEANNOUNCE_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + + return ret; +} + +/** + * @brief deannounce all services. + * @param Obj: pointer to module handle + * @param interface: wifi interface + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_deannounce_service_all(MX_WIFIObject_t *Obj, mwifi_if_t interface) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_deannounce_all_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + cparams.iface = interface; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_DEANNOUNCE_ALL_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + + return ret; +} + +/** + * @brief Send interface state change event to mdns + * @param Obj: pointer to module handle + * @param interface: wifi interface + * @param state: state event, valid interface state from \ref iface_state + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_iface_state_change(MX_WIFIObject_t *Obj, mwifi_if_t interface, + enum iface_state state) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_iface_state_change_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + cparams.iface = interface; + cparams.state = state; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_IFACE_STATE_CHANGE_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + + return ret; +} + +/** + * @brief Set new host name, use mdns_iface_state_change(interface, REANNOUNCE) to anounce + * the new host name. + * @param Obj: pointer to module handle + * @param hostname: new hostname + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_set_hostname(MX_WIFIObject_t *Obj, char *hostname) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_set_hostname_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + strncpy(cparams.hostname, hostname, MDNS_MAX_LABEL_LEN); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_SET_HOSTNAME_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief sets the TXT record field for a given mDNS service. + * @param Obj: pointer to module handle + * @param service: mDNS service + * @param keyvals: new txt record string + * @param separator: the separator used to separate individual key value pairs + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_set_txt_rec(MX_WIFIObject_t *Obj, struct mc_mdns_service *service, char *keyvals, + char separator) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + mdns_set_txt_rec_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + memset(&cparams, 0, sizeof(cparams)); + memcpy(&(cparams.service_data), service, sizeof(cparams.service_data)); + strncpy(cparams.keyvals, keyvals, MDNS_MAX_KEYVAL_LEN); + cparams.separator = separator; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_MDNS_SET_TXT_REC_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/* TLS */ + +/** + * @brief set the TLS protocol version. + * @param Obj: pointer to module handle + * @param version: TLS protocol version + * @retval Operation Status. + * @note This function should be called before TLS is ready to function (before + * mtls_connect and mtls_accept is called by application ). + */ +int32_t MX_WIFI_TLS_set_ver(MX_WIFIObject_t *Obj, mtls_ver_t version) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + tls_set_ver_cparams_t cp; + tls_set_ver_rparams_t rp; + uint16_t out_size = sizeof(rp); + + if ((NULL == Obj)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.version = version; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_SET_VER_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == rp.ret) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + + return ret; +} + +/** + * @brief TLS set client certificate + * @param Obj: pointer to module handle + * @param client_cert: Point to buffer of client cert. + * @param cert_len: length of the client cert. + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_set_clientCertificate(MX_WIFIObject_t *Obj, uint8_t *client_cert, uint16_t cert_len) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + tls_set_client_cert_cparams_t *cp; + uint16_t cp_size; + tls_set_client_cert_rparams_t rp; + uint16_t out_size = sizeof(rp); + + cp_size = sizeof(tls_set_client_cert_cparams_t) -1 + cert_len; + if ((NULL == Obj) || (NULL == client_cert) || (cert_len == (uint16_t)0) + || (cp_size > (uint16_t)(MX_WIFI_IPC_PAYLOAD_SIZE))) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp = (tls_set_client_cert_cparams_t *)MX_WIFI_MALLOC(cp_size); + if (NULL != cp) + { + memset(cp, 0, cp_size); + cp->cert_pem_size = cert_len; + cp->private_key_pem_size = 0; + memcpy(&(cp->cert_data[0]), client_cert, cert_len); + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_SET_CLIENT_CERT_CMD, + (uint8_t *)cp, cp_size, + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == rp.ret) + { + ret = MX_WIFI_STATUS_OK; + } + } + MX_WIFI_FREE(cp); + } + } + + return ret; +} + +/** + * @brief TLS set client private key + * @param Obj: pointer to module handle + * @param client_private_key: Point to buffer of client private key. + * @param key_len: length of the client cert. + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_set_clientPrivateKey(MX_WIFIObject_t *Obj, uint8_t *client_private_key, uint16_t key_len) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + tls_set_client_cert_cparams_t *cp; + uint16_t cp_size; + tls_set_client_cert_rparams_t rp; + uint16_t out_size = sizeof(rp); + + cp_size = sizeof(tls_set_client_cert_cparams_t) -1 + key_len; + if ((NULL == Obj) || (NULL == client_private_key) || (key_len == (uint16_t)0) + || (cp_size > (uint16_t)(MX_WIFI_IPC_PAYLOAD_SIZE))) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp = (tls_set_client_cert_cparams_t *)MX_WIFI_MALLOC(cp_size); + if (NULL != cp) + { + memset(cp, 0, cp_size); + cp->cert_pem_size = 0; + cp->private_key_pem_size = key_len; + memcpy(&(cp->cert_data[0]), client_private_key, key_len); + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_SET_CLIENT_CERT_CMD, + (uint8_t *)cp, cp_size, + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == rp.ret) + { + ret = MX_WIFI_STATUS_OK; + } + } + MX_WIFI_FREE(cp); + } + } + return ret; +} + +/** + * @brief TLS client create a TLS connection. + * @param Obj: pointer to module handle + * @details This function is called on the client side and initiates an TLS/TLS handshake with a + * server. When this function is called, the underlying communication channel has already + * been set up. This function is called after TCP 3-way handshake finished. + * @param domain: Specifies a communication domain + * @param type: Specifies the communication semantics. + * @param protocol: specifies a particular protocol to be used with the socket. + * @param addr: Point to the target address to be connected + * @param addrlen: containing the size of the buffer pointed to by addr + * @param ca: pointer to the CA certificate string, used to verify server's certificate. + * @param calen: the string length of ca. 0=do not verify server's certificate. + * @retval return the TLS context pointer on success or NULL for fail. + */ +int32_t MX_WIFI_TLS_connect(MX_WIFIObject_t *Obj, int32_t domain, int32_t type, int32_t protocol, + const struct sockaddr *addr, int32_t addrlen, char *ca, int32_t calen) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + (void)domain; + (void)type; + (void)protocol; + + if ((NULL == Obj) || (NULL == addr) || (addrlen <= 0)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + ret = MX_WIFI_TLS_connect_sni(Obj, NULL, 0, addr, addrlen, ca, calen); + } + + return ret; +} + +/** + * @brief TLS client create a TLS connection with SNI. + * @param Obj: pointer to module handle + * @details This function is called on the client side and initiates an TLS/TLS handshake with a + * server. When this function is called, the underlying communication channel has already + * been set up. This function is called after TCP 3-way handshake finished. + * @param sni_servername: Specifies the SNI server name + * @param sni_servername_len: Specifies the SNI server name length, max size MX_TLS_SNI_SERVERNAME_SIZE + * @param addr: Point to the target address to be connected + * @param addrlen: containing the size of the buffer pointed to by addr + * @param ca: pointer to the CA certificate string, used to verify server's certificate. + * @param calen: the string length of ca. 0=do not verify server's certificate. + * @retval return the TLS context pointer on success or NULL for fail. + */ +int32_t MX_WIFI_TLS_connect_sni(MX_WIFIObject_t *Obj, const char *sni_servername, int32_t sni_servername_len, + const struct sockaddr *addr, int32_t addrlen, char *ca, int32_t calen) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + tls_connect_sni_cparams_t *cp; + uint16_t cp_size; + tls_connect_sni_rparams_t rp; + uint16_t out_size = sizeof(rp); + + cp_size = sizeof(tls_connect_sni_cparams_t) -1 + calen; + if ((NULL == Obj) || (NULL == addr) || (addrlen <= 0) || (cp_size > (uint16_t)(MX_WIFI_IPC_PAYLOAD_SIZE))) + { + ret = 0; /* null for MX_WIFI_STATUS_PARAM_ERROR */ + } + else + { + rp.tls = NULL; + cp = (tls_connect_sni_cparams_t *)MX_WIFI_MALLOC(cp_size); + if (NULL != cp) + { + memset(cp, 0, cp_size); + if ((sni_servername_len > 0) && (NULL != sni_servername)) + { + strncpy(&(cp->sni_servername[0]), sni_servername, sizeof(cp->sni_servername)); + } + memcpy(&(cp->addr), addr, sizeof(cp->addr)); + cp->length = addrlen; + cp->calen = calen; + if ((calen > 0) && (NULL != ca)) + { + memcpy(&(cp->ca[0]), ca, calen); + } + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_CONNECT_SNI_CMD, + (uint8_t *)cp, cp_size, + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (NULL == rp.tls) + { + ret = 0; /* NULL */ + } + else + { + ret = (int32_t)rp.tls; + } + } + MX_WIFI_FREE(cp); + } + } + + return ret; +} + +/** + * @brief TLS send data + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @param data: Point to data to send. + * @param len: data length. + * @retval On success, return the number of bytes sent. + * On error, error code (< 0) is returned. + */ +int32_t MX_WIFI_TLS_send(MX_WIFIObject_t *Obj, mtls_t tls, void *data, int32_t len) +{ + int32_t ret = -1; + tls_send_cparams_t *cp; + uint16_t cp_size; + tls_send_rparams_t rp; + uint16_t rp_size = sizeof(rp); + int32_t datalen; + + if ((NULL == Obj) || (NULL == tls) || (NULL == data) || (len <= 0)) + { + ret = -1; + } + else + { + rp.sent = 0; + if ((len + sizeof(tls_send_cparams_t) - 1) > MX_WIFI_IPC_PAYLOAD_SIZE) + { + datalen = (MX_WIFI_IPC_PAYLOAD_SIZE - (sizeof(tls_send_cparams_t) - 1)); + } + else + { + datalen = len; + } + cp_size = (sizeof(tls_send_cparams_t) - 1 + datalen); + cp = (tls_send_cparams_t *)MX_WIFI_MALLOC(cp_size); + if (NULL != cp) + { + cp->tls = tls; + memcpy(&(cp->buffer[0]), data, datalen); + cp->size = datalen; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_SEND_CMD, + (uint8_t *)cp, cp_size, + (uint8_t *)&rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + ret = rp.sent; + } + MX_WIFI_FREE(cp); + } + } + return ret; +} + +/** + * @brief TLS redeive data + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @param data: Point to buffer to receive TLS data. + * @param len: max receive buffer length. + * @retval On success, return the number of bytes received. + * On error, error code (< 0) is returned. + */ +int32_t MX_WIFI_TLS_recv(MX_WIFIObject_t *Obj, mtls_t tls, void *buf, int32_t len) +{ + int32_t ret = -1; + tls_recv_cparams_t cp; + tls_recv_rparams_t *rp; + uint16_t rp_size; + int32_t datalen; + + if ((NULL == Obj) || (NULL == tls) || (NULL == buf) || (len <= 0)) + { + ret = -1; + } + else + { + ret = 0; + if ((len + sizeof(tls_recv_rparams_t) - 1) > MX_WIFI_IPC_PAYLOAD_SIZE) + { + datalen = (MX_WIFI_IPC_PAYLOAD_SIZE - (sizeof(tls_recv_rparams_t) - 1)); + } + else + { + datalen = len; + } + rp_size = (sizeof(tls_recv_rparams_t) - 1 + datalen); + rp = (tls_recv_rparams_t *)MX_WIFI_MALLOC(rp_size); + if (NULL != rp) + { + rp->received = 0; + cp.tls = tls; + cp.size = datalen; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_RECV_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)rp, &rp_size, + MX_WIFI_CMD_TIMEOUT)) + { + if ((rp->received <= datalen) && (rp->received > 0)) + { + memcpy(buf, &(rp->buffer[0]), rp->received); + } + ret = rp->received; + } + MX_WIFI_FREE(rp); + } + } + return ret; +} + +/** + * @brief Close the TLS session, release resource. + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_close(MX_WIFIObject_t *Obj, mtls_t tls) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + tls_close_cparams_t cp; + tls_close_rparams_t rp; + uint16_t out_size = sizeof(rp); + + if ((NULL == Obj) || (NULL == tls)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.tls = tls; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_CLOSE_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.ret == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Set TLS nonblock mode. + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @param nonblock: true - nonblock, false - block + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_set_nonblock(MX_WIFIObject_t *Obj, mtls_t tls, int32_t nonblock) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + tls_set_nonblock_cparams_t cp; + tls_set_nonblock_rparams_t rp; + uint16_t out_size = sizeof(rp); + + if ((NULL == Obj) || (NULL == tls)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cp.tls = tls; + cp.nonblock = nonblock; + memset(&rp, 0, sizeof(rp)); + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_TLS_SET_NONBLOCK_CMD, + (uint8_t *)&cp, sizeof(cp), + (uint8_t *)&rp, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (rp.ret == MIPC_CODE_SUCCESS) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Start webserver. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +int32_t MX_WIFI_Webserver_start(MX_WIFIObject_t *Obj) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_val; + int32_t addr_ret_flag; + int32_t *p_addr_ret_val; + int32_t *p_addr_ret_flag; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + p_addr_ret_val = &ret; + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_val, &p_addr_ret_val, sizeof(addr_ret_val)); + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == web_start_cmd(addr_ret_val, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, &ret, Obj->Runtime.Timeout)) + { + ret = MX_WIFI_STATUS_OK; + } + } + } +#endif /* 0 */ + + return ret; +} + +/** + * @brief Stop webserver. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +int32_t MX_WIFI_Webserver_stop(MX_WIFIObject_t *Obj) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_val; + int32_t addr_ret_flag; + int32_t *p_addr_ret_val; + int32_t *p_addr_ret_flag; + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + p_addr_ret_val = &ret; + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_val, &p_addr_ret_val, sizeof(addr_ret_val)); + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == web_stop_cmd(addr_ret_val, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, &ret, Obj->Runtime.Timeout)) + { + ret = MX_WIFI_STATUS_OK; + } + } + } +#endif /* 0 */ + + return ret; +} + +/** + * @brief Start FOTA. + * @param Obj: pointer to module handle + * @param url: HTTP/HTTPS url of bin file to update + * @param md5: MD5 string(32Bytes) of bin file to update + * @param ota_status_callback: callback function for ota status + * @retval Operation Status. + */ +int32_t MX_WIFI_FOTA_start(MX_WIFIObject_t *Obj, const char *url, const char *md5, + mx_wifi_fota_status_cb_t fota_status_callback, uint32_t user_args) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + +#if 0 + int32_t ret_flag = MIPC_RET_FLAG_CLR; + int32_t addr_ret_val; + int32_t addr_ret_flag; + int32_t *p_addr_ret_val; + int32_t *p_addr_ret_flag; + + if ((NULL == Obj) || (NULL == url) || (NULL == md5)) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (NULL != fota_status_callback) + { + Obj->Runtime.fota_status_cb = fota_status_callback; + Obj->Runtime.fota_user_args = user_args; + } + else + { + Obj->Runtime.fota_status_cb = NULL; + Obj->Runtime.fota_user_args = 0; + } + + p_addr_ret_val = &ret; + p_addr_ret_flag = &ret_flag; + (void)memcpy(&addr_ret_val, &p_addr_ret_val, sizeof(addr_ret_val)); + (void)memcpy(&addr_ret_flag, &p_addr_ret_flag, sizeof(addr_ret_flag)); + if (MIPC_CODE_SUCCESS == fota_start_cmd(url, (int32_t)strlen(url), md5, (int32_t)strlen(md5), + addr_ret_val, addr_ret_flag)) + { + if (MIPC_CODE_SUCCESS == mipc_poll(&ret_flag, &ret, Obj->Runtime.Timeout)) + { + ret = MX_WIFI_STATUS_OK; + } + } + } +#endif /* 0 */ + + return ret; +} + +#else /* MX_WIFI_NETWORK_BYPASS_MODE */ + +/** + * @brief Set network bypass mode + * @param Obj: pointer to module handle + * @param enable: 0=disable, 1=enable + * @param netlink_input_callbck: input data callback function + * @param user_args: user arguments for callback function + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Network_bypass_mode_set(MX_WIFIObject_t *Obj, int32_t enable, + mx_wifi_netlink_input_cb_t netlink_input_callbck, + void *user_args) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + wifi_bypass_set_cparams_t cparams; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if ((NULL != netlink_input_callbck) && (1 == enable)) + { + Obj->Runtime.netlink_input_cb = netlink_input_callbck; + Obj->Runtime.netlink_user_args = user_args; + } + else + { + Obj->Runtime.netlink_input_cb = NULL; + Obj->Runtime.netlink_user_args = NULL; + } + + cparams.mode = enable; + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_BYPASS_SET_CMD, + (uint8_t *)&cparams, sizeof(cparams), + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + +/** + * @brief Network bypass mode data output + * @param Obj: pointer to module handle + * @param pbuf: pbuf data to send + * @param size: pbuf size + * @param data: pbuf payload + * @param len: payload len + * @param interface: STATION_IDX, SOFTAP_IDX(not supported now) + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Network_bypass_netlink_output(MX_WIFIObject_t *Obj, void *data, + int32_t len, + int32_t interface) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + wifi_bypass_out_cparams_t *cparams; + uint16_t cparams_size; + int32_t status = MIPC_CODE_ERROR; + uint16_t rparams_size = sizeof(status); + + if ((NULL == Obj) || (len <= 0) || \ + (((int32_t)STATION_IDX != interface) && ((int32_t)SOFTAP_IDX != interface))) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + cparams_size = sizeof(wifi_bypass_out_cparams_t) + len; + if (cparams_size > MX_WIFI_IPC_PAYLOAD_SIZE) + { + len = MX_WIFI_IPC_PAYLOAD_SIZE - sizeof(wifi_bypass_out_cparams_t); + return MX_WIFI_STATUS_PARAM_ERROR; + } +#if MX_WIFI_TX_BUFFER_NO_COPY + /* structure of data buffer must support head room provision to add information in from of data payload */ + cparams = (wifi_bypass_out_cparams_t *)((uint8_t *)data - sizeof(wifi_bypass_out_cparams_t)); +#else + cparams = (wifi_bypass_out_cparams_t *)MX_WIFI_MALLOC(len + sizeof(wifi_bypass_out_cparams_t)); +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + + if (NULL != cparams) + { + cparams->idx = interface; + cparams->data_len = len; + +#if MX_WIFI_TX_BUFFER_NO_COPY == 0 + /* copy the whole payload */ + uint8_t *dst; + dst = (uint8_t *)cparams + sizeof(wifi_bypass_out_cparams_t); + memcpy(dst, data, len); +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + + if (MIPC_CODE_SUCCESS == mipc_request(MIPC_API_WIFI_BYPASS_OUT_CMD, + (uint8_t *)cparams, cparams_size, + (uint8_t *)&status, &rparams_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } +#if MX_WIFI_TX_BUFFER_NO_COPY == 0 + MX_WIFI_FREE(cparams); +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + } + else + { + /* no memory */ + DEBUG_LOG("No memory!!!\n"); + } + } + + return ret; +} +#endif /* MX_WIFI_NETWORK_BYPASS_MODE */ + +/** + * @brief set powersave onoff for wifi station mode. + * @param Obj: pointer to module handle + * @param ps_onoff: 0 -- powersave off, 1 -- powersave on + * @retval Operation Status. + */ +int32_t MX_WIFI_station_powersave(MX_WIFIObject_t *Obj, int32_t ps_onoff) +{ + int32_t ret = MX_WIFI_STATUS_ERROR; + uint16_t mipc_ps_cmd; + int32_t status = MIPC_CODE_ERROR; + uint16_t out_size = sizeof(status); + + if (NULL == Obj) + { + ret = MX_WIFI_STATUS_PARAM_ERROR; + } + else + { + if (ps_onoff) + { + mipc_ps_cmd = MIPC_API_WIFI_PS_ON_CMD; + } + else + { + mipc_ps_cmd = MIPC_API_WIFI_PS_OFF_CMD; + } + if (MIPC_CODE_SUCCESS == mipc_request(mipc_ps_cmd, NULL, 0, + (uint8_t *)&status, &out_size, + MX_WIFI_CMD_TIMEOUT)) + { + if (MIPC_CODE_SUCCESS == status) + { + ret = MX_WIFI_STATUS_OK; + } + } + } + return ret; +} + diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi.h new file mode 100644 index 0000000000..e7aba01f37 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi.h @@ -0,0 +1,1510 @@ +/** + ****************************************************************************** + * @file mx_wifi.h + * @author MCD Application Team + * @brief Header for mx_wifi.c module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_H +#define MX_WIFI_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Includes ------------------------------------------------------------------*/ +#include "mx_wifi_conf.h" + + +/** + * @defgroup MX_WIFI Wi-Fi_API + * @brief Driver API on STM32 for MXCHIP Wi-Fi module, see mx_wifi.h + * @{ ** + */ + +/* API version V2.1.8 */ +#define MX_WIFI_API_VERSION_MAJ (2) +#define MX_WIFI_API_VERSION_SUB (1) +#define MX_WIFI_API_VERSION_REV (10) + +/******************************************************************************* + * MXCHIP Wi-Fi Module Defines + ******************************************************************************/ +/* common defines */ +#define MX_MAX_IP_LEN (16) +#define MX_MAX_SSID_LEN (32) +#define MX_MAX_KEY_LEN (64) +#define MX_MAX_BSSID_LEN (6) +#define MX_MAX_DNSNAME_LEN (253) +#define MX_MAX_IDENTITY_LEN (32) +#define MX_TLS_SNI_SERVERNAME_SIZE (128) +#define MX_SERVICE_NAME_SIZE (255) +#define MC_WIFI_INTERFACE_NUM (2) +#define MX_WIFI_PING_MAX (10) + +#define MX_WIFI_SCAN_TIMEOUT (5000) + +/** + * @brief Wi-Fi mode + */ +enum +{ + MC_SOFTAP, /**< wifi softap mode. */ + MC_STATION /**< wifi station mode. */ +}; + +typedef uint8_t mwifi_if_t; /**< wifi mode. */ + +/** + * @brief Wi-Fi scan mode + */ +enum +{ + MC_SCAN_PASSIVE = 0, /**< wifi passive scan mode. */ + MC_SCAN_ACTIVE = 1 /**< wifi active scan mode. */ +}; + +typedef uint8_t mc_wifi_scan_mode_t; /**< wifi scan mode. */ + +/** + * @brief Wi-Fi ip address info + */ +typedef struct +{ + char localip[MX_MAX_IP_LEN]; /**< lcoal ip address */ + char netmask[MX_MAX_IP_LEN]; /**< netmask */ + char gateway[MX_MAX_IP_LEN]; /**< gateway ip address */ + char dnserver[MX_MAX_IP_LEN]; /**< dns server ip address */ +} mwifi_ip_attr_t; /**< wifi ip address info. */ + +/** + * @brief Wi-Fi EAP type + */ +typedef enum +{ + EAP_TYPE_TLS = 13, /* RFC 2716 */ + EAP_TYPE_TTLS = 21, /* RFC 5281 */ + EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */ +} EapType; + +/** + * @brief Wi-Fi EAP info + */ +typedef struct +{ + uint8_t eap_type; /* support: EAP_TYPE_PEAP, EAP_TYPE_TTLS, EAP_TYPE_TLS */ + const char *rootca; /* the EAP server rootca. NULL for don't check the server's certificate */ + const char *client_cert; /* client cert, only need this if the server need check the client's certificate, + such as EAP_TYPE_TLS mode. */ + const char *client_key; /* client private key. DONOT support encrypted key. */ +} mwifi_eap_attr_t; + +/******************************************************************************* + * STM32Cube Driver API Defines + ******************************************************************************/ +/* status code */ +#define MX_WIFI_STATUS_OK (0) /**< status code success. */ +#define MX_WIFI_STATUS_ERROR (-1) /**< status code common error. */ +#define MX_WIFI_STATUS_TIMEOUT (-2) /**< status code timeout. */ +#define MX_WIFI_STATUS_IO_ERROR (-3) /**< status code I/O error. */ +#define MX_WIFI_STATUS_PARAM_ERROR (-4) /**< status code bad argument error. */ +#define MX_WIFI_STATUS_T int32_t /**< status code. */ + +/* macro */ +#define MX_WIFI_MAC_SIZE (6) /**< max length of MAC address. */ +#define MX_WIFI_SCAN_BUF_SIZE (2000) /**< max size of scan buffer. */ + +#define MIN(a, b) ( ((a) < (b)) ? (a) : (b)) /**< helper function: get minimum. */ + +#if 0 +/* IPv6 address states. */ +#define IP6_ADDR_INVALID 0x00 +#define IP6_ADDR_TENTATIVE 0x08 +#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ +#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ +#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ +#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ +#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ +#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ +#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ +#define IP6_ADDR_VALID 0x10 +#define IP6_ADDR_PREFERRED 0x30 +#define IP6_ADDR_DEPRECATED 0x50 +#endif /* 0 */ + +/* +#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) +#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) +#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) +#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) +#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) + */ + +/** + * @brief Security settings for wifi network + */ +typedef enum +{ + MX_WIFI_SEC_NONE, /**< Open system. */ + MX_WIFI_SEC_WEP, /**< Wired Equivalent Privacy. WEP security. */ + MX_WIFI_SEC_WPA_TKIP, /**< WPA /w TKIP */ + MX_WIFI_SEC_WPA_AES, /**< WPA /w AES */ + MX_WIFI_SEC_WPA2_TKIP, /**< WPA2 /w TKIP */ + MX_WIFI_SEC_WPA2_AES, /**< WPA2 /w AES */ + MX_WIFI_SEC_WPA2_MIXED, /**< WPA2 /w AES or TKIP */ + MX_WIFI_SEC_AUTO /**< It is used when calling @ref mwifi_connect, + MXOS read security type from scan result. */ +} MX_WIFI_SecurityType_t; + +typedef int8_t (*IO_Init_Func)(uint16_t mode); /**< I/O interface init function. */ +typedef int8_t (*IO_DeInit_Func)(void); /**< I/O interface deinit function. */ +typedef void (*IO_Delay_Func)(uint32_t ms); /**< I/O interface delay function. */ +typedef uint16_t (*IO_Send_Func)(uint8_t *data, uint16_t len); /**< I/O interface send function. */ +typedef uint16_t (*IO_Receive_Func)(uint8_t *buffer, uint16_t buff_size); /**< I/O interface receive function. */ + +/** + * @brief Wi-Fi low level I/O interface operation handles + */ +typedef struct +{ + IO_Init_Func IO_Init; /**< I/O interface init function. */ + IO_DeInit_Func IO_DeInit; /**< I/O interface deinit function. */ + IO_Delay_Func IO_Delay; /**< I/O interface delay function. */ + IO_Send_Func IO_Send; /**< I/O interface send function. */ + IO_Receive_Func IO_Receive; /**< I/O interface receive function. */ +} MX_WIFI_IO_t; + +/** + * @brief Wi-Fi system info + */ +typedef struct +{ + /* FW info */ + uint8_t Product_Name[MX_WIFI_PRODUCT_NAME_SIZE];/**< product name. */ + uint8_t Product_ID[MX_WIFI_PRODUCT_ID_SIZE]; /**< product ID. */ + uint8_t FW_Rev[MX_WIFI_FW_REV_SIZE]; /**< firmware version. */ + uint8_t MAC[MX_WIFI_MAC_SIZE]; /**< Wi-Fi MAC address. */ +} MX_WIFI_SystemInfo_t; + +/** + * @brief Wi-Fi station info + */ +typedef struct +{ + /* wifi station setting */ + uint8_t SSID[MX_WIFI_MAX_SSID_NAME_SIZE + 1]; /**< Wi-Fi station SSID. */ + uint8_t pswd[MX_WIFI_MAX_PSWD_NAME_SIZE + 1]; /**< Wi-Fi station passwd. */ + MX_WIFI_SecurityType_t Security; /**< Wi-Fi station security. */ + uint8_t DHCP_IsEnabled; /**< Wi-Fi station DHCP. */ + /* status */ + int8_t IsConnected; /**< Wi-Fi station connection status. */ + /*ipv4 */ + uint8_t IP_Addr[4]; /**< Wi-Fi station IP address. */ + uint8_t IP_Mask[4]; /**< Wi-Fi station IP mask. */ + uint8_t Gateway_Addr[4]; /**< Wi-Fi station gateway. */ + uint8_t DNS1[4]; /**< Wi-Fi station DNS server. */ + /* ipv6 */ + int32_t IP6_state[3]; /**< Wi-Fi station IPv6 address state. */ + uint8_t IP6_Addr[3][16]; /**< Wi-Fi station IPv6 address. */ + uint8_t IP6_Mask[16]; /**< Wi-Fi station IPv6 mask. */ + uint8_t Gateway6_Addr[16]; /**< Wi-Fi station IPv6 gateway. */ + uint8_t IP6_DNS1[16]; /**< Wi-Fi station IPv6 DNS server. */ +} MX_WIFI_Network_t; + +/** + * @brief Wi-Fi softAP info + */ +typedef struct +{ + char SSID[MX_WIFI_MAX_SSID_NAME_SIZE + 1]; /**< Wi-Fi softAP SSID. */ + char pswd[MX_WIFI_MAX_PSWD_NAME_SIZE + 1]; /**< Wi-Fi softAP password. */ + /* MX_WIFI_SecurityType_t Security; OPEN: no passwd, WPA2: has passwd, NOT SUPPORTED NOW */ + uint8_t channel; /**< Wi-Fi softAP Channel. */ + mwifi_ip_attr_t ip; /**< Wi-Fi softAP IP settings. */ +} MX_WIFI_APSettings_t; + +/** Prototype of Wi-Fi status changed callback function. */ +/** + * @param cate wifi status: MC_STATION, MC_SOFTAP + * @param event wifi events: MWIFI_EVENT_STA_DOWN, + * MWIFI_EVENT_STA_UP, + * WIFI_EVENT_STA_GOT_IP, + * MWIFI_EVENT_AP_UP, + * MWIFI_EVENT_AP_DOWN + * @param arg user argument passed by @MX_WIFI_RegisterStatusCallback + */ +typedef void (*mx_wifi_status_callback_t)(uint8_t cate, uint8_t event, void *arg); + +/** + * @brief FOTA status + */ +typedef enum +{ + MX_WIFI_FOTA_SUCCESS, + MX_WIFI_FOTA_FAILED +} mx_wifi_fota_status_e; + +/** + * @brief Prototype of FOTA status callback function + */ +typedef void (*mx_wifi_fota_status_cb_t)(mx_wifi_fota_status_e status, uint32_t user_args); + +/** + * @brief Prototype of netlink input callback function for network bypass mode + */ +typedef void (*mx_wifi_netlink_input_cb_t)(mx_buf_t *pbuf, void *user_args); + +/** + * @brief Wi-Fi runtime info + */ +typedef struct +{ + uint32_t Timeout; /**< Wi-Fi cmd timeout in ms. */ + + mx_wifi_status_callback_t status_cb[MC_WIFI_INTERFACE_NUM]; /**< Wi-Fi status callback. */ + void *callback_arg[MC_WIFI_INTERFACE_NUM]; /**< Wi-Fi status callback argument. */ + + mx_wifi_fota_status_cb_t fota_status_cb; /**< FOTA status callback. */ + uint32_t fota_user_args; /**< FOTA status callback argument. */ + + mx_wifi_netlink_input_cb_t netlink_input_cb; /**< netlink input callback. */ + void *netlink_user_args; /**< netlink input callback argument. */ + + uint8_t scan_result[MX_WIFI_SCAN_BUF_SIZE]; /**< Wi-Fi scan result buffer. */ + uint8_t scan_number; /**< Num of Wi-Fi scan result to get. */ + + uint8_t interfaces; /**< Num of Wi-Fi interfaces inited, 2 if STA+AP inited. */ +} MX_WIFI_Runtime_t; + +/** + * @brief Wi-Fi Wi-Fi object handle + */ +typedef struct +{ + /* HW IO */ + MX_WIFI_IO_t fops; /**< Wi-Fi low level I/O operation handles. */ + + /* system info */ + MX_WIFI_SystemInfo_t SysInfo; /**< Wi-Fi system info. */ + + /* network info */ + MX_WIFI_Network_t NetSettings; /**< Wi-Fi station info. */ + MX_WIFI_APSettings_t APSettings; /**< Wi-Fi softAP info. */ + + /* run time data */ + MX_WIFI_Runtime_t Runtime; /**< Wi-Fi runtime info. */ + + /* wifi obj lock */ + LOCK_DECLARE(lockcmd); +} MX_WIFIObject_t; + + +/* Exported functions --------------------------------------------------------*/ + +/** + * @defgroup MX_WIFI_IO Driver_I/O + * @brief Driver I/O interface setting API + * @{ ** + */ + + +/** + * @brief Register low level IO interface. + * @param Obj wifi object handle. + * @param IO_Init IO init function + * @param IO_DeInit IO de-init function + * @param IO_Delay IO delay function in ms + * @param IO_Send IO send data function + * @param IO_Receive IO receive data function + * + * @return result + * @retval MX_WIFI_STATUS_OK success + * @retval others failure + */ +MX_WIFI_STATUS_T MX_WIFI_RegisterBusIO(MX_WIFIObject_t *Obj, + IO_Init_Func IO_Init, IO_DeInit_Func IO_DeInit, IO_Delay_Func IO_Delay, + IO_Send_Func IO_Send, IO_Receive_Func IO_Receive); +/** + * @brief Reset wifi module by hardware IO. + * @param Obj wifi object handle. + * + * @return result + * @retval MX_WIFI_STATUS_OK success + * @retval others failure + */ +MX_WIFI_STATUS_T MX_WIFI_HardResetModule(MX_WIFIObject_t *Obj); + +/** + * @} ** + */ + +/** + * @defgroup MX_WIFI_INIT Driver_init + * @brief Driver init API + * @{ ** + */ + +/** + * @brief Wi-Fi module init type + */ +typedef enum +{ + MX_WIFI_INIT = 0, /**< Wi-Fi module init(not reboot). */ + MX_WIFI_RESET = 1 /**< Wi-Fi module reset(reboot). */ +} MX_WIFI_InitMode_t; + +/** + * @brief Initialize WIFI module and get module fw & mac info. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Init(MX_WIFIObject_t *Obj); + +/** + * @brief DeInitialize WIFI module. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_DeInit(MX_WIFIObject_t *Obj); + +/** + * @brief Change default Timeout for wifi cmd. + * @param Obj: pointer to module handle + * @param Timeout: Timeout in mS + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_SetTimeout(MX_WIFIObject_t *Obj, uint32_t Timeout); + +/** + * @brief Yield data from Wi-Fi module. + * @param Obj: pointer to module handle + * @param timeout: yield timeout in ms + * @retval Operation Status. + * @note This will be called periodically + */ +MX_WIFI_STATUS_T MX_WIFI_IO_YIELD(MX_WIFIObject_t *Obj, uint32_t timeout); + +/** + * @} ** + */ + +/** + * @defgroup MX_WIFI_NETWORK_BYPASS_MODE Network bypass mode + * @brief Network bypass mode API + * @{ ** + */ + +/** + * @brief Network bypass interface index + */ +enum +{ + STATION_IDX = 0, + SOFTAP_IDX = 1 /* NOT SUPPORTED NOW */ +}; + + +MX_WIFIObject_t *wifi_obj_get(void); + + + +#if (MX_WIFI_NETWORK_BYPASS_MODE == 1) +/** + * @brief Set network bypass mode + * @param Obj: pointer to module handle + * @param enable: 0=disable, 1=enable + * @param netlink_input_callbck: input data callback function + * @param user_args: user arguments for callback function + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Network_bypass_mode_set(MX_WIFIObject_t *Obj, int32_t enable, + mx_wifi_netlink_input_cb_t netlink_input_callbck, void *user_args); + +/** + * @brief Network bypass mode data output + * @param Obj: pointer to module handle + * @param pbuf: pbuf data to send + * @param size: pbuf size + * @param data: pbuf payload + * @param len: payload len + * @param interface: STATION_IDX, SOFTAP_IDX(not supported now) + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Network_bypass_netlink_output(MX_WIFIObject_t *Obj, void *data, + int32_t len, + int32_t interface); +#endif /* MX_WIFI_NETWORK_BYPASS_MODE */ + + +/** + * @brief set powersave onoff for wifi station mode. + * @param Obj: pointer to module handle + * @param ps_onoff: 0 -- powersave off, 1 -- powersave on + * @retval Operation Status. + */ +int32_t MX_WIFI_station_powersave(MX_WIFIObject_t *Obj, int32_t ps_onoff); + + +/** + * @} ** + */ + +enum +{ + MWIFI_EVENT_NONE = 0x00, /* invalid event */ + MWIFI_EVENT_STA_DOWN = 0x01, /**< Wi-Fi station down event. */ + MWIFI_EVENT_STA_UP = 0x02, /**< Wi-Fi station up event. */ + MWIFI_EVENT_STA_GOT_IP = 0X03, /**< Wi-Fi station got ip event. */ + MWIFI_EVENT_AP_DOWN = 0x04, /**< Wi-Fi softap down event. */ + MWIFI_EVENT_AP_UP = 0x05, /**< Wi-Fi softap up event. */ +}; +typedef uint8_t mwifi_status_t; + +/** + * @defgroup MX_WIFI_BASIC Station + * @brief station mode API + * @{ ** + */ + +/** + * @brief Wi-Fi station link info + */ +#pragma pack(1) +typedef struct +{ + uint8_t is_connected; /**< Wi-Fi station connection status. */ + char ssid[MX_MAX_SSID_LEN]; /**< Wi-Fi connection AP ssid to connect. */ + uint8_t bssid[MX_MAX_BSSID_LEN]; /**< Wi-Fi connection AP bssid. */ + uint8_t security; /**< Wi-Fi connection security type. */ + uint8_t channel; /**< Wi-Fi connection channel. */ + int32_t rssi; /**< Wi-Fi connection rssi. */ +} mc_wifi_link_info_t; +#pragma pack() + +/** + * @brief Reset the module by Software. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_ResetModule(MX_WIFIObject_t *Obj); + +/** + * @brief Reset To factory defaults. + * @param Obj: pointer to module handle + * @note NOT USED NOW + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_ResetToFactoryDefault(MX_WIFIObject_t *Obj); + +/** + * @brief Get the firmware version string of the wifi module. + * @param Obj: pointer to module handle + * @param version: buffer pointer to receive the version string. + * @param size: length of the buffer, max size 24Bytes. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_GetVersion(MX_WIFIObject_t *Obj, uint8_t *version, uint32_t size); + +/** + * @brief Get the MAC address of the wifi module. + * @param Obj: pointer to module handle + * @param mac: pointer to the MAC address array, size 6Bytes. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_GetMACAddress(MX_WIFIObject_t *Obj, uint8_t *mac); + +/** + * @brief wifi block scan + * @param Obj: pointer to module handle + * @param scan_mode: scan mode + * @param ssid: ssid for active scan(scan specified AP), not used(set NULL) if do passive scan(scan all APs) + * @param len: ssid len of the AP to scan, not used(set 0) if do passive scan + * @note This API just start scan, use @MX_WIFI_Get_scan_result to get the scan result. + * @code Example: + * Active scan: + * MX_WIFI_Scan(pWifiObj, MC_SCAN_ACTIVE, "ssid_ap", 7); + * Passive scan: + * MX_WIFI_Scan(pWifiObj, MC_SCAN_PASSIVE, NULL, 0); + * + * Get scan result: + * mwifi_ap_info_t mx_aps[MX_WIFI_MAX_DETECTED_AP]; ( array to store scan AP info ) + * int32_t ap_num; + * ap_num = MX_WIFI_Get_scan_result(pWifiObj, (uint8_t*)&(mx_aps[0]), MX_WIFI_MAX_DETECTED_AP); + * if(ap_num > 0) + * { + * for(int32_t i = 0; i < ap_num; i++) + * { + * ( mx_aps[i].ssid ) + * ( mx_aps[i].rssi ) + * } + * } + * @endcode + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Scan(MX_WIFIObject_t *Obj, mc_wifi_scan_mode_t scan_mode, char *ssid, int32_t len); + +/** + * @brief wifi get scan result + * @param Obj: pointer to module handle + * @param results: scan result buffer, contains mwifi_ap_info_t * number + * @param number: max ap number to get, max 10 + * @retval return the real ap number got. + * @note must be called after @MX_WIFI_Scan + */ +int8_t MX_WIFI_Get_scan_result(MX_WIFIObject_t *Obj, uint8_t *results, uint8_t number); + +/** + * @brief Register wifi status changed callback + * @param Obj: pointer to module handle + * @param cb: wifi status callback function + * @param arg: argument pass to callback + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_RegisterStatusCallback(MX_WIFIObject_t *Obj, + mx_wifi_status_callback_t cb, void *arg); +MX_WIFI_STATUS_T MX_WIFI_RegisterStatusCallback_if(MX_WIFIObject_t *Obj, + mx_wifi_status_callback_t cb, + void *arg, + mwifi_if_t interface); + +/** + * @brief UnRegister wifi status changed callback + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_UnRegisterStatusCallback(MX_WIFIObject_t *Obj); +MX_WIFI_STATUS_T MX_WIFI_UnRegisterStatusCallback_if(MX_WIFIObject_t *Obj, mwifi_if_t interface); + +/** + * @brief Join an Access point. + * @param Obj: pointer to module handle + * @param Ssid: the access point id. + * @param Password: the Access point password. + * @param SecType: Security type. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Connect(MX_WIFIObject_t *Obj, const char *SSID, + const char *Password, MX_WIFI_SecurityType_t SecType); + +/** + * @brief Join an Access point with WPA-E. + * @param Obj: pointer to module handle + * @param Ssid: the access point ID. + * @param Identity: client identity. + * @param Password: client password. + * @param attr: extral attributes of EAP method. NULL for default mode EAP-PEAP. + * @param ip: Station IP settings, NULL for DHCP mode. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_EAP_Connect(MX_WIFIObject_t *Obj, const char *SSID, + const char *Identity, const char *Password, + mwifi_eap_attr_t *attr, mwifi_ip_attr_t *ip); + +/** + * @brief Disconnect from a network. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_Disconnect(MX_WIFIObject_t *Obj); + +/** + * @brief Join an Access point with WPS (PUSH-BUTTON) mode. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_WPS_Connect(MX_WIFIObject_t *Obj); + +/** + * @brief Stop WPS connect. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_WPS_Stop(MX_WIFIObject_t *Obj); + +/** + * @brief Check whether the module is connected to an access point. + * @retval link status 1: connected, otherwise not connect. + */ +int8_t MX_WIFI_IsConnected(MX_WIFIObject_t *Obj); + +/** + * @brief Get the local IPv4 address of the wifi module. + * @param Obj: pointer to module handle + * @param ipaddr: pointer to the IP address array(4 bytes). + * @param wifi_if: wifi mode(station or softap). + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_GetIPAddress(MX_WIFIObject_t *Obj, uint8_t *ipaddr, mwifi_if_t wifi_if); + +/** + * @brief Get the local IPv6 address of the wifi module. + * @param Obj: pointer to module handle + * @param ipaddr6: buf to the IPv6 address array(16 bytes). + * @param addr_num: index of the IPv6 address (index: 0/1/2). + * @param wifi_if: wifi mode(station or softap). + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_GetIP6Address(MX_WIFIObject_t *Obj, uint8_t *ipaddr6, int32_t addr_num, mwifi_if_t wifi_if); + +/** + * @brief Get the local IPv6 address state of the wifi module. + * @param Obj: pointer to module handle + * @param addr_num: index of the IPv6 address (index: 0/1/2). + * @param wifi_if: wifi mode(station or softap). + * @retval IPV6 address State, error if < 0 + */ +int32_t MX_WIFI_GetIP6AddressState(MX_WIFIObject_t *Obj, int32_t addr_num, mwifi_if_t wifi_if); + + +/** + * @} ** + */ + +/** + * @defgroup MX_WIFI_SOFTAP SoftAP + * @brief softAP mode API + * @{ ** + */ + +/** + * @brief Wi-Fi softAP info + */ +typedef uint8_t mwifi_security_t; +#pragma pack(1) +typedef struct +{ + int32_t rssi; /**< Signal strength of the AP */ + char ssid[33]; /**< SSID of the AP */ + uint8_t bssid[6]; /**< BSSID of the AP */ + int32_t channel; /**< Channel of the AP */ + mwifi_security_t security; /**< security of the AP */ +} mwifi_ap_info_t; +#pragma pack() + +/** + * @brief Start softAP(miniAP) mode + * @param Obj: pointer to module handle + * @param ap_settings: softAP settings. + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_StartAP(MX_WIFIObject_t *Obj, MX_WIFI_APSettings_t *ap_settings); + +/** + * @brief Stop softAP(miniAP) mode + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +MX_WIFI_STATUS_T MX_WIFI_StopAP(MX_WIFIObject_t *Obj); + +/** + * @} ** + */ + +#if MX_WIFI_NETWORK_BYPASS_MODE == 0 + +/** + * @defgroup WIFI_SOCKET Socket + * @brief socket related API + * @{ ** + */ + +#ifndef socklen_t +#define socklen_t uint32_t +#endif /* socklen_t */ + +/** + * @brief socket address struct + */ + +struct sockaddr +{ + uint8_t sa_len; + uint8_t sa_family; + uint8_t sa_data[14]; +}; + +/** + * @brief socket address(net format) + */ +struct in_addr +{ + uint32_t s_addr; +}; + +/** + * @brief socket address_in struct + */ +struct sockaddr_in +{ + uint8_t sin_len; + uint8_t sin_family; + uint16_t sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +/** + * @brief socket address(IPV6 net format) + */ +struct in6_addr +{ + union + { + uint32_t u32_addr[4]; + uint8_t u8_addr[16]; + } un; + /* #define s6_addr un.u8_addr */ +}; + +/** + * @brief socket address_in6 struct + */ +struct sockaddr_in6 +{ + uint8_t sin6_len; /* length of this structure */ + uint8_t sin6_family; /* AF_INET6 */ + uint16_t sin6_port; /* Transport layer port # */ + uint32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + uint32_t sin6_scope_id; /* Set of interfaces for scope */ +}; + +struct sockaddr_storage +{ + uint8_t s2_len; + uint8_t ss_family; + char s2_data1[2]; + uint32_t s2_data2[3]; + uint32_t s2_data3[3]; +}; + +/** + * @brief socket address_in6 info + */ +struct addrinfo +{ + int32_t ai_flags; /* Input flags. */ + int32_t ai_family; /* Address family of socket. */ + int32_t ai_socktype; /* Socket type. */ + int32_t ai_protocol; /* Protocol of socket. */ + uint32_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +#define SOL_SOCKET 0xfff /* options for socket level */ + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define AF_INET6 10 + +#define PF_UNSPEC AF_UNSPEC +#define PF_INET AF_INET +#define PF_INET6 AF_INET6 + +#define IPPROTO_IP 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define IPPROTO_IPV6 41 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_UDPLITE 136 + +#define F_GETFL 3 +#define F_SETFL 4 + +#define O_NONBLOCK 1 /* nonblocking I/O */ + +/** + * @brief socket option value + */ +typedef enum +{ + SO_DEBUG = 0x0001, /**< Unimplemented: turn on debugging info recording */ + SO_ACCEPTCONN = 0x0002, /**< socket has had listen() */ + SO_REUSEADDR = 0x0004, /**< Allow local address reuse */ + SO_KEEPALIVE = 0x0008, /**< keep connections alive */ + SO_DONTROUTE = 0x0010, /**< Just use interface addresses */ + SO_BROADCAST = 0x0020, /**< Permit to send and to receive broadcast messages */ + SO_USELOOPBACK = 0x0040, /**< Bypass hardware when possible */ + SO_LINGER = 0x0080, /**< linger on close if data present */ + SO_OOBINLINE = 0x0100, /**< Leave received OOB data in line */ + SO_REUSEPORT = 0x0200, /**< Allow local address & port reuse */ + SO_BLOCKMODE = 0x1000, /**< set socket as block(optval=0)/non-block(optval=1) mode. + Default is block mode. */ + SO_SNDBUF = 0x1001, + SO_SNDTIMEO = 0x1005, /**< Send timeout in block mode. block for ever in default mode. */ + SO_RCVTIMEO = 0x1006, /**< Recv timeout in block mode. block 1 second in default mode. */ + SO_ERROR = 0x1007, /**< Get socket error number. */ + SO_TYPE = 0x1008, /**< Get socket type. */ + SO_NO_CHECK = 0x100a /**< Don't create UDP checksum. */ + +} SOCK_OPT_VAL; + +#if !defined __GNUC__ +#define FD_SETSIZE 64 /**< MAX fd number is 64 in MXOS. */ +#define HOWMANY(x, y) (((x) + ((y) - 1)) / (y)) + +#define NBBY 8 /**< number of bits in a byte. */ +#define NFDBITS (sizeof(unsigned long) * NBBY) /**< bits per mask */ + +#define MC_FDSET_MASK(n) ((unsigned long)1 << ((n) % NFDBITS)) + +typedef struct _fd_set +{ + unsigned long fds_bits[HOWMANY(FD_SETSIZE, NFDBITS)]; +} fd_set; + +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= MC_FDSET_MASK(n)) /**< Add a fd to FD set. */ +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~MC_FDSET_MASK(n)) /**< Remove fd from FD set. */ +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & MC_FDSET_MASK(n)) /**< Check if the fd is set in FD set. */ +#define FD_ZERO(p) memset((p), 0, sizeof(*(p))) /**< Clear FD set. */ +#endif /* !__GNUC__ */ + +/** + * @brief IP option types, level: IPPROTO_IP + */ +typedef enum +{ + IP_ADD_MEMBERSHIP = 0x0003, /**< Join multicast group. */ + IP_DROP_MEMBERSHIP = 0x0004, /**< Leave multicast group. */ + IP_MULTICAST_TTL = 0x0005, + IP_MULTICAST_IF = 0x0006, + IP_MULTICAST_LOOP = 0x0007 +} IP_OPT_VAL; + +/** + * @brief Create a socket. + * @param Obj: pointer to module handle + * @param domain: socket domain + * @param type: socket type + * @param protocol: socket protocol + * @retval Socket file descriptor, return < 1 if failed. + */ +int32_t MX_WIFI_Socket_create(MX_WIFIObject_t *Obj, int32_t domain, int32_t type, int32_t protocol); + +/** + * @brief Set option for a socket + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param level: option level + * @param optname: option to set + * @param optvalue: value buffer for the option + * @param optlen: length of the option value + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_setsockopt(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t level, + int32_t optname, const void *optvalue, int32_t optlen); + +/** + * @brief Get option of a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param level: option level + * @param optname: option to set + * @param optvalue: buffer pointer of value of the option + * @param optlen: buffer pointer of length of the option value + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_getsockopt(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t level, + int32_t optname, void *optvalue, uint32_t *optlen); + +/** + * @brief Bind a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: socket address + * @param addrlen: address length + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_bind(MX_WIFIObject_t *Obj, int32_t sockfd, const struct sockaddr *addr, int32_t addrlen); + +/** + * @brief Listen a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param backlog: max number to queued. + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_listen(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t backlog); + +/** + * @brief Accept a socket. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: client address + * @param addrlen: length of client address + * @retval Accepted client socket fd, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_accept(MX_WIFIObject_t *Obj, int32_t sockfd, struct sockaddr *addr, uint32_t *addrlen); + +/** + * @brief Socket connect. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: client address + * @param addrlen: length of client address + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_connect(MX_WIFIObject_t *Obj, int32_t sockfd, const struct sockaddr *addr, int32_t addrlen); + +/** + * @brief Socket shutdown. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param mode: shutdown mode: + * 0 Stop receiving data for this socket; + * 1 Stop trying to transmit data from this socket + * 2 Stop all transmit from this socket + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_shutdown(MX_WIFIObject_t *Obj, int32_t sockfd, int32_t mode); + +/** + * @brief Socket close. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_close(MX_WIFIObject_t *Obj, int32_t sockfd); + +/** + * @brief Socket send. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: send data buffer + * @param len: length of send data + * @param flags: zero for MXOS + * @retval Number of bytes sent, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_send(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, int32_t len, int32_t flags); + +/** + * @brief Socket recv. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: recv buffer + * @param len: length of recv buffer + * @param flags: zero for MXOS + * @retval Number of bytes received, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_recv(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, int32_t len, int32_t flags); + +/** + * @brief Socket sendto. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: send data buffer + * @param len: length of send data + * @param flags: zero for MXOS + * @param toaddr: address to send + * @param toaddrlen: length of address to send + * @retval Number of bytes sent, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_sendto(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, int32_t len, int32_t flags, + struct sockaddr *toaddr, int32_t toaddrlen); + +/** + * @brief Socket recvfrom. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param buf: recv buffer + * @param len: length of recv buffer + * @param fromaddr: address of the data source + * @param fromaddrlen: length of address of the data source + * @param flags: zero for MXOS + * @retval Number of bytes received, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_recvfrom(MX_WIFIObject_t *Obj, int32_t sockfd, uint8_t *buf, int32_t len, int32_t flags, + struct sockaddr *fromaddr, uint32_t *fromaddrlen); + +/** + * @brief Gethostbyname, only for IPv4 address. + * @param Obj: pointer to module handle + * @param addr: address of the host + * @param name: hostname + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_gethostbyname(MX_WIFIObject_t *Obj, struct sockaddr *addr, char *name); + +/** + * @brief Ping a host, only for IPv4 address. + * @param Obj: pointer to module handle + * @param addr: hostname + * @param count: ping max count + * @param delay: ping delay in millisecond + * @param response: response time array of ping result + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_ping(MX_WIFIObject_t *Obj, const char *hostname, int32_t count, int32_t delay, + int32_t response[]); + +#if 0 +/** + * @brief Get IPv4/v6 address info by nodename. + * @param Obj: pointer to module handle + * @param nodename: descriptive name or address string of the host + * @param servname: not used, set NULL + * @param hints: structure containing input values that set socktype and protocol + * @param res: buf to store the result (set to NULL on failure) + * @retval Operation Status. + */ +int32_t MX_WIFI_Socket_getaddrinfo(MX_WIFIObject_t *Obj, const char *nodename, const char *servname, + const struct addrinfo *hints, struct mc_addrinfo *res); + +/** + * @brief Monitor multiple file descriptors for sockets + * @attention Never doing operations in different threads + * @param Obj: pointer to module handle + * @param nfds: is the highest-numbered file descriptor in any of the three + * sets, plus 1 + * @param readfds: A file descriptor sets will be watched to see if characters + * become available for reading + * @param writefds: A file descriptor sets will be watched to see if a write + * will not block. + * @param exceptfds: A file descriptor sets will be watched for exceptions. + * @param timeout: The timeout argument specifies the interval that select() + * should block waiting for a file descriptor to become ready. + * If timeout is NULL (no timeout), select() can block until API timeout. + * @retval On success, return the number of file descriptors contained in the + * three returned descriptor sets (that is, the total number of bits + * that are set in readfds, writefds, exceptfds) which may be zero if + * the timeout expires before anything interesting happens. On error, + * -1 is returned, the file descriptor sets are unmodified, and timeout + * becomes undefined. + */ +int32_t MX_WIFI_Socket_select(MX_WIFIObject_t *Obj, int32_t nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct mc_timeval *timeout); +#endif /* 0 */ + + +/** + * @brief socket getpeername. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: address buffer + * @param addrlen: size of address buffer + * @retval get address of peer socket, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_getpeername(MX_WIFIObject_t *Obj, int32_t sockfd, struct sockaddr *addr, uint32_t *addrlen); + +/** + * @brief socket getsockname. + * @param Obj: pointer to module handle + * @param sockfd: socket fd + * @param addr: address buffer + * @param addrlen: size of address buffer + * @retval get address of local socket, return < 0 if failed. + */ +int32_t MX_WIFI_Socket_getsockname(MX_WIFIObject_t *Obj, int32_t sockfd, struct sockaddr *addr, uint32_t *addrlen); + +/** + * @} ** + */ + +/** + * @defgroup MX_WIFI_MDNS mDNS + * @brief mDNS related API + * @{ ** + */ + +/** Maximum length of labels + * + * A label is one segment of a DNS name. For example, "foo" is a label in the + * name "foo.local.". RFC 1035 requires that labels do not exceed 63 bytes. + */ +#define MDNS_MAX_LABEL_LEN 63 /* defined by the standard */ + +/** Maximum length of names + * + * A name is a list of labels such as "My Webserver.foo.local" or + * mydevice.local. RFC 1035 requires that names do not exceed 255 bytes. + */ +#define MDNS_MAX_NAME_LEN 255 /* defined by the standard : 255*/ + +/** Maximum length of key/value pair + * + * TXT records associated with a service are populated with key/value pairs. + * These key/value pairs must not exceed this length. + */ +#define MDNS_MAX_KEYVAL_LEN 255 /* defined by the standard : 255*/ + +/** protocol values for the proto member of the mdns_service descriptor */ +/** TCP Protocol */ +#define MDNS_PROTO_TCP 0 +/** UDP Protocol */ +#define MDNS_PROTO_UDP 1 + +/** Maximum no. of services allowed to be announced on a single interface. */ +#define MAX_MDNS_LST 5 /* Maximum no. of services */ + +/* MDNS Error Codes */ +#define ERR_MDNS_BASE -36650 /**< Starting error code for all mdns errors. */ +#define ERR_MDNS_INVAL -36651 /**< invalid argument */ +#define ERR_MDNS_BADSRC -36652 /**< bad service descriptor */ +#define ERR_MDNS_TOOBIG -36653 /**< not enough room for everything */ +#define ERR_MDNS_NOIMPL -36654 /**< unimplemented feature */ +#define ERR_MDNS_NOMEM -36655 /**< insufficient memory */ +#define ERR_MDNS_INUSE -36656 /**< requested resource is in use */ +#define ERR_MDNS_NORESP -36657 /**< requested resource is in use */ +#define ERR_MDNS_FSOC -36658 /**< failed to create socket for mdns */ +#define ERR_MDNS_FREUSE -36659 /**< failed to reuse multicast socket */ +#define ERR_MDNS_FBINDTODEVICE -36660 /**< failed to bind mdns socket to device */ +#define ERR_MDNS_FBIND -36661 /**< failed to bind mdns socket */ +#define ERR_MDNS_FMCAST_JOIN -36662 /**< failed to join multicast socket */ +#define ERR_MDNS_FMCAST_SET -36663 /**< failed to set multicast socket */ +#define ERR_MDNS_FQUERY_SOC -36664 /**< failed to create query socket */ +#define ERR_MDNS_FQUERY_THREAD -36665 /**< failed to create mdns thread */ +#define ERR_MDNS_END -36670 /**< Last generic error code (inclusive) */ + +/** mDNS Interface State + * mDNS interface state can be changed by using mdns_iface_state_change() + * function. For details about when to use the enum please refer to + * documentation for mdns_iface_state_change(). */ +enum iface_state +{ + /** UP the interface and announce services + * mDNS will probe and announce all services announced via + * mdns_announce_service() and/or mdns_announce_service_arr(). + * mDNS will go through entire probing sequence explained in above + * functions. Interface state can be changed to UP, if its DOWN. + */ + UP = 0, + /** DOWN the interface and de-announce services + * mDNS sends good bye packet with ttl=0 so that mDNS clients can remove + * the services from their mDNS cache table. + */ + DOWN, + /** Forcefully re-announce services + * This state should be used after services are already + * announced and force announcement is needed due to some reason. + * mDNS will not perform probing sequence, as it does in case of UP, and + * will directly re-announce services. + */ + REANNOUNCE +}; + +/** + * @brief mDNS service info + */ +#pragma pack(1) +struct mc_mdns_service +{ + /** Name of MDNS service */ + char servname[MDNS_MAX_LABEL_LEN + 1]; + /** Type of MDNS service */ + char servtype[MDNS_MAX_LABEL_LEN + 1]; + /** Domain for MDNS service */ + char domain[MDNS_MAX_LABEL_LEN + 1]; + /** Port number */ + uint16_t port; + /** Protocol used */ + int32_t proto; + /** Key value pairs for TXT records*/ + char keyvals[MDNS_MAX_KEYVAL_LEN + 1]; + /** IP Address of device */ + uint32_t ipaddr; + /** IPv6 Address of device */ + uint32_t ip6addr[4]; + + /** separator for txt record */ + char separator; /* user set this for keyvals */ +}; +#pragma pack() + +/** + * @brief start mDNS service. + * @param Obj: pointer to module handle + * @param domain: domain of service + * @param name: hostname + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_start(MX_WIFIObject_t *Obj, const char *domain, char *hostname); + +/** + * @brief stop mDNS service. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_stop(MX_WIFIObject_t *Obj); + +/** + * @brief announce a service. + * @param Obj: pointer to module handle + * @param service: service to announce + * @param interface: wifi interface + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_announce_service(MX_WIFIObject_t *Obj, struct mc_mdns_service *service, mwifi_if_t interface); + +/** + * @brief deannounce a service. + * @param Obj: pointer to module handle + * @param service: service to deannounce + * @param interface: wifi interface + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_deannounce_service(MX_WIFIObject_t *Obj, struct mc_mdns_service *service, mwifi_if_t interface); + +/** + * @brief deannounce all services. + * @param Obj: pointer to module handle + * @param interface: wifi interface + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_deannounce_service_all(MX_WIFIObject_t *Obj, mwifi_if_t interface); + +/** + * @brief Send interface state change event to mdns + * @param Obj: pointer to module handle + * @param interface: wifi interface + * @param state: state event, valid interface state from \ref iface_state + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_iface_state_change(MX_WIFIObject_t *Obj, mwifi_if_t interface, enum iface_state state); + +/** + * @brief Set new host name, use mdns_iface_state_change(interface, REANNOUNCE) to anounce + * the new host name. + * @param Obj: pointer to module handle + * @param hostname: new hostname + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_set_hostname(MX_WIFIObject_t *Obj, char *hostname); + +/** + * @brief sets the TXT record field for a given mDNS service. + * @param Obj: pointer to module handle + * @param service: mDNS service + * @param keyvals: new txt record string + * @param separator: the separator used to separate individual key value pairs + * @retval Operation Status. + */ +int32_t MX_WIFI_MDNS_set_txt_rec(MX_WIFIObject_t *Obj, struct mc_mdns_service *service, char *keyvals, + char separator); + +/** + * @} ** + */ + +/** + * @defgroup MX_WIFI_TLS TLS + * @brief TLS related API + * @{ ** + */ + +/** + * @brief mxchip TLS handler type + */ +typedef void *mtls_t; + +/** + * @brief mxchip TLS version + */ +enum +{ + SSL_V3_MODE = 1, /**< SSL V3 */ + TLS_V1_0_MODE = 2, /**< TLS V1.0 */ + TLS_V1_1_MODE = 3, /**< TLS V1.1 */ + TLS_V1_2_MODE = 4 /**< TLS V1.2 */ +}; + +typedef uint8_t mtls_ver_t; + +/** + * @brief set the TLS protocol version. + * @param Obj: pointer to module handle + * @param version: TLS protocol version + * @retval Operation Status. + * @note This function should be called before TLS is ready to function (before + * mtls_connect and mtls_accept is called by application ). + */ +int32_t MX_WIFI_TLS_set_ver(MX_WIFIObject_t *Obj, mtls_ver_t version); + +/** + * @brief TLS set client certificate + * @param Obj: pointer to module handle + * @param client_cert: Point to buffer of client cert. + * @param cert_len: length of the client cert. + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_set_clientCertificate(MX_WIFIObject_t *Obj, uint8_t *client_cert, uint16_t cert_len); + +/** + * @brief TLS set client private key + * @param Obj: pointer to module handle + * @param client_private_key: Point to buffer of client private key. + * @param key_len: length of the client cert. + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_set_clientPrivateKey(MX_WIFIObject_t *Obj, uint8_t *client_private_key, uint16_t key_len); + +/** + * @brief TLS client create a TLS connection. + * @param Obj: pointer to module handle + * @details This function is called on the client side and initiates an TLS/TLS handshake with a + * server. When this function is called, the underlying communication channel has already + * been set up. This function is called after TCP 3-way handshak finished. + * @param domain: Specifies a communication domain + * @param type: Specifies the communication semantics. + * @param protocol: specifies a particular protocol to be used with the socket. + * @param addr: Point to the target address to be connected + * @param addrlen: containing the size of the buffer pointed to by addr + * @param ca: pointer to the CA certificate string, used to verify server's certificate. + * @param calen: the string length of ca. 0=do not verify server's certificate. + * @retval return the TLS context pointer on success or NULL for fail. + */ +int32_t MX_WIFI_TLS_connect(MX_WIFIObject_t *Obj, int32_t domain, int32_t type, int32_t protocol, + const struct sockaddr *addr, int32_t addrlen, char *ca, int32_t calen); + +/** + * @brief TLS client create a TLS connection with SNI. + * @param Obj: pointer to module handle + * @details This function is called on the client side and initiates an TLS/TLS handshake with a + * server. When this function is called, the underlying communication channel has already + * been set up. This function is called after TCP 3-way handshak finished. + * @param sni_servername: Specifies the SNI servername + * @param sni_servername_len: Specifies the SNI servername length, max size MX_TLS_SNI_SERVERNAME_SIZE + * @param addr: Point to the target address to be connected + * @param addrlen: containing the size of the buffer pointed to by addr + * @param ca: pointer to the CA certificate string, used to verify server's certificate. + * @param calen: the string length of ca. 0=do not verify server's certificate. + * @retval return the TLS context pointer on success or NULL for fail. + */ +int32_t MX_WIFI_TLS_connect_sni(MX_WIFIObject_t *Obj, const char *sni_servername, int32_t sni_servername_len, + const struct sockaddr *addr, int32_t addrlen, char *ca, int32_t calen); + +/** + * @brief TLS send data + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @param data: Point to data to send. + * @param len: data length. + * @retval On success, return the number of bytes sent. On error, + * error code (< 0) is returned. + */ +int32_t MX_WIFI_TLS_send(MX_WIFIObject_t *Obj, mtls_t tls, void *data, int32_t len); + +/** + * @brief TLS redeive data + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @param data: Point to buffer to receive TLS data. + * @param len: max receive buffer length. + * @retval On success, return the number of bytes received. On error, + * error code (< 0) is returned. + */ +int32_t MX_WIFI_TLS_recv(MX_WIFIObject_t *Obj, mtls_t tls, void *buf, int32_t len); + +/** + * @brief Close the TLS session, release resource. + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_close(MX_WIFIObject_t *Obj, mtls_t tls); + +/** + * @brief Set TLS nonblock mode. + * @param Obj: pointer to module handle + * @param tls: Point to the TLS context. + * @param nonblock: true - nonblock, flase - block + * @retval Operation Status. + */ +int32_t MX_WIFI_TLS_set_nonblock(MX_WIFIObject_t *Obj, mtls_t tls, int32_t nonblock); + +/** + * @} ** + */ + + +/** + * @defgroup MX_WIFI_WEBSERVER Webserver + * @brief Webserver related API + * @{ ** + */ + + +/** + * @brief Start webserver. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +int32_t MX_WIFI_Webserver_start(MX_WIFIObject_t *Obj); + +/** + * @brief Stop webserver. + * @param Obj: pointer to module handle + * @retval Operation Status. + */ +int32_t MX_WIFI_Webserver_stop(MX_WIFIObject_t *Obj); + + +/** + * @} ** + */ + + +/** + * @defgroup MX_WIFI_FOTA FOTA + * @brief FOTA related API + * @{ ** + */ + + +/** + * @brief Start FOTA. + * @param Obj: pointer to module handle + * @param url: HTTP/HTTPS url of bin file to update + * @param md5: MD5 string(32Bytes) of bin file to update + * @param ota_status_callback: callback function for ota status + * @retval Operation Status. + */ +int32_t MX_WIFI_FOTA_start(MX_WIFIObject_t *Obj, const char *url, const char *md5, + mx_wifi_fota_status_cb_t fota_status_callback, uint32_t user_args); + +/** + * @} ** + */ + +/** + * @defgroup MX_WIFI_STATION_POWERSAVE + * @brief Wi-Fi station powersave API + * @{ ** + */ + +#endif /* MX_WIFI_NETWORK_BYPASS_MODE */ + +/** + * @} ** + */ + + +/** + * @} ** + */ + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MX_WIFI_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi_conf_template.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi_conf_template.h new file mode 100644 index 0000000000..69b1dab766 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi/mx_wifi_conf_template.h @@ -0,0 +1,251 @@ +/** + ****************************************************************************** + * @file mx_wifi_conf_template.h + * @author MCD Application Team + * @brief Header for mx_wifi_conf_template module + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_CONF_TEMPLATE_H +#define MX_WIFI_CONF_TEMPLATE_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Includes ------------------------------------------------------------------*/ +#include + +int32_t mxwifi_probe(void **ll_drv_context); + +/* use SPI interface by default */ + +#ifndef MX_WIFI_USE_SPI +#define MX_WIFI_USE_SPI (1) +#endif /* MX_WIFI_USE_SPI */ + +/* do not use RTOS but bare metal approach by default */ +#ifndef MX_WIFI_USE_CMSIS_OS +#define MX_WIFI_USE_CMSIS_OS (0) +#endif /* MX_WIFI_USE_CMSIS_OS */ + +/* Use At command mode by default, TCP/IP stack is running on module */ +#ifndef MX_WIFI_NETWORK_BYPASS_MODE +#define MX_WIFI_NETWORK_BYPASS_MODE (0) +#endif /* MX_WIFI_NETWORK_BYPASS_MODE */ + + +/* Do not copy TX buffer */ +#ifndef MX_WIFI_TX_BUFFER_NO_COPY +#define MX_WIFI_TX_BUFFER_NO_COPY (1) +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + + +/* DEBUG LOG */ +/* #define MX_WIFI_API_DEBUG */ +/* #define MX_WIFI_IPC_DEBUG */ +/* #define MX_WIFI_HCI_DEBUG */ +/* #define MX_WIFI_SLIP_DEBUG */ +/* #define MX_WIFI_IO_DEBUG */ + +/* check if OS primitive are already declared */ +/* if not, include default declaration */ +#ifndef LOCK_DECLARE + +#if (MX_WIFI_USE_CMSIS_OS == 1) +#include "mx_wifi_cmsis_os.h" +#define MX_WIFI_BARE_OS 0 +#else +#if (MX_WIFI_USE_MBED_OS == 1) +#include "mx_wifi_mbed_os.h" +#define MX_WIFI_BARE_OS 0 +#else +#include "mx_wifi_bare_os.h" +#define MX_WIFI_BARE_OS 1 +#endif /* mx_wifi_mbed_os.h */ +#endif /* MX_WIFI_USE_CMSIS_OS */ + +#else +/* OS rempa are declared externally , so OS is present */ +#define MX_WIFI_BARE_OS 0 +#endif /* LOCK_DECLARE */ + + + +#define MX_WIFI_PRODUCT_NAME ("MXCHIP-WIFI") +#define MX_WIFI_PRODUCT_ID ("EMW3080B") + +#ifndef MX_WIFI_USE_SPI +#define MX_WIFI_USE_SPI (0) +#endif /* MX_WIFI_USE_SPI */ + + +#ifndef MX_WIFI_UART_BAUDRATE +#define MX_WIFI_UART_BAUDRATE (115200*2) +#endif /* MX_WIFI_UART_BAUDRATE */ + +#ifndef MX_WIFI_MTU_SIZE +#define MX_WIFI_MTU_SIZE (1500) +#endif /* MX_WIFI_MTU_SIZE */ + +#define MX_WIFI_BYPASS_HEADER_SIZE (28) /* MX_IPC_header(6) + sizeof(bypass_in_t)(22), + * set with PBUF_LINK_ENCAPSULATION_HLEN */ +#define MX_WIFI_PBUF_LINK_HLEN (14) /* link header (PBUF_LINK_HLEN) set in lwip */ + +#if (MX_WIFI_NETWORK_BYPASS_MODE==1) +/* Use lwip PBUF_POOL_BUFSIZE = TCP_MSS + 40 + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN. */ +#define MX_WIFI_BUFFER_SIZE \ + (MX_WIFI_MTU_SIZE + MX_WIFI_BYPASS_HEADER_SIZE + MX_WIFI_PBUF_LINK_HLEN) +#else +#define MX_WIFI_BUFFER_SIZE (2500) /* bigger buffer size */ +#endif /* (MX_WIFI_NETWORK_BYPASS_MODE==1) */ + +/* MX_WIFI_BUFFER_SIZE - MX_IPC_header */ +#define MX_WIFI_IPC_PAYLOAD_SIZE ((MX_WIFI_BUFFER_SIZE) - 6) + +/* MX_WIFI_IPC_PAYLOAD_SIZE - socket_api_params_header */ +#define MX_WIFI_SOCKET_DATA_SIZE ((MX_WIFI_IPC_PAYLOAD_SIZE)-12) + +#ifndef MX_WIFI_CMD_TIMEOUT +#define MX_WIFI_CMD_TIMEOUT (10000) +#endif +#define MX_WIFI_MAX_SOCKET_NBR (8) +#define MX_WIFI_MAX_DETECTED_AP (10) + +#define MX_WIFI_MAX_SSID_NAME_SIZE 32 +#define MX_WIFI_MAX_PSWD_NAME_SIZE 64 + +#define MX_WIFI_PRODUCT_NAME_SIZE 32 +#define MX_WIFI_PRODUCT_ID_SIZE 32 + +#define MX_WIFI_FW_REV_SIZE 24 +#ifndef MX_WIFI_SPI_THREAD_PRIORITY +#define MX_WIFI_SPI_THREAD_PRIORITY (OSPRIORITYREALTIME) +#endif /* MX_WIFI_SPI_THREAD_PRIORITY */ +#ifndef MX_WIFI_SPI_THREAD_STACK_SIZE +#define MX_WIFI_SPI_THREAD_STACK_SIZE (1024) +#endif /* MX_WIFI_SPI_THREAD_STACK_SIZE */ + +#ifndef MX_WIFI_UART_THREAD_PRIORITY +#define MX_WIFI_UART_THREAD_PRIORITY (OSPRIORITYREALTIME) +#endif /* MX_WIFI_UART_THREAD_PRIORITY */ +#ifndef MX_WIFI_UART_THREAD_STACK_SIZE +#define MX_WIFI_UART_THREAD_STACK_SIZE (1024) +#endif /* MX_WIFI_UART_THREAD_STACK_SIZE */ + + +#ifndef MX_WIFI_RECEIVED_THREAD_PRIORITY +#define MX_WIFI_RECEIVED_THREAD_PRIORITY (OSPRIORITYABOVENORMAL) +#endif /* MX_WIFI_RECEIVED_THREAD_PRIORITY */ + +#ifndef MX_WIFI_RECEIVED_THREAD_STACK_SIZE +#define MX_WIFI_RECEIVED_THREAD_STACK_SIZE (1024) +#endif /* MX_WIFI_RECEIVED_THREAD_STACK_SIZE*/ + +#ifndef MX_WIFI_TRANSMIT_THREAD_PRIORITY +#define MX_WIFI_TRANSMIT_THREAD_PRIORITY (OSPRIORITYABOVENORMAL) +#endif /* MX_WIFI_TRANSMIT_THREAD_PRIORITY */ + +#ifndef MX_WIFI_TRANSMIT_THREAD_STACK_SIZE +#define MX_WIFI_TRANSMIT_THREAD_STACK_SIZE (1024) +#endif /* MX_WIFI_TRANSMIT_THREAD_STACK_SIZE */ + + +/* Maximum number of RX buffer that can be queued by Hardware interface (SPI/UART) */ +/* This is used to size internal queue, and avoid to block the IP thread if it can still push some buffers */ +/* Impact on Memory foot print is weak , one single void* per place in the queue */ +#ifndef MX_WIFI_MAX_RX_BUFFER_COUNT +#define MX_WIFI_MAX_RX_BUFFER_COUNT (2) +#endif /* MX_WIFI_MAX_RX_BUFFER_COUNT */ + + +/* Maximum number of TX buffer that can be queued by IP stack (LwIP or Netx) without blocking the calling thread */ +/* This is used to size internal queue, and avoid to block the IP thread if it can still push some buffers */ +/* Impact on Memory foot print is one single void* per place in the queue, but it may lead to over allocation */ +/* TCP/IP stack (LwIP for instance ) */ +#ifndef MX_WIFI_MAX_TX_BUFFER_COUNT +#define MX_WIFI_MAX_TX_BUFFER_COUNT (4) +#endif /* MX_WIFI_MAX_TX_BUFFER_COUNT */ + + + +/** + * For the TX buffer, by default no-copy feature is enabled, meaning that + * the IP buffer are used in the whole process and should come with + * available room in front of payload to accommodate transport header buffer. + * This is managed in interface between driver and IP stack + */ + +/** + * For LwIP "PBUF_LINK_ENCAPSULATION_HLEN" must be defined as > MX_WIFI_MIN_TX_HEADER_SIZE, + * see net_mx_wifi/c file for implementation. + */ +#define MX_WIFI_MIN_TX_HEADER_SIZE (28) + +#ifndef MX_WIFI_TX_BUFFER_NO_COPY +#define MX_WIFI_TX_BUFFER_NO_COPY (1) +#endif /* MX_WIFI_TX_BUFFER_NO_COPY */ + + +/* Sizeof the circular buffer for Uart mode, when buffer is hlaf full data are transmitted to next stage */ +#ifndef MX_CIRCULAR_UART_RX_BUFFER_SIZE +#define MX_CIRCULAR_UART_RX_BUFFER_SIZE (400) +#endif /* MX_CIRCULAR_UART_RX_BUFFER_SIZE */ + + + +#ifndef MX_STAT_ON +#define MX_STAT_ON 0 +#endif /* MX_STAT_ON */ + +#if MX_STAT_ON == 1 +typedef struct +{ + uint32_t alloc; + uint32_t free; + uint32_t cmd_get_answer; + uint32_t callback; + uint32_t in_fifo; + uint32_t out_fifo; +} mx_stat_t; + +extern mx_stat_t mx_stat; + +#define MX_STAT_LOG() \ + (void) printf("Number of allocated buffer for Rx and command answer %ld\n", mx_stat.alloc);\ + (void) printf("Number of free buffer %ld\n",mx_stat.free);\ + (void) printf("Number of command answer %ld , callback %ld, sum of both %ld (should match alloc && free)\n",\ + mx_stat.cmd_get_answer,mx_stat.callback,mx_stat.cmd_get_answer+mx_stat.callback);\ + (void) printf("Number of posted answer (callback + cmd answer) %ld, processed answer %ld\n",\ + mx_stat.in_fifo,mx_stat.out_fifo);\ + +#define MX_STAT_INIT() (void) memset((void*)&mx_stat, 0, sizeof(mx_stat)) +#define MX_STAT(A) mx_stat.A++ +#define MX_STAT_DECLARE() mx_stat_t mx_stat + +#else + +#define MX_STAT_INIT() +#define MX_STAT(A) +#define MX_STAT_LOG() +#define MX_STAT_DECLARE() + +#endif /* MX_STAT_ON */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MX_WIFI_CONF_TEMPLATE_H */ + diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_conf.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_conf.h new file mode 100644 index 0000000000..5529c1b842 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_conf.h @@ -0,0 +1,32 @@ +/** + *

© Copyright (c) 2021 STMicroelectronics. + * SPDX-License-Identifier: BSD-3-Clause + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_CONF_H +#define MX_WIFI_CONF_H + +/* Define your Hardware config UART or SPI */ +#define MX_WIFI_USE_SPI (MBED_CONF_EMW3080B_WIFI_SPI_INTERFACE) + +/* Bypass mode or AT command */ +#define MX_WIFI_NETWORK_BYPASS_MODE (1) + +#define MX_WIFI_USE_MBED_OS (1) +//#define MX_WIFI_TX_BUFFER_NO_COPY (0) + + +/* Includes ------------------------------------------------------------------*/ +#include "mx_wifi_mbed_os.h" +#include "mx_wifi_conf_template.h" + +#endif /* MX_WIFI_CONF_H */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_mbed_os.cpp b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_mbed_os.cpp new file mode 100644 index 0000000000..579158bfb1 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_mbed_os.cpp @@ -0,0 +1,203 @@ +/** + *

© Copyright (c) 2021 STMicroelectronics. + * SPDX-License-Identifier: BSD-3-Clause + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#include "EMW3080B_EMAC.h" + +#include "mx_wifi_mbed_os.h" + +extern "C" +{ + +#if BASIC_MALLOC == 0 + + mx_buf_t *mx_buf_alloc(uint32_t len) + { + emac_mem_buf_t *p = emac3080b_global_memory_manager->alloc_pool(len, 0); + return (mx_buf_t *) p; + } + + + void mx_buf_free(mx_buf_t *netb_in) + { + emac_mem_buf_t *netb = (emac_mem_buf_t *) netb_in; + emac3080b_global_memory_manager->free(netb); + } + + + void mx_buf_hide_header(mx_buf_t *netb_in, int32_t n) + { + if (n <= 0) { + error("Hiding header is not supported\n"); + } else { + emac_mem_buf_t *netb = (emac_mem_buf_t *) netb_in; + ssize_t len = emac3080b_global_memory_manager->get_len(netb); + uint8_t *pdata = (uint8_t *) emac3080b_global_memory_manager->get_ptr(netb); + + memmove(pdata, pdata + n, len); + } + + } + + uint8_t *mx_buf_payload(mx_buf_t *netb_in) + { + emac_mem_buf_t *netb = (emac_mem_buf_t *) netb_in; + return (uint8_t *) emac3080b_global_memory_manager->get_ptr(netb); + } + + + uint32_t mx_buf_get_size(mx_buf_t *netb_in) + { + emac_mem_buf_t *netb = (emac_mem_buf_t *) netb_in; + return emac3080b_global_memory_manager->get_len(netb); + } + + void mx_buf_set_size(mx_buf_t *netb_in, int32_t n) + { + emac_mem_buf_t *netb = (emac_mem_buf_t *) netb_in; + return emac3080b_global_memory_manager->set_len(netb, n); + + } + +#endif /* BASIC_ALLOC */ + + + void mbed_delay(uint32_t delay) + { + ThisThread::sleep_for(std::chrono::duration(delay)); + } + + + void *mbed_mutex_new(void) + { + void *m; + m = new Mutex(); + return (void *) m; + } + + void mbed_mutex_delete(void *m) + { + delete ((Mutex *) m); + } + + + void mbed_mutex_lock(void *mutexin) + { + Mutex *mutex = (Mutex *) mutexin; + mutex->lock(); + } + + void mbed_mutex_unlock(void *mutexin) + { + Mutex *mutex = (Mutex *) mutexin; + mutex->unlock(); + } + + void *mbed_sem_new(uint32_t count) + { + Semaphore *sem; + sem = new Semaphore(count); + for (uint32_t ii = 0; ii < count ; ii++) { + sem->acquire(); + } + return (void *) sem; + + } + void mbed_sem_delete(void *insem) + { + Semaphore *sem = (Semaphore *) insem; + delete sem; + } + bool mbed_sem_signal(void *semin) + { + bool ret; + Semaphore *sem = (Semaphore *) semin; + ret = (sem->release() == osOK); + return ret; + } + bool mbed_sem_wait(void *semin, uint32_t timeout) + { + bool ret; + Semaphore *sem = (Semaphore *) semin; + ret = sem->try_acquire_for(std::chrono::duration(timeout)); + return ret; + } + +#define QSIZE 10 + + void *mbed_queue_new(uint32_t count) + { + Queue *queue; + queue = new Queue ; + return (void *) queue; + } + + void mbed_queue_delete(void *queuein) + { + Queue *queue = (Queue *) queuein; + delete queue; + } + + void *mbed_queue_pop(void *queuein, uint32_t timeout) + { + uint32_t *message = NULL; + Queue *queue = (Queue *) queuein; + while (true) { + if (queue->try_get_for(std::chrono::duration(timeout), &message)) { + break; + } + } + return (void *) message; + } + + bool mbed_queue_push(void *queuein, void *value, uint32_t timeout) + { + Queue *queue = (Queue *) queuein; + return queue->try_put_for(std::chrono::duration(timeout), (uint32_t *)value); + } + + + + void *mbed_thread_new(void (*thread_entry)(void), uint32_t stacksize, uint32_t prio_in) + { + osPriority_t priority; + priority = osPriorityNormal; + if (prio_in == OSPRIORITYREALTIME) { + priority = osPriorityRealtime; + } + if (prio_in == OSPRIORITYABOVENORMAL) { + priority = osPriorityAboveNormal; + } + + + Thread *thread = new Thread(priority, stacksize); + if (thread) { + thread->start(callback(thread_entry)); + } + return (void *) thread; + } + + void mbed_thread_delete(void *threadin) + { + Thread *thread = (Thread *) threadin; + thread->join(); + } + + void mbed_thread_terminate(void *threadin) + { + Thread *thread = (Thread *) threadin; + thread->terminate(); + } + +} /* end of extern "C" */ diff --git a/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_mbed_os.h b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_mbed_os.h new file mode 100644 index 0000000000..e621fab5d0 --- /dev/null +++ b/connectivity/drivers/wifi/TARGET_STM/COMPONENT_EMW3080B/mx_wifi_mbed_os.h @@ -0,0 +1,154 @@ +/** + *

© Copyright (c) 2021 STMicroelectronics. + * SPDX-License-Identifier: BSD-3-Clause + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MX_WIFI_CMSIS_OS_H +#define MX_WIFI_CMSIS_OS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include +#include "mbed_assert.h" + +#ifndef MX_WIFI_MALLOC +#define MX_WIFI_MALLOC malloc +#endif /* MX_WIFI_MALLOC */ + +#ifndef MX_WIFI_FREE +#define MX_WIFI_FREE free +#endif /* MX_WIFI_FREE */ + +#define BASIC_MALLOC 1 +/* Assume that OS is not used when bypass is disabled */ + +#if BASIC_MALLOC +typedef struct mx_buf { + uint32_t len; + uint32_t header_len; + uint8_t data[1]; +} mx_buf_t; + +static inline mx_buf_t *mx_buf_alloc(uint32_t len) +{ + mx_buf_t *p = (mx_buf_t *) MX_WIFI_MALLOC(len + sizeof(mx_buf_t) -1U); + if (NULL != p) { + p->len = len; + p->header_len = 0; + } + return p; + +} + +#define MX_NET_BUFFER_ALLOC(len) mx_buf_alloc(len) +#define MX_NET_BUFFER_FREE(p) MX_WIFI_FREE(p) +#define MX_NET_BUFFER_HIDE_HEADER(p, n) (p)->header_len += (n) +#define MX_NET_BUFFER_PAYLOAD(p) &(p)->data[(p)->header_len] +#define MX_NET_BUFFER_SET_PAYLOAD_SIZE(p, size) (p)->len = (size) +#define MX_NET_BUFFER_GET_PAYLOAD_SIZE(p) (p)->len + +#else /* BASIC_ALLOC */ + +#define MX_NET_BUFFER_ALLOC(len) mx_buf_alloc((len)) +#define MX_NET_BUFFER_FREE(p) mx_buf_free((p)) +#define MX_NET_BUFFER_HIDE_HEADER(p, n) mx_buf_hide_header((p),(n)) +#define MX_NET_BUFFER_PAYLOAD(p) mx_buf_payload((p)) +#define MX_NET_BUFFER_SET_PAYLOAD_SIZE(p, size) mx_buf_set_size((p),(size)) +#define MX_NET_BUFFER_GET_PAYLOAD_SIZE(p) mx_buf_get_size((p)) + + +typedef void mx_buf_t; + +mx_buf_t *mx_buf_alloc(uint32_t len); +void mx_buf_free(mx_buf_t *p); +void mx_buf_hide_header(mx_buf_t *p, int32_t n); +uint8_t *mx_buf_payload(mx_buf_t *p); +uint32_t mx_buf_get_size(mx_buf_t *p); +void mx_buf_set_size(mx_buf_t *p, int32_t n); + +#endif /* BASIC_ALLOC */ + + +void mbed_delay(uint32_t delay); +void *mbed_mutex_new(void); +void mbed_mutex_delete(void *); +void mbed_mutex_lock(void *); +void mbed_mutex_unlock(void *); + + +void *mbed_sem_new(uint32_t count); +void mbed_sem_delete(void *sem); +bool mbed_sem_signal(void *sem); +bool mbed_sem_wait(void *sem, uint32_t timeout); + +void *mbed_queue_new(uint32_t count); +void mbed_queue_delete(void *sem); +void *mbed_queue_pop(void *sem, uint32_t timeout); + + +bool mbed_queue_push(void *sem, void *value, uint32_t timeout); + +void *mbed_thread_new(void (*thread_entry)(void), uint32_t stacksize, uint32_t priority); +void mbed_thread_delete(void *thread); +void mbed_thread_terminate(void *thread); + + +#define MX_ASSERT(a) MBED_ASSERT(a) + +#define LOCK_DECLARE(A) void* A +#define LOCK_INIT(A) A = mbed_mutex_new() +#define LOCK_DEINIT(A) mbed_mutex_delete(A) +#define LOCK(A) mbed_mutex_lock(A) +#define UNLOCK(A) mbed_mutex_unlock(A) + +#define SEM_DECLARE(A) void *A +#define SEM_INIT(A,COUNT) A = mbed_sem_new(COUNT); +#define SEM_DEINIT(A) mbed_sem_delete(A) +#define SEM_SIGNAL(A) mbed_sem_signal(A) +#define SEM_WAIT(A,TIMEOUT,IDLE_FUNC) mbed_sem_wait(A,TIMEOUT) + +#define THREAD_DECLARE(A) void *A +#define THREAD_INIT(A, THREAD_FUNC, THREAD_CONTEXT, STACKSIZE, PRIORITY) (((A = mbed_thread_new((THREAD_CONTEXT_FUNC_TYPE)THREAD_FUNC,STACKSIZE, PRIORITY))!= NULL)?true:false) +#define THREAD_DEINIT(A) mbed_thread_delete(A) +#define THREAD_TERMINATE(A) mbed_thread_terminate(A) +#define THREAD_CONTEXT_TYPE void +#define THREAD_CONTEXT_FUNC_TYPE void (*)(void) + +#define FIFO_DECLARE(QUEUE) void* QUEUE +#define FIFO_PUSH(QUEUE, VALUE, TIMEOUT, IDLE_FUNC) mbed_queue_push(QUEUE, VALUE, TIMEOUT) +#define FIFO_POP(QUEUE, TIMEOUT, IDLE_FUNC) mbed_queue_pop(QUEUE, TIMEOUT) +#define FIFO_INIT(QUEUE,QSIZE) QUEUE = mbed_queue_new(QSIZE) +#define FIFO_DEINIT(QUEUE) mbed_queue_delete(QUEUE) + + +#define WAIT_FOREVER 0xffffffff +#define SEM_OK true +#define THREAD_OK true +#define QUEUE_OK true +#define FIFO_OK true +#define OSPRIORITYNORMAL 1 +#define OSPRIORITYREALTIME 2 +#define OSPRIORITYABOVENORMAL 3 +#define DELAYms(n) mbed_delay(n) + +#ifdef __cplusplus +} +#endif + + +#endif /* MX_WIFI_MBED_OS_H */