You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2020/09/24 12:55:41 UTC

[GitHub] [incubator-nuttx] donghengqaz opened a new pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

donghengqaz opened a new pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893


   ## Summary
   
   Add ESP32 WiFi adapter and driver
   
   ## Impact
   
   ESP32 supports WiFi connection and disconnection.
   
   ## Testing
   
   Test with WAPI.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698338794


   > Adding the - to all includes for Make.defs on arch Makefiles isn't something we got away from recently? I understand this may be necessary since the Makefile will be called before the board Make.defs is in place, right?
   
   Exactly, the only issue is that we call `clean_context` before starting the dirlink process, that won't work without the '-'.
   The cleaning could be delayed until `distclean` and we get rid of the '-' but that would break the `context`/`clean_context` symmetry.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] jerpelea commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
jerpelea commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-701233658


   I think that it is better to separate the firmware download from the build process and even store it on our git in a common firmware folder 
   
   What for you think ?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] xiaoxiang781216 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698360124


   @Ouss4 sorry, just found that context/clean_context is already in a separate patch, Makefile related change look good for me, now.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r501658341



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid

Review comment:
       Reference to wrong function name.
   ```suggestion
     /* Loop while while esp_recvframe() successfully retrieves valid
   ```

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. xxx_txavail_process).




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] acassis commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
acassis commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-710956630


   LGTM


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] acassis commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
acassis commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698889964


   > I only added comments to some simple things because I cannot really review the actual contents of this PR since I'm not familiar with WiFi code in NuttX. However, I must say that the adapter file has a **lot** going on, it is a really big file with lots of auxiliary functions. Also, I feel that is quite an obscure implementation, it is very difficult to understand what is this code doing in general, I only get little pieces by looking at the small comments for each function.
   > 
   > It would be good to add some general documentation, either in the form of a README or simple as more detailed comments explaining what all this code is doing and what each part is doing.
   > I fear that besides the obvious fact that there's some closed code behind this, this code itself will be difficult to maintain/debug by someone else as is.
   > 
   > That said, I really appreciate the support for ESP32 WiFi on NuttX.
   
   hi @v01d good points. In fact in the IDF we have a document describing about the WiFi driver blocks, maybe it could come to NuttX as well. It could be added later, but now we just need guarantee that everything is integrated correctly on NuttX.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r502732161



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while esp32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.

Review comment:
       Due to some reason, the TX done function will be added in next MR, because this function should be supported by wifi internal driver.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698336847






----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] masayuki2009 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
masayuki2009 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-710978388


   > LGTM
   
   @acassis 
   Thanks for confirming.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494329082



##########
File path: arch/arm/src/Makefile
##########
@@ -35,7 +35,7 @@
 ############################################################################
 
 include $(TOPDIR)/Make.defs
-include chip/Make.defs
+-include chip/Make.defs

Review comment:
       As I said above `clean_context` is used before linking the directories, at that point chip/ doesn't exist.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > The point is that the build should be reproducible and using master means that every build could be different since master changed in between. If you later need to update the commit, a quick PR is all that is needed to change the hash.
   
   There isn't much going on in that repository, it consists mostly of static libraries and header files.  The risk of a huge change that would break this config is low.
   That said, the script will be updated once a release/tag is created, the repo is relatively new.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494326670



##########
File path: arch/arm/src/Makefile
##########
@@ -35,7 +35,7 @@
 ############################################################################
 
 include $(TOPDIR)/Make.defs
-include chip/Make.defs
+-include chip/Make.defs

Review comment:
       why change? I think chip/Make.defs isn't an optional file.

##########
File path: arch/arm/src/Makefile
##########
@@ -35,7 +35,7 @@
 ############################################################################
 
 include $(TOPDIR)/Make.defs
-include chip/Make.defs
+-include chip/Make.defs

Review comment:
       Ok, understand!




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] masayuki2009 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
masayuki2009 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-701946413


   @donghengqaz 
   Thanks for contributing the ESP32 Wi-Fi driver to the NuttX upstream.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r502261719



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid

Review comment:
       Done.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494718603



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic.
   
   It would be better to split this file then into different files, each with a specific function. It will be easier to review and maintain.
   
   But please try to add some general comment of what the code is doing, how this adapting layer works, etc.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic.
   
   It would be better to split this file then into different files, each with a specific function. It will be easier to review and maintain.
   
   But please try to add some general comment of what the code is doing, how this adapting layer works, etc.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-704926068


   Now that the release branch was created, can we give this another look please?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494337530



##########
File path: arch/arm/src/Makefile
##########
@@ -35,7 +35,7 @@
 ############################################################################
 
 include $(TOPDIR)/Make.defs
-include chip/Make.defs
+-include chip/Make.defs

Review comment:
       Ok, understand!




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698330079






----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494708581



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       better to point to specific commit

##########
File path: arch/xtensa/src/esp32/Kconfig
##########
@@ -531,4 +533,24 @@ config ESP32_ETH_PHY_ADDR
 
 endmenu # ESP32_EMAC
 
+menu "WiFi configuration"
+	depends on ESP32_WIRELESS
+
+config ESP32_WIFI_SAVE_PARAM
+	bool "Save WiFi Parameters"
+	default n
+	help
+		Enable this option, WiFi adapter save WiFi parameters
+		into file system without generating or calculating some
+		connection parameters again.

Review comment:
       ```suggestion
   		If you enable this option, WiFi adapter parameters will be saved
   		into the file system instead of computing them each time.
   ```
   
   Changed a bit the wording. Maybe you could specify which parameters?

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* WiFi interrupt adapter private data */
+
+struct irq_adpt
+{
+  void (*func)(void *arg);  /* Interrupt callback function */
+  void *arg;                /* Interrupt private data */
+};
+
+/* WiFi message queue private data */
+
+struct mq_adpt
+{
+  mqd_t    mq;              /* Message queue handle */
+  uint32_t msgsize;         /* Message size */
+  char     name[16];        /* Message queue name */
+};
+
+/* WiFi time private data */
+
+struct time_adpt
+{
+  time_t      sec;          /* Second value */
+  suseconds_t usec;         /* Micro second value */
+};
+
+/* WiFi timer private data */
+
+struct timer_adpt
+{
+  struct wdog_s wdog;       /* Timer handle */
+  struct work_s work;       /* Work priavte data */
+  bool          repeat;     /* Flags indicate if it is cycle */
+  uint32_t      delay;      /* Timeout ticks */
+
+  /* Timer callback function */
+
+  void          (*func)(void *priv);
+  void          *priv;      /* Timer private data */
+};
+
+/* WiFi event private data */
+
+struct evt_adpt
+{
+  sq_entry_t entry;         /* Sequence entry */
+  int32_t id;               /* Event ID */
+  uint8_t buf[0];           /* Event private data */
+};
+
+/* WiFi event notification private data */
+
+struct wifi_notify
+{
+  bool assigned;            /* Flag indicate if it is used */
+  pid_t pid;                /* Signal's target thread PID */
+  struct sigevent event;    /* Signal event private data */
+  struct sigwork_s work;    /* Signal work private data */
+};
+
+/* WiFi NVS private data */
+
+struct nvs_adpt
+{
+  char *index_name;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_set_isr(int32_t n, void *f, void *arg);
+static void esp32_ints_on(uint32_t mask);
+static void esp32_ints_off(uint32_t mask);
+static void *esp_spin_lock_create(void);
+static void esp_spin_lock_delete(void *lock);
+static uint32_t esp_wifi_int_disable(void *wifi_int_mux);
+static void esp_wifi_int_restore(void *wifi_int_mux, uint32_t tmp);
+static void IRAM_ATTR esp_task_yield_from_isr(void);
+static void *esp_semphr_create(uint32_t max, uint32_t init);
+static void esp_semphr_delete(void *semphr);
+static int32_t esp_semphr_take(void *semphr, uint32_t block_time_tick);
+static int32_t esp_semphr_give(void *semphr);
+static void *esp_thread_semphr_get(void);
+static void *esp_mutex_create(void);
+static void *esp_recursive_mutex_create(void);
+static void esp_mutex_delete(void *mutex_data);
+static int32_t esp_mutex_lock(void *mutex_data);
+static int32_t esp_mutex_unlock(void *mutex_data);
+static void *esp_queue_create(uint32_t queue_len, uint32_t item_size);
+static void esp_queue_delete(void *queue);
+static int32_t esp_queue_send(void *queue, void *item,
+                              uint32_t block_time_tick);
+static int32_t esp_queue_send_from_isr(void *queue, void *item, void *hptw);
+static int32_t esp_queue_send_to_back(void *queue, void *item,
+                                      uint32_t block_time_tick);
+static int32_t esp_queue_send_to_front(void *queue, void *item,
+                                       uint32_t block_time_tick);
+static int32_t esp_queue_recv(void *queue, void *item,
+                              uint32_t block_time_tick);
+static uint32_t esp_queue_msg_waiting(void *queue);
+static void *esp_event_group_create(void);
+static void esp_event_group_delete(void *event);
+static uint32_t esp_event_group_set_bits(void *event, uint32_t bits);
+static uint32_t esp_event_group_clear_bits(void *event, uint32_t bits);
+static uint32_t esp_event_group_wait_bits(void *event,
+                                          uint32_t bits_to_wait_for,
+                                          int32_t clear_on_exit,
+                                          int32_t wait_for_all_bits,
+                                          uint32_t block_time_tick);
+static int32_t esp_task_create_pinned_to_core(void *task_func,
+                                              const char *name,
+                                              uint32_t stack_depth,
+                                              void *param,
+                                              uint32_t prio,
+                                              void *task_handle,
+                                              uint32_t core_id);
+static int32_t esp_task_create(void *task_func, const char *name,
+                               uint32_t stack_depth, void *param,
+                               uint32_t prio, void *task_handle);
+static void esp_task_delete(void *task_handle);
+static void esp_task_delay(uint32_t tick);
+static int32_t esp_task_ms_to_tick(uint32_t ms);
+static void *esp_task_get_current_task(void);
+static int32_t esp_task_get_max_priority(void);
+static void *esp_malloc(uint32_t size);
+static uint32_t esp_rand(void);
+static void esp_dport_access_stall_other_cpu_start(void);
+static void esp_dport_access_stall_other_cpu_end(void);
+static int32_t esp_phy_deinit_rf(uint32_t module);
+static void esp_phy_init(uint32_t module);
+static void esp_phy_enable_clock(void);
+static void esp_phy_disable_clock(void);
+static int32_t esp_wifi_read_mac(uint8_t *mac, uint32_t type);
+static void esp_timer_arm(void *timer, uint32_t tmout, bool repeat);
+static void esp_timer_disarm(void *timer);
+static void esp32_timer_done(void *timer);
+static void esp_timer_setfn(void *timer, void *pfunction, void *parg);
+static void esp_timer_cb(wdparm_t parm);
+static void esp_timer_arm_us(void *timer, uint32_t us, bool repeat);
+static void esp_periph_module_enable(uint32_t periph);
+static void esp_periph_module_disable(uint32_t periph);
+static int32_t esp_nvs_set_i8(uint32_t handle, const char *key,
+                              int8_t value);
+static int32_t esp_nvs_get_i8(uint32_t handle, const char *key,
+                              int8_t *out_value);
+static int32_t esp_nvs_set_u8(uint32_t handle, const char *key,
+                              uint8_t value);
+static int32_t esp_nvs_get_u8(uint32_t handle, const char *key,
+                              uint8_t *out_value);
+static int32_t esp_nvs_set_u16(uint32_t handle, const char *key,
+                               uint16_t value);
+static int32_t esp_nvs_get_u16(uint32_t handle, const char *key,
+                               uint16_t *out_value);
+static int32_t esp_nvs_open(const char *name, uint32_t open_mode,
+                            uint32_t *out_handle);
+static void esp_nvs_close(uint32_t handle);
+static int32_t esp_nvs_commit(uint32_t handle);
+static int32_t esp_nvs_set_blob(uint32_t handle, const char *key,
+                                const void *value, size_t length);
+static int32_t esp_nvs_get_blob(uint32_t handle, const char *key,
+                                void *out_value, size_t *length);
+static int32_t esp_nvs_erase_key(uint32_t handle, const char *key);
+static int32_t esp_get_random(uint8_t *buf, size_t len);
+static int32_t esp_get_time(void *t);
+static void esp_log_writev(uint32_t level, const char *tag,
+                           const char *format, va_list args);
+static void *esp_malloc_internal(size_t size);
+static void *esp_realloc_internal(void *ptr, size_t size);
+static void *esp_calloc_internal(size_t n, size_t size);
+static void *esp_zalloc_internal(size_t size);
+static void *esp_wifi_malloc(size_t size);
+static void *esp_wifi_realloc(void *ptr, size_t size);
+static void *esp_wifi_calloc(size_t n, size_t size);
+static void *esp_wifi_zalloc(size_t size);
+static int32_t esp_modem_enter_sleep(uint32_t module);
+static int32_t esp_modem_exit_sleep(uint32_t module);
+static int32_t esp_modem_register_sleep(uint32_t module);
+static int32_t esp_modem_deregister_sleep(uint32_t module);
+static void *esp_wifi_create_queue(int32_t queue_len, int32_t item_size);
+static void esp_wifi_delete_queue(void *queue);
+static uint32_t esp_coex_status_get(void);
+static void esp_coex_condition_set(uint32_t type, bool dissatisfy);
+static int32_t esp_coex_wifi_request(uint32_t event, uint32_t latency,
+                                     uint32_t duration);
+static int32_t esp_coex_wifi_release(uint32_t event);
+
+/****************************************************************************
+ * Public Functions declaration
+ ****************************************************************************/
+
+int64_t esp_timer_get_time(void);
+void esp_fill_random(void *buf, size_t len);
+void esp_log_write(uint32_t level, const char *tag, const char *format, ...);
+uint32_t esp_log_timestamp(void);
+uint8_t esp_crc8(const uint8_t *p, uint32_t len);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* WiFi interrupt private data */
+
+static int s_wifi_irq;
+
+/* WiFi thread private data */
+
+static pthread_key_t s_wifi_thread_key;
+static bool s_wifi_tkey_init;
+
+/* WiFi sleep private data */
+
+static uint32_t s_esp32_module_mask;
+static uint32_t s_esp32_module_sleep;
+static bool s_esp32_sleep;
+static uint32_t s_phy_clk_en_cnt = 0;
+static bool s_esp23_phy_en;
+static uint32_t s_esp32_phy_init_mask;
+static int64_t s_esp32_phy_rf_stop_tm;
+
+/* WiFi event private data */
+
+static struct work_s s_wifi_evt_work;
+static sq_queue_t s_wifi_evt_queue;
+static struct wifi_notify s_wifi_notify[WIFI_ADPT_EVT_MAX];
+static sem_t s_connect_sem;
+static bool s_connected;
+
+static uint8_t s_ssid[32];
+static uint8_t s_password[64];
+static uint8_t s_ssid_len;
+static uint8_t s_password_len;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* WiFi OS adapter data */
+
+wifi_osi_funcs_t g_wifi_osi_funcs =
+{
+  ._version = ESP_WIFI_OS_ADAPTER_VERSION,
+  ._set_isr = esp_set_isr,
+  ._ints_on = esp32_ints_on,
+  ._ints_off = esp32_ints_off,
+  ._spin_lock_create = esp_spin_lock_create,
+  ._spin_lock_delete = esp_spin_lock_delete,
+  ._wifi_int_disable = esp_wifi_int_disable,
+  ._wifi_int_restore = esp_wifi_int_restore,
+  ._task_yield_from_isr = esp_task_yield_from_isr,
+  ._semphr_create = esp_semphr_create,
+  ._semphr_delete = esp_semphr_delete,
+  ._semphr_take = esp_semphr_take,
+  ._semphr_give = esp_semphr_give,
+  ._wifi_thread_semphr_get = esp_thread_semphr_get,
+  ._mutex_create = esp_mutex_create,
+  ._recursive_mutex_create = esp_recursive_mutex_create,
+  ._mutex_delete = esp_mutex_delete,
+  ._mutex_lock = esp_mutex_lock,
+  ._mutex_unlock = esp_mutex_unlock,
+  ._queue_create = esp_queue_create,
+  ._queue_delete = esp_queue_delete,
+  ._queue_send = esp_queue_send,
+  ._queue_send_from_isr = esp_queue_send_from_isr,
+  ._queue_send_to_back = esp_queue_send_to_back,
+  ._queue_send_to_front = esp_queue_send_to_front,
+  ._queue_recv = esp_queue_recv,
+  ._queue_msg_waiting = esp_queue_msg_waiting,
+  ._event_group_create = esp_event_group_create,
+  ._event_group_delete = esp_event_group_delete,
+  ._event_group_set_bits = esp_event_group_set_bits,
+  ._event_group_clear_bits = esp_event_group_clear_bits,
+  ._event_group_wait_bits = esp_event_group_wait_bits,
+  ._task_create_pinned_to_core = esp_task_create_pinned_to_core,
+  ._task_create = esp_task_create,
+  ._task_delete = esp_task_delete,
+  ._task_delay = esp_task_delay,
+  ._task_ms_to_tick = esp_task_ms_to_tick,
+  ._task_get_current_task = esp_task_get_current_task,
+  ._task_get_max_priority = esp_task_get_max_priority,
+  ._malloc = esp_malloc,
+  ._free = free,
+  ._event_post = esp_event_post,
+  ._get_free_heap_size = esp_get_free_heap_size,
+  ._rand = esp_rand,
+  ._dport_access_stall_other_cpu_start_wrap =
+      esp_dport_access_stall_other_cpu_start,
+  ._dport_access_stall_other_cpu_end_wrap =
+      esp_dport_access_stall_other_cpu_end,
+  ._phy_rf_deinit = esp_phy_deinit_rf,
+  ._phy_load_cal_and_init = esp_phy_init,
+  ._phy_common_clock_enable = esp_phy_enable_clock,
+  ._phy_common_clock_disable = esp_phy_disable_clock,
+  ._read_mac = esp_wifi_read_mac,
+  ._timer_arm = esp_timer_arm,
+  ._timer_disarm = esp_timer_disarm,
+  ._timer_done = esp32_timer_done,
+  ._timer_setfn = esp_timer_setfn,
+  ._timer_arm_us = esp_timer_arm_us,
+  ._periph_module_enable = esp_periph_module_enable,
+  ._periph_module_disable = esp_periph_module_disable,
+  ._esp_timer_get_time = esp_timer_get_time,
+  ._nvs_set_i8 = esp_nvs_set_i8,
+  ._nvs_get_i8 = esp_nvs_get_i8,
+  ._nvs_set_u8 = esp_nvs_set_u8,
+  ._nvs_get_u8 = esp_nvs_get_u8,
+  ._nvs_set_u16 = esp_nvs_set_u16,
+  ._nvs_get_u16 = esp_nvs_get_u16,
+  ._nvs_open = esp_nvs_open,
+  ._nvs_close = esp_nvs_close,
+  ._nvs_commit = esp_nvs_commit,
+  ._nvs_set_blob = esp_nvs_set_blob,
+  ._nvs_get_blob = esp_nvs_get_blob,
+  ._nvs_erase_key = esp_nvs_erase_key,
+  ._get_random = esp_get_random,
+  ._get_time = esp_get_time,
+  ._random = esp_random,
+  ._log_write = esp_log_write,
+  ._log_writev = esp_log_writev,
+  ._log_timestamp = esp_log_timestamp,
+  ._malloc_internal =  esp_malloc_internal,
+  ._realloc_internal = esp_realloc_internal,
+  ._calloc_internal = esp_calloc_internal,
+  ._zalloc_internal = esp_zalloc_internal,
+  ._wifi_malloc = esp_wifi_malloc,
+  ._wifi_realloc = esp_wifi_realloc,
+  ._wifi_calloc = esp_wifi_calloc,
+  ._wifi_zalloc = esp_wifi_zalloc,
+  ._wifi_create_queue = esp_wifi_create_queue,
+  ._wifi_delete_queue = esp_wifi_delete_queue,
+  ._modem_sleep_enter = esp_modem_enter_sleep,
+  ._modem_sleep_exit = esp_modem_exit_sleep,
+  ._modem_sleep_register = esp_modem_register_sleep,
+  ._modem_sleep_deregister = esp_modem_deregister_sleep,
+  ._coex_status_get = esp_coex_status_get,
+  ._coex_condition_set = esp_coex_condition_set,
+  ._coex_wifi_request = esp_coex_wifi_request,
+  ._coex_wifi_release = esp_coex_wifi_release,
+  ._magic = ESP_WIFI_OS_ADAPTER_MAGIC,
+};
+
+/* WiFi feature capacity data */
+
+uint64_t g_wifi_feature_caps;
+
+/* WiFi TAG string data */
+
+ESP_EVENT_DEFINE_BASE(WIFI_EVENT);
+
+/****************************************************************************
+ * Private Functions and Public Functions only used by libraries
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_errno_trans
+ *
+ * Description:
+ *   Transform from nuttx error code to WiFi adapter error code
+ *
+ * Input Parameters:
+ *   ret - Nuttx error code
+ *
+ * Returned Value:
+ *   WiFi adapter error code
+ *
+ ****************************************************************************/
+
+static inline int32_t esp_errno_trans(int ret)
+{
+  if (!ret)
+    {
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+/****************************************************************************
+ * Name: esp_int_adpt_cb
+ *
+ * Description:
+ *   WiFi interrupt adapter callback function
+ *
+ * Input Parameters:
+ *   arg - interrupt adapter private data
+ *
+ * Returned Value:
+ *   0 on success
+ *
+ ****************************************************************************/
+
+static int esp_int_adpt_cb(int irq, void *context, FAR void *arg)
+{
+  struct irq_adpt *adapter = (struct irq_adpt *)arg;
+
+  adapter->func(adapter->arg);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_thread_semphr_free
+ *
+ * Description:
+ *   Delete thread self's semaphore
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_thread_semphr_free(void *semphr)
+{
+  if (semphr)
+    {
+      esp_semphr_delete(semphr);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_update_time
+ *
+ * Description:
+ *   Transform ticks to time and add this time to timespec value
+ *
+ * Input Parameters:
+ *   timespec - Input timespec data pointer
+ *   ticks    - System ticks
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_update_time(struct timespec *timespec, uint32_t ticks)
+{
+  uint32_t tmp;
+
+  tmp = TICK2SEC(ticks);
+  timespec->tv_sec += tmp;
+
+  ticks -= SEC2TICK(tmp);
+  tmp = TICK2NSEC(ticks);
+
+  timespec->tv_nsec += tmp;
+}
+
+/****************************************************************************
+ * Name: esp_set_isr
+ *
+ * Description:
+ *   Register interrupt function
+ *
+ * Input Parameters:
+ *   n   - Interrupt ID
+ *   f   - Interrupt function
+ *   arg - Function private data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_set_isr(int32_t n, void *f, void *arg)
+{
+  int ret;
+  struct irq_adpt *adapter;
+  int irq;
+  int cpu = 0;
+  int tmp;
+
+  irq = esp32_alloc_levelint(1);
+  if (irq < 0)
+    {
+      wlerr("ERROR: Failed to alloc interrupt\n");
+      assert(0);
+      return ;
+    }
+
+  up_disable_irq(irq);
+
+  tmp = sizeof(struct irq_adpt);
+  adapter = kmm_malloc(tmp);
+  if (!adapter)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      assert(0);
+      return ;
+    }
+
+  adapter->func = f;
+  adapter->arg = arg;
+
+  tmp = n + XTENSA_IRQ_FIRSTPERIPH;
+  ret = irq_attach(tmp, esp_int_adpt_cb, adapter);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to attach IRQ %d\n", tmp);
+      assert(0);
+      return ;
+    }
+
+  esp32_attach_peripheral(cpu, n, irq);
+
+  s_wifi_irq = irq;
+}
+
+/****************************************************************************
+ * Name: esp32_ints_on
+ *
+ * Description:
+ *   Enable WiFi interrupt
+ *
+ * Input Parameters:
+ *   mask - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32_ints_on(uint32_t mask)
+{
+  up_enable_irq(s_wifi_irq);
+}
+
+/****************************************************************************
+ * Name: esp32_ints_on
+ *
+ * Description:
+ *   Disable WiFi interrupt
+ *
+ * Input Parameters:
+ *   mask - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32_ints_off(uint32_t mask)
+{
+  up_disable_irq(s_wifi_irq);
+}
+
+/****************************************************************************
+ * Name: esp_spin_lock_create
+ *
+ * Description:
+ *   Create spin lock in SMP mode
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Spin lock data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_spin_lock_create(void)
+{
+#ifdef CONFIG_SMP
+  spinlock_t *lock;
+  int tmp;
+
+  tmp = sizeof(struct spinlock_t);
+  lock = kmm_malloc(tmp);
+  if (!lock)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      DEBUGASSERT(0);
+    }
+
+  spin_initialize(lock, SP_UNLOCKED);
+
+  return lock;
+#else
+  /* If return NULL, code may check fail  */
+
+  return (void *)1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_spin_lock_delete
+ *
+ * Description:
+ *   Delete spin lock
+ *
+ * Input Parameters:
+ *   lock - Spin lock data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_spin_lock_delete(void *lock)
+{
+#ifdef CONFIG_SMP
+  kmm_free(lock);
+#else
+  DEBUGASSERT((int)lock == 1);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_wifi_int_disable
+ *
+ * Description:
+ *   Enter critical by disable interrup, and take spin lock if
+ *   in SMP mode
+ *
+ * Input Parameters:
+ *   wifi_int_mux - Spin lock data pointer
+ *
+ * Returned Value:
+ *   CPU PS value.
+ *
+ ****************************************************************************/
+
+static uint32_t IRAM_ATTR esp_wifi_int_disable(void *wifi_int_mux)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+#ifdef CONFIG_SMP
+  spin_lock((volatile spinlock_t *)wifi_int_mux);
+#endif
+
+  return (uint32_t)flags;
+}
+
+/****************************************************************************
+ * Name: esp_wifi_int_restore
+ *
+ * Description:
+ *   Exit from critical by enable interrup, and release spin
+ *   lock if in SMP mode
+ *
+ * Input Parameters:
+ *   wifi_int_mux - Spin lock data pointer
+ *   tmp          - CPU PS value.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp_wifi_int_restore(void *wifi_int_mux, uint32_t tmp)
+{
+  irqstate_t flags = (irqstate_t)tmp;
+
+#ifdef CONFIG_SMP
+  spin_unlock((volatile spinlock_t *)wifi_int_mux);
+#endif
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp_task_yield_from_isr
+ *
+ * Description:
+ *   Do nothing in Nuttx
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp_task_yield_from_isr(void)
+{
+  /* Do nothing */
+}
+
+/****************************************************************************
+ * Name: esp_semphr_create
+ *
+ * Description:
+ *   Create and initialize semaphore
+ *
+ * Input Parameters:
+ *   max  - No mean
+ *   init - semaphore initialization value
+ *
+ * Returned Value:
+ *   Semphore data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_semphr_create(uint32_t max, uint32_t init)
+{
+  int ret;
+  sem_t *sem;
+  int tmp;
+
+  tmp = sizeof(sem_t);
+  sem = kmm_malloc(tmp);
+  if (!sem)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return NULL;
+    }
+
+  ret = sem_init(sem, 0, init);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize sem error=%d\n", ret);
+      kmm_free(sem);
+      return NULL;
+    }
+
+  return sem;
+}
+
+/****************************************************************************
+ * Name: esp_semphr_delete
+ *
+ * Description:
+ *   Delete semaphore
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_semphr_delete(void *semphr)
+{
+  sem_t *sem = (sem_t *)semphr;
+
+  sem_destroy(sem);
+  kmm_free(sem);
+}
+
+/****************************************************************************
+ * Name: esp_semphr_take
+ *
+ * Description:
+ *   Wait semaphore within a certain period of time
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *   ticks  - Wait system ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_semphr_take(void *semphr, uint32_t ticks)
+{
+  int ret;
+  struct timespec timeout;
+  sem_t *sem = (sem_t *)semphr;
+
+  if (ticks == OSI_FUNCS_TIME_BLOCKING)
+    {
+      ret = sem_wait(sem);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to wait sem\n");
+        }
+    }
+  else
+    {
+      ret = clock_gettime(CLOCK_REALTIME, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to get time\n");
+          return false;
+        }
+
+      if (ticks)
+        {
+          esp_update_time(&timeout, ticks);
+        }
+
+      ret = sem_timedwait(sem, &timeout);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to wait sem in %d ticks\n", ticks);
+        }
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_semphr_give
+ *
+ * Description:
+ *   Post semaphore
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_semphr_give(void *semphr)
+{
+  int ret;
+  sem_t *sem = (sem_t *)semphr;
+
+  ret = sem_post(sem);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to post sem error=%d\n", ret);
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_thread_semphr_get
+ *
+ * Description:
+ *   Get thread self's semaphore
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Semphore data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_thread_semphr_get(void)
+{
+  int ret;
+  void *sem;
+
+  if (s_wifi_tkey_init)
+  {
+    ret = pthread_key_create(&s_wifi_thread_key, esp_thread_semphr_free);
+    if (ret)
+      {
+        wlerr("ERROR: Failed to create pthread key\n");
+        return NULL;
+      }
+
+    s_wifi_tkey_init = true;
+  }
+
+  sem = pthread_getspecific(s_wifi_thread_key);
+  if (!sem)
+    {
+      sem = esp_semphr_create(1, 0);
+      if (!sem)
+        {
+          wlerr("ERROR: Failed to create semaphore\n");
+          return NULL;
+        }
+
+      ret = pthread_setspecific(s_wifi_thread_key, sem);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to set specific\n");
+          esp_semphr_delete(sem);
+          return NULL;
+        }
+    }
+
+  return sem;
+}
+
+/****************************************************************************
+ * Name: esp_mutex_create
+ *
+ * Description:
+ *   Create mutex
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Mutex data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_mutex_create(void)
+{
+  int ret;
+  pthread_mutex_t *mutex;
+  int tmp;
+
+  tmp = sizeof(pthread_mutex_t);
+  mutex = kmm_malloc(tmp);
+  if (!mutex)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return NULL;
+    }
+
+  ret = pthread_mutex_init(mutex, NULL);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize mutex error=%d\n", ret);
+      kmm_free(mutex);
+      return NULL;
+    }
+
+  return mutex;
+}
+
+/****************************************************************************
+ * Name: esp_recursive_mutex_create
+ *
+ * Description:
+ *   Create recursive mutex
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Recursive mutex data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_recursive_mutex_create(void)
+{
+  int ret;
+  pthread_mutex_t *mutex;
+  pthread_mutexattr_t attr;
+  int tmp;
+
+  ret = pthread_mutexattr_init(&attr);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize attr error=%d\n", ret);
+      return NULL;
+    }
+
+  ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to set attr type error=%d\n", ret);
+      return NULL;
+    }
+
+  tmp = sizeof(pthread_mutex_t);
+  mutex = kmm_malloc(tmp);
+  if (!mutex)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return NULL;
+    }
+
+  ret = pthread_mutex_init(mutex, &attr);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize mutex error=%d\n", ret);
+      kmm_free(mutex);
+      return NULL;
+    }
+
+  return mutex;
+}
+
+/****************************************************************************
+ * Name: esp_mutex_delete
+ *
+ * Description:
+ *   Delete mutex
+ *
+ * Input Parameters:
+ *   mutex_data - mutex data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_mutex_delete(void *mutex_data)
+{
+  pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data;
+
+  pthread_mutex_destroy(mutex);
+  kmm_free(mutex);
+}
+
+/****************************************************************************
+ * Name: esp_mutex_lock
+ *
+ * Description:
+ *   Lock mutex
+ *
+ * Input Parameters:
+ *   mutex_data - mutex data pointer
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_mutex_lock(void *mutex_data)
+{
+  int ret;
+  pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data;
+
+  ret = pthread_mutex_lock(mutex);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to lock mutex error=%d\n", ret);
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_mutex_unlock
+ *
+ * Description:
+ *   Unlock mutex
+ *
+ * Input Parameters:
+ *   mutex_data - mutex data pointer
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_mutex_unlock(void *mutex_data)
+{
+  int ret;
+  pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data;
+
+  ret = pthread_mutex_unlock(mutex);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to unlock mutex error=%d\n", ret);
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_queue_create
+ *
+ * Description:
+ *   Create message queue
+ *
+ * Input Parameters:
+ *   queue_len - queue message number
+ *   item_size - message size
+ *
+ * Returned Value:
+ *   Message queue data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_queue_create(uint32_t queue_len, uint32_t item_size)
+{
+  struct mq_attr attr;
+  mqd_t mq;
+  struct mq_adpt *mq_adpt;
+
+  mq_adpt = kmm_malloc(sizeof(struct mq_adpt));
+  if (!mq_adpt)
+    {
+      wlerr("ERROR: Failed to malloc\n");
+      return NULL;
+    }
+
+  snprintf(mq_adpt->name, sizeof(mq_adpt->name),
+           "/tmp/%X", mq_adpt);
+
+  attr.mq_maxmsg  = queue_len;
+  attr.mq_msgsize = item_size;
+  attr.mq_curmsgs = 0;
+  attr.mq_flags   = 0;
+
+  mq = mq_open(mq_adpt->name, O_RDWR | O_CREAT, 0644, &attr);
+  if (!mq)
+    {
+      wlerr("ERROR: Failed to create mqueue\n");
+      kmm_free(mq_adpt);
+      return NULL;
+    }
+
+  mq_adpt->mq = mq;
+  mq_adpt->msgsize = item_size;
+
+  return (void *)mq_adpt;
+}
+
+/****************************************************************************
+ * Name: esp_queue_delete
+ *
+ * Description:
+ *   Delete message queue
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_queue_delete(void *queue)
+{
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  mq_close(mq_adpt->mq);
+  mq_unlink(mq_adpt->name);
+  kmm_free(mq_adpt);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_generic
+ *
+ * Description:
+ *   Generic send message to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *   prio  - Message priority
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_generic(void *queue, void *item,
+                                      uint32_t ticks, int prio)
+{
+  int ret;
+  struct timespec timeout;
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  if (ticks == OSI_FUNCS_TIME_BLOCKING || ticks == 0)
+    {
+      /**
+       * WiFi interrupt function will call this adapter function to send
+       * message to message queue, so here we should call kernel API
+       * instead of application API
+       */
+
+      ret = nxmq_send(mq_adpt->mq, (const char *)item,
+                    mq_adpt->msgsize, prio);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to send message to mqueue error=%d\n",
+               ret);
+        }
+    }
+  else
+    {
+      ret = clock_gettime(CLOCK_REALTIME, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to get time\n");
+          return false;
+        }
+
+      if (ticks)
+        {
+          esp_update_time(&timeout, ticks);
+        }
+
+      ret = mq_timedsend(mq_adpt->mq, (const char *)item,
+                         mq_adpt->msgsize, prio, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to timedsend message to mqueue error=%d\n",
+               ret);
+        }
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send
+ *
+ * Description:
+ *   Send message of low priority to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send(void *queue, void *item, uint32_t ticks)
+{
+  return esp_queue_send_generic(queue, item, ticks, 0);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_from_isr
+ *
+ * Description:
+ *   Send message of low priority to queue in ISR within
+ *   a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   hptw  - No mean
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_from_isr(void *queue, void *item, void *hptw)
+{
+  /* Force to set the value to be false */
+
+  *((int *)hptw) = false;
+
+  return esp_queue_send_generic(queue, item, 0, 0);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_to_back
+ *
+ * Description:
+ *   Send message of low priority to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_to_back(void *queue, void *item,
+                                      uint32_t ticks)
+{
+  return esp_queue_send_generic(queue, item, ticks, 0);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_from_isr
+ *
+ * Description:
+ *   Send message of high priority to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_to_front(void *queue, void *item,
+                                       uint32_t ticks)
+{
+  return esp_queue_send_generic(queue, item, ticks, 1);
+}
+
+/****************************************************************************
+ * Name: esp_queue_recv
+ *
+ * Description:
+ *   Receive message from queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_recv(void *queue, void *item, uint32_t ticks)
+{
+  ssize_t ret;
+  struct timespec timeout;
+  unsigned int prio;
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  if (ticks == OSI_FUNCS_TIME_BLOCKING)
+    {
+      ret = mq_receive(mq_adpt->mq, (char *)item,
+                       mq_adpt->msgsize, &prio);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to receive from mqueue error=%d\n", ret);
+        }
+    }
+  else
+    {
+      ret = clock_gettime(CLOCK_REALTIME, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to get time\n");
+          return false;
+        }
+
+      if (ticks)
+        {
+          esp_update_time(&timeout, ticks);
+        }
+
+      ret = mq_timedreceive(mq_adpt->mq, (char *)item,
+                            mq_adpt->msgsize, &prio, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to timedreceive from mqueue error=%d\n",
+               ret);
+        }
+    }
+
+  return ret > 0 ? true : false;
+}
+
+/****************************************************************************
+ * Name: esp_queue_msg_waiting
+ *
+ * Description:
+ *   Get message number in the message queue
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *
+ * Returned Value:
+ *   Message number
+ *
+ ****************************************************************************/
+
+static uint32_t esp_queue_msg_waiting(void *queue)
+{
+  int ret;
+  struct mq_attr attr;
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  ret = mq_getattr(mq_adpt->mq, &attr);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to get attr from mqueue error=%d\n", ret);
+      return 0;
+    }
+
+  return attr.mq_curmsgs;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_create
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void *esp_event_group_create(void)
+{
+  DEBUGASSERT(0);
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_delete
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_event_group_delete(void *event)
+{
+  DEBUGASSERT(0);
+}
+
+/****************************************************************************
+ * Name: esp_event_group_set_bits
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_event_group_set_bits(void *event, uint32_t bits)
+{
+  DEBUGASSERT(0);
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_clear_bits
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_event_group_clear_bits(void *event, uint32_t bits)
+{
+  DEBUGASSERT(0);
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_wait_bits
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_event_group_wait_bits(void *event,
+                                          uint32_t bits_to_wait_for,
+                                          int32_t clear_on_exit,
+                                          int32_t wait_for_all_bits,
+                                          uint32_t block_time_tick)
+{
+  DEBUGASSERT(0);
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: esp_task_create_pinned_to_core
+ *
+ * Description:
+ *   Create task and bind it to target CPU, the task will run when it
+ *   is created
+ *
+ * Input Parameters:
+ *   entry       - Task entry
+ *   name        - Task name
+ *   stack_depth - Task stack size
+ *   param       - Task private data
+ *   prio        - Task priority
+ *   task_handle - Task handle pointer which is used to pause, resume
+ *                 and delete the task
+ *   core_id     - CPU which the task runs in
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_create_pinned_to_core(void *entry,
+                                              const char *name,
+                                              uint32_t stack_depth,
+                                              void *param,
+                                              uint32_t prio,
+                                              void *task_handle,
+                                              uint32_t core_id)
+{
+  int pid;
+#ifdef CONFIG_SMP
+  int ret;
+  cpu_set_t cpuset;
+#endif
+
+  pid = kthread_create(name, prio, stack_depth, entry,
+                      (char * const *)param);
+  if (pid > 0)
+    {
+      *((int *)task_handle) = pid;
+
+#ifdef CONFIG_SMP
+      if (core_id < CONFIG_SMP_NCPUS)
+        {
+          CPU_ZERO(&cpuset);
+          CPU_SET(core_id, &cpuset);
+          ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset);
+          if (ret)
+            {
+              wlerr("ERROR: Failed to set affinity error=%d\n", ret);
+              return false;
+            }
+        }
+#endif
+    }
+  else
+    {
+      wlerr("ERROR: Failed to create task\n");
+    }
+
+  return pid > 0 ? true : false;
+}
+
+/****************************************************************************
+ * Name: esp_task_create
+ *
+ * Description:
+ *   Create task and the task will run when it is created
+ *
+ * Input Parameters:
+ *   entry       - Task entry
+ *   name        - Task name
+ *   stack_depth - Task stack size
+ *   param       - Task private data
+ *   prio        - Task priority
+ *   task_handle - Task handle pointer which is used to pause, resume
+ *                 and delete the task
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_create(void *entry, const char *name,
+                               uint32_t stack_depth, void *param,
+                               uint32_t prio, void *task_handle)
+{
+  return esp_task_create_pinned_to_core(entry, name, stack_depth, param,
+                                        prio, task_handle, UINT32_MAX);
+}
+
+/****************************************************************************
+ * Name: esp_task_delete
+ *
+ * Description:
+ *   Delete the target task
+ *
+ * Input Parameters:
+ *   task_handle - Task handle pointer which is used to pause, resume
+ *                 and delete the task
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_task_delete(void *task_handle)
+{
+  pid_t pid = (pid_t)((uintptr_t)task_handle);
+
+  kthread_delete(pid);
+}
+
+/****************************************************************************
+ * Name: esp_task_delay
+ *
+ * Description:
+ *   Current task wait for some ticks
+ *
+ * Input Parameters:
+ *   tick - Waiting ticks
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_task_delay(uint32_t tick)
+{
+  useconds_t us = TICK2USEC(tick);
+
+  usleep(us);
+}
+
+/****************************************************************************
+ * Name: esp_task_ms_to_tick
+ *
+ * Description:
+ *   Transform from millim seconds to system ticks
+ *
+ * Input Parameters:
+ *   ms - Millim seconds
+ *
+ * Returned Value:
+ *   System ticks
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_ms_to_tick(uint32_t ms)
+{
+  return MSEC2TICK(ms);
+}
+
+/****************************************************************************
+ * Name: esp_task_get_current_task
+ *
+ * Description:
+ *   Transform from millim seconds to system ticks
+ *
+ * Input Parameters:
+ *   ms - Millim seconds
+ *
+ * Returned Value:
+ *   System ticks
+ *
+ ****************************************************************************/
+
+static void *esp_task_get_current_task(void)
+{
+  pid_t pid = getpid();
+
+  return (void *)((uintptr_t)pid);
+}
+
+/****************************************************************************
+ * Name: esp_task_get_current_task
+ *
+ * Description:
+ *   Get OS task maxium priority
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Task maxium priority
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_get_max_priority(void)
+{
+  return SCHED_PRIORITY_MAX;
+}
+
+/****************************************************************************
+ * Name: esp_malloc_internal
+ *
+ * Description:
+ *   Allocate a block of memory
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   Memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_malloc(uint32_t size)
+{
+  return malloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_event_id_map
+ *
+ * Description:
+ *   Transform from esp-idf event ID to WiFi adapter event ID
+ *
+ * Input Parameters:
+ *   event_id - esp-idf event ID
+ *
+ * Returned Value:
+ *   WiFi adapter event ID
+ *
+ ****************************************************************************/
+
+static int esp_event_id_map(int event_id)
+{
+  int id;
+
+  switch (event_id)
+    {
+      case WIFI_EVENT_STA_START:
+        id = WIFI_ADPT_EVT_STA_START;
+        break;
+      case WIFI_EVENT_STA_CONNECTED:
+        id = WIFI_ADPT_EVT_STA_CONNECT;
+        break;
+      case WIFI_EVENT_STA_DISCONNECTED:
+        id = WIFI_ADPT_EVT_STA_DISCONNECT;
+        break;
+      case WIFI_EVENT_STA_AUTHMODE_CHANGE:
+        id = WIFI_ADPT_EVT_STA_AUTHMODE_CHANGE;
+        break;
+      case WIFI_EVENT_STA_STOP:
+        id = WIFI_ADPT_EVT_STA_STOP;
+        break;
+      default:
+        return -1;
+    }
+
+  return id;
+}
+
+/****************************************************************************
+ * Name: esp_evt_work_cb
+ *
+ * Description:
+ *   Process the cached event
+ *
+ * Input Parameters:
+ *   arg - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_evt_work_cb(FAR void *arg)
+{
+  int ret;
+  irqstate_t flags;
+  struct evt_adpt *evt_adpt;
+  struct wifi_notify *notify;
+
+  while (1)
+    {
+      flags = enter_critical_section();
+      evt_adpt = (struct evt_adpt *)sq_remfirst(&s_wifi_evt_queue);
+      leave_critical_section(flags);
+      if (!evt_adpt)
+        {
+          break;
+        }
+
+      switch (evt_adpt->id)
+        {
+          case WIFI_ADPT_EVT_STA_START:
+            ret = esp_wifi_connect();
+            if (ret)
+              {
+                wlerr("ERROR: Failed to connect\n");
+              }
+            break;
+          case WIFI_ADPT_EVT_STA_CONNECT:
+            s_connected = true;
+            ret = sem_post(&s_connect_sem);
+            if (ret)
+              {
+                wlerr("ERROR: Failed to post sem error=%d\n", errno);
+              }
+            break;
+          case WIFI_ADPT_EVT_STA_DISCONNECT:
+            s_connected = false;
+            ret = esp_wifi_connect();
+            if (ret)
+              {
+                wlerr("ERROR: Failed to connect\n");
+              }
+            break;
+          default:
+            break;
+        }
+
+      notify = &s_wifi_notify[evt_adpt->id];
+      if (notify->assigned)
+        {
+          notify->event.sigev_value.sival_ptr = evt_adpt->buf;
+
+          ret = nxsig_notification(notify->pid, &notify->event,
+                                   SI_QUEUE, &notify->work);
+          if (ret < 0)
+            {
+              wlwarn("ERROR: nxsig_notification event ID=%d failed: %d\n",
+                     evt_adpt->id, ret);
+            }
+        }
+
+      free(evt_adpt);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_event_post
+ *
+ * Description:
+ *   Active work queue and let the work to process the cached event
+ *
+ * Input Parameters:
+ *   event_base      - Event set name
+ *   event_id        - Event ID
+ *   event_data      - Event private data
+ *   event_data_size - Event data size
+ *   ticks           - Waiting system ticks
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+int32_t esp_event_post(esp_event_base_t event_base,
+                       int32_t event_id,
+                       void *event_data,
+                       size_t event_data_size,
+                       uint32_t ticks)
+{
+  size_t size;
+  int32_t id;
+  irqstate_t flags;
+  struct evt_adpt *evt_adpt;
+
+  wlinfo("Event: base=%s id=%d data=%p data_size=%d ticks=%u\n", event_base,
+         event_id, event_data, event_data_size, ticks);
+
+  id = esp_event_id_map(event_id);
+  if (id < 0)
+    {
+      wlerr("ERROR: No process event %d\n", event_id);
+      return -1;
+    }
+
+  size = event_data_size + sizeof(struct evt_adpt);
+  evt_adpt = malloc(size);
+  if (!evt_adpt)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", size);
+      return -1;
+    }
+
+  evt_adpt->id = id;
+  memcpy(evt_adpt->buf, event_data, event_data_size);
+
+  flags = enter_critical_section();
+  sq_addlast(&evt_adpt->entry, &s_wifi_evt_queue);
+  leave_critical_section(flags);
+
+  work_queue(LPWORK, &s_wifi_evt_work, esp_evt_work_cb, NULL, 0);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_task_get_current_task
+ *
+ * Description:
+ *   Get free heap size by byte
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Free heap size
+ *
+ ****************************************************************************/
+
+uint32_t esp_get_free_heap_size(void)
+{
+  int ret;
+  struct mallinfo info;
+
+  ret = mm_mallinfo(&g_mmheap, &info);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to create task\n");
+      return 0;
+    }
+
+  return info.fordblks;
+}
+
+/****************************************************************************
+ * Name: esp_random
+ *
+ * Description:
+ *   Get a random data of type unsigned long
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Random data
+ *
+ ****************************************************************************/
+
+unsigned long esp_random(void)
+{
+  return (unsigned long)random();
+}
+
+/****************************************************************************
+ * Name: esp_dport_access_stall_other_cpu_start
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_dport_access_stall_other_cpu_start(void)
+{
+#ifdef CONFIG_SMP
+  DEBUGASSERT(0);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_dport_access_stall_other_cpu_end
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_dport_access_stall_other_cpu_end(void)
+{
+#ifdef CONFIG_SMP
+  DEBUGASSERT(0);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_phy_rf_init
+ *
+ * Description:
+ *   Initialize PHY hardware with given parameters
+ *
+ * Input Parameters:
+ *   init_data        - PHY hardware initialization parameters
+ *   mode             - PHY RF calculation mode
+ *   calibration_data - PHY RF calculation parameters
+ *   module           - PHY mode which is to be initialized
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+int32_t esp_phy_rf_init(const esp_phy_init_data_t *init_data,
+                        esp_phy_calibration_mode_t mode,
+                        esp_phy_calibration_data_t *calibration_data,
+                        phy_rf_module_t module)
+{
+  irqstate_t flags;
+  int64_t time;
+  bool enable = false;
+
+  if (module >= PHY_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_phy_init_mask |= 1 << module;
+
+  if (s_esp23_phy_en)
+    {
+      leave_critical_section(flags);
+      return 0;
+    }
+
+  if (module == PHY_MODEM_MODULE)
+    {
+      if (s_esp32_phy_init_mask & PHY_RF_MASK)
+        {
+          enable = true;
+        }
+    }
+  else if (module == PHY_WIFI_MODULE || module == PHY_BT_MODULE)
+    {
+      enable = true;
+    }
+
+  if (enable)
+    {
+      if (s_esp32_phy_rf_stop_tm)
+        {
+          time = esp_timer_get_time() - s_esp32_phy_rf_stop_tm;
+          esp_wifi_internal_update_mac_time((uint32_t)time);
+          s_esp32_phy_rf_stop_tm = 0;
+        }
+
+      esp_phy_enable_clock();
+
+      phy_set_wifi_mode_only(0);
+
+      register_chipv7_phy(init_data, calibration_data, mode);
+
+      s_esp23_phy_en = true;
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_phy_deinit_rf
+ *
+ * Description:
+ *   Deinitialize PHY hardware
+ *
+ * Input Parameters:
+ *   module - PHY mode which is to be deinitialized
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_phy_deinit_rf(uint32_t module)
+{
+  irqstate_t flags;
+  bool disable = false;
+
+  if (module >= PHY_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_phy_init_mask |= ~(1 << module);
+
+  if (!s_esp23_phy_en)
+    {
+      leave_critical_section(flags);
+      return 0;
+    }
+
+  if (module == PHY_MODEM_MODULE)
+    {
+      disable = true;
+    }
+  else if (module == PHY_WIFI_MODULE || module == PHY_BT_MODULE)
+    {
+      if (!(s_esp32_phy_init_mask & PHY_RF_MASK))
+        {
+          disable = true;
+        }
+    }
+
+  if (disable)
+    {
+      phy_close_rf();
+
+      s_esp32_phy_rf_stop_tm = esp_timer_get_time();
+
+      esp_phy_disable_clock();
+
+      s_esp23_phy_en = false;
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_phy_init
+ *
+ * Description:
+ *   Initialize PHY hardware
+ *
+ * Input Parameters:
+ *   module - PHY mode which is to be initialized
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_phy_init(uint32_t module)
+{
+  int ret;
+  esp_phy_calibration_data_t *cal_data;
+
+  cal_data = kmm_zalloc(sizeof(esp_phy_calibration_data_t));
+  if (!cal_data)
+    {
+      wlerr("ERROR: Failed to malloc");
+      DEBUGASSERT(0);
+    }
+
+  ret = esp_phy_rf_init(&phy_init_data, PHY_RF_CAL_FULL, cal_data, module);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize RF");
+      DEBUGASSERT(0);
+    }
+
+  kmm_free(cal_data);
+}
+
+/****************************************************************************
+ * Name: esp_phy_enable_clock
+ *
+ * Description:
+ *   Enable PHY hardware clock
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_phy_enable_clock(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (s_phy_clk_en_cnt == 0)
+    {
+      modifyreg32(DPORT_WIFI_CLK_EN_REG, 0,
+                  DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
+    }
+
+  s_phy_clk_en_cnt++;
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp_phy_disable_clock
+ *
+ * Description:
+ *   Disable PHY hardware clock
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_phy_disable_clock(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (s_phy_clk_en_cnt)
+    {
+      s_phy_clk_en_cnt--;
+      if (!s_phy_clk_en_cnt)
+        {
+          modifyreg32(DPORT_WIFI_CLK_EN_REG,
+                      DPORT_WIFI_CLK_WIFI_BT_COMMON_M,
+                      0);
+        }
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp_read_mac
+ *
+ * Description:
+ *   Read MAC address from efuse
+ *
+ * Input Parameters:
+ *   mac  - MAC address buffer pointer
+ *   type - MAC address type
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+int32_t esp_read_mac(uint8_t *mac, esp_mac_type_t type)
+{
+  uint32_t regval[2];
+  uint8_t tmp;
+  uint8_t *data = (uint8_t *)regval;
+  uint8_t crc;
+  int i;
+
+  if (type > ESP_MAC_WIFI_SOFTAP)
+    {
+      wlerr("ERROR: Input type is error=%d\n", type);
+      return -1;
+    }
+
+  regval[0] = getreg32(MAC_ADDR0_REG);
+  regval[1] = getreg32(MAC_ADDR1_REG);
+
+  crc = data[6];
+  for (i = 0; i < 6; i++)
+    {
+      mac[i] = data[5 - i];
+    }
+
+  if (crc != esp_crc8(mac, 6))
+    {
+      wlerr("ERROR: Failed to check MAC address CRC\n");
+      return -1;
+    }
+
+  if (type == ESP_MAC_WIFI_SOFTAP)
+    {
+      tmp = mac[0];
+      for (i = 0; i < 64; i++)
+        {
+          mac[0] = tmp | 0x02;
+          mac[0] ^= i << 2;
+
+          if (mac[0] != tmp)
+            {
+              break;
+            }
+        }
+
+      if (i >= 64)
+        {
+          wlerr("ERROR: Failed to generate softAP MAC\n");
+          return -1;
+        }
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_wifi_read_mac
+ *
+ * Description:
+ *   Read MAC address from efuse
+ *
+ * Input Parameters:
+ *   mac  - MAC address buffer pointer
+ *   type - MAC address type
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_wifi_read_mac(uint8_t *mac, uint32_t type)
+{
+  return esp_read_mac(mac, type);
+}
+
+/****************************************************************************
+ * Name: esp_timer_arm
+ *
+ * Description:
+ *   Set timer timeout period and repeat flag
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *   ms     - millim seconds
+ *   repeat - true: run cycle, false: run once
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_arm(void *ptimer, uint32_t ms, bool repeat)
+{
+  esp_timer_arm_us(ptimer, ms * 1000, repeat);
+}
+
+/****************************************************************************
+ * Name: esp_timer_disarm
+ *
+ * Description:
+ *   Disable timer
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_disarm(void *ptimer)
+{
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      timer_adpt = (struct timer_adpt *)ets_timer->priv;
+
+      wd_cancel(&timer_adpt->wdog);
+      work_cancel(LPWORK, &timer_adpt->work);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32_timer_done
+ *
+ * Description:
+ *   Disable and free timer
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32_timer_done(void *ptimer)
+{
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      timer_adpt = (struct timer_adpt *)ets_timer->priv;
+
+      wd_cancel(&timer_adpt->wdog);
+      work_cancel(LPWORK, &timer_adpt->work);
+
+      kmm_free(timer_adpt);
+
+      ets_timer->priv = NULL;
+    }
+}
+
+/****************************************************************************
+ * Name: esp_timer_setfn
+ *
+ * Description:
+ *   Set timer callback function and private data
+ *
+ * Input Parameters:
+ *   ptimer    - Timer data pointer
+ *   pfunction - Callback function
+ *   parg      - Callback function private data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_setfn(void *ptimer, void *pfunction, void *parg)
+{
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      return ;
+    }
+
+  timer_adpt = kmm_zalloc(sizeof(struct timer_adpt));
+  if (!timer_adpt)
+    {
+      wlerr("ERROR: Failed to malloc\n");
+      return ;
+    }
+
+  timer_adpt->func = pfunction;
+  timer_adpt->priv = parg;
+
+  ets_timer->priv = timer_adpt;
+}
+
+/****************************************************************************
+ * Name: esp_timer_work_cb
+ *
+ * Description:
+ *   Process timer callback function in workqueue and active
+ *   it if it has repeat flag
+ *
+ * Input Parameters:
+ *   arg - Timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_work_cb(FAR void *arg)
+{
+  struct ets_timer *ets_timer = (struct ets_timer *)arg;
+  struct timer_adpt *timer_adpt =
+            (struct timer_adpt *)ets_timer->priv;
+
+  timer_adpt->func(timer_adpt->priv);
+  if (timer_adpt->repeat)
+    {
+      wd_start(&timer_adpt->wdog, timer_adpt->delay,
+               esp_timer_cb, (wdparm_t)ets_timer);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_timer_cb
+ *
+ * Description:
+ *   Post event to work queue and let work queue to process the timer's
+ *   real callback function
+ *
+ * Input Parameters:
+ *   parm - Timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_cb(wdparm_t parm)
+{
+  struct ets_timer *ets_timer = (struct ets_timer *)parm;
+  struct timer_adpt *timer_adpt =
+            (struct timer_adpt *)ets_timer->priv;
+
+  work_queue(LPWORK, &timer_adpt->work,
+             esp_timer_work_cb, ets_timer, 0);
+}
+
+/****************************************************************************
+ * Name: esp_timer_arm_us
+ *
+ * Description:
+ *   Set timer timeout period and repeat flag
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *   us     - micro seconds
+ *   repeat - true: run cycle, false: run once
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_arm_us(void *ptimer, uint32_t us, bool repeat)
+{
+  uint32_t delay;
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      timer_adpt = (struct timer_adpt *)ets_timer->priv;
+
+      wd_cancel(&timer_adpt->wdog);
+      work_cancel(LPWORK, &timer_adpt->work);
+
+      delay = USEC2TICK(us);
+      timer_adpt->repeat = (uint32_t)repeat;
+      timer_adpt->delay = delay;
+
+      wd_start(&timer_adpt->wdog, delay,
+               esp_timer_cb, (wdparm_t)ets_timer);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_periph_module_enable
+ *
+ * Description:
+ *   Enable WiFi module clock
+ *
+ * Input Parameters:
+ *   periph - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_periph_module_enable(uint32_t periph)
+{
+  modifyreg32(DPORT_WIFI_CLK_EN_REG, 0, DPORT_WIFI_CLK_WIFI_EN_M);
+}
+
+/****************************************************************************
+ * Name: esp_periph_module_enable
+ *
+ * Description:
+ *   Disable WiFi module clock
+ *
+ * Input Parameters:
+ *   periph - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_periph_module_disable(uint32_t periph)
+{
+  modifyreg32(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M, 0);
+}
+
+/****************************************************************************
+ * Name: esp_timer_get_time
+ *
+ * Description:
+ *   Get system time of type int64_t
+ *
+ * Input Parameters:
+ *   periph - No mean
+ *
+ * Returned Value:
+ *   System time
+ *
+ ****************************************************************************/
+
+int64_t esp_timer_get_time(void)
+{
+  int64_t us;
+  struct timeval tv;
+  int ret;
+
+  ret = gettimeofday(&tv, NULL);
+  if (!ret)
+    {
+      us = tv.tv_sec * (1000 * 1000) + tv.tv_usec;
+    }
+  else
+    {
+      us = 0;
+      wlerr("ERROR: Failed to get time of day\n");
+    }
+
+  return us;
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_i8
+ *
+ * Description:
+ *   Save data of type int8_t into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored data
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_i8(uint32_t handle,
+                              const char *key,
+                              int8_t value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  return esp_nvs_set_blob(handle, key, &value, sizeof(int8_t));
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_i8
+ *
+ * Description:
+ *   Read data of type int8_t from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_i8(uint32_t handle,
+                              const char *key,
+                              int8_t *out_value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  size_t len = sizeof(int8_t);
+
+  return esp_nvs_get_blob(handle, key, out_value, &len);
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_u8
+ *
+ * Description:
+ *   Save data of type uint8_t into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored data
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_u8(uint32_t handle,
+                              const char *key,
+                              uint8_t value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  return esp_nvs_set_blob(handle, key, &value, sizeof(uint8_t));
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_u8
+ *
+ * Description:
+ *   Read data of type uint8_t from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_u8(uint32_t handle,
+                              const char *key,
+                              uint8_t *out_value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  size_t len = sizeof(uint8_t);
+
+  return esp_nvs_get_blob(handle, key, out_value, &len);
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_u16
+ *
+ * Description:
+ *   Save data of type uint16_t into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored data
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_u16(uint32_t handle,
+                               const char *key,
+                               uint16_t value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  return esp_nvs_set_blob(handle, key, &value, sizeof(uint16_t));
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_u16
+ *
+ * Description:
+ *   Read data of type uint16_t from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_u16(uint32_t handle,
+                               const char *key,
+                               uint16_t *out_value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  size_t len = sizeof(uint16_t);
+
+  return esp_nvs_get_blob(handle, key, out_value, &len);
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_open
+ *
+ * Description:
+ *   Create a file system storage data object
+ *
+ * Input Parameters:
+ *   name       - Storage index
+ *   open_mode  - Storage mode
+ *   out_handle - Storage handle
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_open(const char *name,
+                            uint32_t open_mode,
+                            uint32_t *out_handle)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int ret;
+  struct nvs_adpt *nvs_adpt;
+  int tmp;
+  char *index_name;
+
+  tmp = sizeof(struct nvs_adpt);
+  nvs_adpt = kmm_malloc(tmp);
+  if (!nvs_adpt)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return -1;
+    }
+
+  ret = asprintf(&index_name, "%s", name);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS index_name string\n");
+      kmm_free(nvs_adpt);
+      return -1;
+    }
+
+  nvs_adpt->index_name = index_name;
+  *out_handle = (uint32_t)nvs_adpt;
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_close
+ *
+ * Description:
+ *   Close storage data object and free resource
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static void esp_nvs_close(uint32_t handle)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+
+  kmm_free(nvs_adpt->index_name);
+  kmm_free(nvs_adpt);
+#else
+  DEBUGASSERT(0);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_commit
+ *
+ * Description:
+ *   This function has no practical effect
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_commit(uint32_t handle)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_blob
+ *
+ * Description:
+ *   Save a block of data into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored buffer pointer
+ *   length - Buffer length
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_blob(uint32_t handle,
+                                const char *key,
+                                const void *value,
+                                size_t length)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int fd;
+  int ret;
+  char *dir;
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+  char *index_name = nvs_adpt->index_name;
+
+  ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS dir string\n");
+      return -1;
+    }
+
+  ret = unlink(dir);
+  if (ret)
+    {
+      if (errno != ENOENT)
+        {
+          wlerr("ERROR: Failed to unlink %s error=%d\n", dir, errno);
+          free(dir);
+          return -1;
+        }
+    }
+
+  fd = open(dir, O_WRONLY | O_CREAT, NVS_FILE_MODE);
+  if (fd < 0)
+    {
+      wlerr("ERROR: Failed to set open %s\n", dir);
+      free(dir);
+      return -1;
+    }
+
+  ret = write(fd, value, length);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to write to %s\n", dir);
+      free(dir);
+      close(fd);
+      return -1;
+    }
+
+  free(dir);
+  close(fd);
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_blob
+ *
+ * Description:
+ *   Read a block of data from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *   length    - Buffer length
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_blob(uint32_t handle,
+                                const char *key,
+                                void *out_value,
+                                size_t *length)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int fd;
+  int ret;
+  char *dir;
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+  char *index_name = nvs_adpt->index_name;
+
+  ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS dir string\n");
+      return -1;
+    }
+
+  fd = open(dir, O_RDONLY, NVS_FILE_MODE);
+  if (fd < 0)
+    {
+      free(dir);
+      if (errno == ENOENT)
+        {
+          wlinfo("INFO: No file %s\n", dir);
+          return ESP_ERR_NVS_NOT_FOUND;
+        }
+      wlerr("ERROR: Failed to get open %s\n", dir);
+      return -1;
+    }
+
+  ret = read(fd, out_value, *length);
+  if (ret <= 0)
+    {
+      wlerr("ERROR: Failed to write to %s\n", dir);
+      free(dir);
+      close(fd);
+      return -1;
+    }
+  else
+    {
+      *length = ret;
+    }
+
+  free(dir);
+  close(fd);
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_erase_key
+ *
+ * Description:
+ *   Read a block of data from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_erase_key(uint32_t handle, const char *key)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int ret;
+  char *dir;
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+  char *index_name = nvs_adpt->index_name;
+
+  ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS dir string\n");
+      return -1;
+    }
+
+  ret = unlink(dir);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to delete NVS file %s\n", dir);
+      free(dir);
+      return -1;
+    }
+
+  free(dir);
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_fill_random
+ *
+ * Description:
+ *   Fill random data int given buffer of given length
+ *
+ * Input Parameters:
+ *   buf - buffer pointer
+ *   len - buffer length
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void esp_fill_random(void *buf, size_t len)
+{
+  uint8_t *p = (uint8_t *)buf;
+  uint32_t tmp;
+  uint32_t n;
+
+  while (len > 0)
+    {
+      tmp = random();
+      n = len < 4 ? len : 4;
+
+      memcpy(p, &tmp, n);
+
+      p += n;
+      len -= n;
+    }
+}
+
+/****************************************************************************
+ * Name: esp_get_random
+ *
+ * Description:
+ *   Fill random data int given buffer of given length
+ *
+ * Input Parameters:
+ *   buf - buffer pointer
+ *   len - buffer length
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_get_random(uint8_t *buf, size_t len)
+{
+  esp_fill_random(buf, len);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_get_time
+ *
+ * Description:
+ *   Get std C time
+ *
+ * Input Parameters:
+ *   t - buffer to store time of type timeval
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_get_time(void *t)
+{
+  int ret;
+  struct timeval tv;
+  struct time_adpt *time_adpt = (struct time_adpt *)t;
+
+  ret = gettimeofday(&tv, NULL);
+  if (!ret)
+    {
+      time_adpt->sec  = (time_t)tv.tv_sec;
+      time_adpt->usec = (suseconds_t)tv.tv_usec;
+    }
+  else
+    {
+      wlerr("ERROR: Failed to get time of day\n");
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_rand
+ *
+ * Description:
+ *   Get random data of type uint32_t
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Random data
+ *
+ ****************************************************************************/
+
+static uint32_t esp_rand(void)
+{
+  return esp_random();
+}
+
+/****************************************************************************
+ * Name: esp_log_writev
+ *
+ * Description:
+ *   Output log with by format string and its arguments
+ *
+ * Input Parameters:
+ *   level  - log level, no mean here
+ *   tag    - log TAG, no mean here
+ *   format - format string
+ *   args   - arguments list
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_log_writev(uint32_t level, const char *tag,
+                           const char *format, va_list args)
+{
+  int pri;
+
+  switch (level)
+    {
+      case ESP_LOG_ERROR:
+        pri = LOG_ERR;
+        break;
+      case ESP_LOG_WARN:
+        pri = LOG_WARNING;
+        break;
+      case ESP_LOG_INFO:
+        pri = LOG_INFO;
+        break;
+      default:
+        pri = LOG_DEBUG;
+        break;
+    }
+
+  vsyslog(pri, format, args);
+}
+
+/****************************************************************************
+ * Name: esp_log_write
+ *
+ * Description:
+ *   Output log with by format string and its arguments
+ *
+ * Input Parameters:
+ *   level  - log level, no mean here
+ *   tag    - log TAG, no mean here
+ *   format - format string
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_log_write(uint32_t level,
+                   const char *tag,
+                   const char *format, ...)
+{
+    va_list list;
+    va_start(list, format);
+    esp_log_writev(level, tag, format, list);
+    va_end(list);
+}
+
+/****************************************************************************
+ * Name: esp_log_timestamp
+ *
+ * Description:
+ *   Get system time by millim second
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   System time
+ *
+ ****************************************************************************/
+
+uint32_t esp_log_timestamp(void)
+{
+  return (uint32_t)(esp_timer_get_time() / 1000);
+}
+
+/****************************************************************************
+ * Name: esp_malloc_internal
+ *
+ * Description:
+ *   Drivers allocate a block of memory
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   Memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_malloc_internal(size_t size)
+{
+  return kmm_malloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_realloc_internal
+ *
+ * Description:
+ *   Drivers allocate a block of memory by old memory block
+ *
+ * Input Parameters:
+ *   ptr  - old memory pointer
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_realloc_internal(void *ptr, size_t size)
+{
+  return kmm_realloc(ptr, size);
+}
+
+/****************************************************************************
+ * Name: esp_calloc_internal
+ *
+ * Description:
+ *   Drivers allocate some continuous blocks of memory
+ *
+ * Input Parameters:
+ *   n    - memory block number
+ *   size - memory block size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_calloc_internal(size_t n, size_t size)
+{
+  return kmm_calloc(n, size);
+}
+
+/****************************************************************************
+ * Name: esp_zalloc_internal
+ *
+ * Description:
+ *   Drivers allocate a block of memory and clear it with 0
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_zalloc_internal(size_t size)
+{
+  return kmm_zalloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_malloc_internal
+ *
+ * Description:
+ *   Applications allocate a block of memory
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   Memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_malloc(size_t size)
+{
+  return malloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_realloc_internal
+ *
+ * Description:
+ *   Applications allocate a block of memory by old memory block
+ *
+ * Input Parameters:
+ *   ptr  - old memory pointer
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_realloc(void *ptr, size_t size)
+{
+  return realloc(ptr, size);
+}
+
+/****************************************************************************
+ * Name: esp_calloc_internal
+ *
+ * Description:
+ *   Applications allocate some continuous blocks of memory
+ *
+ * Input Parameters:
+ *   n    - memory block number
+ *   size - memory block size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_calloc(size_t n, size_t size)
+{
+  return calloc(n, size);
+}
+
+/****************************************************************************
+ * Name: esp_zalloc_internal
+ *
+ * Description:
+ *   Applications allocate a block of memory and clear it with 0
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_zalloc(size_t size)
+{
+  return zalloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_wifi_create_queue
+ *
+ * Description:
+ *   Create WiFi static message queue
+ *
+ * Input Parameters:
+ *   queue_len - queue message number
+ *   item_size - message size
+ *
+ * Returned Value:
+ *   WiFi static message queue data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_create_queue(int32_t queue_len, int32_t item_size)
+{
+  wifi_static_queue_t *wifi_queue;
+
+  wifi_queue = kmm_malloc(sizeof(wifi_static_queue_t));
+  if (!wifi_queue)
+    {
+      wlerr("ERROR: Failed to malloc\n");
+      return NULL;
+    }
+
+  wifi_queue->handle = esp_queue_create(queue_len, item_size);
+  if (!wifi_queue->handle)
+    {
+      wlerr("ERROR: Failed to create queue\n");
+      kmm_free(wifi_queue);
+      return NULL;
+    }
+
+  return wifi_queue;
+}
+
+/****************************************************************************
+ * Name: esp_wifi_delete_queue
+ *
+ * Description:
+ *   Delete WiFi static message queue
+ *
+ * Input Parameters:
+ *   queue - WiFi static message queue data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_wifi_delete_queue(void *queue)
+{
+  wifi_static_queue_t *wifi_queue = (wifi_static_queue_t *)queue;
+
+  esp_queue_delete(wifi_queue->handle);
+  kmm_free(wifi_queue);
+}
+
+/****************************************************************************
+ * Name: esp_modem_enter_sleep
+ *
+ * Description:
+ *   Let given module to enter sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_enter_sleep(uint32_t module)
+{
+  int ret = 0;
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  if (!(s_esp32_module_mask & bit))
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_module_sleep |= bit;
+  if (!s_esp32_sleep && (s_esp32_module_sleep == s_esp32_module_mask))
+    {
+      ret = esp_phy_deinit_rf(PHY_MODEM_MODULE);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to close RF\n");
+        }
+      else
+        {
+          s_esp32_sleep = true;
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_modem_enter_sleep
+ *
+ * Description:
+ *   Let given module to exit from sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_exit_sleep(uint32_t module)
+{
+  int ret = 0;
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  if (!(s_esp32_module_mask & bit))
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_module_sleep &= ~bit;
+  if (s_esp32_sleep)
+    {
+      ret = esp_phy_rf_init(NULL, PHY_RF_CAL_NONE,
+                            NULL, PHY_MODEM_MODULE);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to open RF\n");
+        }
+      else
+        {
+          s_esp32_sleep = false;
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_modem_register_sleep
+ *
+ * Description:
+ *   Regitser given module so that it can enter sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_register_sleep(uint32_t module)
+{
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  flags = enter_critical_section();
+
+  if (s_esp32_module_mask & bit)
+    {
+      /* Has registered and return success */
+
+      return 0;
+    }
+
+  s_esp32_module_mask |= bit;
+  s_esp32_module_sleep |= bit;
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_modem_deregister_sleep
+ *
+ * Description:
+ *   Deregitser given module so that it can't enter sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_deregister_sleep(uint32_t module)
+{
+  int ret;
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  flags = enter_critical_section();
+
+  if (!(s_esp32_module_mask & bit))
+    {
+      /* Has deregistered and return success */
+
+      return 0;
+    }
+
+  s_esp32_module_mask &= ~bit;
+  s_esp32_module_sleep &= ~bit;
+  if (!s_esp32_module_mask)
+    {
+      s_esp32_module_mask = 0;
+      if (s_esp32_sleep)
+        {
+          s_esp32_sleep = false;
+          ret = esp_phy_rf_init(NULL, PHY_RF_CAL_NONE,
+                                NULL, PHY_MODEM_MODULE);
+          if (ret)
+            {
+              wlerr("ERROR: Failed to open RF\n");
+            }
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_coex_status_get
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_coex_status_get(void)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_coex_condition_set
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_coex_condition_set(uint32_t type, bool dissatisfy)
+{
+}
+
+/****************************************************************************
+ * Name: esp_coex_wifi_request
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static int32_t esp_coex_wifi_request(uint32_t event, uint32_t latency,
+                                     uint32_t duration)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_coex_wifi_release
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static int32_t esp_coex_wifi_release(uint32_t event)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Functions needed by libphy.a
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_dport_access_reg_read
+ *
+ * Description:
+ *   Read regitser value safely in SMP
+ *
+ * Input Parameters:
+ *   reg - Regitser address
+ *
+ * Returned Value:
+ *   Regitser value
+ *
+ ****************************************************************************/
+
+uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
+{
+#ifdef CONFIG_SMP
+  DEBUGASSERT(0);
+#else
+  return getreg32(reg);
+#endif
+}
+
+/****************************************************************************
+ * Name: phy_enter_critical
+ *
+ * Description:
+ *   Enter critical state
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   CPU PS value
+ *
+ ****************************************************************************/
+
+uint32_t IRAM_ATTR phy_enter_critical(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  return flags;
+}
+
+/****************************************************************************
+ * Name: phy_exit_critical
+ *
+ * Description:
+ *   Exit from critical state
+ *
+ * Input Parameters:
+ *   level - CPU PS value
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void IRAM_ATTR phy_exit_critical(uint32_t level)
+{
+  leave_critical_section(level);
+}
+
+/****************************************************************************
+ * Name: phy_printf
+ *
+ * Description:
+ *   Output format string and its arguments
+ *
+ * Input Parameters:
+ *   format - format string
+ *
+ * Returned Value:
+ *   0
+ *
+ ****************************************************************************/
+
+int phy_printf(const char *format, ...)
+{
+  va_list arg;
+
+  va_start(arg, format);
+  vsyslog(LOG_INFO, format, arg);
+  va_end(arg);
+
+  return 0;
+}

Review comment:
       why not use wlinfo?

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* WiFi interrupt adapter private data */
+
+struct irq_adpt
+{
+  void (*func)(void *arg);  /* Interrupt callback function */
+  void *arg;                /* Interrupt private data */
+};
+
+/* WiFi message queue private data */
+
+struct mq_adpt
+{
+  mqd_t    mq;              /* Message queue handle */
+  uint32_t msgsize;         /* Message size */
+  char     name[16];        /* Message queue name */
+};
+
+/* WiFi time private data */
+
+struct time_adpt
+{
+  time_t      sec;          /* Second value */
+  suseconds_t usec;         /* Micro second value */
+};
+
+/* WiFi timer private data */
+
+struct timer_adpt
+{
+  struct wdog_s wdog;       /* Timer handle */
+  struct work_s work;       /* Work priavte data */

Review comment:
       ```suggestion
     struct work_s work;       /* Work private data */
   ```

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)

Review comment:
       make this configurable?

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic.
   
   It would be better to split this file then into different files, each with a specific function. It will be easier to review and maintain.
   
   But please try to add some general comment of what the code is doing, how this adapting layer works, etc.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic.
   
   It would be better to split this file then into different files, each with a specific function. It will be easier to review and maintain.
   
   But please try to add some general comment of what the code is doing, how this adapting layer works, etc.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > Yes, you are right. Because the `3rdparty` is just created, and we will talk about create like branch `release/vX.X` to bind with NuttX specific branch, so now please let me use master now.
   
   Before merging it will be better to point to a specific commit, even if that commit is the latest one. The point is that the build should be reproducible and using master means that every build could be different since master changed in between. If you later need to update the commit, a quick PR is all that is needed to change the hash.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698330079


   @patacongo @xiaoxiang781216 @v01d @btashton @liuguo09
   Please note that this PR also adds ARCH_SRC to the context/clean_context directories.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494329082



##########
File path: arch/arm/src/Makefile
##########
@@ -35,7 +35,7 @@
 ############################################################################
 
 include $(TOPDIR)/Make.defs
-include chip/Make.defs
+-include chip/Make.defs

Review comment:
       As I said above `clean_context` is used before linking the directories, at that point chip/ doesn't exist.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494716868



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > I only added comments to some simple things because I cannot really review the actual contents of this PR since I'm not familiar with WiFi code in NuttX. However, I must say that the adapter file has a **lot** going on, it is a really big file with lots of auxiliary functions. Also, I feel that is quite an obscure implementation, it is very difficult to understand what is this code doing in general, I only get little pieces by looking at the small comments for each function.
   > 
   > It would be good to add some general documentation, either in the form of a README or simple as more detailed comments explaining what all this code is doing and what each part is doing.
   > I fear that besides the obvious fact that there's some closed code behind this, this code itself will be difficult to maintain/debug by someone else as is.
   > 
   > That said, I really appreciate the support for ESP32 WiFi on NuttX.
   
   There are 2 main source files, one is `esp32_wlan.c` and another is `esp32_wifi_adapter.c`, we can think the `esp32_wlan.c` is alike with `esp32_emac.c`, and it realizes the Ethernet communication. `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic. 
   
   But when espressif developed the wifi driver, they don't fully consider porting this driver to other OS platforms, so there are some complex designing which I think should be taken into libraries. Because these logic functions are not related to porting OS adapter functions. So I have been trying to improve the wifi adapter layer to reduce the functions which we should add to support other OS.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494708581



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       better to point to specific commit

##########
File path: arch/xtensa/src/esp32/Kconfig
##########
@@ -531,4 +533,24 @@ config ESP32_ETH_PHY_ADDR
 
 endmenu # ESP32_EMAC
 
+menu "WiFi configuration"
+	depends on ESP32_WIRELESS
+
+config ESP32_WIFI_SAVE_PARAM
+	bool "Save WiFi Parameters"
+	default n
+	help
+		Enable this option, WiFi adapter save WiFi parameters
+		into file system without generating or calculating some
+		connection parameters again.

Review comment:
       ```suggestion
   		If you enable this option, WiFi adapter parameters will be saved
   		into the file system instead of computing them each time.
   ```
   
   Changed a bit the wording. Maybe you could specify which parameters?

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* WiFi interrupt adapter private data */
+
+struct irq_adpt
+{
+  void (*func)(void *arg);  /* Interrupt callback function */
+  void *arg;                /* Interrupt private data */
+};
+
+/* WiFi message queue private data */
+
+struct mq_adpt
+{
+  mqd_t    mq;              /* Message queue handle */
+  uint32_t msgsize;         /* Message size */
+  char     name[16];        /* Message queue name */
+};
+
+/* WiFi time private data */
+
+struct time_adpt
+{
+  time_t      sec;          /* Second value */
+  suseconds_t usec;         /* Micro second value */
+};
+
+/* WiFi timer private data */
+
+struct timer_adpt
+{
+  struct wdog_s wdog;       /* Timer handle */
+  struct work_s work;       /* Work priavte data */
+  bool          repeat;     /* Flags indicate if it is cycle */
+  uint32_t      delay;      /* Timeout ticks */
+
+  /* Timer callback function */
+
+  void          (*func)(void *priv);
+  void          *priv;      /* Timer private data */
+};
+
+/* WiFi event private data */
+
+struct evt_adpt
+{
+  sq_entry_t entry;         /* Sequence entry */
+  int32_t id;               /* Event ID */
+  uint8_t buf[0];           /* Event private data */
+};
+
+/* WiFi event notification private data */
+
+struct wifi_notify
+{
+  bool assigned;            /* Flag indicate if it is used */
+  pid_t pid;                /* Signal's target thread PID */
+  struct sigevent event;    /* Signal event private data */
+  struct sigwork_s work;    /* Signal work private data */
+};
+
+/* WiFi NVS private data */
+
+struct nvs_adpt
+{
+  char *index_name;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_set_isr(int32_t n, void *f, void *arg);
+static void esp32_ints_on(uint32_t mask);
+static void esp32_ints_off(uint32_t mask);
+static void *esp_spin_lock_create(void);
+static void esp_spin_lock_delete(void *lock);
+static uint32_t esp_wifi_int_disable(void *wifi_int_mux);
+static void esp_wifi_int_restore(void *wifi_int_mux, uint32_t tmp);
+static void IRAM_ATTR esp_task_yield_from_isr(void);
+static void *esp_semphr_create(uint32_t max, uint32_t init);
+static void esp_semphr_delete(void *semphr);
+static int32_t esp_semphr_take(void *semphr, uint32_t block_time_tick);
+static int32_t esp_semphr_give(void *semphr);
+static void *esp_thread_semphr_get(void);
+static void *esp_mutex_create(void);
+static void *esp_recursive_mutex_create(void);
+static void esp_mutex_delete(void *mutex_data);
+static int32_t esp_mutex_lock(void *mutex_data);
+static int32_t esp_mutex_unlock(void *mutex_data);
+static void *esp_queue_create(uint32_t queue_len, uint32_t item_size);
+static void esp_queue_delete(void *queue);
+static int32_t esp_queue_send(void *queue, void *item,
+                              uint32_t block_time_tick);
+static int32_t esp_queue_send_from_isr(void *queue, void *item, void *hptw);
+static int32_t esp_queue_send_to_back(void *queue, void *item,
+                                      uint32_t block_time_tick);
+static int32_t esp_queue_send_to_front(void *queue, void *item,
+                                       uint32_t block_time_tick);
+static int32_t esp_queue_recv(void *queue, void *item,
+                              uint32_t block_time_tick);
+static uint32_t esp_queue_msg_waiting(void *queue);
+static void *esp_event_group_create(void);
+static void esp_event_group_delete(void *event);
+static uint32_t esp_event_group_set_bits(void *event, uint32_t bits);
+static uint32_t esp_event_group_clear_bits(void *event, uint32_t bits);
+static uint32_t esp_event_group_wait_bits(void *event,
+                                          uint32_t bits_to_wait_for,
+                                          int32_t clear_on_exit,
+                                          int32_t wait_for_all_bits,
+                                          uint32_t block_time_tick);
+static int32_t esp_task_create_pinned_to_core(void *task_func,
+                                              const char *name,
+                                              uint32_t stack_depth,
+                                              void *param,
+                                              uint32_t prio,
+                                              void *task_handle,
+                                              uint32_t core_id);
+static int32_t esp_task_create(void *task_func, const char *name,
+                               uint32_t stack_depth, void *param,
+                               uint32_t prio, void *task_handle);
+static void esp_task_delete(void *task_handle);
+static void esp_task_delay(uint32_t tick);
+static int32_t esp_task_ms_to_tick(uint32_t ms);
+static void *esp_task_get_current_task(void);
+static int32_t esp_task_get_max_priority(void);
+static void *esp_malloc(uint32_t size);
+static uint32_t esp_rand(void);
+static void esp_dport_access_stall_other_cpu_start(void);
+static void esp_dport_access_stall_other_cpu_end(void);
+static int32_t esp_phy_deinit_rf(uint32_t module);
+static void esp_phy_init(uint32_t module);
+static void esp_phy_enable_clock(void);
+static void esp_phy_disable_clock(void);
+static int32_t esp_wifi_read_mac(uint8_t *mac, uint32_t type);
+static void esp_timer_arm(void *timer, uint32_t tmout, bool repeat);
+static void esp_timer_disarm(void *timer);
+static void esp32_timer_done(void *timer);
+static void esp_timer_setfn(void *timer, void *pfunction, void *parg);
+static void esp_timer_cb(wdparm_t parm);
+static void esp_timer_arm_us(void *timer, uint32_t us, bool repeat);
+static void esp_periph_module_enable(uint32_t periph);
+static void esp_periph_module_disable(uint32_t periph);
+static int32_t esp_nvs_set_i8(uint32_t handle, const char *key,
+                              int8_t value);
+static int32_t esp_nvs_get_i8(uint32_t handle, const char *key,
+                              int8_t *out_value);
+static int32_t esp_nvs_set_u8(uint32_t handle, const char *key,
+                              uint8_t value);
+static int32_t esp_nvs_get_u8(uint32_t handle, const char *key,
+                              uint8_t *out_value);
+static int32_t esp_nvs_set_u16(uint32_t handle, const char *key,
+                               uint16_t value);
+static int32_t esp_nvs_get_u16(uint32_t handle, const char *key,
+                               uint16_t *out_value);
+static int32_t esp_nvs_open(const char *name, uint32_t open_mode,
+                            uint32_t *out_handle);
+static void esp_nvs_close(uint32_t handle);
+static int32_t esp_nvs_commit(uint32_t handle);
+static int32_t esp_nvs_set_blob(uint32_t handle, const char *key,
+                                const void *value, size_t length);
+static int32_t esp_nvs_get_blob(uint32_t handle, const char *key,
+                                void *out_value, size_t *length);
+static int32_t esp_nvs_erase_key(uint32_t handle, const char *key);
+static int32_t esp_get_random(uint8_t *buf, size_t len);
+static int32_t esp_get_time(void *t);
+static void esp_log_writev(uint32_t level, const char *tag,
+                           const char *format, va_list args);
+static void *esp_malloc_internal(size_t size);
+static void *esp_realloc_internal(void *ptr, size_t size);
+static void *esp_calloc_internal(size_t n, size_t size);
+static void *esp_zalloc_internal(size_t size);
+static void *esp_wifi_malloc(size_t size);
+static void *esp_wifi_realloc(void *ptr, size_t size);
+static void *esp_wifi_calloc(size_t n, size_t size);
+static void *esp_wifi_zalloc(size_t size);
+static int32_t esp_modem_enter_sleep(uint32_t module);
+static int32_t esp_modem_exit_sleep(uint32_t module);
+static int32_t esp_modem_register_sleep(uint32_t module);
+static int32_t esp_modem_deregister_sleep(uint32_t module);
+static void *esp_wifi_create_queue(int32_t queue_len, int32_t item_size);
+static void esp_wifi_delete_queue(void *queue);
+static uint32_t esp_coex_status_get(void);
+static void esp_coex_condition_set(uint32_t type, bool dissatisfy);
+static int32_t esp_coex_wifi_request(uint32_t event, uint32_t latency,
+                                     uint32_t duration);
+static int32_t esp_coex_wifi_release(uint32_t event);
+
+/****************************************************************************
+ * Public Functions declaration
+ ****************************************************************************/
+
+int64_t esp_timer_get_time(void);
+void esp_fill_random(void *buf, size_t len);
+void esp_log_write(uint32_t level, const char *tag, const char *format, ...);
+uint32_t esp_log_timestamp(void);
+uint8_t esp_crc8(const uint8_t *p, uint32_t len);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* WiFi interrupt private data */
+
+static int s_wifi_irq;
+
+/* WiFi thread private data */
+
+static pthread_key_t s_wifi_thread_key;
+static bool s_wifi_tkey_init;
+
+/* WiFi sleep private data */
+
+static uint32_t s_esp32_module_mask;
+static uint32_t s_esp32_module_sleep;
+static bool s_esp32_sleep;
+static uint32_t s_phy_clk_en_cnt = 0;
+static bool s_esp23_phy_en;
+static uint32_t s_esp32_phy_init_mask;
+static int64_t s_esp32_phy_rf_stop_tm;
+
+/* WiFi event private data */
+
+static struct work_s s_wifi_evt_work;
+static sq_queue_t s_wifi_evt_queue;
+static struct wifi_notify s_wifi_notify[WIFI_ADPT_EVT_MAX];
+static sem_t s_connect_sem;
+static bool s_connected;
+
+static uint8_t s_ssid[32];
+static uint8_t s_password[64];
+static uint8_t s_ssid_len;
+static uint8_t s_password_len;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* WiFi OS adapter data */
+
+wifi_osi_funcs_t g_wifi_osi_funcs =
+{
+  ._version = ESP_WIFI_OS_ADAPTER_VERSION,
+  ._set_isr = esp_set_isr,
+  ._ints_on = esp32_ints_on,
+  ._ints_off = esp32_ints_off,
+  ._spin_lock_create = esp_spin_lock_create,
+  ._spin_lock_delete = esp_spin_lock_delete,
+  ._wifi_int_disable = esp_wifi_int_disable,
+  ._wifi_int_restore = esp_wifi_int_restore,
+  ._task_yield_from_isr = esp_task_yield_from_isr,
+  ._semphr_create = esp_semphr_create,
+  ._semphr_delete = esp_semphr_delete,
+  ._semphr_take = esp_semphr_take,
+  ._semphr_give = esp_semphr_give,
+  ._wifi_thread_semphr_get = esp_thread_semphr_get,
+  ._mutex_create = esp_mutex_create,
+  ._recursive_mutex_create = esp_recursive_mutex_create,
+  ._mutex_delete = esp_mutex_delete,
+  ._mutex_lock = esp_mutex_lock,
+  ._mutex_unlock = esp_mutex_unlock,
+  ._queue_create = esp_queue_create,
+  ._queue_delete = esp_queue_delete,
+  ._queue_send = esp_queue_send,
+  ._queue_send_from_isr = esp_queue_send_from_isr,
+  ._queue_send_to_back = esp_queue_send_to_back,
+  ._queue_send_to_front = esp_queue_send_to_front,
+  ._queue_recv = esp_queue_recv,
+  ._queue_msg_waiting = esp_queue_msg_waiting,
+  ._event_group_create = esp_event_group_create,
+  ._event_group_delete = esp_event_group_delete,
+  ._event_group_set_bits = esp_event_group_set_bits,
+  ._event_group_clear_bits = esp_event_group_clear_bits,
+  ._event_group_wait_bits = esp_event_group_wait_bits,
+  ._task_create_pinned_to_core = esp_task_create_pinned_to_core,
+  ._task_create = esp_task_create,
+  ._task_delete = esp_task_delete,
+  ._task_delay = esp_task_delay,
+  ._task_ms_to_tick = esp_task_ms_to_tick,
+  ._task_get_current_task = esp_task_get_current_task,
+  ._task_get_max_priority = esp_task_get_max_priority,
+  ._malloc = esp_malloc,
+  ._free = free,
+  ._event_post = esp_event_post,
+  ._get_free_heap_size = esp_get_free_heap_size,
+  ._rand = esp_rand,
+  ._dport_access_stall_other_cpu_start_wrap =
+      esp_dport_access_stall_other_cpu_start,
+  ._dport_access_stall_other_cpu_end_wrap =
+      esp_dport_access_stall_other_cpu_end,
+  ._phy_rf_deinit = esp_phy_deinit_rf,
+  ._phy_load_cal_and_init = esp_phy_init,
+  ._phy_common_clock_enable = esp_phy_enable_clock,
+  ._phy_common_clock_disable = esp_phy_disable_clock,
+  ._read_mac = esp_wifi_read_mac,
+  ._timer_arm = esp_timer_arm,
+  ._timer_disarm = esp_timer_disarm,
+  ._timer_done = esp32_timer_done,
+  ._timer_setfn = esp_timer_setfn,
+  ._timer_arm_us = esp_timer_arm_us,
+  ._periph_module_enable = esp_periph_module_enable,
+  ._periph_module_disable = esp_periph_module_disable,
+  ._esp_timer_get_time = esp_timer_get_time,
+  ._nvs_set_i8 = esp_nvs_set_i8,
+  ._nvs_get_i8 = esp_nvs_get_i8,
+  ._nvs_set_u8 = esp_nvs_set_u8,
+  ._nvs_get_u8 = esp_nvs_get_u8,
+  ._nvs_set_u16 = esp_nvs_set_u16,
+  ._nvs_get_u16 = esp_nvs_get_u16,
+  ._nvs_open = esp_nvs_open,
+  ._nvs_close = esp_nvs_close,
+  ._nvs_commit = esp_nvs_commit,
+  ._nvs_set_blob = esp_nvs_set_blob,
+  ._nvs_get_blob = esp_nvs_get_blob,
+  ._nvs_erase_key = esp_nvs_erase_key,
+  ._get_random = esp_get_random,
+  ._get_time = esp_get_time,
+  ._random = esp_random,
+  ._log_write = esp_log_write,
+  ._log_writev = esp_log_writev,
+  ._log_timestamp = esp_log_timestamp,
+  ._malloc_internal =  esp_malloc_internal,
+  ._realloc_internal = esp_realloc_internal,
+  ._calloc_internal = esp_calloc_internal,
+  ._zalloc_internal = esp_zalloc_internal,
+  ._wifi_malloc = esp_wifi_malloc,
+  ._wifi_realloc = esp_wifi_realloc,
+  ._wifi_calloc = esp_wifi_calloc,
+  ._wifi_zalloc = esp_wifi_zalloc,
+  ._wifi_create_queue = esp_wifi_create_queue,
+  ._wifi_delete_queue = esp_wifi_delete_queue,
+  ._modem_sleep_enter = esp_modem_enter_sleep,
+  ._modem_sleep_exit = esp_modem_exit_sleep,
+  ._modem_sleep_register = esp_modem_register_sleep,
+  ._modem_sleep_deregister = esp_modem_deregister_sleep,
+  ._coex_status_get = esp_coex_status_get,
+  ._coex_condition_set = esp_coex_condition_set,
+  ._coex_wifi_request = esp_coex_wifi_request,
+  ._coex_wifi_release = esp_coex_wifi_release,
+  ._magic = ESP_WIFI_OS_ADAPTER_MAGIC,
+};
+
+/* WiFi feature capacity data */
+
+uint64_t g_wifi_feature_caps;
+
+/* WiFi TAG string data */
+
+ESP_EVENT_DEFINE_BASE(WIFI_EVENT);
+
+/****************************************************************************
+ * Private Functions and Public Functions only used by libraries
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_errno_trans
+ *
+ * Description:
+ *   Transform from nuttx error code to WiFi adapter error code
+ *
+ * Input Parameters:
+ *   ret - Nuttx error code
+ *
+ * Returned Value:
+ *   WiFi adapter error code
+ *
+ ****************************************************************************/
+
+static inline int32_t esp_errno_trans(int ret)
+{
+  if (!ret)
+    {
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+/****************************************************************************
+ * Name: esp_int_adpt_cb
+ *
+ * Description:
+ *   WiFi interrupt adapter callback function
+ *
+ * Input Parameters:
+ *   arg - interrupt adapter private data
+ *
+ * Returned Value:
+ *   0 on success
+ *
+ ****************************************************************************/
+
+static int esp_int_adpt_cb(int irq, void *context, FAR void *arg)
+{
+  struct irq_adpt *adapter = (struct irq_adpt *)arg;
+
+  adapter->func(adapter->arg);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_thread_semphr_free
+ *
+ * Description:
+ *   Delete thread self's semaphore
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_thread_semphr_free(void *semphr)
+{
+  if (semphr)
+    {
+      esp_semphr_delete(semphr);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_update_time
+ *
+ * Description:
+ *   Transform ticks to time and add this time to timespec value
+ *
+ * Input Parameters:
+ *   timespec - Input timespec data pointer
+ *   ticks    - System ticks
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_update_time(struct timespec *timespec, uint32_t ticks)
+{
+  uint32_t tmp;
+
+  tmp = TICK2SEC(ticks);
+  timespec->tv_sec += tmp;
+
+  ticks -= SEC2TICK(tmp);
+  tmp = TICK2NSEC(ticks);
+
+  timespec->tv_nsec += tmp;
+}
+
+/****************************************************************************
+ * Name: esp_set_isr
+ *
+ * Description:
+ *   Register interrupt function
+ *
+ * Input Parameters:
+ *   n   - Interrupt ID
+ *   f   - Interrupt function
+ *   arg - Function private data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_set_isr(int32_t n, void *f, void *arg)
+{
+  int ret;
+  struct irq_adpt *adapter;
+  int irq;
+  int cpu = 0;
+  int tmp;
+
+  irq = esp32_alloc_levelint(1);
+  if (irq < 0)
+    {
+      wlerr("ERROR: Failed to alloc interrupt\n");
+      assert(0);
+      return ;
+    }
+
+  up_disable_irq(irq);
+
+  tmp = sizeof(struct irq_adpt);
+  adapter = kmm_malloc(tmp);
+  if (!adapter)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      assert(0);
+      return ;
+    }
+
+  adapter->func = f;
+  adapter->arg = arg;
+
+  tmp = n + XTENSA_IRQ_FIRSTPERIPH;
+  ret = irq_attach(tmp, esp_int_adpt_cb, adapter);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to attach IRQ %d\n", tmp);
+      assert(0);
+      return ;
+    }
+
+  esp32_attach_peripheral(cpu, n, irq);
+
+  s_wifi_irq = irq;
+}
+
+/****************************************************************************
+ * Name: esp32_ints_on
+ *
+ * Description:
+ *   Enable WiFi interrupt
+ *
+ * Input Parameters:
+ *   mask - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32_ints_on(uint32_t mask)
+{
+  up_enable_irq(s_wifi_irq);
+}
+
+/****************************************************************************
+ * Name: esp32_ints_on
+ *
+ * Description:
+ *   Disable WiFi interrupt
+ *
+ * Input Parameters:
+ *   mask - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32_ints_off(uint32_t mask)
+{
+  up_disable_irq(s_wifi_irq);
+}
+
+/****************************************************************************
+ * Name: esp_spin_lock_create
+ *
+ * Description:
+ *   Create spin lock in SMP mode
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Spin lock data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_spin_lock_create(void)
+{
+#ifdef CONFIG_SMP
+  spinlock_t *lock;
+  int tmp;
+
+  tmp = sizeof(struct spinlock_t);
+  lock = kmm_malloc(tmp);
+  if (!lock)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      DEBUGASSERT(0);
+    }
+
+  spin_initialize(lock, SP_UNLOCKED);
+
+  return lock;
+#else
+  /* If return NULL, code may check fail  */
+
+  return (void *)1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_spin_lock_delete
+ *
+ * Description:
+ *   Delete spin lock
+ *
+ * Input Parameters:
+ *   lock - Spin lock data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_spin_lock_delete(void *lock)
+{
+#ifdef CONFIG_SMP
+  kmm_free(lock);
+#else
+  DEBUGASSERT((int)lock == 1);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_wifi_int_disable
+ *
+ * Description:
+ *   Enter critical by disable interrup, and take spin lock if
+ *   in SMP mode
+ *
+ * Input Parameters:
+ *   wifi_int_mux - Spin lock data pointer
+ *
+ * Returned Value:
+ *   CPU PS value.
+ *
+ ****************************************************************************/
+
+static uint32_t IRAM_ATTR esp_wifi_int_disable(void *wifi_int_mux)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+#ifdef CONFIG_SMP
+  spin_lock((volatile spinlock_t *)wifi_int_mux);
+#endif
+
+  return (uint32_t)flags;
+}
+
+/****************************************************************************
+ * Name: esp_wifi_int_restore
+ *
+ * Description:
+ *   Exit from critical by enable interrup, and release spin
+ *   lock if in SMP mode
+ *
+ * Input Parameters:
+ *   wifi_int_mux - Spin lock data pointer
+ *   tmp          - CPU PS value.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp_wifi_int_restore(void *wifi_int_mux, uint32_t tmp)
+{
+  irqstate_t flags = (irqstate_t)tmp;
+
+#ifdef CONFIG_SMP
+  spin_unlock((volatile spinlock_t *)wifi_int_mux);
+#endif
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp_task_yield_from_isr
+ *
+ * Description:
+ *   Do nothing in Nuttx
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp_task_yield_from_isr(void)
+{
+  /* Do nothing */
+}
+
+/****************************************************************************
+ * Name: esp_semphr_create
+ *
+ * Description:
+ *   Create and initialize semaphore
+ *
+ * Input Parameters:
+ *   max  - No mean
+ *   init - semaphore initialization value
+ *
+ * Returned Value:
+ *   Semphore data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_semphr_create(uint32_t max, uint32_t init)
+{
+  int ret;
+  sem_t *sem;
+  int tmp;
+
+  tmp = sizeof(sem_t);
+  sem = kmm_malloc(tmp);
+  if (!sem)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return NULL;
+    }
+
+  ret = sem_init(sem, 0, init);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize sem error=%d\n", ret);
+      kmm_free(sem);
+      return NULL;
+    }
+
+  return sem;
+}
+
+/****************************************************************************
+ * Name: esp_semphr_delete
+ *
+ * Description:
+ *   Delete semaphore
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_semphr_delete(void *semphr)
+{
+  sem_t *sem = (sem_t *)semphr;
+
+  sem_destroy(sem);
+  kmm_free(sem);
+}
+
+/****************************************************************************
+ * Name: esp_semphr_take
+ *
+ * Description:
+ *   Wait semaphore within a certain period of time
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *   ticks  - Wait system ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_semphr_take(void *semphr, uint32_t ticks)
+{
+  int ret;
+  struct timespec timeout;
+  sem_t *sem = (sem_t *)semphr;
+
+  if (ticks == OSI_FUNCS_TIME_BLOCKING)
+    {
+      ret = sem_wait(sem);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to wait sem\n");
+        }
+    }
+  else
+    {
+      ret = clock_gettime(CLOCK_REALTIME, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to get time\n");
+          return false;
+        }
+
+      if (ticks)
+        {
+          esp_update_time(&timeout, ticks);
+        }
+
+      ret = sem_timedwait(sem, &timeout);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to wait sem in %d ticks\n", ticks);
+        }
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_semphr_give
+ *
+ * Description:
+ *   Post semaphore
+ *
+ * Input Parameters:
+ *   semphr - Semphore data pointer
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_semphr_give(void *semphr)
+{
+  int ret;
+  sem_t *sem = (sem_t *)semphr;
+
+  ret = sem_post(sem);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to post sem error=%d\n", ret);
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_thread_semphr_get
+ *
+ * Description:
+ *   Get thread self's semaphore
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Semphore data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_thread_semphr_get(void)
+{
+  int ret;
+  void *sem;
+
+  if (s_wifi_tkey_init)
+  {
+    ret = pthread_key_create(&s_wifi_thread_key, esp_thread_semphr_free);
+    if (ret)
+      {
+        wlerr("ERROR: Failed to create pthread key\n");
+        return NULL;
+      }
+
+    s_wifi_tkey_init = true;
+  }
+
+  sem = pthread_getspecific(s_wifi_thread_key);
+  if (!sem)
+    {
+      sem = esp_semphr_create(1, 0);
+      if (!sem)
+        {
+          wlerr("ERROR: Failed to create semaphore\n");
+          return NULL;
+        }
+
+      ret = pthread_setspecific(s_wifi_thread_key, sem);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to set specific\n");
+          esp_semphr_delete(sem);
+          return NULL;
+        }
+    }
+
+  return sem;
+}
+
+/****************************************************************************
+ * Name: esp_mutex_create
+ *
+ * Description:
+ *   Create mutex
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Mutex data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_mutex_create(void)
+{
+  int ret;
+  pthread_mutex_t *mutex;
+  int tmp;
+
+  tmp = sizeof(pthread_mutex_t);
+  mutex = kmm_malloc(tmp);
+  if (!mutex)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return NULL;
+    }
+
+  ret = pthread_mutex_init(mutex, NULL);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize mutex error=%d\n", ret);
+      kmm_free(mutex);
+      return NULL;
+    }
+
+  return mutex;
+}
+
+/****************************************************************************
+ * Name: esp_recursive_mutex_create
+ *
+ * Description:
+ *   Create recursive mutex
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Recursive mutex data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_recursive_mutex_create(void)
+{
+  int ret;
+  pthread_mutex_t *mutex;
+  pthread_mutexattr_t attr;
+  int tmp;
+
+  ret = pthread_mutexattr_init(&attr);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize attr error=%d\n", ret);
+      return NULL;
+    }
+
+  ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to set attr type error=%d\n", ret);
+      return NULL;
+    }
+
+  tmp = sizeof(pthread_mutex_t);
+  mutex = kmm_malloc(tmp);
+  if (!mutex)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return NULL;
+    }
+
+  ret = pthread_mutex_init(mutex, &attr);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize mutex error=%d\n", ret);
+      kmm_free(mutex);
+      return NULL;
+    }
+
+  return mutex;
+}
+
+/****************************************************************************
+ * Name: esp_mutex_delete
+ *
+ * Description:
+ *   Delete mutex
+ *
+ * Input Parameters:
+ *   mutex_data - mutex data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_mutex_delete(void *mutex_data)
+{
+  pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data;
+
+  pthread_mutex_destroy(mutex);
+  kmm_free(mutex);
+}
+
+/****************************************************************************
+ * Name: esp_mutex_lock
+ *
+ * Description:
+ *   Lock mutex
+ *
+ * Input Parameters:
+ *   mutex_data - mutex data pointer
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_mutex_lock(void *mutex_data)
+{
+  int ret;
+  pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data;
+
+  ret = pthread_mutex_lock(mutex);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to lock mutex error=%d\n", ret);
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_mutex_unlock
+ *
+ * Description:
+ *   Unlock mutex
+ *
+ * Input Parameters:
+ *   mutex_data - mutex data pointer
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_mutex_unlock(void *mutex_data)
+{
+  int ret;
+  pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data;
+
+  ret = pthread_mutex_unlock(mutex);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to unlock mutex error=%d\n", ret);
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_queue_create
+ *
+ * Description:
+ *   Create message queue
+ *
+ * Input Parameters:
+ *   queue_len - queue message number
+ *   item_size - message size
+ *
+ * Returned Value:
+ *   Message queue data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_queue_create(uint32_t queue_len, uint32_t item_size)
+{
+  struct mq_attr attr;
+  mqd_t mq;
+  struct mq_adpt *mq_adpt;
+
+  mq_adpt = kmm_malloc(sizeof(struct mq_adpt));
+  if (!mq_adpt)
+    {
+      wlerr("ERROR: Failed to malloc\n");
+      return NULL;
+    }
+
+  snprintf(mq_adpt->name, sizeof(mq_adpt->name),
+           "/tmp/%X", mq_adpt);
+
+  attr.mq_maxmsg  = queue_len;
+  attr.mq_msgsize = item_size;
+  attr.mq_curmsgs = 0;
+  attr.mq_flags   = 0;
+
+  mq = mq_open(mq_adpt->name, O_RDWR | O_CREAT, 0644, &attr);
+  if (!mq)
+    {
+      wlerr("ERROR: Failed to create mqueue\n");
+      kmm_free(mq_adpt);
+      return NULL;
+    }
+
+  mq_adpt->mq = mq;
+  mq_adpt->msgsize = item_size;
+
+  return (void *)mq_adpt;
+}
+
+/****************************************************************************
+ * Name: esp_queue_delete
+ *
+ * Description:
+ *   Delete message queue
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_queue_delete(void *queue)
+{
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  mq_close(mq_adpt->mq);
+  mq_unlink(mq_adpt->name);
+  kmm_free(mq_adpt);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_generic
+ *
+ * Description:
+ *   Generic send message to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *   prio  - Message priority
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_generic(void *queue, void *item,
+                                      uint32_t ticks, int prio)
+{
+  int ret;
+  struct timespec timeout;
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  if (ticks == OSI_FUNCS_TIME_BLOCKING || ticks == 0)
+    {
+      /**
+       * WiFi interrupt function will call this adapter function to send
+       * message to message queue, so here we should call kernel API
+       * instead of application API
+       */
+
+      ret = nxmq_send(mq_adpt->mq, (const char *)item,
+                    mq_adpt->msgsize, prio);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to send message to mqueue error=%d\n",
+               ret);
+        }
+    }
+  else
+    {
+      ret = clock_gettime(CLOCK_REALTIME, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to get time\n");
+          return false;
+        }
+
+      if (ticks)
+        {
+          esp_update_time(&timeout, ticks);
+        }
+
+      ret = mq_timedsend(mq_adpt->mq, (const char *)item,
+                         mq_adpt->msgsize, prio, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to timedsend message to mqueue error=%d\n",
+               ret);
+        }
+    }
+
+  return esp_errno_trans(ret);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send
+ *
+ * Description:
+ *   Send message of low priority to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send(void *queue, void *item, uint32_t ticks)
+{
+  return esp_queue_send_generic(queue, item, ticks, 0);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_from_isr
+ *
+ * Description:
+ *   Send message of low priority to queue in ISR within
+ *   a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   hptw  - No mean
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_from_isr(void *queue, void *item, void *hptw)
+{
+  /* Force to set the value to be false */
+
+  *((int *)hptw) = false;
+
+  return esp_queue_send_generic(queue, item, 0, 0);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_to_back
+ *
+ * Description:
+ *   Send message of low priority to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_to_back(void *queue, void *item,
+                                      uint32_t ticks)
+{
+  return esp_queue_send_generic(queue, item, ticks, 0);
+}
+
+/****************************************************************************
+ * Name: esp_queue_send_from_isr
+ *
+ * Description:
+ *   Send message of high priority to queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_send_to_front(void *queue, void *item,
+                                       uint32_t ticks)
+{
+  return esp_queue_send_generic(queue, item, ticks, 1);
+}
+
+/****************************************************************************
+ * Name: esp_queue_recv
+ *
+ * Description:
+ *   Receive message from queue within a certain period of time
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *   item  - Message data pointer
+ *   ticks - Wait ticks
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_queue_recv(void *queue, void *item, uint32_t ticks)
+{
+  ssize_t ret;
+  struct timespec timeout;
+  unsigned int prio;
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  if (ticks == OSI_FUNCS_TIME_BLOCKING)
+    {
+      ret = mq_receive(mq_adpt->mq, (char *)item,
+                       mq_adpt->msgsize, &prio);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to receive from mqueue error=%d\n", ret);
+        }
+    }
+  else
+    {
+      ret = clock_gettime(CLOCK_REALTIME, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to get time\n");
+          return false;
+        }
+
+      if (ticks)
+        {
+          esp_update_time(&timeout, ticks);
+        }
+
+      ret = mq_timedreceive(mq_adpt->mq, (char *)item,
+                            mq_adpt->msgsize, &prio, &timeout);
+      if (ret < 0)
+        {
+          wlerr("ERROR: Failed to timedreceive from mqueue error=%d\n",
+               ret);
+        }
+    }
+
+  return ret > 0 ? true : false;
+}
+
+/****************************************************************************
+ * Name: esp_queue_msg_waiting
+ *
+ * Description:
+ *   Get message number in the message queue
+ *
+ * Input Parameters:
+ *   queue - Message queue data pointer
+ *
+ * Returned Value:
+ *   Message number
+ *
+ ****************************************************************************/
+
+static uint32_t esp_queue_msg_waiting(void *queue)
+{
+  int ret;
+  struct mq_attr attr;
+  struct mq_adpt *mq_adpt = (struct mq_adpt *)queue;
+
+  ret = mq_getattr(mq_adpt->mq, &attr);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to get attr from mqueue error=%d\n", ret);
+      return 0;
+    }
+
+  return attr.mq_curmsgs;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_create
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void *esp_event_group_create(void)
+{
+  DEBUGASSERT(0);
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_delete
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_event_group_delete(void *event)
+{
+  DEBUGASSERT(0);
+}
+
+/****************************************************************************
+ * Name: esp_event_group_set_bits
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_event_group_set_bits(void *event, uint32_t bits)
+{
+  DEBUGASSERT(0);
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_clear_bits
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_event_group_clear_bits(void *event, uint32_t bits)
+{
+  DEBUGASSERT(0);
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: esp_event_group_wait_bits
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_event_group_wait_bits(void *event,
+                                          uint32_t bits_to_wait_for,
+                                          int32_t clear_on_exit,
+                                          int32_t wait_for_all_bits,
+                                          uint32_t block_time_tick)
+{
+  DEBUGASSERT(0);
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: esp_task_create_pinned_to_core
+ *
+ * Description:
+ *   Create task and bind it to target CPU, the task will run when it
+ *   is created
+ *
+ * Input Parameters:
+ *   entry       - Task entry
+ *   name        - Task name
+ *   stack_depth - Task stack size
+ *   param       - Task private data
+ *   prio        - Task priority
+ *   task_handle - Task handle pointer which is used to pause, resume
+ *                 and delete the task
+ *   core_id     - CPU which the task runs in
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_create_pinned_to_core(void *entry,
+                                              const char *name,
+                                              uint32_t stack_depth,
+                                              void *param,
+                                              uint32_t prio,
+                                              void *task_handle,
+                                              uint32_t core_id)
+{
+  int pid;
+#ifdef CONFIG_SMP
+  int ret;
+  cpu_set_t cpuset;
+#endif
+
+  pid = kthread_create(name, prio, stack_depth, entry,
+                      (char * const *)param);
+  if (pid > 0)
+    {
+      *((int *)task_handle) = pid;
+
+#ifdef CONFIG_SMP
+      if (core_id < CONFIG_SMP_NCPUS)
+        {
+          CPU_ZERO(&cpuset);
+          CPU_SET(core_id, &cpuset);
+          ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset);
+          if (ret)
+            {
+              wlerr("ERROR: Failed to set affinity error=%d\n", ret);
+              return false;
+            }
+        }
+#endif
+    }
+  else
+    {
+      wlerr("ERROR: Failed to create task\n");
+    }
+
+  return pid > 0 ? true : false;
+}
+
+/****************************************************************************
+ * Name: esp_task_create
+ *
+ * Description:
+ *   Create task and the task will run when it is created
+ *
+ * Input Parameters:
+ *   entry       - Task entry
+ *   name        - Task name
+ *   stack_depth - Task stack size
+ *   param       - Task private data
+ *   prio        - Task priority
+ *   task_handle - Task handle pointer which is used to pause, resume
+ *                 and delete the task
+ *
+ * Returned Value:
+ *   True if success or false if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_create(void *entry, const char *name,
+                               uint32_t stack_depth, void *param,
+                               uint32_t prio, void *task_handle)
+{
+  return esp_task_create_pinned_to_core(entry, name, stack_depth, param,
+                                        prio, task_handle, UINT32_MAX);
+}
+
+/****************************************************************************
+ * Name: esp_task_delete
+ *
+ * Description:
+ *   Delete the target task
+ *
+ * Input Parameters:
+ *   task_handle - Task handle pointer which is used to pause, resume
+ *                 and delete the task
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_task_delete(void *task_handle)
+{
+  pid_t pid = (pid_t)((uintptr_t)task_handle);
+
+  kthread_delete(pid);
+}
+
+/****************************************************************************
+ * Name: esp_task_delay
+ *
+ * Description:
+ *   Current task wait for some ticks
+ *
+ * Input Parameters:
+ *   tick - Waiting ticks
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_task_delay(uint32_t tick)
+{
+  useconds_t us = TICK2USEC(tick);
+
+  usleep(us);
+}
+
+/****************************************************************************
+ * Name: esp_task_ms_to_tick
+ *
+ * Description:
+ *   Transform from millim seconds to system ticks
+ *
+ * Input Parameters:
+ *   ms - Millim seconds
+ *
+ * Returned Value:
+ *   System ticks
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_ms_to_tick(uint32_t ms)
+{
+  return MSEC2TICK(ms);
+}
+
+/****************************************************************************
+ * Name: esp_task_get_current_task
+ *
+ * Description:
+ *   Transform from millim seconds to system ticks
+ *
+ * Input Parameters:
+ *   ms - Millim seconds
+ *
+ * Returned Value:
+ *   System ticks
+ *
+ ****************************************************************************/
+
+static void *esp_task_get_current_task(void)
+{
+  pid_t pid = getpid();
+
+  return (void *)((uintptr_t)pid);
+}
+
+/****************************************************************************
+ * Name: esp_task_get_current_task
+ *
+ * Description:
+ *   Get OS task maxium priority
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Task maxium priority
+ *
+ ****************************************************************************/
+
+static int32_t esp_task_get_max_priority(void)
+{
+  return SCHED_PRIORITY_MAX;
+}
+
+/****************************************************************************
+ * Name: esp_malloc_internal
+ *
+ * Description:
+ *   Allocate a block of memory
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   Memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_malloc(uint32_t size)
+{
+  return malloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_event_id_map
+ *
+ * Description:
+ *   Transform from esp-idf event ID to WiFi adapter event ID
+ *
+ * Input Parameters:
+ *   event_id - esp-idf event ID
+ *
+ * Returned Value:
+ *   WiFi adapter event ID
+ *
+ ****************************************************************************/
+
+static int esp_event_id_map(int event_id)
+{
+  int id;
+
+  switch (event_id)
+    {
+      case WIFI_EVENT_STA_START:
+        id = WIFI_ADPT_EVT_STA_START;
+        break;
+      case WIFI_EVENT_STA_CONNECTED:
+        id = WIFI_ADPT_EVT_STA_CONNECT;
+        break;
+      case WIFI_EVENT_STA_DISCONNECTED:
+        id = WIFI_ADPT_EVT_STA_DISCONNECT;
+        break;
+      case WIFI_EVENT_STA_AUTHMODE_CHANGE:
+        id = WIFI_ADPT_EVT_STA_AUTHMODE_CHANGE;
+        break;
+      case WIFI_EVENT_STA_STOP:
+        id = WIFI_ADPT_EVT_STA_STOP;
+        break;
+      default:
+        return -1;
+    }
+
+  return id;
+}
+
+/****************************************************************************
+ * Name: esp_evt_work_cb
+ *
+ * Description:
+ *   Process the cached event
+ *
+ * Input Parameters:
+ *   arg - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_evt_work_cb(FAR void *arg)
+{
+  int ret;
+  irqstate_t flags;
+  struct evt_adpt *evt_adpt;
+  struct wifi_notify *notify;
+
+  while (1)
+    {
+      flags = enter_critical_section();
+      evt_adpt = (struct evt_adpt *)sq_remfirst(&s_wifi_evt_queue);
+      leave_critical_section(flags);
+      if (!evt_adpt)
+        {
+          break;
+        }
+
+      switch (evt_adpt->id)
+        {
+          case WIFI_ADPT_EVT_STA_START:
+            ret = esp_wifi_connect();
+            if (ret)
+              {
+                wlerr("ERROR: Failed to connect\n");
+              }
+            break;
+          case WIFI_ADPT_EVT_STA_CONNECT:
+            s_connected = true;
+            ret = sem_post(&s_connect_sem);
+            if (ret)
+              {
+                wlerr("ERROR: Failed to post sem error=%d\n", errno);
+              }
+            break;
+          case WIFI_ADPT_EVT_STA_DISCONNECT:
+            s_connected = false;
+            ret = esp_wifi_connect();
+            if (ret)
+              {
+                wlerr("ERROR: Failed to connect\n");
+              }
+            break;
+          default:
+            break;
+        }
+
+      notify = &s_wifi_notify[evt_adpt->id];
+      if (notify->assigned)
+        {
+          notify->event.sigev_value.sival_ptr = evt_adpt->buf;
+
+          ret = nxsig_notification(notify->pid, &notify->event,
+                                   SI_QUEUE, &notify->work);
+          if (ret < 0)
+            {
+              wlwarn("ERROR: nxsig_notification event ID=%d failed: %d\n",
+                     evt_adpt->id, ret);
+            }
+        }
+
+      free(evt_adpt);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_event_post
+ *
+ * Description:
+ *   Active work queue and let the work to process the cached event
+ *
+ * Input Parameters:
+ *   event_base      - Event set name
+ *   event_id        - Event ID
+ *   event_data      - Event private data
+ *   event_data_size - Event data size
+ *   ticks           - Waiting system ticks
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+int32_t esp_event_post(esp_event_base_t event_base,
+                       int32_t event_id,
+                       void *event_data,
+                       size_t event_data_size,
+                       uint32_t ticks)
+{
+  size_t size;
+  int32_t id;
+  irqstate_t flags;
+  struct evt_adpt *evt_adpt;
+
+  wlinfo("Event: base=%s id=%d data=%p data_size=%d ticks=%u\n", event_base,
+         event_id, event_data, event_data_size, ticks);
+
+  id = esp_event_id_map(event_id);
+  if (id < 0)
+    {
+      wlerr("ERROR: No process event %d\n", event_id);
+      return -1;
+    }
+
+  size = event_data_size + sizeof(struct evt_adpt);
+  evt_adpt = malloc(size);
+  if (!evt_adpt)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", size);
+      return -1;
+    }
+
+  evt_adpt->id = id;
+  memcpy(evt_adpt->buf, event_data, event_data_size);
+
+  flags = enter_critical_section();
+  sq_addlast(&evt_adpt->entry, &s_wifi_evt_queue);
+  leave_critical_section(flags);
+
+  work_queue(LPWORK, &s_wifi_evt_work, esp_evt_work_cb, NULL, 0);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_task_get_current_task
+ *
+ * Description:
+ *   Get free heap size by byte
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Free heap size
+ *
+ ****************************************************************************/
+
+uint32_t esp_get_free_heap_size(void)
+{
+  int ret;
+  struct mallinfo info;
+
+  ret = mm_mallinfo(&g_mmheap, &info);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to create task\n");
+      return 0;
+    }
+
+  return info.fordblks;
+}
+
+/****************************************************************************
+ * Name: esp_random
+ *
+ * Description:
+ *   Get a random data of type unsigned long
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Random data
+ *
+ ****************************************************************************/
+
+unsigned long esp_random(void)
+{
+  return (unsigned long)random();
+}
+
+/****************************************************************************
+ * Name: esp_dport_access_stall_other_cpu_start
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_dport_access_stall_other_cpu_start(void)
+{
+#ifdef CONFIG_SMP
+  DEBUGASSERT(0);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_dport_access_stall_other_cpu_end
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_dport_access_stall_other_cpu_end(void)
+{
+#ifdef CONFIG_SMP
+  DEBUGASSERT(0);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_phy_rf_init
+ *
+ * Description:
+ *   Initialize PHY hardware with given parameters
+ *
+ * Input Parameters:
+ *   init_data        - PHY hardware initialization parameters
+ *   mode             - PHY RF calculation mode
+ *   calibration_data - PHY RF calculation parameters
+ *   module           - PHY mode which is to be initialized
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+int32_t esp_phy_rf_init(const esp_phy_init_data_t *init_data,
+                        esp_phy_calibration_mode_t mode,
+                        esp_phy_calibration_data_t *calibration_data,
+                        phy_rf_module_t module)
+{
+  irqstate_t flags;
+  int64_t time;
+  bool enable = false;
+
+  if (module >= PHY_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_phy_init_mask |= 1 << module;
+
+  if (s_esp23_phy_en)
+    {
+      leave_critical_section(flags);
+      return 0;
+    }
+
+  if (module == PHY_MODEM_MODULE)
+    {
+      if (s_esp32_phy_init_mask & PHY_RF_MASK)
+        {
+          enable = true;
+        }
+    }
+  else if (module == PHY_WIFI_MODULE || module == PHY_BT_MODULE)
+    {
+      enable = true;
+    }
+
+  if (enable)
+    {
+      if (s_esp32_phy_rf_stop_tm)
+        {
+          time = esp_timer_get_time() - s_esp32_phy_rf_stop_tm;
+          esp_wifi_internal_update_mac_time((uint32_t)time);
+          s_esp32_phy_rf_stop_tm = 0;
+        }
+
+      esp_phy_enable_clock();
+
+      phy_set_wifi_mode_only(0);
+
+      register_chipv7_phy(init_data, calibration_data, mode);
+
+      s_esp23_phy_en = true;
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_phy_deinit_rf
+ *
+ * Description:
+ *   Deinitialize PHY hardware
+ *
+ * Input Parameters:
+ *   module - PHY mode which is to be deinitialized
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_phy_deinit_rf(uint32_t module)
+{
+  irqstate_t flags;
+  bool disable = false;
+
+  if (module >= PHY_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_phy_init_mask |= ~(1 << module);
+
+  if (!s_esp23_phy_en)
+    {
+      leave_critical_section(flags);
+      return 0;
+    }
+
+  if (module == PHY_MODEM_MODULE)
+    {
+      disable = true;
+    }
+  else if (module == PHY_WIFI_MODULE || module == PHY_BT_MODULE)
+    {
+      if (!(s_esp32_phy_init_mask & PHY_RF_MASK))
+        {
+          disable = true;
+        }
+    }
+
+  if (disable)
+    {
+      phy_close_rf();
+
+      s_esp32_phy_rf_stop_tm = esp_timer_get_time();
+
+      esp_phy_disable_clock();
+
+      s_esp23_phy_en = false;
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_phy_init
+ *
+ * Description:
+ *   Initialize PHY hardware
+ *
+ * Input Parameters:
+ *   module - PHY mode which is to be initialized
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_phy_init(uint32_t module)
+{
+  int ret;
+  esp_phy_calibration_data_t *cal_data;
+
+  cal_data = kmm_zalloc(sizeof(esp_phy_calibration_data_t));
+  if (!cal_data)
+    {
+      wlerr("ERROR: Failed to malloc");
+      DEBUGASSERT(0);
+    }
+
+  ret = esp_phy_rf_init(&phy_init_data, PHY_RF_CAL_FULL, cal_data, module);
+  if (ret)
+    {
+      wlerr("ERROR: Failed to initialize RF");
+      DEBUGASSERT(0);
+    }
+
+  kmm_free(cal_data);
+}
+
+/****************************************************************************
+ * Name: esp_phy_enable_clock
+ *
+ * Description:
+ *   Enable PHY hardware clock
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_phy_enable_clock(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (s_phy_clk_en_cnt == 0)
+    {
+      modifyreg32(DPORT_WIFI_CLK_EN_REG, 0,
+                  DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
+    }
+
+  s_phy_clk_en_cnt++;
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp_phy_disable_clock
+ *
+ * Description:
+ *   Disable PHY hardware clock
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_phy_disable_clock(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (s_phy_clk_en_cnt)
+    {
+      s_phy_clk_en_cnt--;
+      if (!s_phy_clk_en_cnt)
+        {
+          modifyreg32(DPORT_WIFI_CLK_EN_REG,
+                      DPORT_WIFI_CLK_WIFI_BT_COMMON_M,
+                      0);
+        }
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp_read_mac
+ *
+ * Description:
+ *   Read MAC address from efuse
+ *
+ * Input Parameters:
+ *   mac  - MAC address buffer pointer
+ *   type - MAC address type
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+int32_t esp_read_mac(uint8_t *mac, esp_mac_type_t type)
+{
+  uint32_t regval[2];
+  uint8_t tmp;
+  uint8_t *data = (uint8_t *)regval;
+  uint8_t crc;
+  int i;
+
+  if (type > ESP_MAC_WIFI_SOFTAP)
+    {
+      wlerr("ERROR: Input type is error=%d\n", type);
+      return -1;
+    }
+
+  regval[0] = getreg32(MAC_ADDR0_REG);
+  regval[1] = getreg32(MAC_ADDR1_REG);
+
+  crc = data[6];
+  for (i = 0; i < 6; i++)
+    {
+      mac[i] = data[5 - i];
+    }
+
+  if (crc != esp_crc8(mac, 6))
+    {
+      wlerr("ERROR: Failed to check MAC address CRC\n");
+      return -1;
+    }
+
+  if (type == ESP_MAC_WIFI_SOFTAP)
+    {
+      tmp = mac[0];
+      for (i = 0; i < 64; i++)
+        {
+          mac[0] = tmp | 0x02;
+          mac[0] ^= i << 2;
+
+          if (mac[0] != tmp)
+            {
+              break;
+            }
+        }
+
+      if (i >= 64)
+        {
+          wlerr("ERROR: Failed to generate softAP MAC\n");
+          return -1;
+        }
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_wifi_read_mac
+ *
+ * Description:
+ *   Read MAC address from efuse
+ *
+ * Input Parameters:
+ *   mac  - MAC address buffer pointer
+ *   type - MAC address type
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_wifi_read_mac(uint8_t *mac, uint32_t type)
+{
+  return esp_read_mac(mac, type);
+}
+
+/****************************************************************************
+ * Name: esp_timer_arm
+ *
+ * Description:
+ *   Set timer timeout period and repeat flag
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *   ms     - millim seconds
+ *   repeat - true: run cycle, false: run once
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_arm(void *ptimer, uint32_t ms, bool repeat)
+{
+  esp_timer_arm_us(ptimer, ms * 1000, repeat);
+}
+
+/****************************************************************************
+ * Name: esp_timer_disarm
+ *
+ * Description:
+ *   Disable timer
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_disarm(void *ptimer)
+{
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      timer_adpt = (struct timer_adpt *)ets_timer->priv;
+
+      wd_cancel(&timer_adpt->wdog);
+      work_cancel(LPWORK, &timer_adpt->work);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32_timer_done
+ *
+ * Description:
+ *   Disable and free timer
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32_timer_done(void *ptimer)
+{
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      timer_adpt = (struct timer_adpt *)ets_timer->priv;
+
+      wd_cancel(&timer_adpt->wdog);
+      work_cancel(LPWORK, &timer_adpt->work);
+
+      kmm_free(timer_adpt);
+
+      ets_timer->priv = NULL;
+    }
+}
+
+/****************************************************************************
+ * Name: esp_timer_setfn
+ *
+ * Description:
+ *   Set timer callback function and private data
+ *
+ * Input Parameters:
+ *   ptimer    - Timer data pointer
+ *   pfunction - Callback function
+ *   parg      - Callback function private data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_setfn(void *ptimer, void *pfunction, void *parg)
+{
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      return ;
+    }
+
+  timer_adpt = kmm_zalloc(sizeof(struct timer_adpt));
+  if (!timer_adpt)
+    {
+      wlerr("ERROR: Failed to malloc\n");
+      return ;
+    }
+
+  timer_adpt->func = pfunction;
+  timer_adpt->priv = parg;
+
+  ets_timer->priv = timer_adpt;
+}
+
+/****************************************************************************
+ * Name: esp_timer_work_cb
+ *
+ * Description:
+ *   Process timer callback function in workqueue and active
+ *   it if it has repeat flag
+ *
+ * Input Parameters:
+ *   arg - Timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_work_cb(FAR void *arg)
+{
+  struct ets_timer *ets_timer = (struct ets_timer *)arg;
+  struct timer_adpt *timer_adpt =
+            (struct timer_adpt *)ets_timer->priv;
+
+  timer_adpt->func(timer_adpt->priv);
+  if (timer_adpt->repeat)
+    {
+      wd_start(&timer_adpt->wdog, timer_adpt->delay,
+               esp_timer_cb, (wdparm_t)ets_timer);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_timer_cb
+ *
+ * Description:
+ *   Post event to work queue and let work queue to process the timer's
+ *   real callback function
+ *
+ * Input Parameters:
+ *   parm - Timer data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_cb(wdparm_t parm)
+{
+  struct ets_timer *ets_timer = (struct ets_timer *)parm;
+  struct timer_adpt *timer_adpt =
+            (struct timer_adpt *)ets_timer->priv;
+
+  work_queue(LPWORK, &timer_adpt->work,
+             esp_timer_work_cb, ets_timer, 0);
+}
+
+/****************************************************************************
+ * Name: esp_timer_arm_us
+ *
+ * Description:
+ *   Set timer timeout period and repeat flag
+ *
+ * Input Parameters:
+ *   ptimer - timer data pointer
+ *   us     - micro seconds
+ *   repeat - true: run cycle, false: run once
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_timer_arm_us(void *ptimer, uint32_t us, bool repeat)
+{
+  uint32_t delay;
+  struct timer_adpt *timer_adpt;
+  struct ets_timer *ets_timer = (struct ets_timer *)ptimer;
+
+  if (ets_timer->priv)
+    {
+      timer_adpt = (struct timer_adpt *)ets_timer->priv;
+
+      wd_cancel(&timer_adpt->wdog);
+      work_cancel(LPWORK, &timer_adpt->work);
+
+      delay = USEC2TICK(us);
+      timer_adpt->repeat = (uint32_t)repeat;
+      timer_adpt->delay = delay;
+
+      wd_start(&timer_adpt->wdog, delay,
+               esp_timer_cb, (wdparm_t)ets_timer);
+    }
+}
+
+/****************************************************************************
+ * Name: esp_periph_module_enable
+ *
+ * Description:
+ *   Enable WiFi module clock
+ *
+ * Input Parameters:
+ *   periph - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_periph_module_enable(uint32_t periph)
+{
+  modifyreg32(DPORT_WIFI_CLK_EN_REG, 0, DPORT_WIFI_CLK_WIFI_EN_M);
+}
+
+/****************************************************************************
+ * Name: esp_periph_module_enable
+ *
+ * Description:
+ *   Disable WiFi module clock
+ *
+ * Input Parameters:
+ *   periph - No mean
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_periph_module_disable(uint32_t periph)
+{
+  modifyreg32(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M, 0);
+}
+
+/****************************************************************************
+ * Name: esp_timer_get_time
+ *
+ * Description:
+ *   Get system time of type int64_t
+ *
+ * Input Parameters:
+ *   periph - No mean
+ *
+ * Returned Value:
+ *   System time
+ *
+ ****************************************************************************/
+
+int64_t esp_timer_get_time(void)
+{
+  int64_t us;
+  struct timeval tv;
+  int ret;
+
+  ret = gettimeofday(&tv, NULL);
+  if (!ret)
+    {
+      us = tv.tv_sec * (1000 * 1000) + tv.tv_usec;
+    }
+  else
+    {
+      us = 0;
+      wlerr("ERROR: Failed to get time of day\n");
+    }
+
+  return us;
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_i8
+ *
+ * Description:
+ *   Save data of type int8_t into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored data
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_i8(uint32_t handle,
+                              const char *key,
+                              int8_t value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  return esp_nvs_set_blob(handle, key, &value, sizeof(int8_t));
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_i8
+ *
+ * Description:
+ *   Read data of type int8_t from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_i8(uint32_t handle,
+                              const char *key,
+                              int8_t *out_value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  size_t len = sizeof(int8_t);
+
+  return esp_nvs_get_blob(handle, key, out_value, &len);
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_u8
+ *
+ * Description:
+ *   Save data of type uint8_t into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored data
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_u8(uint32_t handle,
+                              const char *key,
+                              uint8_t value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  return esp_nvs_set_blob(handle, key, &value, sizeof(uint8_t));
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_u8
+ *
+ * Description:
+ *   Read data of type uint8_t from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_u8(uint32_t handle,
+                              const char *key,
+                              uint8_t *out_value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  size_t len = sizeof(uint8_t);
+
+  return esp_nvs_get_blob(handle, key, out_value, &len);
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_u16
+ *
+ * Description:
+ *   Save data of type uint16_t into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored data
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_u16(uint32_t handle,
+                               const char *key,
+                               uint16_t value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  return esp_nvs_set_blob(handle, key, &value, sizeof(uint16_t));
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_u16
+ *
+ * Description:
+ *   Read data of type uint16_t from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_u16(uint32_t handle,
+                               const char *key,
+                               uint16_t *out_value)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  size_t len = sizeof(uint16_t);
+
+  return esp_nvs_get_blob(handle, key, out_value, &len);
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_open
+ *
+ * Description:
+ *   Create a file system storage data object
+ *
+ * Input Parameters:
+ *   name       - Storage index
+ *   open_mode  - Storage mode
+ *   out_handle - Storage handle
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_open(const char *name,
+                            uint32_t open_mode,
+                            uint32_t *out_handle)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int ret;
+  struct nvs_adpt *nvs_adpt;
+  int tmp;
+  char *index_name;
+
+  tmp = sizeof(struct nvs_adpt);
+  nvs_adpt = kmm_malloc(tmp);
+  if (!nvs_adpt)
+    {
+      wlerr("ERROR: Failed to alloc %d memory\n", tmp);
+      return -1;
+    }
+
+  ret = asprintf(&index_name, "%s", name);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS index_name string\n");
+      kmm_free(nvs_adpt);
+      return -1;
+    }
+
+  nvs_adpt->index_name = index_name;
+  *out_handle = (uint32_t)nvs_adpt;
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_close
+ *
+ * Description:
+ *   Close storage data object and free resource
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static void esp_nvs_close(uint32_t handle)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+
+  kmm_free(nvs_adpt->index_name);
+  kmm_free(nvs_adpt);
+#else
+  DEBUGASSERT(0);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_commit
+ *
+ * Description:
+ *   This function has no practical effect
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_commit(uint32_t handle)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_nvs_set_blob
+ *
+ * Description:
+ *   Save a block of data into file system
+ *
+ * Input Parameters:
+ *   handle - NVS handle
+ *   key    - Data index
+ *   value  - Stored buffer pointer
+ *   length - Buffer length
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_set_blob(uint32_t handle,
+                                const char *key,
+                                const void *value,
+                                size_t length)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int fd;
+  int ret;
+  char *dir;
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+  char *index_name = nvs_adpt->index_name;
+
+  ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS dir string\n");
+      return -1;
+    }
+
+  ret = unlink(dir);
+  if (ret)
+    {
+      if (errno != ENOENT)
+        {
+          wlerr("ERROR: Failed to unlink %s error=%d\n", dir, errno);
+          free(dir);
+          return -1;
+        }
+    }
+
+  fd = open(dir, O_WRONLY | O_CREAT, NVS_FILE_MODE);
+  if (fd < 0)
+    {
+      wlerr("ERROR: Failed to set open %s\n", dir);
+      free(dir);
+      return -1;
+    }
+
+  ret = write(fd, value, length);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to write to %s\n", dir);
+      free(dir);
+      close(fd);
+      return -1;
+    }
+
+  free(dir);
+  close(fd);
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_get_blob
+ *
+ * Description:
+ *   Read a block of data from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *   out_value - Read buffer pointer
+ *   length    - Buffer length
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_get_blob(uint32_t handle,
+                                const char *key,
+                                void *out_value,
+                                size_t *length)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int fd;
+  int ret;
+  char *dir;
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+  char *index_name = nvs_adpt->index_name;
+
+  ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS dir string\n");
+      return -1;
+    }
+
+  fd = open(dir, O_RDONLY, NVS_FILE_MODE);
+  if (fd < 0)
+    {
+      free(dir);
+      if (errno == ENOENT)
+        {
+          wlinfo("INFO: No file %s\n", dir);
+          return ESP_ERR_NVS_NOT_FOUND;
+        }
+      wlerr("ERROR: Failed to get open %s\n", dir);
+      return -1;
+    }
+
+  ret = read(fd, out_value, *length);
+  if (ret <= 0)
+    {
+      wlerr("ERROR: Failed to write to %s\n", dir);
+      free(dir);
+      close(fd);
+      return -1;
+    }
+  else
+    {
+      *length = ret;
+    }
+
+  free(dir);
+  close(fd);
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_nvs_erase_key
+ *
+ * Description:
+ *   Read a block of data from file system
+ *
+ * Input Parameters:
+ *   handle    - NVS handle
+ *   key       - Data index
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_nvs_erase_key(uint32_t handle, const char *key)
+{
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+  int ret;
+  char *dir;
+  struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle;
+  char *index_name = nvs_adpt->index_name;
+
+  ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to create NVS dir string\n");
+      return -1;
+    }
+
+  ret = unlink(dir);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to delete NVS file %s\n", dir);
+      free(dir);
+      return -1;
+    }
+
+  free(dir);
+
+  return 0;
+#else
+  DEBUGASSERT(0);
+
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp_fill_random
+ *
+ * Description:
+ *   Fill random data int given buffer of given length
+ *
+ * Input Parameters:
+ *   buf - buffer pointer
+ *   len - buffer length
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void esp_fill_random(void *buf, size_t len)
+{
+  uint8_t *p = (uint8_t *)buf;
+  uint32_t tmp;
+  uint32_t n;
+
+  while (len > 0)
+    {
+      tmp = random();
+      n = len < 4 ? len : 4;
+
+      memcpy(p, &tmp, n);
+
+      p += n;
+      len -= n;
+    }
+}
+
+/****************************************************************************
+ * Name: esp_get_random
+ *
+ * Description:
+ *   Fill random data int given buffer of given length
+ *
+ * Input Parameters:
+ *   buf - buffer pointer
+ *   len - buffer length
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_get_random(uint8_t *buf, size_t len)
+{
+  esp_fill_random(buf, len);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_get_time
+ *
+ * Description:
+ *   Get std C time
+ *
+ * Input Parameters:
+ *   t - buffer to store time of type timeval
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_get_time(void *t)
+{
+  int ret;
+  struct timeval tv;
+  struct time_adpt *time_adpt = (struct time_adpt *)t;
+
+  ret = gettimeofday(&tv, NULL);
+  if (!ret)
+    {
+      time_adpt->sec  = (time_t)tv.tv_sec;
+      time_adpt->usec = (suseconds_t)tv.tv_usec;
+    }
+  else
+    {
+      wlerr("ERROR: Failed to get time of day\n");
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_rand
+ *
+ * Description:
+ *   Get random data of type uint32_t
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Random data
+ *
+ ****************************************************************************/
+
+static uint32_t esp_rand(void)
+{
+  return esp_random();
+}
+
+/****************************************************************************
+ * Name: esp_log_writev
+ *
+ * Description:
+ *   Output log with by format string and its arguments
+ *
+ * Input Parameters:
+ *   level  - log level, no mean here
+ *   tag    - log TAG, no mean here
+ *   format - format string
+ *   args   - arguments list
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_log_writev(uint32_t level, const char *tag,
+                           const char *format, va_list args)
+{
+  int pri;
+
+  switch (level)
+    {
+      case ESP_LOG_ERROR:
+        pri = LOG_ERR;
+        break;
+      case ESP_LOG_WARN:
+        pri = LOG_WARNING;
+        break;
+      case ESP_LOG_INFO:
+        pri = LOG_INFO;
+        break;
+      default:
+        pri = LOG_DEBUG;
+        break;
+    }
+
+  vsyslog(pri, format, args);
+}
+
+/****************************************************************************
+ * Name: esp_log_write
+ *
+ * Description:
+ *   Output log with by format string and its arguments
+ *
+ * Input Parameters:
+ *   level  - log level, no mean here
+ *   tag    - log TAG, no mean here
+ *   format - format string
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_log_write(uint32_t level,
+                   const char *tag,
+                   const char *format, ...)
+{
+    va_list list;
+    va_start(list, format);
+    esp_log_writev(level, tag, format, list);
+    va_end(list);
+}
+
+/****************************************************************************
+ * Name: esp_log_timestamp
+ *
+ * Description:
+ *   Get system time by millim second
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   System time
+ *
+ ****************************************************************************/
+
+uint32_t esp_log_timestamp(void)
+{
+  return (uint32_t)(esp_timer_get_time() / 1000);
+}
+
+/****************************************************************************
+ * Name: esp_malloc_internal
+ *
+ * Description:
+ *   Drivers allocate a block of memory
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   Memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_malloc_internal(size_t size)
+{
+  return kmm_malloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_realloc_internal
+ *
+ * Description:
+ *   Drivers allocate a block of memory by old memory block
+ *
+ * Input Parameters:
+ *   ptr  - old memory pointer
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_realloc_internal(void *ptr, size_t size)
+{
+  return kmm_realloc(ptr, size);
+}
+
+/****************************************************************************
+ * Name: esp_calloc_internal
+ *
+ * Description:
+ *   Drivers allocate some continuous blocks of memory
+ *
+ * Input Parameters:
+ *   n    - memory block number
+ *   size - memory block size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_calloc_internal(size_t n, size_t size)
+{
+  return kmm_calloc(n, size);
+}
+
+/****************************************************************************
+ * Name: esp_zalloc_internal
+ *
+ * Description:
+ *   Drivers allocate a block of memory and clear it with 0
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_zalloc_internal(size_t size)
+{
+  return kmm_zalloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_malloc_internal
+ *
+ * Description:
+ *   Applications allocate a block of memory
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   Memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_malloc(size_t size)
+{
+  return malloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_realloc_internal
+ *
+ * Description:
+ *   Applications allocate a block of memory by old memory block
+ *
+ * Input Parameters:
+ *   ptr  - old memory pointer
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_realloc(void *ptr, size_t size)
+{
+  return realloc(ptr, size);
+}
+
+/****************************************************************************
+ * Name: esp_calloc_internal
+ *
+ * Description:
+ *   Applications allocate some continuous blocks of memory
+ *
+ * Input Parameters:
+ *   n    - memory block number
+ *   size - memory block size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_calloc(size_t n, size_t size)
+{
+  return calloc(n, size);
+}
+
+/****************************************************************************
+ * Name: esp_zalloc_internal
+ *
+ * Description:
+ *   Applications allocate a block of memory and clear it with 0
+ *
+ * Input Parameters:
+ *   size - memory size
+ *
+ * Returned Value:
+ *   New memory pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_zalloc(size_t size)
+{
+  return zalloc(size);
+}
+
+/****************************************************************************
+ * Name: esp_wifi_create_queue
+ *
+ * Description:
+ *   Create WiFi static message queue
+ *
+ * Input Parameters:
+ *   queue_len - queue message number
+ *   item_size - message size
+ *
+ * Returned Value:
+ *   WiFi static message queue data pointer
+ *
+ ****************************************************************************/
+
+static void *esp_wifi_create_queue(int32_t queue_len, int32_t item_size)
+{
+  wifi_static_queue_t *wifi_queue;
+
+  wifi_queue = kmm_malloc(sizeof(wifi_static_queue_t));
+  if (!wifi_queue)
+    {
+      wlerr("ERROR: Failed to malloc\n");
+      return NULL;
+    }
+
+  wifi_queue->handle = esp_queue_create(queue_len, item_size);
+  if (!wifi_queue->handle)
+    {
+      wlerr("ERROR: Failed to create queue\n");
+      kmm_free(wifi_queue);
+      return NULL;
+    }
+
+  return wifi_queue;
+}
+
+/****************************************************************************
+ * Name: esp_wifi_delete_queue
+ *
+ * Description:
+ *   Delete WiFi static message queue
+ *
+ * Input Parameters:
+ *   queue - WiFi static message queue data pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_wifi_delete_queue(void *queue)
+{
+  wifi_static_queue_t *wifi_queue = (wifi_static_queue_t *)queue;
+
+  esp_queue_delete(wifi_queue->handle);
+  kmm_free(wifi_queue);
+}
+
+/****************************************************************************
+ * Name: esp_modem_enter_sleep
+ *
+ * Description:
+ *   Let given module to enter sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_enter_sleep(uint32_t module)
+{
+  int ret = 0;
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  if (!(s_esp32_module_mask & bit))
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_module_sleep |= bit;
+  if (!s_esp32_sleep && (s_esp32_module_sleep == s_esp32_module_mask))
+    {
+      ret = esp_phy_deinit_rf(PHY_MODEM_MODULE);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to close RF\n");
+        }
+      else
+        {
+          s_esp32_sleep = true;
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_modem_enter_sleep
+ *
+ * Description:
+ *   Let given module to exit from sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_exit_sleep(uint32_t module)
+{
+  int ret = 0;
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  if (!(s_esp32_module_mask & bit))
+    {
+      return -1;
+    }
+
+  flags = enter_critical_section();
+
+  s_esp32_module_sleep &= ~bit;
+  if (s_esp32_sleep)
+    {
+      ret = esp_phy_rf_init(NULL, PHY_RF_CAL_NONE,
+                            NULL, PHY_MODEM_MODULE);
+      if (ret)
+        {
+          wlerr("ERROR: Failed to open RF\n");
+        }
+      else
+        {
+          s_esp32_sleep = false;
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_modem_register_sleep
+ *
+ * Description:
+ *   Regitser given module so that it can enter sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_register_sleep(uint32_t module)
+{
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  flags = enter_critical_section();
+
+  if (s_esp32_module_mask & bit)
+    {
+      /* Has registered and return success */
+
+      return 0;
+    }
+
+  s_esp32_module_mask |= bit;
+  s_esp32_module_sleep |= bit;
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_modem_deregister_sleep
+ *
+ * Description:
+ *   Deregitser given module so that it can't enter sleep mode
+ *
+ * Input Parameters:
+ *   module - hardware module ID
+ *
+ * Returned Value:
+ *   0 if success or -1 if fail
+ *
+ ****************************************************************************/
+
+static int32_t esp_modem_deregister_sleep(uint32_t module)
+{
+  int ret;
+  irqstate_t flags;
+  uint32_t bit;
+
+  if (module >= (uint32_t)MODEM_MODULE_COUNT)
+    {
+      return -1;
+    }
+
+  bit = 1 << module;
+
+  flags = enter_critical_section();
+
+  if (!(s_esp32_module_mask & bit))
+    {
+      /* Has deregistered and return success */
+
+      return 0;
+    }
+
+  s_esp32_module_mask &= ~bit;
+  s_esp32_module_sleep &= ~bit;
+  if (!s_esp32_module_mask)
+    {
+      s_esp32_module_mask = 0;
+      if (s_esp32_sleep)
+        {
+          s_esp32_sleep = false;
+          ret = esp_phy_rf_init(NULL, PHY_RF_CAL_NONE,
+                                NULL, PHY_MODEM_MODULE);
+          if (ret)
+            {
+              wlerr("ERROR: Failed to open RF\n");
+            }
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_coex_status_get
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static uint32_t esp_coex_status_get(void)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_coex_condition_set
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static void esp_coex_condition_set(uint32_t type, bool dissatisfy)
+{
+}
+
+/****************************************************************************
+ * Name: esp_coex_wifi_request
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static int32_t esp_coex_wifi_request(uint32_t event, uint32_t latency,
+                                     uint32_t duration)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_coex_wifi_release
+ *
+ * Description:
+ *   Don't support
+ *
+ ****************************************************************************/
+
+static int32_t esp_coex_wifi_release(uint32_t event)
+{
+  return 0;
+}
+
+/****************************************************************************
+ * Functions needed by libphy.a
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_dport_access_reg_read
+ *
+ * Description:
+ *   Read regitser value safely in SMP
+ *
+ * Input Parameters:
+ *   reg - Regitser address
+ *
+ * Returned Value:
+ *   Regitser value
+ *
+ ****************************************************************************/
+
+uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
+{
+#ifdef CONFIG_SMP
+  DEBUGASSERT(0);
+#else
+  return getreg32(reg);
+#endif
+}
+
+/****************************************************************************
+ * Name: phy_enter_critical
+ *
+ * Description:
+ *   Enter critical state
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   CPU PS value
+ *
+ ****************************************************************************/
+
+uint32_t IRAM_ATTR phy_enter_critical(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  return flags;
+}
+
+/****************************************************************************
+ * Name: phy_exit_critical
+ *
+ * Description:
+ *   Exit from critical state
+ *
+ * Input Parameters:
+ *   level - CPU PS value
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void IRAM_ATTR phy_exit_critical(uint32_t level)
+{
+  leave_critical_section(level);
+}
+
+/****************************************************************************
+ * Name: phy_printf
+ *
+ * Description:
+ *   Output format string and its arguments
+ *
+ * Input Parameters:
+ *   format - format string
+ *
+ * Returned Value:
+ *   0
+ *
+ ****************************************************************************/
+
+int phy_printf(const char *format, ...)
+{
+  va_list arg;
+
+  va_start(arg, format);
+  vsyslog(LOG_INFO, format, arg);
+  va_end(arg);
+
+  return 0;
+}

Review comment:
       why not use wlinfo?

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* WiFi interrupt adapter private data */
+
+struct irq_adpt
+{
+  void (*func)(void *arg);  /* Interrupt callback function */
+  void *arg;                /* Interrupt private data */
+};
+
+/* WiFi message queue private data */
+
+struct mq_adpt
+{
+  mqd_t    mq;              /* Message queue handle */
+  uint32_t msgsize;         /* Message size */
+  char     name[16];        /* Message queue name */
+};
+
+/* WiFi time private data */
+
+struct time_adpt
+{
+  time_t      sec;          /* Second value */
+  suseconds_t usec;         /* Micro second value */
+};
+
+/* WiFi timer private data */
+
+struct timer_adpt
+{
+  struct wdog_s wdog;       /* Timer handle */
+  struct work_s work;       /* Work priavte data */

Review comment:
       ```suggestion
     struct work_s work;       /* Work private data */
   ```

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)

Review comment:
       make this configurable?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494719069



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > Yes, you are right. Because the `3rdparty` is just created, and we will talk about create like branch `release/vX.X` to bind with NuttX specific branch, so now please let me use master now.
   
   Before merging it will be better to point to a specific commit, even if that commit is the latest one. The point is that the build should be reproducible and using master means that every build could be different since master changed in between. If you later need to update the commit, a quick PR is all that is needed to change the hash.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r502262236



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       In this case it's referring to the `esp_txavail` function.
   Fixed too. Thanks.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r501662502



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them reference the same functions that no longer exist (e.g. \<chip\>_txavail_process).
   Could you please review this documentation?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494718502



##########
File path: arch/xtensa/src/esp32/Kconfig
##########
@@ -531,4 +533,24 @@ config ESP32_ETH_PHY_ADDR
 
 endmenu # ESP32_EMAC
 
+menu "WiFi configuration"
+	depends on ESP32_WIRELESS
+
+config ESP32_WIFI_SAVE_PARAM
+	bool "Save WiFi Parameters"
+	default n
+	help
+		Enable this option, WiFi adapter save WiFi parameters
+		into file system without generating or calculating some
+		connection parameters again.

Review comment:
       Great, I will list the more important parameters for users, but some background parameters for wifi, I think they are not needed to be mentioned, because users don't use this directly and they event don't care about this.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494717555



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       Yes, you are right. Because the `3rdparty` is just created, and we will talk about create like branch `release/vX.X` to bind with NuttX specific branch, so now please let me use master now.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-701341136


   > > I only added comments to some simple things because I cannot really review the actual contents of this PR since I'm not familiar with WiFi code in NuttX. However, I must say that the adapter file has a **lot** going on, it is a really big file with lots of auxiliary functions. Also, I feel that is quite an obscure implementation, it is very difficult to understand what is this code doing in general, I only get little pieces by looking at the small comments for each function.
   > > It would be good to add some general documentation, either in the form of a README or simple as more detailed comments explaining what all this code is doing and what each part is doing.
   > > I fear that besides the obvious fact that there's some closed code behind this, this code itself will be difficult to maintain/debug by someone else as is.
   > > That said, I really appreciate the support for ESP32 WiFi on NuttX.
   > 
   > hi @v01d good points. In fact in the IDF we have a document describing about the WiFi driver blocks, maybe it could come to NuttX as well. It could be added later, but now we just need guarantee that everything is integrated correctly on NuttX.
   
   Some time ago we mentioned that new functionality should be accompanied with documentation. I understand that if the documentation addition is considerable, it can be in a separate PR. But in that case I think it is best to add a separate issue to track the pending documentation, as it was done for the note driver.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] masayuki2009 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
masayuki2009 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-711476115


   Hi @donghengqaz,
   
   I confirmed that esp32-core:wapi works with the latest upstream.
   However, I noticed that the following message are shown in the console.
   
   ```
   nsh> esp_receive: WARNING: DROPPED Too big: 718
   esp_receive: WARNING: DROPPED Too big: 698
   ...
   ```
   
   According to the .config, CONFIG_NET_ETH_PKTSIZE was set to 590.
   I think this value is small for Wi-Fi.
   Shall you change this value?
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494725449



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > Before merging it will be better to point to a specific commit, even if that commit is the latest one. The point is that the build should be reproducible and using master means that every build could be different since master changed in between. If you later need to update the commit, a quick PR is all that is needed to change the hash.
   
   OK, it is meaningful.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698352503


   > > @patacongo @xiaoxiang781216 @v01d @btashton @liuguo09
   > > Please note that this PR also adds ARCH_SRC to the context/clean_context directories.
   > 
   > Should we split context/clean_context change to another patch because it's unrelated to WiFi driver.
   
   Yes, and actually, if this is only needed for this arch. Maybe we can also do this change for this arch? Maybe this minimizes risks of regressions.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] masayuki2009 edited a comment on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
masayuki2009 edited a comment on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-705254004


   > Now that the release branch was created, can we give this another look please?
   
   @Ouss4 
   I think you need to resolve conflicts to be merged.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] xiaoxiang781216 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698351489






----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698336847


   Very exciting PR! Sadly I don't have an ESP32 to try it out. Hopefully someone else can.
   Adding the `-` to all includes for Make.defs on arch Makefiles isn't something we got away from recently? I understand this may be necessary since the Makefile will be called before the board Make.defs is in place, right?
   I'm guessing we should also note the License of the resulting binary if the closed blob is included in the build.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] xiaoxiang781216 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698351489


   > @patacongo @xiaoxiang781216 @v01d @btashton @liuguo09
   > Please note that this PR also adds ARCH_SRC to the context/clean_context directories.
   
   Should we split context/clean_context change to another patch because it's unrelated to WiFi driver.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r501658341



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid

Review comment:
       Reference to wrong function name.
   ```suggestion
     /* Loop while while esp_recvframe() successfully retrieves valid
   ```

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. xxx_txavail_process).

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. <chip>_txavail_process).

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. \<chip\>_txavail_process).

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. \<chip\>_txavail_process).
   Could you please review this documentation?

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them reference the same functions that no longer exist (e.g. \<chip\>_txavail_process).
   Could you please review this documentation?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-701984724


   > > I think that it is better to separate the firmware download from the build process and even store it on our git in a common firmware folder
   > > What for you think ?
   > 
   > I'm not sure it would be compatible with Apache license. Anyway, downloading external projects is very common in NuttX build, don't see why we can't do it here as well.
   
   Even though it's Apache licensed I think it will be treated as third-party.  That repository is meant to be general and can be used by other projects.  It makes sense to have it outside of our code base. 
   And as Matias said we already have the option of downloading external projects, part of this PR just adds that possibility to the arch/ folder.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698354075


   > Yes, and actually, if this is only needed for this arch. Maybe we can also do this change for this arch? Maybe this minimizes risks of regressions.
   
   If we add ARCH_SRC to `context` all archs have to provide a `context` target otherwise they won't build.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-706351508


   It is important that the documentation is clear, and not just a copy and paste from other implementation.
   Please, try not to leave misleading comments in the source code.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494729432



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > > `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic.
   > 
   > It would be better to split this file then into different files, each with a specific function. It will be easier to review and maintain.
   > 
   > But please try to add some general comment of what the code is doing, how this adapting layer works, etc.
   
   Adding more comment to introduce the principle how the adapter works is meaningful. But I would not like to split `adapter` into multiply files, because they are adapter's private function, and mainly just adapter of OS APIs, not realize some wifi functions.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-707085261


   The conflicts have been resolved and the comments addressed.  Can we please give it a look and hopefully a merge?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] v01d commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
v01d commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-701340554


   > I think that it is better to separate the firmware download from the build process and even store it on our git in a common firmware folder
   > 
   > What for you think ?
   
   I'm not sure it would be compatible with Apache license. Anyway, downloading external projects is very common in NuttX build, don't see why we can't do it here as well.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494720457



##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)

Review comment:
       Of course.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r501662502



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. \<chip\>_txavail_process).
   Could you please review this documentation?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r501662502



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. \<chip\>_txavail_process).




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-711489218


   > Hi @donghengqaz,
   > 
   > I confirmed that esp32-core:wapi works with the latest upstream.
   > However, I noticed that the following message are shown in the console.
   > 
   > ```
   > nsh> esp_receive: WARNING: DROPPED Too big: 718
   > esp_receive: WARNING: DROPPED Too big: 698
   > ...
   > ```
   > 
   > According to the .config, CONFIG_NET_ETH_PKTSIZE was set to 590.
   > I think this value is small for Wi-Fi.
   > Shall you change this value?
   
   @masayuki2009 Yes, this value is small for WiFi and also for Ethernet, I will add configuration of appropriate value into config file. Thanks for your pointing at this. 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] acassis commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
acassis commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698889964


   > I only added comments to some simple things because I cannot really review the actual contents of this PR since I'm not familiar with WiFi code in NuttX. However, I must say that the adapter file has a **lot** going on, it is a really big file with lots of auxiliary functions. Also, I feel that is quite an obscure implementation, it is very difficult to understand what is this code doing in general, I only get little pieces by looking at the small comments for each function.
   > 
   > It would be good to add some general documentation, either in the form of a README or simple as more detailed comments explaining what all this code is doing and what each part is doing.
   > I fear that besides the obvious fact that there's some closed code behind this, this code itself will be difficult to maintain/debug by someone else as is.
   > 
   > That said, I really appreciate the support for ESP32 WiFi on NuttX.
   
   hi @v01d good points. In fact in the IDF we have a document describing about the WiFi driver blocks, maybe it could come to NuttX as well. It could be added later, but now we just need guarantee that everything is integrated correctly on NuttX.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r502261719



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid

Review comment:
       Done.

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       In this case it's referring to the `esp_txavail` function.
   Fixed too. Thanks.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494326670



##########
File path: arch/arm/src/Makefile
##########
@@ -35,7 +35,7 @@
 ############################################################################
 
 include $(TOPDIR)/Make.defs
-include chip/Make.defs
+-include chip/Make.defs

Review comment:
       why change? I think chip/Make.defs isn't an optional file.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r501662502



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while stm32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),
+ *   2. When new TX data is available (esp32_txavail_process), and
+ *   3. After a TX timeout to restart the sending process
+ *      (stm32_txtimeout_process).

Review comment:
       I've found that these steps are replicated through several ethernet driver implementations (STM32, SAM, tiva, rx65n...), and all of them are reference the same functions that no longer exist (e.g. <chip>_txavail_process).




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] masayuki2009 merged pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
masayuki2009 merged pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] donghengqaz commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
donghengqaz commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494716868



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > I only added comments to some simple things because I cannot really review the actual contents of this PR since I'm not familiar with WiFi code in NuttX. However, I must say that the adapter file has a **lot** going on, it is a really big file with lots of auxiliary functions. Also, I feel that is quite an obscure implementation, it is very difficult to understand what is this code doing in general, I only get little pieces by looking at the small comments for each function.
   > 
   > It would be good to add some general documentation, either in the form of a README or simple as more detailed comments explaining what all this code is doing and what each part is doing.
   > I fear that besides the obvious fact that there's some closed code behind this, this code itself will be difficult to maintain/debug by someone else as is.
   > 
   > That said, I really appreciate the support for ESP32 WiFi on NuttX.
   
   There are 2 main source files, one is `esp32_wlan.c` and another is `esp32_wifi_adapter.c`, we can think the `esp32_wlan.c` is alike with `esp32_emac.c`, and it realizes the Ethernet communication. `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic. 
   
   But when espressif developed the wifi driver, they don't fully consider porting this driver to other OS platforms, so there are some complex designing which I think should be taken into libraries. Because these logic functions are not related to porting OS adapter functions. So I have been trying to improve the wifi adapter layer to reduce the functions which we should add to support other OS.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       Yes, you are right. Because the `3rdparty` is just created, and we will talk about create like branch `release/vX.X` to bind with NuttX specific branch, so now please let me use master now.

##########
File path: arch/xtensa/src/esp32/Kconfig
##########
@@ -531,4 +533,24 @@ config ESP32_ETH_PHY_ADDR
 
 endmenu # ESP32_EMAC
 
+menu "WiFi configuration"
+	depends on ESP32_WIRELESS
+
+config ESP32_WIFI_SAVE_PARAM
+	bool "Save WiFi Parameters"
+	default n
+	help
+		Enable this option, WiFi adapter save WiFi parameters
+		into file system without generating or calculating some
+		connection parameters again.

Review comment:
       Great, I will list the more important parameters for users, but some background parameters for wifi, I think they are not needed to be mentioned, because users don't use this directly and they event don't care about this.

##########
File path: arch/xtensa/src/esp32/esp32_wifi_adapter.c
##########
@@ -0,0 +1,4443 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wifi_adapter.c
+ *
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <mqueue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <clock/clock.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "nuttx/kmalloc.h"
+#include "nuttx/spinlock.h"
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/kthread.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/sched.h>
+#include <nuttx/signal.h>
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_emac.h"
+#include "esp32_cpuint.h"
+#include "esp32_wifi_adapter.h"
+
+#include "espidf_wifi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHY_RF_MASK   ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE))
+
+#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM
+#  define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT
+#  define NVS_DIR_BASE  NVS_FS_PREFIX"/wifi."
+#  define NVS_FILE_MODE 0777
+#endif
+
+#define WIFI_CONNECT_TIMEOUT  (10)

Review comment:
       Of course.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > Before merging it will be better to point to a specific commit, even if that commit is the latest one. The point is that the build should be reproducible and using master means that every build could be different since master changed in between. If you later need to update the commit, a quick PR is all that is needed to change the hash.
   
   OK, it is meaningful.

##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > > `esp32_wifi_adapter.c` is mainly contains of `OS adapter` fucntions, like `task, semaphore, mutex, message queue`, even including `libc`, `log`, `file system` and so on. So it mainly have no specific logic.
   > 
   > It would be better to split this file then into different files, each with a specific function. It will be easier to review and maintain.
   > 
   > But please try to add some general comment of what the code is doing, how this adapting layer works, etc.
   
   Adding more comment to introduce the principle how the adapter works is meaningful. But I would not like to split `adapter` into multiply files, because they are adapter's private function, and mainly just adapter of OS APIs, not realize some wifi functions.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r494815701



##########
File path: arch/xtensa/src/esp32/Make.defs
##########
@@ -136,3 +136,36 @@ ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
 CHIP_CSRCS += esp32_modtext.c
 CMN_ASRCS += xtensa_loadstore.S
 endif
+
+ifeq ($(CONFIG_ESP32_WIRELESS),y)
+WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
+WIRELESS_DRV_ZIP     = master.zip
+WIRELESS_DRV_URL     = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive

Review comment:
       > The point is that the build should be reproducible and using master means that every build could be different since master changed in between. If you later need to update the commit, a quick PR is all that is needed to change the hash.
   
   There isn't much going on in that repository, it consists mostly of static libraries and header files.  The risk of a huge change that would break this config is low.
   That said, the script will be updated once a release/tag is created, the repo is relatively new.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] ghn-certi commented on a change in pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
ghn-certi commented on a change in pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#discussion_r502610057



##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while esp32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.
+   * This may disable further Tx interrupts if there are no pending
+   * transmissions.
+   */
+
+  net_unlock();
+  if (priv->esp_dev.d_buf)
+    {
+      priv->esp_dev.d_buf = NULL;
+      memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf));
+      priv->rx_len = 0;
+    }
+
+  esp_givesem(priv);
+}
+
+/****************************************************************************
+ * Function: esp_dopoll
+ *
+ * Description:
+ *   The function is called in order to perform an out-of-sequence TX poll.
+ *   This is done:
+ *
+ *   1. After completion of a transmission (esp32_txdone),

Review comment:
       esp32_txdone does not seem to be defined.

##########
File path: arch/xtensa/src/esp32/esp32_wlan.c
##########
@@ -0,0 +1,1589 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_wlan.c
+ *
+ * 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 <debug.h>
+#include <queue.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/netdev.h>
+#include <crc64.h>
+
+#if defined(CONFIG_NET_PKT)
+#  include <nuttx/net/pkt.h>
+#endif
+
+#include <nuttx/net/net.h>
+#include <nuttx/kmalloc.h>
+#include <debug.h>
+
+#include "esp32_wifi_adapter.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_ESP32_WIRELESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Only one ESP32 */
+
+#ifndef CONFIG_ESP32_NINTERFACES
+#  define CONFIG_ESP32_NINTERFACES 1
+#endif
+#define STA_DEVNO                  0           
+
+/* TX poll delay = 1 seconds.
+ * CLK_TCK is the number of clock ticks per second
+ */
+
+#define ESP_WDDELAY                (1*CLK_TCK)
+#define ESPWORK                    LPWORK
+
+/* TX timeout = 1 minute */
+
+#define ESP_TXTIMEOUT              (60*CLK_TCK)
+#define DEFAULT_SCAN_LIST_SIZE     2
+
+/* Add 4 to the configured buffer size to account for the 2 byte checksum
+ * memory needed at the end of the maximum size packet.  Buffer sizes must
+ * be an even multiple of 4, 8, or 16 bytes (depending on buswidth).  We
+ * will use the 16-byte alignment in all cases.
+ */
+
+#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15)
+
+#ifndef CONFIG_ESP_ETH_BUFSIZE
+#  define CONFIG_ESP_ETH_BUFSIZE   OPTIMAL_ETH_BUFSIZE
+#endif
+
+#ifndef CONFIG_ESP_ETH_NTXDESC
+#  define CONFIG_ESP_ETH_NTXDESC   4
+#endif
+
+/* We need at least one more free buffer than transmit buffers */
+
+#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1)
+#define ETH_MAX_LEN                1518
+
+/* This is a helper pointer for accessing the contents of wlan header */
+
+#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The esp_dev_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct esp_dev_s
+{
+  bool   ifup;                  /* true:ifup false:ifdown */
+  struct wdog_s esp_txpoll;     /* TX poll timer */
+  struct wdog_s esp_txtimeout;  /* TX timeout timer */
+  struct work_s esp_irqwork;    /* For deferring interrupt work to the work queue */
+  struct work_s esp_pollwork;   /* For deferring poll work to the work queue */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s esp_dev;
+  sq_queue_t           freeb;    /* The free buffer list */
+  sem_t              waitsem;    /* Implements event waiting */
+
+  /* Buffer allocations */
+
+  uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE];
+  uint8_t rxbuf[ETH_MAX_LEN];
+  uint32_t rx_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct esp_dev_s g_esp32[CONFIG_ESP32_NINTERFACES];
+static bool g_tx_ready = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv);
+#define     esp_givesem(priv) (nxsem_post(&priv->waitsem))
+
+/* Free buffer management */
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv);
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv);
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer);
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv);
+
+/* Common TX logic */
+
+static int  esp_transmit(FAR struct esp_dev_s *priv);
+static void esp_receive(FAR struct esp_dev_s *priv);
+static int  esp_txpoll(FAR struct net_driver_s *dev);
+static void esp_rxpoll(FAR void *arg);
+static void esp_dopoll(FAR struct esp_dev_s *priv);
+static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv,
+                                 void *buffer, uint16_t len);
+static int esp_sta_input(void *buffer, uint16_t len, void *eb);
+
+/* Watchdog timer expirations */
+
+static void esp_txtimeout_work(FAR void *arg);
+static void esp_txtimeout_expiry(wdparm_t arg);
+
+static void esp_poll_work(FAR void *arg);
+static void esp_poll_expiry(wdparm_t arg);
+
+/* NuttX callback functions */
+
+static int  esp_ifup(struct net_driver_s *dev);
+static int  esp_ifdown(struct net_driver_s *dev);
+
+static void esp_txavail_work(FAR void *arg);
+static int  esp_txavail(struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_MCASTGROUP
+static int  esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  esp_ioctl(struct net_driver_s *dev, int cmd,
+              unsigned long arg);
+#endif
+static void esp_sem_initialize(FAR struct esp_dev_s *priv);
+static int esp32_net_initialize(unsigned int devno);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_takesem
+ *
+ * Description:
+ *   Take the wait semaphore (handling false alarm wakeups due to the receipt
+ *   of signals).
+ *
+ * Input Parameters:
+ *   dev - Instance of the esp32 wlan driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_takesem(struct esp_dev_s *priv)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(&priv->waitsem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Function: esp_initbuffer
+ *
+ * Description:
+ *   Initialize the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called during early driver initialization before Ethernet interrupts
+ *   are enabled.
+ *
+ ****************************************************************************/
+
+static void esp_initbuffer(FAR struct esp_dev_s *priv)
+{
+  uint8_t *buffer;
+  int i;
+
+  /* Initialize the head of the free buffer list */
+
+  sq_init(&priv->freeb);
+
+  /* Add all of the pre-allocated buffers to the free buffer list */
+
+  for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS;
+       i++, buffer += CONFIG_ESP_ETH_BUFSIZE)
+    {
+      sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+    }
+}
+
+/****************************************************************************
+ * Function: esp_allocbuffer
+ *
+ * Description:
+ *   Allocate one buffer from the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer on success; NULL on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv)
+{
+  /* Allocate a buffer by returning the head of the free buffer list */
+
+  return (uint8_t *)sq_remfirst(&priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_freebuffer
+ *
+ * Description:
+ *   Return a buffer to the free buffer list.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *   buffer - A pointer to the buffer to be freed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void esp_freebuffer(FAR struct esp_dev_s *priv,
+                                  uint8_t *buffer)
+{
+  /* Free the buffer by adding it to the end of the free buffer list */
+
+  sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb);
+}
+
+/****************************************************************************
+ * Function: esp_isfreebuffer
+ *
+ * Description:
+ *   Return TRUE if the free buffer list is not empty.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   True if there are one or more buffers in the free buffer list;
+ *   false if the free buffer list is empty
+ *
+ * Assumptions:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv)
+{
+  /* Return TRUE if the free buffer list is not empty */
+
+  return !sq_empty(&priv->freeb);
+}
+
+/****************************************************************************
+ * Name: esp_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_transmit(FAR struct esp_dev_s *priv)
+{
+  int ret = 0;
+  uint8_t *buffer;
+  uint32_t buffer_len;
+
+  /* Set up all but the last TX descriptor */
+
+  buffer = priv->esp_dev.d_buf;
+  buffer_len = priv->esp_dev.d_len;
+  ret = esp_wifi_sta_send_data(buffer, buffer_len);
+
+  if (ret != 0)
+    {
+      wlerr("ERROR: Failed to transmit frame\n");
+      (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT,
+                     esp_txtimeout_expiry, (uint32_t)priv);
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_recvframe
+ *
+ * Description:
+ *   The function is called when a frame is received using the DMA receive
+ *   interrupt.  It scans the RX descriptors of the received frame.
+ *
+ *   NOTE: This function will silently discard any packets containing errors.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK if a packet was successfully returned; -EAGAIN if there are no
+ *   further packets available
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int esp_recvframe(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+  uint8_t *buffer;
+  uint32_t buffer_len = 0;
+  buffer = dev->d_buf;
+  buffer_len = dev->d_len;
+
+  /* Check if there are free buffers.  We cannot receive new frames in this
+   * design unless there is at least one free buffer.
+   */
+
+  if (!esp_isfreebuffer(priv))
+    {
+      wlerr("ERROR: No free buffers\n");
+      return -ENOMEM;
+    }
+
+  /* Check if any errors are reported in the frame */
+
+  if (buffer == NULL || buffer_len == 0)
+    {
+      return -EAGAIN;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: esp_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void esp_receive(FAR struct esp_dev_s *priv)
+{
+  struct net_driver_s *dev = &priv->esp_dev;
+
+  /* Loop while while esp32_recvframe() successfully retrieves valid
+   * Ethernet frames.
+   */
+
+  while (esp_recvframe(priv) == OK)
+    {
+#ifdef CONFIG_NET_PKT
+
+      /* When packet sockets are enabled,
+       * feed the frame into the packet tap.
+       */
+
+      pkt_input(&priv->esp_dev);
+#endif
+
+      /* Check if the packet is a valid size for the network
+       * buffer configuration (this should not happen)
+       */
+
+      if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
+        {
+          wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
+
+          /* Free dropped packet buffer */
+
+          if (dev->d_buf)
+            {
+              esp_freebuffer(priv, dev->d_buf);
+              dev->d_buf = NULL;
+              dev->d_len = 0;
+            }
+
+          continue;
+        }
+
+      /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+      if (BUF->type == HTONS(ETHTYPE_IP))
+        {
+          wlinfo("IPv4 frame\n");
+
+          /* Handle ARP on input then give the IPv4 packet to the network
+           * layer
+           */
+
+          arp_ipin(&priv->esp_dev);
+          ipv4_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network,
+           * the field  d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+                {
+                  arp_out(&priv->esp_dev);
+                }
+#ifdef CONFIG_NET_IPv6
+              else
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_IPv6
+      if (BUF->type == HTONS(ETHTYPE_IP6))
+        {
+          wlinfo("Iv6 frame\n");
+
+          /* Give the IPv6 packet to the network layer */
+
+          ipv6_input(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+              if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+                {
+                  arp_out(&priv->esp_dev);
+                }
+              else
+#endif
+#ifdef CONFIG_NET_IPv6
+                {
+                  neighbor_out(&priv->esp_dev);
+                }
+#endif
+
+              /* And send the packet */
+
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+#ifdef CONFIG_NET_ARP
+      if (BUF->type == htons(ETHTYPE_ARP))
+        {
+          wlinfo("ARP frame\n");
+
+          /* Handle ARP packet */
+
+          arp_arpin(&priv->esp_dev);
+
+          /* If the above function invocation resulted in data
+           * that should be sent out on the network, the field
+           * d_len will set to a value > 0.
+           */
+
+          if (priv->esp_dev.d_len > 0)
+            {
+              esp_transmit(priv);
+            }
+        }
+      else
+#endif
+        {
+          wlerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type);
+        }
+
+      /* We are finished with the RX buffer.  NOTE:  If the buffer is
+       * re-used for transmission, the dev->d_buf field will have been
+       * nullified.
+       */
+
+      if (dev->d_buf)
+        {
+          /* Free the receive packet buffer */
+
+          esp_freebuffer(priv, dev->d_buf);
+          dev->d_buf = NULL;
+          dev->d_len = 0;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: esp_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send times out and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   the network is locked.
+ *
+ ****************************************************************************/
+
+static int esp_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private;
+
+  DEBUGASSERT(priv->esp_dev.d_buf != NULL);
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->esp_dev.d_len > 0)
+    {
+      /* Look up the destination MAC address and add it to the Ethernet
+       * header.
+       */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+      if (IFF_IS_IPv4(priv->esp_dev.d_flags))
+#endif
+        {
+          arp_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+      else
+#endif
+        {
+          neighbor_out(&priv->esp_dev);
+        }
+#endif /* CONFIG_NET_IPv6 */
+
+      if (!devif_loopback(&priv->esp_dev))
+        {
+          /* Send the packet */
+
+          int ret = esp_transmit(priv);
+          if (ret != OK)
+            {
+              wlerr("TX failed\r\n");
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until
+   * all connections have been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_rxpoll
+ *
+ * Description:
+ *   Process RX frames
+ *
+ * Input Parameters:
+ *   arg - context of device to use
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static void esp_rxpoll(FAR void *arg)
+{
+  FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg;
+
+  if (priv->esp_dev.d_buf == NULL)
+    {
+      priv->esp_dev.d_buf = priv->rxbuf;
+      priv->esp_dev.d_len = priv->rx_len;
+    }
+  else
+    {
+      wlinfo("priv->esp_dev.d_buf != NULL");
+      return;
+    }
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  esp_takesem(priv);
+
+  net_lock();
+
+  esp_receive(priv);
+
+  /* Check if a packet transmission just completed.  If so, call esp_txdone.

Review comment:
       esp_txdone does not seem to exist.
   Please review this comment.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] Ouss4 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
Ouss4 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-698351407


   @donghengqaz please run `./tools/refresh.sh --silent esp32-core:wapi` to update the defconfig, it's preventing the builds to run.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] masayuki2009 commented on pull request #1893: xtensa/esp32: Add ESP32 WiFi adapter and driver

Posted by GitBox <gi...@apache.org>.
masayuki2009 commented on pull request #1893:
URL: https://github.com/apache/incubator-nuttx/pull/1893#issuecomment-705254004


   > Now that the release branch was created, can we give this another look please?
   
   @Ouss4 
   I think you need to resolve conflicts.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org