blob: 529f1ed9d9a455bfab2746824dd5a09d0f98ab03 [file] [log] [blame]
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_wlan_netdev.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <debug.h>
#include <arpa/inet.h>
#include <nuttx/wireless/wireless.h>
#include <nuttx/net/netdev_lowerhalf.h>
#include "esp_attr.h"
#include "esp_wifi_api.h"
#include "esp_wifi_utils.h"
#include "esp_wlan_netdev.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Only need 1 TX buf because packets are transmitted immediately and we can
* reuse the same buffer for the next packet.
* RX buf should match CONFIG_ESPRESSIF_WIFI_DYNAMIC_RX_BUFFER_NUM.
*/
#define RX_BUF_COUNT CONFIG_ESPRESSIF_WIFI_DYNAMIC_RX_BUFFER_NUM
#define TX_BUF_COUNT 1
#define CONNECT_TIMEOUT CONFIG_ESPRESSIF_WIFI_CONNECT_TIMEOUT
/****************************************************************************
* Private Types
****************************************************************************/
static int esp_wlan_ifup(struct netdev_lowerhalf_s *dev);
static int esp_wlan_ifdown(struct netdev_lowerhalf_s *dev);
static int esp_wlan_transmit(struct netdev_lowerhalf_s *dev, netpkt_t *pkt);
static netpkt_t *esp_wlan_receive(struct netdev_lowerhalf_s *dev);
static void esp_wlan_reclaim(struct netdev_lowerhalf_s *dev);
static int esp_wlan_ioctl(struct netdev_lowerhalf_s *dev, int cmd,
unsigned long arg);
static int esp_wlan_connect(struct netdev_lowerhalf_s *dev);
static int esp_wlan_disconnect(struct netdev_lowerhalf_s *dev);
static int esp_wlan_essid(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_bssid(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_passwd(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_mode(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_auth(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_freq(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_bitrate(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_txpower(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_country(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_sensitivity(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_scan(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set);
static int esp_wlan_range(struct netdev_lowerhalf_s *dev, struct iwreq *iwr);
/****************************************************************************
* Private Data
****************************************************************************/
/* Common Wi-Fi controller data */
struct esp_common_wifi_s
{
bool driver_init;
};
/* Main driver control structure, contains the upper-half data structure
* and lower-half driver information.
*/
struct esp_wlan_priv_s
{
/* Upper-half interface */
struct netdev_lowerhalf_s dev;
/* Lower-half data */
struct esp_common_wifi_s *common;
uint32_t mode;
netpkt_queue_t netdev_rx_queue;
uint8_t flatbuf[CONFIG_NET_ETH_PKTSIZE];
};
/* Netdev operations */
static const struct netdev_ops_s g_netdev_ops =
{
.ifup = esp_wlan_ifup,
.ifdown = esp_wlan_ifdown,
.transmit = esp_wlan_transmit,
.receive = esp_wlan_receive,
.ioctl = esp_wlan_ioctl,
.reclaim = esp_wlan_reclaim,
};
/* Wireless operations */
static const struct wireless_ops_s g_wireless_ops =
{
.connect = esp_wlan_connect,
.disconnect = esp_wlan_disconnect,
.essid = esp_wlan_essid,
.bssid = esp_wlan_bssid,
.passwd = esp_wlan_passwd,
.mode = esp_wlan_mode,
.auth = esp_wlan_auth,
.freq = esp_wlan_freq,
.bitrate = esp_wlan_bitrate,
.txpower = esp_wlan_txpower,
.country = esp_wlan_country,
.sensitivity = esp_wlan_sensitivity,
.scan = esp_wlan_scan,
.range = esp_wlan_range,
};
/* Common Wi-Fi controller data */
struct esp_common_wifi_s g_common_wifi =
{
.driver_init = false,
};
/* Station interface control structure */
#ifdef ESP_WLAN_HAS_STA
static struct esp_wlan_priv_s g_wlan_sta =
{
.dev =
{
.ops = &g_netdev_ops,
.iw_ops = &g_wireless_ops,
},
.common = &g_common_wifi,
.mode = IW_MODE_INFRA,
};
#endif /* ESP_WLAN_HAS_STA */
/* SoftAP interface control structure */
#ifdef ESP_WLAN_HAS_SOFTAP
static struct esp_wlan_priv_s g_wlan_softap =
{
.dev =
{
.ops = &g_netdev_ops,
.iw_ops = &g_wireless_ops,
},
.common = &g_common_wifi,
.mode = IW_MODE_MASTER,
};
#endif /* ESP_WLAN_HAS_SOFTAP */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp_wlan_ifup
*
* Description:
* Bring up the network device.
*
* Input Parameters:
* dev - The network device.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_ifup(struct netdev_lowerhalf_s *dev)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
struct net_driver_s *netdev = &priv->dev.netdev;
int ret = OK;
#ifdef CONFIG_NET_IPv4
wlinfo("Bringing up: %u.%u.%u.%u\n",
ip4_addr1(netdev->d_ipaddr), ip4_addr2(netdev->d_ipaddr),
ip4_addr3(netdev->d_ipaddr), ip4_addr4(netdev->d_ipaddr));
#endif
#ifdef CONFIG_NET_IPv6
wlinfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
netdev->d_ipv6addr[0], netdev->d_ipv6addr[1], netdev->d_ipv6addr[2],
netdev->d_ipv6addr[3], netdev->d_ipv6addr[4], netdev->d_ipv6addr[5],
netdev->d_ipv6addr[6], netdev->d_ipv6addr[7]);
#endif
/* Clear RX queue */
netpkt_free_queue(&priv->netdev_rx_queue);
/* Start Wi-Fi interface */
ret = esp_wifi_api_start(priv->mode);
if (ret != 0)
{
wlerr("ERROR: Failed to start Wi-Fi station\n");
return ret;
}
return ret;
}
/****************************************************************************
* Name: esp_wlan_ifdown
*
* Description:
* Bring down the network device.
* If using STA + SoftAP, both interfaces are stopped, followed by another
* bringup of the other interface.
*
* If using only STA, only the STA interface is stopped.
* If using only SoftAP, only the SoftAP interface is stopped.
* If using STA + SoftAP and request to stop SoftAP:
* Both are disabled and STA is restarted.
* If using STA + SoftAP and request to stop STA:
* Both are disabled and SoftAP is restarted.
*
* Input Parameters:
* dev - The network device.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_ifdown(struct netdev_lowerhalf_s *dev)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
int ret = OK;
ret = esp_wifi_api_stop(priv->mode);
if (ret != OK)
{
wlerr("ERROR: Failed to stop Wi-Fi station\n");
}
return ret;
}
/****************************************************************************
* Name: esp_wlan_transmit
*
* Description:
* Transmit function required by the netdev ops.
*
* Input Parameters:
* dev - The network device.
* pkt - The packet to transmit.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_transmit(struct netdev_lowerhalf_s *dev,
netpkt_t *pkt)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
unsigned int len = netpkt_getdatalen(dev, pkt);
int ret = OK;
/* Copy data from the packet to the flat buffer, then push it
* to the Wi-Fi driver.
*/
netpkt_copyout(dev, priv->flatbuf, pkt, len, 0);
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
ret = esp_wifi_sta_send_data(priv->flatbuf, len);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
ret = esp_wifi_softap_send_data(priv->flatbuf, len);
}
#endif
if (ret < 0)
{
return ret;
}
/* Free the packet after sending */
netpkt_free(dev, pkt, NETPKT_TX);
return ret;
}
/****************************************************************************
* Name: esp_wlan_receive
*
* Description:
* Receive function required by the netdev ops.
*
* Input Parameters:
* dev - The network device.
*
* Returned Value:
* A pointer to the received packet.
*
****************************************************************************/
static netpkt_t *esp_wlan_receive(struct netdev_lowerhalf_s *dev)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
netpkt_t *pkt = netpkt_remove_queue(&priv->netdev_rx_queue);
return pkt;
}
/****************************************************************************
* Name: esp_wlan_ioctl
*
* Description:
* Ioctl function required by the netdev ops.
*
* Input Parameters:
* dev - The network device.
* cmd - The command.
* arg - The argument.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
#ifdef CONFIG_NETDEV_IOCTL
static int esp_wlan_ioctl(struct netdev_lowerhalf_s *dev, int cmd,
unsigned long arg)
{
/* TODO: Implement ioctl handler */
return -ENOSYS;
}
#endif
/****************************************************************************
* Name: esp_wlan_reclaim
*
* Description:
* Reclaim function required by the netdev ops.
*
* Input Parameters:
* dev - The network device.
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_wlan_reclaim(struct netdev_lowerhalf_s *dev)
{
/* TODO: Implement reclaim logic */
}
/* Skeleton implementations for wireless_ops_s functions */
/****************************************************************************
* Name: esp_wlan_connect
*
* Description:
* Connect function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_connect(struct netdev_lowerhalf_s *dev)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
int ret;
useconds_t timeout = 1000 * 1000; /* 1 second */
int timeout_count = CONNECT_TIMEOUT;
volatile bool connection_success = false;
volatile bool timeout_reached = false;
if (priv->mode == IW_MODE_INFRA)
{
ret = esp_wifi_sta_connect();
if (ret < 0)
{
wlerr("Failed to connect to Wi-Fi\n");
return ret;
}
/* Wait for connection success or timeout.
*
* Note: IFF_RUNNING is set when WIFI_ADPT_EVT_STA_CONNECT event is
* received.
*/
while (timeout_count >= 0 && !connection_success)
{
if (priv->dev.netdev.d_flags & IFF_RUNNING)
{
connection_success = true;
break;
}
nxsched_usleep(timeout);
timeout_count--;
}
if (!connection_success)
{
wlerr("Connection timeout after %d seconds\n", CONNECT_TIMEOUT);
return -ETIMEDOUT;
}
return ret;
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_connect();
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_disconnect
*
* Description:
* Disconnect function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_disconnect(struct netdev_lowerhalf_s *dev)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_disconnect(false);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_disconnect();
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_essid
*
* Description:
* ESSID function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the ESSID is to be set, false if the ESSID is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_essid(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_essid(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_essid(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_bssid
*
* Description:
* BSSID function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the BSSID is to be set, false if the BSSID is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_bssid(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_bssid(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_bssid(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_passwd
*
* Description:
* Password function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the password is to be set, false if the password is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_passwd(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_password(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_password(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_mode
*
* Description:
* Mode function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if mode is to be set, false if the mode is to be retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_mode(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_mode(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_mode(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_auth
*
* Description:
* Authentication function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if authentication is to be set, false if the authentication
* is to be retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_auth(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_auth(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_auth(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_freq
*
* Description:
* Frequency function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if frequency is to be set, false if the frequency is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_freq(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_freq(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_freq(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_bitrate
*
* Description:
* Bitrate function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the bitrate is to be set, false if the bitrate is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_bitrate(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_bitrate(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_bitrate(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_txpower
*
* Description:
* TX power function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the TX power is to be set, false if the TX power is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_txpower(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_txpower(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_txpower(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_country
*
* Description:
* Country function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the country is to be set, false if the country is to be
* retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_country(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_country(iwr, set);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (priv->mode == IW_MODE_MASTER)
{
return esp_wifi_softap_country(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_sensitivity
*
* Description:
* Sensitivity function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if the sensitivity is to be set, false if the sensitivity is
* to be retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_sensitivity(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
struct esp_wlan_priv_s *priv = (struct esp_wlan_priv_s *)dev;
#ifdef ESP_WLAN_HAS_STA
if (priv->mode == IW_MODE_INFRA)
{
return esp_wifi_sta_rssi(iwr, set);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_scan
*
* Description:
* Scan function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
* set - True if scan is to be started, false if the scan results are to
* be retrieved.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_scan(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr, bool set)
{
#ifdef ESP_WLAN_HAS_STA
if (set)
{
return esp_wifi_start_scan(iwr);
}
else
{
return esp_wifi_get_scan_results(iwr);
}
#endif
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wlan_range
*
* Description:
* Range get function required by the wireless ops.
*
* Input Parameters:
* dev - The network device.
* iwr - The wireless request.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_range(struct netdev_lowerhalf_s *dev,
struct iwreq *iwr)
{
/* TODO: Implement range get */
return -ENOSYS;
}
/****************************************************************************
* Name: esp_wifi_tx_done_cb
*
* Description:
* TX done callback. Called when the TX packet is sent. Informs the upper
* layer that the TX packet has been sent.
*
* Input Parameters:
* ifidx - The interface index.
* data - The data of the TX packet.
* len - The length of the TX packet.
* txstatus - The status of the TX packet.
*
* Returned Value:
* None.
*
****************************************************************************/
void IRAM_ATTR esp_wifi_tx_done_cb(uint8_t ifidx,
uint8_t *data,
uint16_t *len,
bool txstatus)
{
#ifdef ESP_WLAN_HAS_STA
if (ifidx == ESP_IF_WIFI_STA)
{
netdev_lower_txdone(&g_wlan_sta.dev);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (ifidx == ESP_IF_WIFI_AP)
{
netdev_lower_txdone(&g_wlan_softap.dev);
}
#endif
}
/****************************************************************************
* Name: wlan_rx_done
*
* Description:
* RX done function. Allocates a new packet and copies the received
* data into a packet, which is then added to the receive queue.
*
* When done, informs the upper layer that the packet is ready to be
* processed.
*
* Input Parameters:
* priv - The private data structure for the specified mode.
* buffer - The buffer containing the received packet.
* len - The length of the received packet.
* eb - The event buffer.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int wlan_rx_done(struct esp_wlan_priv_s *priv,
void *buffer, uint16_t len, void *eb)
{
int ret = OK;
netpkt_t *pkt = NULL;
pkt = netpkt_alloc(&priv->dev, NETPKT_RX);
if (pkt == NULL)
{
ret = -ENOMEM;
goto out;
}
ret = netpkt_copyin(&priv->dev, pkt, buffer, len, 0);
if (ret < 0)
{
wlerr("ERROR: Failed to copy packet\n");
goto out;
}
ret = netpkt_tryadd_queue(pkt, &priv->netdev_rx_queue);
if (ret != OK)
{
wlerr("ERROR: Failed to add packet to queue\n");
goto out;
}
out:
if (eb != NULL)
{
esp_wifi_api_free_rx_buffer(eb);
}
if (ret != OK && pkt != NULL)
{
netpkt_free(&priv->dev, pkt, NETPKT_RX);
}
if (ret == OK)
{
netdev_lower_rxready(&priv->dev);
}
return ret;
}
/****************************************************************************
* Name: wlan_sta_rx_done
*
* Description:
* RX done callback for station mode. This call back is specified by
* IDF's API.
*
* Input Parameters:
* buffer - The buffer containing the received packet.
* len - The length of the received packet.
* eb - The event buffer.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_STA
static int wlan_sta_rx_done(void *buffer, uint16_t len, void *eb)
{
struct esp_wlan_priv_s *priv = &g_wlan_sta;
return wlan_rx_done(priv, buffer, len, eb);
}
#endif /* ESP_WLAN_HAS_STA */
/****************************************************************************
* Name: wlan_softap_rx_done
*
* Description:
* RX done callback for SoftAP mode. This call back is specified by
* IDF's API.
*
* Input Parameters:
* buffer - The buffer containing the received packet.
* len - The length of the received packet.
* eb - The event buffer.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_SOFTAP
static int wlan_softap_rx_done(void *buffer, uint16_t len, void *eb)
{
struct esp_wlan_priv_s *priv = &g_wlan_softap;
return wlan_rx_done(priv, buffer, len, eb);
}
#endif /* ESP_WLAN_HAS_SOFTAP */
/****************************************************************************
* Name: esp_wifi_initialize
*
* Description:
* Initialize the Wi-Fi controller.
*
* Input Parameters:
* None.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wifi_initialize(void)
{
int ret;
wlinfo("INFO: Bring up Wi-Fi adapter\n");
if (!g_common_wifi.driver_init)
{
ret = esp_wifi_api_adapter_init();
if (ret != OK)
{
wlerr("ERROR: Initialize Wi-Fi adapter error: %d\n", ret);
return ret;
}
g_common_wifi.driver_init = true;
}
else
{
wlwarn("WARN: Wi-Fi adapter is already initialized\n");
}
return OK;
}
/****************************************************************************
* Name: esp_wlan_initialize
*
* Description:
* Initialize the Wi-Fi adapter for the specified mode.
*
* 1. Calls esp_wifi_initialize() to initialize the Wi-Fi controller. This
* should be done only once.
*
* 2. Reads the MAC address from the Wi-Fi controller.
*
* 3. Copies the MAC address to the netdev.
*
* 4. Sets the number of RX and TX buffers.
*
* 5. Registers the TX and RX callback.
*
* 6. Registers the network device at /dev/wlanN.
*
* Input Parameters:
* mode - The Wi-Fi mode to initialize (from wireless.h).
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp_wlan_initialize(uint32_t mode)
{
int ret;
uint8_t mac[6];
struct esp_wlan_priv_s *priv = NULL;
ret = esp_wifi_initialize();
if (ret != OK)
{
wlerr("ERROR: Failed to initialize Wi-Fi adapter\n");
return ret;
}
switch (mode)
{
case IW_MODE_INFRA:
#ifdef ESP_WLAN_HAS_STA
wlinfo("INFO: Initialize Wi-Fi station\n");
priv = &g_wlan_sta;
ret = esp_wifi_sta_read_mac(mac);
#endif
break;
case IW_MODE_MASTER:
#ifdef ESP_WLAN_HAS_SOFTAP
wlinfo("INFO: Initialize Wi-Fi SoftAP\n");
priv = &g_wlan_softap;
ret = esp_wifi_softap_read_mac(mac);
#endif
break;
default:
wlerr("ERROR: Invalid Wi-Fi mode\n");
return -EINVAL;
}
if (ret != OK)
{
wlerr("ERROR: Failed to read MAC address\n");
return ret;
}
wlinfo("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
/* Copy the ESP MAC Address to the netdev */
memcpy(priv->dev.netdev.d_mac.ether.ether_addr_octet, mac, sizeof(mac));
/* Set the number of RX and TX buffers. */
priv->dev.quota[NETPKT_RX] = RX_BUF_COUNT;
priv->dev.quota[NETPKT_TX] = TX_BUF_COUNT;
IOB_QINIT(&priv->netdev_rx_queue);
/* Register RX done callback. Called when the RX packet is received. */
#ifdef ESP_WLAN_HAS_STA
if (mode == IW_MODE_INFRA)
{
ret = esp_wifi_api_sta_register_rx_callback(wlan_sta_rx_done);
}
#endif
#ifdef ESP_WLAN_HAS_SOFTAP
if (mode == IW_MODE_MASTER)
{
ret = esp_wifi_api_softap_register_rx_callback(wlan_softap_rx_done);
}
#endif
if (ret != OK)
{
wlerr("ERROR: Failed to register RX callback\n");
return ret;
}
/* Register TX done callback. Called when the TX packet is sent. */
ret = esp_wifi_api_register_tx_done_callback(esp_wifi_tx_done_cb);
if (ret != OK)
{
wlerr("ERROR: Failed to register TX done callback\n");
return ret;
}
/* Registers the network device at /dev/wlanN */
ret = netdev_lower_register((FAR struct netdev_lowerhalf_s *) priv,
NET_LL_IEEE80211);
if (ret != OK)
{
wlerr("ERROR: Failed to register IEEE 802.11 netdev: %d\n", ret);
return ret;
}
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp_wlan_sta_connect_success_hook
*
* Description:
* Notify the networking layer that connection has succeeded.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_STA
void esp_wlan_sta_connect_success_hook(void)
{
struct esp_wlan_priv_s *priv = &g_wlan_sta;
netdev_lower_carrier_on(&priv->dev);
}
#endif
/****************************************************************************
* Name: esp_wlan_sta_disconnect_hook
*
* Description:
* Notify the networking layer that connection has been disconnected.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_STA
void esp_wlan_sta_disconnect_hook(void)
{
struct esp_wlan_priv_s *priv = &g_wlan_sta;
netdev_lower_carrier_off(&priv->dev);
}
#endif
/****************************************************************************
* Name: esp_wlan_softap_connect_success_hook
*
* Description:
* Notify the networking layer that connection has succeeded.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_SOFTAP
void esp_wlan_softap_connect_success_hook(void)
{
struct esp_wlan_priv_s *priv = &g_wlan_softap;
netdev_lower_carrier_on(&priv->dev);
}
#endif
/****************************************************************************
* Name: esp_wlan_softap_disconnect_hook
*
* Description:
* Notify the networking layer that connection has been disconnected.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_SOFTAP
void esp_wlan_softap_disconnect_hook(void)
{
struct esp_wlan_priv_s *priv = &g_wlan_softap;
netdev_lower_carrier_off(&priv->dev);
}
#endif
/****************************************************************************
* Name: esp_wlan_sta_initialize
*
* Description:
* Initialize the Wi-Fi adapter for station mode.
* Called from board level initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_STA
int esp_wlan_sta_initialize(void)
{
return esp_wlan_initialize(IW_MODE_INFRA);
}
#endif
/****************************************************************************
* Name: esp_wlan_softap_initialize
*
* Description:
* Initialize the Wi-Fi adapter for SoftAP mode.
* Called from board level initialization.
*
* Input Parameters:
* None.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
#ifdef ESP_WLAN_HAS_SOFTAP
int esp_wlan_softap_initialize(void)
{
return esp_wlan_initialize(IW_MODE_MASTER);
}
#endif /* ESP_WLAN_HAS_SOFTAP */