Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: drivers/network/COMPONENT_WIFI_WIZFI310/WizFi310Interface.cpp
- Revision:
- 0:8f0bb79ddd48
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_WIZFI310/WizFi310Interface.cpp Tue May 04 08:55:12 2021 +0000 @@ -0,0 +1,567 @@ +/* WizFi310 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * 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. + */ + +/** + ****************************************************************************** + * @file WizFi310Interface.h + * @author Gateway Team + * @brief Implementation file of the NetworkStack for the WizFi310 WiFi Device + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> + ****************************************************************************** + */ + +#include <string.h> +#include "WizFi310Interface.h" +#include "mbed_trace.h" + +#define TRACE_GROUP "WZ__" + +using namespace mbed; +// Various timeouts for different WizFi310 operations +#ifndef WIZFI310_CONNECT_TIMEOUT +#define WIZFI310_CONNECT_TIMEOUT 15000 +#endif +#ifndef WIZFI310_SEND_TIMEOUT +#define WIZFI310_SEND_TIMEOUT 500 +#endif +#ifndef WIZFI310_RECV_TIMEOUT +#define WIZFI310_RECV_TIMEOUT 0 +#endif +#ifndef WIZFI310_MISC_TIMEOUT +#define WIZFI310_MISC_TIMEOUT 500 +#endif +#ifndef WIZFI310_OPEN_TIMEOUT +#define WIZFI310_OPEN_TIMEOUT 10000 +#endif +#ifndef WIZFI310_CLOSE_TIMEOUT +#define WIZFI310_CLOSE_TIMEOUT 500 +#endif + +#ifndef WIZFI310_MAX_CONNECT_COUNT +#define WIZFI310_MAX_CONNECT 2 +#endif + +#ifndef WIZFI310_DELAY_MS +#define WIZFI310_DELAY_MS 300 +#endif + +// ================================================================================================= +// helper functions +static const char *sec2str(nsapi_security_t sec) +{ + switch (sec) { + case NSAPI_SECURITY_NONE: + return "OPEN"; + case NSAPI_SECURITY_WEP: + return "WEP"; + case NSAPI_SECURITY_WPA: + return "WPA"; + case NSAPI_SECURITY_WPA2: + return "WPA2"; + case NSAPI_SECURITY_WPA_WPA2: + return "WPAWPA2"; + default: + return ""; + } +} + +// ================================================================================================= +// WizFi310Interface implementation +WizFi310Interface::WizFi310Interface(PinName tx, PinName rx, PinName rts, PinName cts, PinName rst) : + m_wizfi310(tx, rx, rts, cts, rst), + m_mutex("WizFi310Interface") +{ + memset(ap_ssid, 0, sizeof(ap_ssid)); + memset(ap_pass, 0, sizeof(ap_pass)); + ap_sec = NSAPI_SECURITY_NONE; + m_wizfi310.attach(Callback<void(nsapi_connection_status_t)>(this, &WizFi310Interface::link_status_change)); +} + +void WizFi310Interface::link_status_change(nsapi_connection_status_t status) +{ + if (m_on_status_change) { + m_on_status_change(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, status); + } + m_semphr.release(); +} + +// ================================================================================================= +// WiFi network api + +nsapi_error_t WizFi310Interface::connect( + const char *ssid, + const char *pass, + nsapi_security_t security, + uint8_t channel) +{ + m_mutex.lock(); + nsapi_error_t res = set_channel(channel); + if (res == NSAPI_ERROR_OK) { + res = set_credentials(ssid, pass, security); + } + if (res == NSAPI_ERROR_OK) { + res = connect(); + } + m_mutex.unlock(); + return res; +} + +nsapi_error_t WizFi310Interface::connect() +{ + if (strlen(ap_ssid) == 0) { + return NSAPI_ERROR_PARAMETER; + } + if ((ap_sec != NSAPI_SECURITY_NONE) && ((strlen(ap_pass) == 0) || (strlen(ap_pass) >= 64))) { + return NSAPI_ERROR_PARAMETER; + } + if (m_wizfi310.status() == NSAPI_STATUS_GLOBAL_UP) { + return NSAPI_ERROR_IS_CONNECTED; + } else if (m_wizfi310.status() == NSAPI_STATUS_CONNECTING) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + nsapi_error_t res = NSAPI_ERROR_OK; + + m_mutex.lock(); + if (!m_wizfi310.dhcp(true)) { + res = NSAPI_ERROR_DHCP_FAILURE; + } else { + if (ap_sec == NSAPI_SECURITY_NONE && (strlen(ap_pass) > 0)) { + ap_sec = NSAPI_SECURITY_UNKNOWN; + } + + m_semphr.wait(0); + while ((res = m_wizfi310.connect(ap_ssid, ap_pass, sec2str(ap_sec))) == NSAPI_ERROR_WOULD_BLOCK) { + wait_ms(10); + } + if (res == NSAPI_ERROR_IN_PROGRESS) { + do { + // wait for connect + m_semphr.wait(); + } while (m_wizfi310.status() == NSAPI_STATUS_CONNECTING); + res = (m_wizfi310.status() == NSAPI_STATUS_DISCONNECTED) ? NSAPI_ERROR_NO_CONNECTION : NSAPI_ERROR_OK; + } + } + m_mutex.unlock(); + + return res; +} + +nsapi_error_t WizFi310Interface::set_channel(uint8_t chan) +{ + if (chan != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + return NSAPI_ERROR_OK; +} + +int WizFi310Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + if ((ssid == NULL) || (strlen(ssid) == 0)) { + return NSAPI_ERROR_PARAMETER; + } + if ((security != NSAPI_SECURITY_NONE) && ((pass == NULL) || (strlen(pass) == 0) || (strlen(pass) >= 64))) { + return NSAPI_ERROR_PARAMETER; + } + + m_mutex.lock(); + memset(ap_ssid, 0, sizeof(ap_ssid)); + strncpy(ap_ssid, ssid, sizeof(ap_ssid)); + + memset(ap_pass, 0, sizeof(ap_pass)); + if (pass != NULL) { + strncpy(ap_pass, pass, sizeof(ap_pass)); + } + + ap_sec = security; + m_mutex.unlock(); + + return NSAPI_ERROR_OK; +} + +int WizFi310Interface::disconnect() +{ + nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION; + + m_mutex.lock(); + if (m_wizfi310.status() != NSAPI_STATUS_DISCONNECTED) { + m_semphr.wait(0); + while ((err = m_wizfi310.disconnect()) == NSAPI_ERROR_WOULD_BLOCK) { + wait_ms(10); + } + if (err == NSAPI_ERROR_IN_PROGRESS) { + while (m_wizfi310.status() != NSAPI_STATUS_DISCONNECTED) { + m_semphr.wait(); + err = NSAPI_ERROR_OK; + } + } + } + m_mutex.unlock(); + return err; +} + +nsapi_connection_status_t WizFi310Interface::get_connection_status() const +{ + return m_wizfi310.status(); +} + +const char *WizFi310Interface::get_ip_address() +{ + return m_wizfi310.get_ip_address(); +} + +int8_t WizFi310Interface::get_rssi() +{ + return 0; +} + +void WizFi310Interface::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb) +{ + m_mutex.lock(); + m_on_status_change = status_cb; + m_mutex.unlock(); +} + +nsapi_size_or_error_t WizFi310Interface::scan(WiFiAccessPoint *res, nsapi_size_t count) +{ + m_mutex.lock(); + m_scan_ctx.res = res; + m_scan_ctx.count = count; + m_scan_ctx.idx = 0; + + m_semphr.wait(0); + nsapi_error_t err = m_wizfi310.scan(Callback<void(nsapi_wifi_ap_t *)>(this, &WizFi310Interface::scan_ap)); + if (err == NSAPI_ERROR_IN_PROGRESS) { + m_semphr.wait(); + } + + uint32_t total = m_scan_ctx.idx; + if ((count != 0) && (count < total)) { + total = count; + } + m_mutex.unlock(); + return total; +} + +void WizFi310Interface::scan_ap(nsapi_wifi_ap_t *ap) +{ + if (ap == NULL) { + m_semphr.release(); + return; + } + if (m_scan_ctx.idx < m_scan_ctx.count) { + m_scan_ctx.res[m_scan_ctx.idx] = WiFiAccessPoint(*ap); + } + m_scan_ctx.idx += 1; +} + +// ================================================================================================= +// Socket API +nsapi_error_t WizFi310Interface::socket_open(void **handle, nsapi_protocol_t proto) +{ + tr_debug("socket_open(%p, %d)", handle, proto); + if (handle == NULL) { + tr_debug("socket_open()=%d,--", NSAPI_ERROR_PARAMETER); + return NSAPI_ERROR_PARAMETER; + } + + // Look for an unused socket + m_mutex.lock(); + // limit the number of active socket to WIZFI310_SOCKET_COUNT + if (m_socket_count == WIZFI310_SOCKET_COUNT) { + m_mutex.unlock(); + tr_debug("socket_open()=%d,--", NSAPI_ERROR_NO_SOCKET); + return NSAPI_ERROR_NO_SOCKET; + } + + struct wizfi310_socket *socket = new (std::nothrow) struct wizfi310_socket(m_wizfi310, proto); + if (!socket) { + m_mutex.unlock(); + tr_debug("socket_open()=%d,--", NSAPI_ERROR_NO_MEMORY); + return NSAPI_ERROR_NO_MEMORY; + } + m_socket_count += 1; + m_mutex.unlock(); + + *handle = socket; + tr_debug("socket_open()=0,%p", socket); + + return 0; +} + +int WizFi310Interface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int WizFi310Interface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int WizFi310Interface::socket_connect(void *handle, const SocketAddress &addr) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + if (addr.get_ip_version() != NSAPI_IPv4) { + return NSAPI_ERROR_UNSUPPORTED; + } + + tr_debug("socket_connect(%p, %s:%u)", handle, addr.get_ip_address(), addr.get_port()); + socket->op_mtx.lock(); + nsapi_error_t res = NSAPI_ERROR_DEVICE_ERROR; + if (socket->id >= 0) { + if (socket->connected) { + res = NSAPI_ERROR_IS_CONNECTED; + } else { + res = NSAPI_ERROR_ALREADY; + } + } else { + socket->addr = addr; + const char *proto = (socket->proto == NSAPI_UDP) ? "UCN" : "TCN"; + int id = NSAPI_ERROR_WOULD_BLOCK; + while (id == NSAPI_ERROR_WOULD_BLOCK) { + id = m_wizfi310.open(proto, addr.get_ip_address(), addr.get_port(), socket_event, socket); + if (id == NSAPI_ERROR_WOULD_BLOCK) { + wait_ms(1000); + } else if (id < 0) { + res = id; + } else { + socket->id = id; + res = NSAPI_ERROR_IN_PROGRESS; + } + } + } + socket->op_mtx.unlock(); + tr_debug("socket_connect(%p,...)=(%d)%d", handle, socket->id, res); + return res; +} + +int WizFi310Interface::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int WizFi310Interface::socket_send(void *handle, const void *data, unsigned size) +{ + tr_debug("socket_send(%p, %p, %u)", handle, data, size); + if (size == 0) { + return 0; + } + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + socket->op_mtx.lock(); + if (!socket->connected) { + socket->op_mtx.unlock(); + return NSAPI_ERROR_NO_CONNECTION; + } + nsapi_error_t res; + do { + socket->semphr.wait(0); + res = m_wizfi310.send(socket->id, data, size); + if (res == NSAPI_ERROR_WOULD_BLOCK) { + wait_ms(10); + } + } while (res == NSAPI_ERROR_WOULD_BLOCK); + if (res == NSAPI_ERROR_IN_PROGRESS) { + socket->semphr.wait(); + res = size; + } + socket->op_mtx.unlock(); + tr_debug("socket_send(%p, %p, %u)=%d", handle, data, size, res); + return res; +} + +int WizFi310Interface::socket_recv(void *handle, void *data, unsigned size) +{ + tr_debug("socket_recv(%p, %p, %u)", handle, data, size); + struct wizfi310_socket *s = (struct wizfi310_socket *)handle; + int32_t read = NSAPI_ERROR_WOULD_BLOCK; + Packet *p = NULL; + + s->state_mtx.lock(); + if (s->first != NULL) { + p = s->first; + + uint32_t plen = p->len(); + read = p->consume((char *)data, size); + tr_debug("%d: f: %p l: %p; read: %lu/%lu", __LINE__, s->first, s->last, read, plen); + (void)plen; + if (p->len() == 0) { + s->first = p->next(); + if (s->first == NULL) { + s->last = NULL; + } else { + p->set_next(NULL); // detach head from the rest + } + delete p; + + // TODO: we need a way to signal the driver that we made some space for further reception + } + tr_debug("%d: f: %p l: %p", __LINE__, s->first, s->last); + } else if (!s->connected) { + read = 0; + } + s->state_mtx.unlock(); + tr_debug("socket_recv(%p, %p, %u)=%ld", s, data, size, read); + return read; +} + +int WizFi310Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + if (addr.get_ip_version() != NSAPI_IPv4) { + return NSAPI_ERROR_PARAMETER; + } + nsapi_error_t res; + + tr_debug("socket_sendto(%p, %s:%hu, %p, %u)", handle, addr.get_ip_address(), (uint16_t)addr.get_port(), data, size); + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + socket->op_mtx.lock(); + if (socket->connected && socket->addr != addr) { + socket->close(); + } + res = socket_connect(socket, addr); + if ((res == NSAPI_ERROR_IN_PROGRESS) || (res == NSAPI_ERROR_ALREADY) || (res == NSAPI_ERROR_IS_CONNECTED)) { + if (!socket->connected) { + socket->semphr.wait(); + } + if (!socket->connected) { + res = NSAPI_ERROR_NO_CONNECTION; + } else { + res = socket_send(socket, data, size); + } + } + socket->op_mtx.unlock(); + return res; +} +int WizFi310Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + tr_debug("socket_recvfrom(%p, %p, %u)", handle, data, size); + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + int ret = socket_recv(socket, data, size); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +nsapi_error_t WizFi310Interface::socket_close(void *handle) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + tr_debug("socket_close(%p)", handle); + + m_mutex.lock(); + socket->close(); + m_socket_count -= 1; + m_mutex.unlock(); + delete socket; + + return NSAPI_ERROR_OK; +} +void WizFi310Interface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + tr_debug("socket_attach(%p, %p, %p)", handle, callback, data); + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + socket->state_mtx.lock(); + socket->cbk = callback; + socket->data = data; + socket->state_mtx.unlock(); +} + +void WizFi310Interface::socket_event(void *ctx, WizFi310::socket_event_t type, WizFi310::socket_event_data_t &data) +{ + struct wizfi310_socket *s = (struct wizfi310_socket *)ctx; + tr_debug("socket_event(%p, %s)", ctx, WizFi310::event2str(type)); + s->state_mtx.lock(); + switch (type) { + case WizFi310::EventConnected: { + s->connected = true; + s->semphr.release(); + break; + } + case WizFi310::EventDataReceived: { + tr_debug("%d: Data received: %p (f:%p l:%p)", __LINE__, data.data_received.packet, s->first, s->last); + if (s->last == NULL) { + s->last = data.data_received.packet; + s->first = s->last; + } else { + s->last->set_next(data.data_received.packet); + s->last = data.data_received.packet; + } + tr_debug("%d: f: %p l: %p", __LINE__, s->first, s->last); + break; + } + case WizFi310::EventDataSent: { + s->semphr.release(); + break; + } + case WizFi310::EventDisconnected: { + s->connected = false; + s->id = -1; + // TODO: on recv transfer the packet owner ship to this layer as we may be disconnected before those data are actually read. + // This would also remove the need of the WizFi310::recv method. + s->semphr.release(); + break; + } + default: { + // tr_error("Unknown event %d", type); + break; + } + } + if (s->cbk) { + s->cbk(s->data); + } + s->state_mtx.unlock(); +} + +void WizFi310Interface::wizfi310_socket::close() +{ + // no lock required here as no other thread shall access this object as it is freed. + state_mtx.lock(); + int id = this->id; + this->id = -1; + state_mtx.unlock(); + if (id >= 0) { + wifi.close(id); + } +} + +WizFi310Interface::wizfi310_socket::~wizfi310_socket() +{ + close(); + if (first != NULL) { + delete first; + } +} + +#ifdef MBED_CONF_WIZFI310_PROVIDE_DEFAULT + +WiFiInterface *WiFiInterface::get_default_instance() +{ + static WizFi310Interface wizfi; + return &wizfi; +} + +#endif