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/10/09 08:13:05 UTC

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

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