chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
ESP-WIFI-MESH Programming Guide
|
||||
===============================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
This is a programming guide for ESP-WIFI-MESH, including the API reference and coding examples. This guide is split into the following parts:
|
||||
|
||||
1. :ref:`mesh-programming-model`
|
||||
|
||||
2. :ref:`mesh-writing-mesh-application`
|
||||
|
||||
3. :ref:`mesh-self-organized-behavior`
|
||||
|
||||
4. :ref:`mesh-application-examples`
|
||||
|
||||
5. :ref:`mesh-api-reference`
|
||||
|
||||
For documentation regarding the ESP-WIFI-MESH protocol, please see the :doc:`ESP-WIFI-MESH API Guide <../../api-guides/esp-wifi-mesh>`. For more information about ESP-WIFI-MESH Development Framework, please see `ESP-WIFI-MESH Development Framework <https://github.com/espressif/esp-mdf>`_.
|
||||
|
||||
|
||||
.. ---------------------- ESP-WIFI-MESH Programming Model --------------------------
|
||||
|
||||
.. _mesh-programming-model:
|
||||
|
||||
ESP-WIFI-MESH Programming Model
|
||||
-------------------------------------
|
||||
|
||||
Software Stack
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The ESP-WIFI-MESH software stack is built atop the Wi-Fi Driver/FreeRTOS and may use the LwIP Stack in some instances (i.e., the root node). The following diagram illustrates the ESP-WIFI-MESH software stack.
|
||||
|
||||
.. _mesh-going-to-software-stack:
|
||||
|
||||
.. figure:: ../../../_static/mesh-software-stack.png
|
||||
:align: center
|
||||
:alt: ESP-WIFI-MESH Software Stack
|
||||
:figclass: align-center
|
||||
|
||||
ESP-WIFI-MESH Software Stack
|
||||
|
||||
.. _mesh-events:
|
||||
|
||||
System Events
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
An application interfaces with ESP-WIFI-MESH via **ESP-WIFI-MESH Events**. Since ESP-WIFI-MESH is built atop the Wi-Fi stack, it is also possible for the application to interface with the Wi-Fi driver via the **Wi-Fi Event Task**. The following diagram illustrates the interfaces for the various System Events in an ESP-WIFI-MESH application.
|
||||
|
||||
.. figure:: ../../../_static/mesh-events-delivery.png
|
||||
:align: center
|
||||
:alt: ESP-WIFI-MESH System Events Delivery
|
||||
:figclass: align-center
|
||||
|
||||
ESP-WIFI-MESH System Events Delivery
|
||||
|
||||
The :cpp:type:`mesh_event_id_t` defines all possible ESP-WIFI-MESH events and can indicate events such as the connection/disconnection of parent/child. Before ESP-WIFI-MESH events can be used, the application must register a **Mesh Events handler** via :cpp:func:`esp_event_handler_register` to the default event task. The Mesh Events handler that is registered contain handlers for each ESP-WIFI-MESH event relevant to the application.
|
||||
|
||||
Typical use cases of mesh events include using events such as :cpp:enumerator:`MESH_EVENT_PARENT_CONNECTED` and :cpp:enumerator:`MESH_EVENT_CHILD_CONNECTED` to indicate when a node can begin transmitting data upstream and downstream respectively. Likewise, :cpp:enumerator:`IP_EVENT_STA_GOT_IP` and :cpp:enumerator:`IP_EVENT_STA_LOST_IP` can be used to indicate when the root node can and cannot transmit data to the external IP network.
|
||||
|
||||
.. warning::
|
||||
|
||||
When using ESP-WIFI-MESH under self-organized mode, users must ensure that no calls to Wi-Fi API are made. This is due to the fact that the self-organizing mode will internally make Wi-Fi API calls to connect/disconnect/scan etc. **Any Wi-Fi calls from the application (including calls from callbacks and handlers of Wi-Fi events) may interfere with ESP-WIFI-MESH's self-organizing behavior**. Therefore, users should not call Wi-Fi APIs after :cpp:func:`esp_mesh_start` is called, and before :cpp:func:`esp_mesh_stop` is called.
|
||||
|
||||
LwIP & ESP-WIFI-MESH
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The application can access the ESP-WIFI-MESH stack directly without having to go through the LwIP stack. The LwIP stack is only required by the root node to transmit/receive data to/from an external IP network. However, since every node can potentially become the root node (due to automatic root node selection), each node must still initialize the LwIP stack.
|
||||
|
||||
**Each node that could become root is required to initialize LwIP by calling** :cpp:func:`esp_netif_init`. In order to prevent non-root node access to LwIP, the application should not create or register any network interfaces using esp_netif APIs.
|
||||
|
||||
|
||||
ESP-WIFI-MESH requires a root node to be connected with a router. Therefore, in the event that a node becomes the root, **the corresponding handler must start the DHCP client service and immediately obtain an IP address**. Doing so will allow other nodes to begin transmitting/receiving packets to/from the external IP network. However, this step is unnecessary if static IP settings are used.
|
||||
|
||||
|
||||
.. ---------------------- Writing a Mesh Application --------------------------
|
||||
|
||||
.. _mesh-writing-mesh-application:
|
||||
|
||||
Writing an ESP-WIFI-MESH Application
|
||||
-------------------------------------------
|
||||
|
||||
The prerequisites for starting ESP-WIFI-MESH is to initialize LwIP and Wi-Fi, The following code snippet demonstrates the necessary prerequisite steps before ESP-WIFI-MESH itself can be initialized.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* event initialization */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Wi-Fi initialization */
|
||||
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&config));
|
||||
/* register IP events handler */
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
After initializing LwIP and Wi-Fi, the process of getting an ESP-WIFI-MESH network up and running can be summarized into the following three steps:
|
||||
|
||||
1. :ref:`mesh-initialize-mesh`
|
||||
2. :ref:`mesh-configuring-mesh`
|
||||
3. :ref:`mesh-start-mesh`
|
||||
|
||||
.. _mesh-initialize-mesh:
|
||||
|
||||
Initialize Mesh
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following code snippet demonstrates how to initialize ESP-WIFI-MESH
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* mesh initialization */
|
||||
ESP_ERROR_CHECK(esp_mesh_init());
|
||||
/* register mesh events handler */
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL));
|
||||
|
||||
.. _mesh-configuring-mesh:
|
||||
|
||||
Configuring an ESP-WIFI-MESH Network
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. todo - Add note about unified configuration
|
||||
|
||||
ESP-WIFI-MESH is configured via :cpp:func:`esp_mesh_set_config` which receives its arguments using the :cpp:type:`mesh_cfg_t` structure. The structure contains the following parameters used to configure ESP-WIFI-MESH:
|
||||
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 15 25
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - Channel
|
||||
- Range from 1 to 14
|
||||
|
||||
* - Mesh ID
|
||||
- ID of ESP-WIFI-MESH Network, see :cpp:type:`mesh_addr_t`
|
||||
|
||||
* - Router
|
||||
- Router Configuration, see :cpp:type:`mesh_router_t`
|
||||
|
||||
* - Mesh AP
|
||||
- Mesh AP Configuration, see :cpp:type:`mesh_ap_cfg_t`
|
||||
|
||||
* - Crypto Functions
|
||||
- Crypto Functions for Mesh IE, see :cpp:type:`mesh_crypto_funcs_t`
|
||||
|
||||
|
||||
The following code snippet demonstrates how to configure ESP-WIFI-MESH.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Enable the Mesh IE encryption by default */
|
||||
mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
|
||||
/* mesh ID */
|
||||
memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
|
||||
/* channel (must match the router's channel) */
|
||||
cfg.channel = CONFIG_MESH_CHANNEL;
|
||||
/* router */
|
||||
cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID);
|
||||
memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len);
|
||||
memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD,
|
||||
strlen(CONFIG_MESH_ROUTER_PASSWD));
|
||||
/* mesh softAP */
|
||||
cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS;
|
||||
memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD,
|
||||
strlen(CONFIG_MESH_AP_PASSWD));
|
||||
ESP_ERROR_CHECK(esp_mesh_set_config(&cfg));
|
||||
|
||||
.. _mesh-start-mesh:
|
||||
|
||||
Start Mesh
|
||||
^^^^^^^^^^
|
||||
|
||||
The following code snippet demonstrates how to start ESP-WIFI-MESH.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* mesh start */
|
||||
ESP_ERROR_CHECK(esp_mesh_start());
|
||||
|
||||
After starting ESP-WIFI-MESH, the application should check for ESP-WIFI-MESH events to determine when it has connected to the network. After connecting, the application can start transmitting and receiving packets over the ESP-WIFI-MESH network using :cpp:func:`esp_mesh_send` and :cpp:func:`esp_mesh_recv`.
|
||||
|
||||
|
||||
.. --------------------- ESP-WIFI-MESH Application Examples ------------------------
|
||||
|
||||
.. _mesh-self-organized-behavior:
|
||||
|
||||
Self-Organized Networking
|
||||
-------------------------
|
||||
|
||||
Self-organized networking is a feature of ESP-WIFI-MESH where nodes can autonomously scan/select/connect/reconnect to other nodes and routers. This feature allows an ESP-WIFI-MESH network to operate with high degree of autonomy by making the network robust to dynamic network topologies and conditions. With self-organized networking enabled, nodes in an ESP-WIFI-MESH network are able to carry out the following actions without autonomously:
|
||||
|
||||
- Selection or election of the root node (see **Automatic Root Node Selection** in :ref:`mesh-building-a-network`)
|
||||
- Selection of a preferred parent node (see **Parent Node Selection** in :ref:`mesh-building-a-network`)
|
||||
- Automatic reconnection upon detecting a disconnection (see **Intermediate Parent Node Failure** in :ref:`mesh-managing-a-network`)
|
||||
|
||||
When self-organized networking is enabled, the ESP-WIFI-MESH stack will internally make calls to Wi-Fi APIs. Therefore, **the application layer should not make any calls to Wi-Fi APIs whilst self-organized networking is enabled as doing so would risk interfering with ESP-WIFI-MESH**.
|
||||
|
||||
Toggling Self-Organized Networking
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Self-organized networking can be enabled or disabled by the application at runtime by calling the :cpp:func:`esp_mesh_set_self_organized` function. The function has the two following parameters:
|
||||
|
||||
- ``bool enable`` specifies whether to enable or disable self-organized networking.
|
||||
|
||||
- ``bool select_parent`` specifies whether a new parent node should be selected when enabling self-organized networking. Selecting a new parent has different effects depending the node type and the node's current state. This parameter is unused when disabling self-organized networking.
|
||||
|
||||
Disabling Self-Organized Networking
|
||||
"""""""""""""""""""""""""""""""""""
|
||||
The following code snippet demonstrates how to disable self-organized networking.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
//Disable self-organized networking
|
||||
esp_mesh_set_self_organized(false, false);
|
||||
|
||||
ESP-WIFI-MESH will attempt to maintain the node's current Wi-Fi state when disabling self-organized networking.
|
||||
|
||||
- If the node was previously connected to other nodes, it will remain connected.
|
||||
- If the node was previously disconnected and was scanning for a parent node or router, it will stop scanning.
|
||||
- If the node was previously attempting to reconnect to a parent node or router, it will stop reconnecting.
|
||||
|
||||
Enabling Self-Organized Networking
|
||||
""""""""""""""""""""""""""""""""""
|
||||
|
||||
ESP-WIFI-MESH will attempt to maintain the node's current Wi-Fi state when enabling self-organized networking. However, depending on the node type and whether a new parent is selected, the Wi-Fi state of the node can change. The following table shows effects of enabling self-organized networking.
|
||||
|
||||
+---------------+--------------+------------------------------------------------------------------------------------------------------------------+
|
||||
| Select Parent | Is Root Node | Effects |
|
||||
+===============+==============+==================================================================================================================+
|
||||
| N | N | - Nodes already connected to a parent node will remain connected. |
|
||||
| | | - Nodes previously scanning for a parent nodes will stop scanning. Call :cpp:func:`esp_mesh_connect` to restart. |
|
||||
| +--------------+------------------------------------------------------------------------------------------------------------------+
|
||||
| | Y | - A root node already connected to router will stay connected. |
|
||||
| | | - A root node disconnected from router will need to call :cpp:func:`esp_mesh_connect` to reconnect. |
|
||||
+---------------+--------------+------------------------------------------------------------------------------------------------------------------+
|
||||
| Y | N | - Nodes without a parent node will automatically select a preferred parent and connect. |
|
||||
| | | - Nodes already connected to a parent node will disconnect, reselect a preferred parent node, and connect. |
|
||||
| +--------------+------------------------------------------------------------------------------------------------------------------+
|
||||
| | Y | - For a root node to connect to a parent node, it must give up it's role as root. Therefore, a root node will |
|
||||
| | | disconnect from the router and all child nodes, select a preferred parent node, and connect. |
|
||||
+---------------+--------------+------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
The following code snipping demonstrates how to enable self-organized networking.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
//Enable self-organized networking and select a new parent
|
||||
esp_mesh_set_self_organized(true, true);
|
||||
|
||||
...
|
||||
|
||||
//Enable self-organized networking and manually reconnect
|
||||
esp_mesh_set_self_organized(true, false);
|
||||
esp_mesh_connect();
|
||||
|
||||
|
||||
Calling Wi-Fi API
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
There can be instances in which an application may want to directly call Wi-Fi API whilst using ESP-WIFI-MESH. For example, an application may want to manually scan for neighboring APs. However, **self-organized networking must be disabled before the application calls any Wi-Fi APIs**. This will prevent the ESP-WIFI-MESH stack from attempting to call any Wi-Fi APIs and potentially interfering with the application's calls.
|
||||
|
||||
Therefore, application calls to Wi-Fi APIs should be placed in between calls of :cpp:func:`esp_mesh_set_self_organized` which disable and enable self-organized networking. The following code snippet demonstrates how an application can safely call :cpp:func:`esp_wifi_scan_start` whilst using ESP-WIFI-MESH.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
//Disable self-organized networking
|
||||
esp_mesh_set_self_organized(0, 0);
|
||||
|
||||
//Stop any scans already in progress
|
||||
esp_wifi_scan_stop();
|
||||
//Manually start scan. Will automatically stop when run to completion
|
||||
esp_wifi_scan_start();
|
||||
|
||||
//Process scan results
|
||||
|
||||
...
|
||||
|
||||
//Re-enable self-organized networking if still connected
|
||||
esp_mesh_set_self_organized(1, 0);
|
||||
|
||||
...
|
||||
|
||||
//Re-enable self-organized networking if non-root and disconnected
|
||||
esp_mesh_set_self_organized(1, 1);
|
||||
|
||||
...
|
||||
|
||||
//Re-enable self-organized networking if root and disconnected
|
||||
esp_mesh_set_self_organized(1, 0); //Do not select new parent
|
||||
esp_mesh_connect(); //Manually reconnect to router
|
||||
|
||||
|
||||
.. --------------------- ESP-WIFI-MESH Application Examples ------------------------
|
||||
|
||||
.. _mesh-application-examples:
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`mesh/internal_communication` demonstrates how to use the mesh APIs to establish a mesh network, configure it, start it, handle events, and send and receive messages across the network.
|
||||
|
||||
- :example:`mesh/ip_internal_network` demonstrates how to use mesh to create an IP capable sub-network where all nodes publish their IP and internal mesh layer to an MQTT broker while using internal communication.
|
||||
|
||||
- :example:`mesh/manual_networking` demonstrates how to manually configure a mesh network using ESP-MESH, including scanning for parent candidates, selecting a suitable parent for a node, and configuring network settings.
|
||||
|
||||
.. ------------------------- ESP-WIFI-MESH API Reference ---------------------------
|
||||
|
||||
.. _mesh-api-reference:
|
||||
|
||||
API Reference
|
||||
--------------
|
||||
|
||||
.. include-build-file:: inc/esp_mesh.inc
|
||||
@@ -0,0 +1,29 @@
|
||||
Wi-Fi Easy Connect\ :sup:`TM` (DPP)
|
||||
===================================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Wi-Fi Easy Connect\ :sup:`TM`, also known as Device Provisioning Protocol (DPP) or Easy Connect, is a provisioning protocol certified by Wi-Fi Alliance. It is a secure and standardized provisioning protocol for configuration of Wi-Fi Devices. With Easy Connect, adding a new device to a network is as simple as scanning a QR Code. This reduces complexity and enhances user experience while onboarding devices without UI like Smart Home and IoT products. Unlike old protocols like Wi-Fi Protected Setup (WPS), Wi-Fi Easy Connect incorporates strong encryption through public key cryptography to ensure networks remain secure as new devices are added.
|
||||
|
||||
Easy Connect brings many benefits in the user experience:
|
||||
|
||||
- Simple and intuitive to use; no lengthy instructions to follow for new device setup
|
||||
- No need to remember and enter passwords into the device being provisioned
|
||||
- Works with electronic or printed QR codes, or human-readable strings
|
||||
- Supports both WPA2 and WPA3 networks
|
||||
|
||||
Please refer to Wi-Fi Alliance's official page on `Easy Connect <https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect>`_ for more information.
|
||||
|
||||
{IDF_TARGET_NAME} supports Enrollee mode of Easy Connect with QR Code as the provisioning method. A display is required to display this QR Code. Users can scan this QR Code using their capable device and provision the {IDF_TARGET_NAME} to their Wi-Fi network. The provisioning device needs to be connected to the AP which need not support Wi-Fi Easy Connect\ :sup:`TM`.
|
||||
|
||||
Easy Connect is still an evolving protocol. Of known platforms that support the QR Code method are some Android smartphones with Android 10 or higher. To use Easy Connect, no additional App needs to be installed on the supported smartphone.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`wifi/wifi_easy_connect/dpp-enrollee` demonstrates how to configure {IDF_TARGET_NAME} as an enrollee using DPP to securely onboard ESP devices to a network with the help of a QR code and an Android 10+ device.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/esp_dpp.inc
|
||||
@@ -0,0 +1,700 @@
|
||||
Ethernet
|
||||
========
|
||||
|
||||
{IDF_TARGET_SOC_DMA_DESC_SIZE:default="", esp32="32 bytes", esp32p4=" 32 bytes (64 bytes in fact due to the need for proper memory alignment)"}
|
||||
{IDF_TARGET_SOC_REF_CLK_IN_GPIO:default="", esp32="GPIO0", esp32p4="GPIO32, GPIO44 and GPIO50"}
|
||||
{IDF_TARGET_SOC_REF_CLK_OUT_GPIO:default="", esp32="GPIO0, GPIO16 and GPIO17", esp32p4="GPIO23 and GPIO39"}
|
||||
{IDF_TARGET_SOC_RMII_TX_EN:default="", esp32="GPIO21", esp32p4="GPIO33, GPIO40 and GPIO49"}
|
||||
{IDF_TARGET_SOC_RMII_TXD0:default="", esp32="GPIO19", esp32p4="GPIO34 and GPIO41"}
|
||||
{IDF_TARGET_SOC_RMII_TXD1:default="", esp32="GPIO22", esp32p4="GPIO35 and GPIO42"}
|
||||
{IDF_TARGET_SOC_RMII_CRS_DV:default="", esp32="GPIO27", esp32p4="GPIO28, GPIO45 and GPIO51"}
|
||||
{IDF_TARGET_SOC_RMII_RXD0:default="", esp32="GPIO25", esp32p4="GPIO29, GPIO46 and GPIO52"}
|
||||
{IDF_TARGET_SOC_RMII_RXD1:default="", esp32="GPIO26", esp32p4="GPIO30, GPIO47 and GPIO53"}
|
||||
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
.. -------------------------------- Overview -----------------------------------
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
.. only:: SOC_EMAC_SUPPORTED
|
||||
|
||||
ESP-IDF provides a set of consistent and flexible APIs to support both internal Ethernet MAC (EMAC) controller and external SPI-Ethernet modules.
|
||||
|
||||
.. only:: not SOC_EMAC_SUPPORTED
|
||||
|
||||
ESP-IDF provides a set of consistent and flexible APIs to support external SPI-Ethernet modules.
|
||||
|
||||
This programming guide is split into the following sections:
|
||||
|
||||
1. :ref:`basic-ethernet-concepts`
|
||||
2. :ref:`driver-configuration-and-installation`
|
||||
3. :ref:`connect-driver-to-stack`
|
||||
4. :ref:`misc-operation-of-driver`
|
||||
|
||||
.. --------------------------- Basic Ethernet Concepts ------------------------------
|
||||
|
||||
.. _basic-ethernet-concepts:
|
||||
|
||||
Basic Ethernet Concepts
|
||||
-----------------------
|
||||
|
||||
Ethernet is an asynchronous Carrier Sense Multiple Access with Collision Detect (CSMA/CD) protocol/interface. It is generally not well suited for low-power applications. However, with ubiquitous deployment, internet connectivity, high data rates, and limitless-range expandability, Ethernet can accommodate nearly all wired communications.
|
||||
|
||||
Normal IEEE 802.3 compliant Ethernet frames are between 64 and 1518 bytes in length. They are made up of five or six different fields: a destination MAC address (DA), a source MAC address (SA), a type/length field, a data payload, an optional padding field and a Cyclic Redundancy Check (CRC). Additionally, when transmitted on the Ethernet medium, a 7-byte preamble field and Start-of-Frame (SOF) delimiter byte are appended to the beginning of the Ethernet packet.
|
||||
|
||||
Thus the traffic on the twist-pair cabling appears as shown below:
|
||||
|
||||
.. rackdiag:: ../../../_static/diagrams/ethernet/data_frame_format.diag
|
||||
:caption: Ethernet Data Frame Format
|
||||
:align: center
|
||||
|
||||
Preamble and Start-of-Frame Delimiter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The preamble contains seven bytes of ``55H``. It allows the receiver to lock onto the stream of data before the actual frame arrives.
|
||||
|
||||
The Start-of-Frame Delimiter (SFD) is a binary sequence ``10101011`` (as seen on the physical medium). It is sometimes considered to be part of the preamble.
|
||||
|
||||
When transmitting and receiving data, the preamble and SFD bytes will be automatically generated or stripped from the packets.
|
||||
|
||||
Destination Address
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The destination address field contains a 6-byte length MAC address of the device that the packet is directed to. If the Least Significant bit in the first byte of the MAC address is set, the address is a multicast destination. For example, 01-00-00-00-F0-00 and 33-45-67-89-AB-CD are multi-cast addresses, while 00-00-00-00-F0-00 and 32-45-67-89-AB-CD are not.
|
||||
|
||||
Packets with multi-cast destination addresses are designed to arrive and be important to a selected group of Ethernet nodes. If the destination address field is the reserved multicast address, i.e., FF-FF-FF-FF-FF-FF, the packet is a broadcast packet and it will be directed to everyone sharing the network. If the Least Significant bit in the first byte of the MAC address is clear, the address is a unicast address and will be designed for usage by only the addressed node.
|
||||
|
||||
Normally the EMAC controller incorporates receive filters which can be used to discard or accept packets with multi-cast, broadcast and/or unicast destination addresses. When transmitting packets, the host controller is responsible for writing the desired destination address into the transmit buffer.
|
||||
|
||||
Source Address
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The source address field contains a 6-byte length MAC address of the node which created the Ethernet packet. Users of Ethernet must generate a unique MAC address for each controller used. MAC addresses consist of two portions. The first three bytes are known as the Organizationally Unique Identifier (OUI). OUIs are distributed by the IEEE. The last three bytes are address bytes at the discretion of the company that purchased the OUI. For more information about MAC Address used in ESP-IDF, please see :ref:`MAC Address Allocation <MAC-Address-Allocation>`.
|
||||
|
||||
When transmitting packets, the assigned source MAC address must be written into the transmit buffer by the host controller.
|
||||
|
||||
Type/Length
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The type/length field is a 2-byte field. If the value in this field is <= 1500 (decimal), it is considered a length field and it specifies the amount of non-padding data which follows in the data field. If the value is >= 1536, it represents the protocol the following packet data belongs to. The following are the most common type values:
|
||||
|
||||
* IPv4 = 0800H
|
||||
* IPv6 = 86DDH
|
||||
* ARP = 0806H
|
||||
|
||||
Users implementing proprietary networks may choose to treat this field as a length field, while applications implementing protocols such as the Internet Protocol (IP) or Address Resolution Protocol (ARP), should program this field with the appropriate type defined by the protocol's specification when transmitting packets.
|
||||
|
||||
Payload
|
||||
^^^^^^^
|
||||
|
||||
The payload field is a variable length field, anywhere from 0 to 1500 bytes. Larger data packets violates Ethernet standards and will be dropped by most Ethernet nodes.
|
||||
|
||||
This field contains the client data, such as an IP datagram.
|
||||
|
||||
Padding and FCS
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The padding field is a variable length field added to meet the IEEE 802.3 specification requirements when small data payloads are used.
|
||||
|
||||
The DA, SA, type, payload, and padding of an Ethernet packet must be no smaller than 60 bytes in total. If the required 4-byte FCS field is added, packets must be no smaller than 64 bytes. If the payload field is less than 46-byte long, a padding field is required.
|
||||
|
||||
The FCS field is a 4-byte field that contains an industry-standard 32-bit CRC calculated with the data from the DA, SA, type, payload, and padding fields. Given the complexity of calculating a CRC, the hardware normally automatically generates a valid CRC and transmit it. Otherwise, the host controller must generate the CRC and place it in the transmit buffer.
|
||||
|
||||
Normally, the host controller does not need to concern itself with padding and the CRC which the hardware EMAC will also be able to automatically generate when transmitting and verify when receiving. However, the padding and CRC fields will be written into the receive buffer when packets arrive, so they may be evaluated by the host controller if needed.
|
||||
|
||||
.. note::
|
||||
Besides the basic data frame described above, there are two other common frame types in 10/100 Mbps Ethernet: control frames and VLAN-tagged frames. They are not supported in ESP-IDF.
|
||||
|
||||
.. ------------------------------ Driver Operation --------------------------------
|
||||
|
||||
.. _driver-configuration-and-installation:
|
||||
|
||||
Configure MAC and PHY
|
||||
---------------------
|
||||
|
||||
The Ethernet driver is composed of two parts: MAC and PHY.
|
||||
|
||||
.. only:: SOC_EMAC_SUPPORTED
|
||||
|
||||
The communication between MAC and PHY can have diverse choices: **MII** (Media Independent Interface), **RMII** (Reduced Media Independent Interface), etc.
|
||||
|
||||
.. figure:: ../../../_static/rmii-interface.png
|
||||
:scale: 80 %
|
||||
:alt: Ethernet RMII Interface
|
||||
:figclass: align-center
|
||||
|
||||
Ethernet RMII Interface
|
||||
|
||||
One of the obvious differences between MII and RMII is signal consumption. MII usually costs up to 18 signals, while the RMII interface can reduce the consumption to 9.
|
||||
|
||||
.. note::
|
||||
ESP-IDF only supports the RMII interface. Therefore, always set :cpp:member:`eth_esp32_emac_config_t::interface` to :cpp:enumerator:`eth_data_interface_t::EMAC_DATA_INTERFACE_RMII`.
|
||||
|
||||
In RMII mode, both the receiver and transmitter signals are referenced to the ``REF_CLK``. ``REF_CLK`` **must be stable during any access to PHY and MAC**. Generally, there are three ways to generate the ``REF_CLK`` depending on the PHY device in your design:
|
||||
|
||||
* Some PHY chips can derive the ``REF_CLK`` from its externally connected 25 MHz crystal oscillator (as seen the option **a** in the picture). In this case, you should configure :cpp:member:`eth_mac_clock_config_t::clock_mode` of :cpp:member:`eth_esp32_emac_config_t::clock_config` to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`.
|
||||
|
||||
* Some PHY chip uses an externally connected 50 MHz crystal oscillator or other clock sources, which can also be used as the ``REF_CLK`` for the MAC side (as seen the option **b** in the picture). In this case, you still need to configure :cpp:member:`eth_mac_clock_config_t::clock_mode` of :cpp:member:`eth_esp32_emac_config_t::clock_config` to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`.
|
||||
|
||||
* Some EMAC controllers can generate the ``REF_CLK`` using an internal high-precision PLL (as seen the option **c** in the picture). In this case, you should configure :cpp:member:`eth_mac_clock_config_t::clock_mode` of :cpp:member:`eth_esp32_emac_config_t::clock_config` to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
.. warning::
|
||||
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`, internal Audio PLL clock is used as a source of 50 MHz clock. Hence be sure it is not in collision with I2S bus configuration.
|
||||
|
||||
When internal clock is selected, then ``GPIO0`` can be used to output the ``REF_CLK`` signal. However, the clock is outputted directly to the GPIO in this particular case and so it does not have direct relationship with EMAC peripheral. Sometimes this configuration may not work well with your PHY chip. If you are not using PSRAM in your design, GPIO16 and GPIO17 are also available to output the reference clock signal. The source of clock is the same (APLL) but these signals are routed from EMAC peripheral.
|
||||
|
||||
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`, then ``GPIO0`` is the only choice to input the ``REF_CLK`` signal. Please note that ``GPIO0`` is also an important strapping GPIO on ESP32. If GPIO0 samples a low level during power-up, ESP32 will go into download mode. The system will get halted until a manually reset. The workaround for this issue is disabling the ``REF_CLK`` in hardware by default so that the strapping pin is not interfered by other signals in the boot stage. Then, re-enable the ``REF_CLK`` in the Ethernet driver installation stage.
|
||||
|
||||
The ways to disable the ``REF_CLK`` signal can be:
|
||||
|
||||
* Disable or power down the crystal oscillator (as the case **b** in the picture).
|
||||
|
||||
* Force the PHY device to reset status (as the case **a** in the picture). **This could fail for some PHY device** (i.e., it still outputs signals to GPIO0 even in reset state).
|
||||
|
||||
.. warning::
|
||||
|
||||
If you want the **Ethernet to work with Wi-Fi or Bluetooth**, don’t select ESP32 as source of ``REF_CLK`` as it would result in ``REF_CLK`` instability. Either disable Wi-Fi or use a PHY or an external oscillator as the ``REF_CLK`` source.
|
||||
|
||||
.. only:: not esp32
|
||||
|
||||
.. note::
|
||||
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`, {IDF_TARGET_SOC_REF_CLK_OUT_GPIO} can be selected as output pin of the ``REF_CLK`` signal via IO_MUX.
|
||||
|
||||
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`, {IDF_TARGET_SOC_REF_CLK_IN_GPIO} can be selected as input pin for the ``REF_CLK`` signal via IO_MUX.
|
||||
|
||||
.. only:: esp32p4
|
||||
|
||||
.. warning::
|
||||
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`, the EMAC derives the 50 MHz RMII reference clock from the MPLL via an integer divider. When PSRAM is also enabled, both peripherals share the MPLL, and PSRAM locks it to a frequency determined by its speed configuration. If PSRAM speed is configured to 80 MHz (:ref:`CONFIG_SPIRAM_SPEED`), the MPLL runs at 320 MHz, and no integer divisor of 320 MHz can produce 50 MHz within the required ±50 ppm tolerance (the closest candidate is 320 / 6 ≈ 53.33 MHz). EMAC initialization will fail in this configuration.
|
||||
|
||||
If you must use 80 MHz PSRAM speed, provide the ``REF_CLK`` from an external source (PHY or oscillator) and configure :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN` instead.
|
||||
|
||||
.. only:: not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK
|
||||
|
||||
.. warning::
|
||||
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`, the ``REF_CLK`` output signal must be looped back to the EMAC externally. You have to configure :cpp:member:`eth_mac_clock_config_t::clock_mode` of :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in` to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN` and select GPIO number associated with ``REF_CLK`` input GPIO's ({IDF_TARGET_SOC_REF_CLK_IN_GPIO}).
|
||||
|
||||
.. only:: esp32p4
|
||||
|
||||
.. figure:: ../../../_static/rmii_ref_clk_esp32p4.png
|
||||
:scale: 95 %
|
||||
:alt: RMII REF_CKL Output Loopback
|
||||
:figclass: align-center
|
||||
|
||||
RMII REF_CKL Output Loopback
|
||||
|
||||
**No matter which RMII clock mode you select, you really need to take care of the signal integrity of REF_CLK in your hardware design!** Keep the trace as short as possible. Keep it away from RF devices and inductor elements.
|
||||
|
||||
.. only:: not SOC_EMAC_USE_MULTI_IO_MUX
|
||||
|
||||
.. note::
|
||||
Signals used in the data plane are fixed to specific GPIOs via IO_MUX, they can not be modified to other GPIOs. Signals used in the control plane can be routed to any free GPIOs via Matrix. Please refer to `ESP32-Ethernet-Kit <https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-ethernet-kit/index.html>`_ for hardware design example.
|
||||
|
||||
.. only:: SOC_EMAC_USE_MULTI_IO_MUX
|
||||
|
||||
.. note::
|
||||
Signals used in the data plane can be configured to predefined set of GPIOs via IO_MUX for the RMII, see below table. The data plane GPIO configuration is performed by the driver based on content of :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`. Signals used in the control plane can be routed to any free GPIOs via GPIO Matrix.
|
||||
|
||||
.. list-table:: {IDF_TARGET_NAME} RMII Data Plane GPIO
|
||||
:header-rows: 1
|
||||
:widths: 50 50
|
||||
:align: center
|
||||
|
||||
* - Pin Name
|
||||
- GPIO Number
|
||||
|
||||
* - TX_EN
|
||||
- {IDF_TARGET_SOC_RMII_TX_EN}
|
||||
|
||||
* - TXD0
|
||||
- {IDF_TARGET_SOC_RMII_TXD0}
|
||||
|
||||
* - TXD1
|
||||
- {IDF_TARGET_SOC_RMII_TXD1}
|
||||
|
||||
* - CRS_DV
|
||||
- {IDF_TARGET_SOC_RMII_CRS_DV}
|
||||
|
||||
* - RXD0
|
||||
- {IDF_TARGET_SOC_RMII_RXD0}
|
||||
|
||||
* - RXD1
|
||||
- {IDF_TARGET_SOC_RMII_RXD1}
|
||||
|
||||
You need to set up the necessary parameters for MAC and PHY respectively based on your Ethernet board design, and then combine the two together to complete the driver installation.
|
||||
|
||||
Basic common configuration for MAC layer is described in :cpp:class:`eth_mac_config_t`, including:
|
||||
|
||||
.. list::
|
||||
|
||||
* :cpp:member:`eth_mac_config_t::sw_reset_timeout_ms`: software reset timeout value, in milliseconds. Typically, MAC reset should be finished within 100 ms.
|
||||
|
||||
* :cpp:member:`eth_mac_config_t::rx_task_stack_size` and :cpp:member:`eth_mac_config_t::rx_task_prio`: the MAC driver creates a dedicated task to process incoming packets. These two parameters are used to set the stack size and priority of the task.
|
||||
|
||||
* :cpp:member:`eth_mac_config_t::flags`: specifying extra features that the MAC driver should have, it could be useful in some special situations. The value of this field can be OR'd with macros prefixed with ``ETH_MAC_FLAG_``. For example, if the MAC driver should work when the cache is disabled, then you should configure this field with :c:macro:`ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE`.
|
||||
|
||||
.. only:: SOC_EMAC_SUPPORTED
|
||||
|
||||
Specific configuration for **internal MAC module** is described in :cpp:class:`eth_esp32_emac_config_t`, including:
|
||||
|
||||
.. list::
|
||||
|
||||
* :cpp:member:`eth_esp32_emac_config_t::smi_mdc_gpio_num` and :cpp:member:`eth_esp32_emac_config_t::smi_mdio_gpio_num`: the GPIO number used to connect the SMI signals.
|
||||
|
||||
* :cpp:member:`eth_esp32_emac_config_t::interface`: configuration of MAC Data interface to PHY (MII/RMII).
|
||||
|
||||
* :cpp:member:`eth_esp32_emac_config_t::clock_config`: configuration of EMAC Interface clock (``REF_CLK`` mode and GPIO number in case of RMII).
|
||||
|
||||
* :cpp:member:`eth_esp32_emac_config_t::intr_priority`: sets the priority of the MAC interrupt. If it is set to ``0`` or a negative value, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. Note that *Low* and *Medium* interrupt priorities (1 to 3) can be set since these can be handled in C.
|
||||
|
||||
:SOC_EMAC_USE_MULTI_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers.
|
||||
|
||||
:not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`: configuration of EMAC input interface clock when ``REF_CLK`` signal is generated internally and is looped back to the EMAC externally. The mode must be always configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`. This option is valid only when configuration of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`.
|
||||
|
||||
Memory Considerations when Using Internal MAC
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The internal MAC subsystem transfers data to and from the CPU domain via DMA using a linked list of descriptors. There are two types of descriptors: Transmit and Receive. Based on its type, a descriptor holds status information about the received or transmitted frame or provides controls for transmission. Each descriptor also contains pointers to the current data buffer and the next descriptor. As such, a single EMAC DMA descriptor has size of {IDF_TARGET_SOC_DMA_DESC_SIZE} in DMA-capable memory.
|
||||
|
||||
The default configuration should cover most use cases. However, certain scenarios may require configuring the Ethernet DMA memory utilization to suit specific needs. Typical problems may arise in the following situations:
|
||||
|
||||
.. list::
|
||||
|
||||
* **Short and frequent frames dominate network traffic**: If your network traffic primarily consists of very short and frequently transmitted/received frames, you may observe issues such as lower-than-expected throughput (despite the rated 100 Mbps) and missed frames during reception. On transmission, the socket send API may return ``errno`` equal to ``ENOMEM``, accompanied by the `insufficient TX buffer size` message (if debug log level is enabled). This is because the default memory configuration is optimized for larger frames; :ref:`CONFIG_ETH_DMA_BUFFER_SIZE` is set to 512 bytes by default to ensure a better *data buffer* to *descriptor* size overhead ratio. The solution is to increase :ref:`CONFIG_ETH_DMA_RX_BUFFER_NUM` or :ref:`CONFIG_ETH_DMA_TX_BUFFER_NUM`. Additionally, consider decreasing :ref:`CONFIG_ETH_DMA_BUFFER_SIZE` to match the typical frame size in your network to maintain a reasonable memory footprint of the Ethernet driver.
|
||||
|
||||
* **High throughput leads to buffer exhaustion**: If the socket send API intermittently returns ``errno`` equal to ``ENOMEM``, accompanied by the `insufficient TX buffer size` message (if debug log level is enabled), and the throughput is close to the rated 100 Mbps, this likely indicates nearing hardware limitations. In such case, the hardware cannot keep up with the transmission requests. The solution is to increase :ref:`CONFIG_ETH_DMA_TX_BUFFER_NUM` to buffer more frames and mitigate temporary peaks in transmission requests. However, this will not help if the requested traffic consistently exceeds the rated throughput. In such situations, the only solution is to limit the bandwidth by software means at the application level.
|
||||
|
||||
Configuration for PHY is described in :cpp:class:`eth_phy_config_t`, including:
|
||||
|
||||
.. list::
|
||||
|
||||
* :cpp:member:`eth_phy_config_t::phy_addr`: multiple PHY devices can share the same SMI bus, so each PHY needs a unique address. Usually, this address is configured during hardware design by pulling up/down some PHY strapping pins. You can set the value from ``0`` to ``15`` based on your Ethernet board. Especially, if the SMI bus is shared by only one PHY device, setting this value to ``-1`` can enable the driver to detect the PHY address automatically.
|
||||
|
||||
* :cpp:member:`eth_phy_config_t::reset_timeout_ms`: reset timeout value, in milliseconds. Typically, PHY reset should be finished within 100 ms.
|
||||
|
||||
* :cpp:member:`eth_phy_config_t::autonego_timeout_ms`: auto-negotiation timeout value, in milliseconds. The Ethernet driver starts negotiation with the peer Ethernet node automatically, to determine to duplex and speed mode. This value usually depends on the ability of the PHY device on your board.
|
||||
|
||||
* :cpp:member:`eth_phy_config_t::reset_gpio_num`: if your board also connects the PHY reset pin to one of the GPIO, then set it here. Otherwise, set this field to ``-1``.
|
||||
|
||||
* :cpp:member:`eth_phy_config_t::hw_reset_assert_time_us`: Time the PHY reset pin is asserted in usec. Set this field to ``0`` to use chip specific default timing.
|
||||
|
||||
* :cpp:member:`eth_phy_config_t::post_hw_reset_delay_ms`: Time to wait after the PHY hardware reset is done in msec. Set this field to ``0`` to use chip specific default timing. Set this field to ``-1`` to not wait after the PHY hardware reset.
|
||||
|
||||
ESP-IDF provides a default configuration for MAC and PHY in macro :c:macro:`ETH_MAC_DEFAULT_CONFIG` and :c:macro:`ETH_PHY_DEFAULT_CONFIG`.
|
||||
|
||||
|
||||
Create MAC and PHY Instance
|
||||
---------------------------
|
||||
|
||||
The Ethernet driver is implemented in an Object-Oriented style. Any operation on MAC and PHY should be based on the instance of the two.
|
||||
|
||||
.. only:: SOC_EMAC_SUPPORTED
|
||||
|
||||
Internal EMAC + External PHY
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default common MAC configuration
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); // apply default vendor-specific MAC configuration
|
||||
esp32_emac_config.smi_gpio.mdc_num = CONFIG_ETHERNET_MDC_GPIO; // alter the GPIO used for MDC signal
|
||||
esp32_emac_config.smi_gpio.mdio_num = CONFIG_ETHERNET_MDIO_GPIO; // alter the GPIO used for MDIO signal
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
|
||||
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
|
||||
phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; // alter the PHY address according to your board design
|
||||
phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; // alter the GPIO used for PHY reset
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config); // create generic PHY instance
|
||||
|
||||
.. note::
|
||||
Any Ethernet PHY chip compliant with IEEE 802.3 can be used when creating new PHY instance with :cpp:func:`esp_eth_phy_new_generic`. However, while basic functionality should always work, some specific features might be limited, even if the PHY meets IEEE 802.3 standard. A typical example is loopback functionality, where certain PHYs may require setting a specific speed mode to operate correctly. If this is the concern and you need PHY driver specifically tailored to your chip needs, use drivers for PHY chips the ESP-IDF already officially supports or consult with :ref:`Custom PHY Driver <custom-phy-driver>` section to create a new custom driver.
|
||||
|
||||
.. tip::
|
||||
Espressif provides drivers for several specific Ethernet PHY chips in the `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ repository. Drivers are distributed as components and are available in the `ESP Component Registry <https://components.espressif.com/>`_.
|
||||
|
||||
Optional Runtime MAC Clock Configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
EMAC ``REF_CLK`` can be optionally configured from the user application code.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); // apply default vendor-specific MAC configuration
|
||||
|
||||
// ...
|
||||
|
||||
esp32_emac_config.interface = EMAC_DATA_INTERFACE_RMII; // alter EMAC Data Interface
|
||||
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT; // select EMAC REF_CLK mode
|
||||
esp32_emac_config.clock_config.rmii.clock_gpio = 17; // select GPIO number used to input/output EMAC REF_CLK
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
|
||||
|
||||
|
||||
SPI-Ethernet Module
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default common MAC configuration
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
|
||||
phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; // alter the PHY address according to your board design
|
||||
phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; // alter the GPIO used for PHY reset
|
||||
// Install GPIO interrupt service (as the SPI-Ethernet module is interrupt-driven)
|
||||
gpio_install_isr_service(0);
|
||||
// SPI bus configuration
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_ETHERNET_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_ETHERNET_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_ETHERNET_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_ETHERNET_SPI_HOST, &buscfg, 1));
|
||||
// Configure SPI device
|
||||
spi_device_interface_config_t spi_devcfg = {
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_ETHERNET_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_ETHERNET_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_ETHERNET_SPI_HOST, &spi_devcfg);
|
||||
dm9051_config.int_gpio_num = CONFIG_ETHERNET_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
|
||||
|
||||
.. note::
|
||||
* When creating MAC and PHY instances for SPI-Ethernet modules (e.g., DM9051), the constructor function must have the same suffix (e.g., `esp_eth_mac_new_dm9051` and `esp_eth_phy_new_dm9051`). This is because we don not have other choices but the integrated PHY.
|
||||
|
||||
* The SPI device configuration (i.e., `spi_device_interface_config_t`) may slightly differ for other Ethernet modules or to meet SPI timing on specific PCB. Please check out your module's specs and the examples in ESP-IDF.
|
||||
|
||||
.. tip::
|
||||
Espressif provides drivers for various SPI-Ethernet modules in the `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ repository. Drivers are distributed as components and are available in the `ESP Component Registry <https://components.espressif.com/>`_.
|
||||
|
||||
Install Driver
|
||||
--------------
|
||||
|
||||
To install the Ethernet driver, we need to combine the instance of MAC and PHY and set some additional high-level configurations (i.e., not specific to either MAC or PHY) in :cpp:class:`esp_eth_config_t`:
|
||||
|
||||
* :cpp:member:`esp_eth_config_t::mac`: instance that created from MAC generator (e.g., :cpp:func:`esp_eth_mac_new_esp32`).
|
||||
|
||||
* :cpp:member:`esp_eth_config_t::phy`: instance that created from PHY generator (e.g., :cpp:func:`esp_eth_phy_new_generic`).
|
||||
|
||||
* :cpp:member:`esp_eth_config_t::check_link_period_ms`: Ethernet driver starts an OS timer to check the link status periodically, this field is used to set the interval, in milliseconds.
|
||||
|
||||
* :cpp:member:`esp_eth_config_t::stack_input` or :cpp:member:`esp_eth_config_t::stack_input_info`: In most Ethernet IoT applications, any Ethernet frame received by a driver should be passed to the upper layer (e.g., TCP/IP stack). This field is set to a function that is responsible to deal with the incoming frames. You can even update this field at runtime via function :cpp:func:`esp_eth_update_input_path` after driver installation.
|
||||
|
||||
* :cpp:member:`esp_eth_config_t::on_lowlevel_init_done` and :cpp:member:`esp_eth_config_t::on_lowlevel_deinit_done`: These two fields are used to specify the hooks which get invoked when low-level hardware has been initialized or de-initialized.
|
||||
|
||||
ESP-IDF provides a default configuration for driver installation in macro :c:macro:`ETH_DEFAULT_CONFIG`.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
|
||||
esp_eth_handle_t eth_handle = NULL; // after the driver is installed, we will get the handle of the driver
|
||||
esp_eth_driver_install(&config, ð_handle); // install driver
|
||||
|
||||
The Ethernet driver also includes an event-driven model, which sends useful and important events to user space. We need to initialize the event loop before installing the Ethernet driver. For more information about event-driven programming, please refer to :doc:`ESP Event <../system/esp_event>`.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
/** Event handler for Ethernet events */
|
||||
static void eth_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
uint8_t mac_addr[6] = {0};
|
||||
/* we can get the ethernet driver handle from event data */
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
|
||||
break;
|
||||
case ETHERNET_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Down");
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
ESP_LOGI(TAG, "Ethernet Started");
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
ESP_LOGI(TAG, "Ethernet Stopped");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_event_loop_create_default(); // create a default event loop that runs in the background
|
||||
esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL); // register Ethernet event handler (to deal with user-specific stuff when events like link up/down happened)
|
||||
|
||||
Start Ethernet Driver
|
||||
---------------------
|
||||
|
||||
After driver installation, we can start Ethernet immediately.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
esp_eth_start(eth_handle); // start Ethernet driver state machine
|
||||
|
||||
.. _connect-driver-to-stack:
|
||||
|
||||
Connect Driver to TCP/IP Stack
|
||||
------------------------------
|
||||
|
||||
Up until now, we have installed the Ethernet driver. From the view of OSI (Open System Interconnection), we are still on level 2 (i.e., Data Link Layer). While we can detect link up and down events and gain MAC address in user space, it is infeasible to obtain the IP address, let alone send an HTTP request. The TCP/IP stack used in ESP-IDF is called LwIP. For more information about it, please refer to :doc:`LwIP <../../api-guides/lwip>`.
|
||||
|
||||
To connect the Ethernet driver to TCP/IP stack, follow these three steps:
|
||||
|
||||
1. Create a network interface for the Ethernet driver
|
||||
2. Attach the network interface to the Ethernet driver
|
||||
3. Register IP event handlers
|
||||
|
||||
For more information about the network interface, please refer to :doc:`Network Interface <esp_netif>`.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
|
||||
ESP_LOGI(TAG, "Ethernet Got IP Address");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
|
||||
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
|
||||
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
}
|
||||
|
||||
esp_netif_init()); // Initialize TCP/IP network interface (should be called only once in application)
|
||||
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); // apply default network interface configuration for Ethernet
|
||||
esp_netif_t *eth_netif = esp_netif_new(&cfg); // create network interface for Ethernet driver
|
||||
|
||||
esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); // attach Ethernet driver to TCP/IP stack
|
||||
esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL); // register user defined IP event handlers
|
||||
esp_eth_start(eth_handle); // start Ethernet driver state machine
|
||||
|
||||
.. warning::
|
||||
It is recommended to fully initialize the Ethernet driver and network interface before registering the user's Ethernet/IP event handlers, i.e., register the event handlers as the last thing prior to starting the Ethernet driver. Such an approach ensures that Ethernet/IP events get executed first by the Ethernet driver or network interface so the system is in the expected state when executing the user's handlers.
|
||||
|
||||
.. _misc-operation-of-driver:
|
||||
|
||||
Misc Control of Ethernet Driver
|
||||
-------------------------------
|
||||
|
||||
The following functions should only be invoked after the Ethernet driver has been installed.
|
||||
|
||||
* Stop Ethernet driver: :cpp:func:`esp_eth_stop`
|
||||
* Update Ethernet data input path: :cpp:func:`esp_eth_update_input_path`
|
||||
* Misc get/set of Ethernet driver attributes: :cpp:func:`esp_eth_ioctl`
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
/* get MAC address */
|
||||
uint8_t mac_addr[6];
|
||||
memset(mac_addr, 0, sizeof(mac_addr));
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
|
||||
ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
|
||||
|
||||
/* get PHY address */
|
||||
int phy_addr = -1;
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr);
|
||||
ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr);
|
||||
|
||||
.. _time-stamping:
|
||||
|
||||
.. only:: SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
|
||||
EMAC Hardware Time Stamping
|
||||
---------------------------
|
||||
|
||||
Time stamping in EMAC allows precise tracking of when Ethernet frames are transmitted or received. Hardware time stamping is crucial for applications like Precision Time Protocol (PTP) because it minimizes jitter and inaccuracies that can occur when relying on software time stamps. Embedded time stamps in hardware avoid delays introduced by software layers or processing overhead. Therefore, it ensures nanosecond-level precision.
|
||||
|
||||
.. warning::
|
||||
|
||||
Time stamp associated API is currently in **"Experimental Feature"** state so be aware it may change with future releases.
|
||||
|
||||
The basic way how to enable time stamping, get and set time in the EMAC is demonstrated below.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
esp_eth_mac_t *mac;
|
||||
esp_eth_get_mac_instance(eth_hndl, &mac);
|
||||
|
||||
// Enable hardware time stamping
|
||||
eth_mac_ptp_config_t ptp_cfg = ETH_MAC_ESP_PTP_DEFAULT_CONFIG();
|
||||
esp_eth_mac_ptp_enable(mac, &ptp_cfg);
|
||||
|
||||
// Get current EMAC time
|
||||
eth_mac_time_t ptp_time;
|
||||
esp_eth_mac_get_ptp_time(mac, &ptp_time);
|
||||
|
||||
// Set EMAC time
|
||||
ptp_time = {
|
||||
.seconds = 42,
|
||||
.nanoseconds = 0
|
||||
};
|
||||
esp_eth_mac_set_ptp_time(mac, &ptp_time);
|
||||
|
||||
The PTP module be can configured as follows:
|
||||
|
||||
.. list::
|
||||
* :cpp:member:`eth_mac_ptp_config_t::clk_src`: Clock source for PTP. Select one of the clock sources offered by the :cpp:type:`soc_periph_emac_ptp_clk_src_t` enumeration.
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::clk_src_period_ns`: Period of the clock source for PTP in nanoseconds. For example, if the clock source is 40MHz, the period is 25ns.
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::required_accuracy_ns`: Required accuracy for PTP in nanoseconds. The required accuracy must be worse than clock source for PTP. For example, if the clock source is 40MHz (25ns period), the required accuracy is 40ns.
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::roll_type`: Rollover mode (digital or binary) for subseconds register. The binary rollover mode is recommended as it provides a more precise time synchronization.
|
||||
|
||||
Time stamps for transmitted and received frames can be accessed via the last argument of the registered :cpp:member:`esp_eth_config_t::stack_input_info` function for the receive path, and via the ``ctrl`` argument of the :cpp:func:`esp_eth_transmit_ctrl_vargs` function for the transmit path. However, a more user-friendly approach to retrieve time stamp information in user space is by utilizing the L2 TAP :ref:`Extended Buffer <esp_netif_l2tap_ext_buff>` mechanism.
|
||||
|
||||
You have an option to schedule event at precise point in time by registering callback function and configuring a target time when the event is supposed to be fired. Note that the callback function is then called from ISR context so it should be as brief as possible.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
// Register the callback function
|
||||
esp_eth_mac_set_target_time_cb(mac, ts_callback);
|
||||
|
||||
// Set time when event is triggered
|
||||
eth_mac_time_t mac_target_time = {
|
||||
.seconds = 42,
|
||||
.nanoseconds = 0
|
||||
};
|
||||
esp_eth_mac_set_target_time(mac, &mac_target_time);
|
||||
|
||||
Alternatively, the PTP-synchronized time can be exposed via a PPS (Pulse-Per-Second) signal on a GPIO. This provides a precise hardware time reference that can be used to synchronize external devices, align independent clock domains, or drive time-critical processes outside the ESP32 chip series. As the name suggests, the PPS signal is a pulse that occurs once per second by default. However, the frequency can be adjusted by setting the PPS0 output frequency using the :cpp:func:`esp_eth_mac_set_pps_out_freq` function. The command accepts an integer value in the range of 0-16384, where 0 = 1PPS (narrow pulse), other values generate square clock signal. The clock frequency must be power of two and less than or equal to 16384 Hz. Note that due to non-linear toggling of bits in the digital rollover mode, the actual frequency is an average number (duty cycle differs from 50% in overall one second period). This behavior does not apply to the binary rollover mode and so this mode is recommended. The PPS signal can be configured to be output at a GPIO using the :cpp:func:`esp_eth_mac_set_pps_out_gpio` function.
|
||||
|
||||
.. only:: esp32p4
|
||||
|
||||
.. note::
|
||||
The PPS signal output on GPIO pin is available starting from ESP32-P4 silicon revision 3.
|
||||
|
||||
.. _flow-control:
|
||||
|
||||
Flow Control
|
||||
------------
|
||||
|
||||
Ethernet on MCU usually has a limitation in the number of frames it can handle during network congestion, because of the limitation in RAM size. A sending station might be transmitting data faster than the peer end can accept it. The ethernet flow control mechanism allows the receiving node to signal the sender requesting the suspension of transmissions until the receiver catches up. The magic behind that is the pause frame, which was defined in IEEE 802.3x.
|
||||
|
||||
Pause frame is a special Ethernet frame used to carry the pause command, whose EtherType field is ``0x8808``, with the Control opcode set to ``0x0001``. Only stations configured for full-duplex operation may send pause frames. When a station wishes to pause the other end of a link, it sends a pause frame to the 48-bit reserved multicast address of ``01-80-C2-00-00-01``. The pause frame also includes the period of pause time being requested, in the form of a two-byte integer, ranging from ``0`` to ``65535``.
|
||||
|
||||
After the Ethernet driver installation, the flow control feature is disabled by default. You can enable it by:
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
bool flow_ctrl_enable = true;
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, &flow_ctrl_enable);
|
||||
|
||||
One thing that should be kept in mind is that the pause frame ability is advertised to the peer end by PHY during auto-negotiation. The Ethernet driver sends a pause frame only when both sides of the link support it.
|
||||
|
||||
.. -------------------------------- Examples -----------------------------------
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
* :example:`ethernet/basic` demonstrates how to use the Ethernet driver, covering driver installation, attaching it to `esp_netif`, sending DHCP requests, and obtaining a pingable IP address.
|
||||
|
||||
* :example:`ethernet/iperf` demonstrates how to use the Ethernet capabilities to measure the throughput/bandwidth using iPerf.
|
||||
|
||||
* :example:`ethernet/ptp` demonstrates the use of Precision Time Protocol (PTP) for time synchronization over Ethernet.
|
||||
|
||||
* :example:`network/vlan_support` demonstrates how to create virtual network interfaces over Ethernet, including VLAN and non-VLAN interfaces.
|
||||
|
||||
* :example:`network/sta2eth` demonstrates how to create a 1-to-1 bridge using a Wi-Fi station and a wired interface such as Ethernet or USB.
|
||||
|
||||
* :example:`network/simple_sniffer` demonstrates how to use Wi-Fi and Ethernet in sniffer mode to capture packets and save them in PCAP format.
|
||||
|
||||
* :example:`network/eth2ap` demonstrates how to implement a bridge that forwards packets between an Ethernet port and a Wi-Fi AP interface. It uses {IDF_TARGET_NAME} to create a 1-to-many connection between Ethernet and Wi-Fi without initializing the TCP/IP stack.
|
||||
|
||||
* :example:`network/bridge` demonstrates how to use the LwIP IEEE 802.1D bridge to forward Ethernet frames between multiple network segments based on MAC addresses.
|
||||
|
||||
* Most protocol examples should also work for Ethernet: :example:`protocols`.
|
||||
|
||||
.. ------------------------------ Advanced Topics -------------------------------
|
||||
|
||||
.. _advanced-topics:
|
||||
|
||||
Advanced Topics
|
||||
---------------
|
||||
|
||||
.. _custom-phy-driver:
|
||||
|
||||
Custom PHY Driver
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are multiple PHY manufacturers with wide portfolios of chips available. The ESP-IDF supports ``Generic PHY`` and also several specific PHY chips however one can easily get to a point where none of them satisfies the user's actual needs due to price, features, stock availability, etc.
|
||||
|
||||
Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task.
|
||||
|
||||
.. note::
|
||||
Always consult with PHY datasheet since some PHY chips may not comply with IEEE 802.3, Section 22.2.4. It does not mean you are not able to create a custom PHY driver, but it just requires more effort. You will have to define all PHY management functions.
|
||||
|
||||
The majority of PHY management functionality required by the ESP-IDF Ethernet driver is covered by the :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c`. However, the following may require developing chip-specific management functions:
|
||||
|
||||
* Link status which is almost always chip-specific
|
||||
* Chip initialization, even though not strictly required, should be customized to at least ensure that the expected chip is used
|
||||
* Chip-specific features configuration
|
||||
|
||||
**Steps to create a custom PHY driver:**
|
||||
|
||||
1. Define vendor-specific registry layout based on the PHY datasheet.
|
||||
2. Prepare derived PHY management object info structure which:
|
||||
|
||||
* must contain at least parent IEEE 802.3 :cpp:class:`phy_802_3_t` object
|
||||
* optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality.
|
||||
|
||||
3. Define chip-specific management call-back functions.
|
||||
4. Initialize parent IEEE 802.3 object and re-assign chip-specific management call-back functions.
|
||||
|
||||
Once you finish the new custom PHY driver implementation, consider sharing it among other users via `ESP Component Registry <https://components.espressif.com/>`_.
|
||||
|
||||
.. ---------------------------- API Reference ----------------------------------
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/eth_types.inc
|
||||
.. include-build-file:: inc/esp_eth.inc
|
||||
.. include-build-file:: inc/esp_eth_driver.inc
|
||||
.. include-build-file:: inc/esp_eth_com.inc
|
||||
.. include-build-file:: inc/esp_eth_mac.inc
|
||||
.. include-build-file:: inc/esp_eth_mac_esp.inc
|
||||
.. include-build-file:: inc/esp_eth_mac_spi.inc
|
||||
.. include-build-file:: inc/esp_eth_phy.inc
|
||||
.. include-build-file:: inc/esp_eth_phy_802_3.inc
|
||||
.. include-build-file:: inc/esp_eth_netif_glue.inc
|
||||
@@ -0,0 +1,28 @@
|
||||
Wi-Fi Aware\ :sup:`TM` (NAN)
|
||||
===================================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Wi-Fi Aware\ :sup:`TM` or NAN (Neighbor Awareness Networking) is a protocol that allows Wi-Fi devices to discover services in their proximity. Typically, location-based services are based on querying servers for information about the environment and the location knowledge is based on GPS or other location reckoning techniques. However, NAN does not require real-time connection to servers, GPS or other geo-location, but instead uses direct device-to-device Wi-Fi to discover and exchange information. NAN scales effectively in dense Wi-Fi environments and complements the connectivity of Wi-Fi by providing information about people and services in the proximity.
|
||||
|
||||
Multiple NAN devices which are in the vicinity form a NAN cluster which allows them to communicate with each other. Devices within a NAN cluster can advertise (Publish method) or look for (Subscribe method) services using NAN Service Discovery protocols. Matching of services is done by service name, once a match is found, a device can either send a message or establish an IPv6 Datapath with the peer.
|
||||
|
||||
{IDF_TARGET_NAME} supports Wi-Fi Aware in standalone mode with support for both Service Discovery and Datapath. Wi-Fi Aware is still an evolving protocol. Please refer to Wi-Fi Alliance's official page on `Wi-Fi Aware <https://www.wi-fi.org/discover-wi-fi/wi-fi-aware>`_ for more information. Many Android smartphones with Android 8 or higher support Wi-Fi Aware. Refer to Android's developer guide on Wi-Fi Aware `Wi-Fi Aware <https://www.wi-fi.org/discover-wi-fi/wi-fi-aware>`_ for more information.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`wifi/wifi_aware/nan_console` demonstrates how to use the NAN protocol to discover services in proximity, establish a datapath, and communicate between devices without requiring an Internet or AP connection. It provides console commands for configuring NAN services, publishing or subscribing to a service, sending messages, and initiating or terminating a datapath.
|
||||
|
||||
- :example:`wifi/wifi_aware/nan_publisher` demonstrates how to use the NAN protocol to publish a service for advertising a service to other devices in the vicinity, and how to respond to the devices that subscribes to the service.
|
||||
|
||||
- :example:`wifi/wifi_aware/nan_subscriber` demonstrates how to use the NAN protocol to discover other devices that publish the required service in the proximity, and communicate with them either by sending a message or initiating a datapath.
|
||||
|
||||
- :example:`wifi/wifi_aware/usd_publisher` demonstrates how to use lightweight NAN Unsynchronized Service Discovery (NAN-USD) protocol to advertise a service to nearby devices without forming NAN clusters. It walks through bringing up USD, publishing a service, responding to subscribers with follow-up messages, and returning to the idle state once discovery completes.
|
||||
|
||||
- :example:`wifi/wifi_aware/usd_subscriber` demonstrates how to use the lightweight NAN Unsynchronized Service Discovery (NAN-USD) protocol to discover services advertised by nearby devices and interact with them. It covers enabling USD discovery, subscribing to services, handling follow-up exchanges, and terminating discovery after the session ends.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/esp_nan.inc
|
||||
@@ -0,0 +1,300 @@
|
||||
ESP-NETIF
|
||||
*********
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
The purpose of the ESP-NETIF library is twofold:
|
||||
|
||||
- It provides an abstraction layer for the application on top of the TCP/IP stack. This allows applications to choose between IP stacks in the future.
|
||||
- The APIs it provides are thread-safe, even if the underlying TCP/IP stack APIs are not.
|
||||
|
||||
ESP-IDF currently implements ESP-NETIF for the lwIP TCP/IP stack only. However, the adapter itself is TCP/IP implementation-agnostic and allows different implementations.
|
||||
|
||||
Some ESP-NETIF API functions are intended to be called by application code, for example, to get or set interface IP addresses, and configure DHCP. Other functions are intended for internal ESP-IDF use by the network driver layer. In many cases, applications do not need to call ESP-NETIF APIs directly as they are called by the default network event handlers.
|
||||
|
||||
If you are only interested in using the most common network interfaces with default setting, please read :ref:`esp_netif_user` to see how you can initialize default interfaces and register event handlers.
|
||||
|
||||
If you would like to learn more about the library interaction with other components, please refer to the :ref:`esp-netif structure`.
|
||||
|
||||
In case your application needs to configure the network interfaces differently, e.g. setting a static IP address or just update the configuration runtime, please read :ref:`esp_netif_programmer`.
|
||||
|
||||
If you would like to develop your own network driver, implement support for a new TCP/IP stack or customize the ESP-NETIF in some other way, please refer to the :ref:`esp_netif_developer`.
|
||||
|
||||
.. _esp_netif_user:
|
||||
|
||||
ESP-NETIF User's Manual
|
||||
=======================
|
||||
|
||||
It is usually just enough to create a default network interface after startup and destroy it upon closing (see :ref:`esp_netif_init`). It is also useful to receive a notification upon assigning a new IP address or losing it (see :ref:`esp-netif-ip-events`).
|
||||
|
||||
|
||||
.. _esp_netif_init:
|
||||
|
||||
Initialization
|
||||
--------------
|
||||
|
||||
Since the ESP-NETIF component uses system events, the typical network startup code looks like this (note that error handling is omitted for clarity, see :example_file:`ethernet/basic/main/ethernet_example_main.c` for complete startup code):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// 1) Initialize the TCP/IP stack and the event loop
|
||||
esp_netif_init();
|
||||
esp_event_loop_create_default();
|
||||
|
||||
// 2) Create the network interface handle
|
||||
esp_netif = esp_netif_new(&config);
|
||||
|
||||
// 3) Create the network interface driver (e.g., Ethernet) and it's network layer glue
|
||||
// and register the ESP-NETIF event (e.g., to bring the interface up upon link-up event)
|
||||
esp_netif_glue_t glue = driver_glue(driver);
|
||||
|
||||
// 4) Attach the driver's glue layer to the network interface handle
|
||||
esp_netif_attach(esp_netif, glue);
|
||||
|
||||
// 5) Register user-side event handlers
|
||||
esp_event_handler_register(DRIVER_EVENT, ...); // to observe driver states, e.g., link-up
|
||||
esp_event_handler_register(IP_EVENT, ...); // to observe ESP-NETIF states, e.g., get an IP
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
These steps must be performed in the exact order shown above, as the network interface drivers use the default event loop when registering system events.
|
||||
|
||||
- The default event loop needs to be created **before** initializing an interface driver, as the driver typically needs to register system event handlers.
|
||||
- Registering application event handlers must occur **after** calling :cpp:func:`esp_netif_attach`, because event handlers are called in the order they were registered. To ensure that system handlers are called first, you should register application handlers afterward.
|
||||
|
||||
Steps ``2)``, ``3)`` and ``4)`` are quite complex for most common use-cases, so ESP-NETIF provides some pre-configured interfaces and convenience functions that create the most common network interfaces in their most common configurations.
|
||||
|
||||
.. note::
|
||||
|
||||
Each network interface needs to be initialized separately, so if you would like to use multiple interfaces, you would have to run steps ``2)`` to ``5)`` for every interface. Set ``1)`` should be performed only once.
|
||||
|
||||
|
||||
Creating and configuring the interface and attaching the network interface driver to it (steps ``2)``, ``3)`` and ``4)``) is described in :ref:`create_esp_netif`.
|
||||
|
||||
Using the ESP-NETIF event handlers (step ``5)``) is described in :ref:`esp-netif-ip-events`.
|
||||
|
||||
|
||||
.. _create_esp_netif:
|
||||
|
||||
Common Network Interfaces
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As the initialization of network interfaces could be quite complex, ESP-NETIF provides some convenient methods of creating the most common ones, such as Wi-Fi and Ethernet.
|
||||
|
||||
Please refer to the following examples to understand the initialization process of the default interface:
|
||||
|
||||
.. list::
|
||||
|
||||
:SOC_WIFI_SUPPORTED: - :example:`wifi/getting_started/station` demonstrates how to use the station functionality to connect {IDF_TARGET_NAME} to an AP.
|
||||
|
||||
:CONFIG_ESP_WIFI_SOFTAP_SUPPORT: - :example:`wifi/getting_started/softAP` demonstrates how to use the SoftAP functionality to configure {IDF_TARGET_NAME} as an AP.
|
||||
|
||||
- :example:`ethernet/basic` demonstrates how to use the Ethernet driver, attach it to `esp_netif`, and obtain an IP address that can be pinged.
|
||||
|
||||
- :example:`protocols/l2tap` demonstrates how to use the ESP-NETIF L2 TAP interface to access the Data Link Layer for receiving and transmitting frames, implement non-IP protocols, and echo Ethernet frames with specific EthTypes.
|
||||
|
||||
- :example:`protocols/static_ip` demonstrates how to configure Wi-Fi as a station, including setting up a static IP, netmask, gateway and DNS server.
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
|
||||
Wi-Fi Default Initialization
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The initialization code as well as registering event handlers for default interfaces, such as softAP and station, are provided in separate APIs to facilitate simple startup code for most applications:
|
||||
|
||||
* :cpp:func:`esp_netif_create_default_wifi_sta()`
|
||||
|
||||
.. only:: CONFIG_ESP_WIFI_SOFTAP_SUPPORT
|
||||
|
||||
* :cpp:func:`esp_netif_create_default_wifi_ap()`
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
|
||||
Please note that these functions return the ``esp_netif`` handle, i.e., a pointer to a network interface object allocated and configured with default settings, which means that:
|
||||
|
||||
* The created object has to be destroyed if a network de-initialization is provided by an application using :cpp:func:`esp_netif_destroy_default_wifi()`.
|
||||
|
||||
* These *default* interfaces must not be created multiple times unless the created handle is deleted using :cpp:func:`esp_netif_destroy_default_wifi()`.
|
||||
|
||||
|
||||
.. only:: CONFIG_ESP_WIFI_SOFTAP_SUPPORT
|
||||
|
||||
* When using Wi-Fi in ``AP+STA`` mode, both these interfaces have to be created. Please refer to the example :example_file:`wifi/softap_sta/main/softap_sta.c`.
|
||||
|
||||
.. _esp-netif-ip-events:
|
||||
|
||||
IP Events
|
||||
---------
|
||||
|
||||
In the final section of :ref:`esp_netif_init` code (step ``5)``), you register two sets of event handlers:
|
||||
|
||||
* **Network Interface Driver Events**: These events notify you about the driver's lifecycle states, such as when a Wi-Fi station joins an AP or gets disconnected. Handling these events is outside the scope of the ESP-NETIF component. It is worth noting that the same events are also used by ESP-NETIF to set the network interface to a desired state. Therefore, if your application uses the driver's events to determine specific states of the network interface, you should register these handlers **after** registering the system handlers (which typically happens when attaching the driver to the interface). This is why handler registration occurs in the final step of the :ref:`esp_netif_init` code.
|
||||
|
||||
* **IP Events**: These events notify you about IP address changes, such as when a new address is assigned or when a valid address is lost. Specific types of these events are listed in :cpp:type:`ip_event_t`. Each common interface has a related pair of ``GOT_IP`` and ``LOST_IP`` events.
|
||||
|
||||
Registering event handlers is crucial due to the asynchronous nature of networking, where changes in network state can occur unpredictably. By registering event handlers, applications can respond to these changes promptly, ensuring appropriate actions are taken in response to network events.
|
||||
|
||||
.. note::
|
||||
|
||||
Lost IP events are triggered by a timer that can be enabled or disabled by :ref:`CONFIG_ESP_NETIF_LOST_IP_TIMER_ENABLE`,
|
||||
with the delay configured by :ref:`CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL`. The timer is started upon losing the IP address, and the event is raised after the configured interval (120 s by default).
|
||||
For backward compatibility, setting the interval to 0 also disables the timer.
|
||||
|
||||
.. _esp-netif structure:
|
||||
|
||||
ESP-NETIF Architecture
|
||||
----------------------
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
|
||||
| (A) USER CODE |
|
||||
| Apps |
|
||||
.................| init settings events |
|
||||
. +----------------------------------------+
|
||||
. . | *
|
||||
. . | *
|
||||
--------+ +================================+ * +-----------------------+
|
||||
| | new/config get/set/apps | * | init |
|
||||
| | |...*.....| Apps (DHCP, SNTP) |
|
||||
| |--------------------------------| * | |
|
||||
init | | |**** | |
|
||||
start |************| event handler |*********| DHCP |
|
||||
stop | | | | |
|
||||
| |--------------------------------| | |
|
||||
| | | | NETIF |
|
||||
+-----| | | +-----------------+ |
|
||||
| glue|---<----|---| esp_netif_transmit |--<------| netif_output | |
|
||||
| | | | | | | |
|
||||
| |--->----|---| esp_netif_receive |-->------| netif_input | |
|
||||
| | | | | + ----------------+ |
|
||||
| |...<....|...| esp_netif_free_rx_buffer |...<.....| packet buffer |
|
||||
+-----| | | | | | |
|
||||
| | | | | | (D) |
|
||||
(B) | | | | (C) | +-----------------------+
|
||||
--------+ | | +================================+ NETWORK STACK
|
||||
NETWORK | | ESP-NETIF
|
||||
INTERFACE | |
|
||||
DRIVER | | +--------------------------------+ +------------------+
|
||||
| | | |.........| open/close |
|
||||
| | | | | |
|
||||
| -<--| l2tap_write |-----<---| write |
|
||||
| | | | |
|
||||
---->--| esp_vfs_l2tap_eth_filter_frame |----->---| read |
|
||||
| | | (A) |
|
||||
| (E) | +------------------+
|
||||
+--------------------------------+ USER CODE
|
||||
ESP-NETIF L2 TAP
|
||||
|
||||
|
||||
Data and Event Flow in the Diagram
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* ``........`` Initialization line from user code to ESP-NETIF and network interface driver
|
||||
|
||||
* ``--<--->--`` Data packets going from communication media to TCP/IP stack and back
|
||||
|
||||
* ``********`` Events aggregated in ESP-NETIF propagate to the driver, user code, and network stack
|
||||
|
||||
* ``|`` User settings and runtime configuration
|
||||
|
||||
ESP-NETIF Interaction
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A) User Code, Boilerplate
|
||||
'''''''''''''''''''''''''
|
||||
|
||||
Overall application interaction with a specific IO driver for the communication media (network interface driver) and configured TCP/IP network stack is abstracted using ESP-NETIF APIs and is outlined as below:
|
||||
|
||||
A) Initialization code
|
||||
|
||||
1) Initializes IO driver
|
||||
2) Creates a new instance of ESP-NETIF and configure it with
|
||||
|
||||
* ESP-NETIF specific options (flags, behavior, name)
|
||||
* Network stack options (netif init and input functions, not publicly available)
|
||||
* IO driver specific options (transmit, free rx buffer functions, IO driver handle)
|
||||
|
||||
3) Attaches the IO driver handle to the ESP-NETIF instance created in the above steps
|
||||
4) Configures event handlers
|
||||
|
||||
* Use default handlers for common interfaces defined in IO drivers; or define a specific handler for customized behavior or new interfaces
|
||||
* Register handlers for app-related events (such as IP lost or acquired)
|
||||
|
||||
B) Interaction with network interfaces using ESP-NETIF API
|
||||
|
||||
1) Gets and sets TCP/IP-related parameters (DHCP, IP, etc)
|
||||
2) Receives IP events (connect or disconnect)
|
||||
3) Controls application lifecycle (set interface up or down)
|
||||
|
||||
|
||||
B) Network Interface Driver
|
||||
'''''''''''''''''''''''''''
|
||||
|
||||
Network interface driver (also called I/O Driver, or Media Driver) plays these two important roles in relation to ESP-NETIF:
|
||||
|
||||
1) Event handlers: Defines behavior patterns of interaction with ESP-NETIF (e.g., ethernet link-up -> turn netif on)
|
||||
|
||||
2) Glue IO layer: Adapts the input or output functions to use ESP-NETIF transmit, receive, and free receive buffer
|
||||
|
||||
* Installs driver_transmit to the appropriate ESP-NETIF object so that outgoing packets from the network stack are passed to the IO driver
|
||||
* Calls :cpp:func:`esp_netif_receive()` to pass incoming data to the network stack
|
||||
|
||||
|
||||
C) ESP-NETIF
|
||||
''''''''''''
|
||||
|
||||
ESP-NETIF serves as an intermediary between an IO driver and a network stack, connecting the packet data path between the two. It provides a set of interfaces for attaching a driver to an ESP-NETIF object at runtime and configures a network stack during compiling. Additionally, a set of APIs is provided to control the network interface lifecycle and its TCP/IP properties. As an overview, the ESP-NETIF public interface can be divided into six groups:
|
||||
|
||||
1) Initialization APIs (to create and configure ESP-NETIF instance)
|
||||
2) Input or Output API (for passing data between IO driver and network stack)
|
||||
3) Event or Action API
|
||||
|
||||
* Used for network interface lifecycle management
|
||||
* ESP-NETIF provides building blocks for designing event handlers
|
||||
|
||||
4) Setters and Getters API for basic network interface properties
|
||||
5) Network stack abstraction API: enabling user interaction with TCP/IP stack
|
||||
|
||||
* Set interface up or down
|
||||
* DHCP server and client API
|
||||
* DNS API
|
||||
* :ref:`esp_netif-sntp-api`
|
||||
|
||||
6) Driver conversion utilities API
|
||||
|
||||
|
||||
D) Network Stack
|
||||
''''''''''''''''
|
||||
|
||||
The network stack has no public interaction with application code with regard to public interfaces and shall be fully abstracted by ESP-NETIF API.
|
||||
|
||||
|
||||
E) ESP-NETIF L2 TAP Interface
|
||||
'''''''''''''''''''''''''''''
|
||||
|
||||
The ESP-NETIF L2 TAP interface is a mechanism in ESP-IDF used to access Data Link Layer (L2 per OSI/ISO) for frame reception and transmission from the user application. Its typical usage in the embedded world might be the implementation of non-IP-related protocols, e.g., PTP, Wake on LAN. Note that only Ethernet (IEEE 802.3) is currently supported. Please read more about L2 TAP in :ref:`esp_netif_l2tap`.
|
||||
|
||||
.. _esp_netif_programmer:
|
||||
|
||||
ESP-NETIF Programmer's Manual
|
||||
=============================
|
||||
|
||||
In some cases, it is not enough to simply initialize a network interface by default, start using it and connect to the local network. If so, please consult the programming guide: :doc:`/api-reference/network/esp_netif_programming`.
|
||||
|
||||
You would typically need to use specific sets of ESP-NETIF APIs in the following use-cases:
|
||||
|
||||
* :ref:`esp_netif_set_ip`
|
||||
* :ref:`esp_netif_set_dhcp`
|
||||
* :ref:`esp_netif-sntp-api`
|
||||
* :ref:`esp_netif_l2tap`
|
||||
* :ref:`esp_netif_other_events`
|
||||
* :ref:`esp_netif_api_reference`
|
||||
|
||||
.. _esp_netif_developer:
|
||||
|
||||
ESP-NETIF Developer's Manual
|
||||
============================
|
||||
|
||||
In some cases, user applications might need to customize ESP-NETIF, register custom drivers or even use a custom TCP/IP stack. If so, please consult the :doc:`/api-reference/network/esp_netif_driver`.
|
||||
@@ -0,0 +1,120 @@
|
||||
ESP-NETIF Developer's manual
|
||||
============================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
As shown in the :ref:`esp-netif structure` diagram, ESP-NETIF is in fact an intermediary between the I/O driver and the TCP/IP stack. This manual describes customization of these two sides, that is if you need to implement :ref:`esp_netif_custom_driver` or if you need to employ :ref:`esp_netif_tcpip_stack`.
|
||||
|
||||
|
||||
.. _esp_netif_custom_driver:
|
||||
|
||||
ESP-NETIF Custom I/O Driver
|
||||
---------------------------
|
||||
|
||||
This section outlines implementing a new I/O driver with ESP-NETIF connection capabilities.
|
||||
|
||||
By convention, the I/O driver has to register itself as an ESP-NETIF driver, and thus holds a dependency on ESP-NETIF component and is responsible for providing data path functions, post-attach callback and in most cases, also default event handlers to define network interface actions based on driver's lifecycle transitions.
|
||||
|
||||
|
||||
Packet Input/Output
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
According to the diagram shown in the :ref:`esp-netif structure` part, the following three API functions for the packet data path must be defined for connecting with ESP-NETIF:
|
||||
|
||||
* :cpp:func:`esp_netif_transmit()`
|
||||
* :cpp:func:`esp_netif_free_rx_buffer()`
|
||||
* :cpp:func:`esp_netif_receive()`
|
||||
|
||||
The first two functions for transmitting and freeing the rx buffer are provided as callbacks, i.e., they get called from ESP-NETIF (and its underlying TCP/IP stack) and I/O driver provides their implementation.
|
||||
|
||||
The receiving function on the other hand gets called from the I/O driver, so that the driver's code simply calls :cpp:func:`esp_netif_receive()` on a new data received event.
|
||||
|
||||
|
||||
Post Attach Callback
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A final part of the network interface initialization consists of attaching the ESP-NETIF instance to the I/O driver, by means of calling the following API:
|
||||
|
||||
.. code:: c
|
||||
|
||||
esp_err_t esp_netif_attach(esp_netif_t *esp_netif, esp_netif_iodriver_handle driver_handle);
|
||||
|
||||
It is assumed that the ``esp_netif_iodriver_handle`` is a pointer to driver's object, a struct derived from ``struct esp_netif_driver_base_s``, so that the first member of I/O driver structure must be this base structure with pointers to:
|
||||
|
||||
* post-attach function callback
|
||||
* related ESP-NETIF instance
|
||||
|
||||
As a result, the I/O driver has to create an instance of the struct per below:
|
||||
|
||||
.. code:: c
|
||||
|
||||
typedef struct my_netif_driver_s {
|
||||
esp_netif_driver_base_t base; /*!< base structure reserved as esp-netif driver */
|
||||
driver_impl *h; /*!< handle of driver implementation */
|
||||
} my_netif_driver_t;
|
||||
|
||||
with actual values of ``my_netif_driver_t::base.post_attach`` and the actual drivers handle ``my_netif_driver_t::h``.
|
||||
|
||||
So when the :cpp:func:`esp_netif_attach()` gets called from the initialization code, the post-attach callback from I/O driver's code gets executed to mutually register callbacks between ESP-NETIF and I/O driver instances. Typically the driver is started as well in the post-attach callback. An example of a simple post-attach callback is outlined below:
|
||||
|
||||
.. code:: c
|
||||
|
||||
static esp_err_t my_post_attach_start(esp_netif_t * esp_netif, void * args)
|
||||
{
|
||||
my_netif_driver_t *driver = args;
|
||||
const esp_netif_driver_ifconfig_t driver_ifconfig = {
|
||||
.driver_free_rx_buffer = my_free_rx_buf,
|
||||
.transmit = my_transmit,
|
||||
.handle = driver->driver_impl
|
||||
};
|
||||
driver->base.netif = esp_netif;
|
||||
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig));
|
||||
my_driver_start(driver->driver_impl);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
Default Handlers
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
I/O drivers also typically provide default definitions of lifecycle behavior of related network interfaces based on state transitions of I/O drivers. For example *driver start* ``->`` *network start*, etc.
|
||||
|
||||
An example of such a default handler is provided below:
|
||||
|
||||
.. code:: c
|
||||
|
||||
esp_err_t my_driver_netif_set_default_handlers(my_netif_driver_t *driver, esp_netif_t * esp_netif)
|
||||
{
|
||||
driver_set_event_handler(driver->driver_impl, esp_netif_action_start, MY_DRV_EVENT_START, esp_netif);
|
||||
driver_set_event_handler(driver->driver_impl, esp_netif_action_stop, MY_DRV_EVENT_STOP, esp_netif);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
Network Stack Connection
|
||||
------------------------
|
||||
|
||||
The packet data path functions for transmitting and freeing the rx buffer (defined in the I/O driver) are called from the ESP-NETIF, specifically from its TCP/IP stack connecting layer.
|
||||
|
||||
Note that ESP-IDF provides several network stack configurations for the most common network interfaces, such as for the Wi-Fi station or Ethernet. These configurations are defined in :component_file:`esp_netif/include/esp_netif_defaults.h` and should be sufficient for most network drivers.
|
||||
|
||||
In some cases, you might want to define a custom lwIP based interface, for example if you need to update :component_file:`esp_netif/lwip/netif/wlanif.c` with a specific packet pool. In that case, you would have to define an explicit dependency to lwIP and include :component_file:`esp_netif/include/lwip/esp_netif_net_stack.h` for the relevant lwIP configuration structures.
|
||||
|
||||
|
||||
.. _esp_netif_tcpip_stack:
|
||||
|
||||
ESP-NETIF Custom TCP/IP Stack
|
||||
-----------------------------
|
||||
|
||||
It is possible to use a custom TCP/IP stack with ESP-IDF, provided it implements BSD API. You can add support for your own TCP/IP stack, while using the generic ESP-NETIF functionality, so the application code can stay the same as with the lwIP.
|
||||
|
||||
In this case, please choose ``ESP_NETIF_PROVIDE_CUSTOM_IMPLEMENTATION`` in the ESP-NETIF component configuration menu. This option will disable lwIP implementation of the ESP-NETIF functions and provide only header files with declarations of types and API. You will have to supply the necessary implementation in your custom component. You can refer to the :component_file:`esp_netif/loopback/esp_netif_loopback.c` for example of dummy implementations of these functions.
|
||||
|
||||
It is also possible to build ESP-IDF without lwIP, please refer to :idf_file:`components/esp_netif_stack/README.md`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
The following API reference outlines these network stack interaction with the ESP-NETIF:
|
||||
|
||||
.. include-build-file:: inc/esp_netif_net_stack.inc
|
||||
@@ -0,0 +1,426 @@
|
||||
ESP-NETIF Programmers Manual
|
||||
============================
|
||||
|
||||
.. _esp_netif_set_ip:
|
||||
|
||||
Configure IP, Gateway, and DNS
|
||||
------------------------------
|
||||
|
||||
Typically, IP addresses -- including the gateway, network mask, and DNS servers -- are automatically obtained through a DHCP server or Router Advertisement services. Notifications regarding IP address assignments are received via the ``IP_EVENT``, which provides the relevant IP address information. You can also retrieve the current address details using the function :cpp:func:`esp_netif_get_ip_info()`. This function returns a structure, :cpp:type:`esp_netif_ip_info_t`, that contains the IPv4 address of the network interface, along with its network mask and gateway address. Similarly, the function :cpp:func:`esp_netif_get_all_ip6()` can be used to obtain all IPv6 addresses associated with the interface.
|
||||
|
||||
In order to configure static IP addresses and DNS servers, it's necessary to disable or stop DHCP client (which is enabled by default on some network interfaces, such as the default Ethernet, or the default WiFi station). Please refer to the example :example:`/protocols/static_ip` for more details.
|
||||
|
||||
To set IPv4 address, you can use :cpp:func:`esp_netif_set_ip_info()`. For IPv6, these two functions can be used for adding or removing addresses: :cpp:func:`esp_netif_add_ip6_address()`, :cpp:func:`esp_netif_remove_ip6_address()`.
|
||||
To configure DNS servers, please use :cpp:func:`esp_netif_set_dns_info()` API.
|
||||
|
||||
Custom Got/Lost IP Events
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For user-defined interfaces, esp-netif lets you select which IP events are posted when an interface obtains or loses an IP address. Two generic event IDs are provided for this purpose:
|
||||
|
||||
- ``IP_EVENT_CUSTOM_GOT_IP``
|
||||
- ``IP_EVENT_CUSTOM_LOST_IP``
|
||||
|
||||
Configure these by setting :cpp:member:`esp_netif_inherent_config_t::get_ip_event` and :cpp:member:`esp_netif_inherent_config_t::lost_ip_event` when creating the interface:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_netif_inherent_config_t base = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA();
|
||||
base.get_ip_event = IP_EVENT_CUSTOM_GOT_IP;
|
||||
base.lost_ip_event = IP_EVENT_CUSTOM_LOST_IP;
|
||||
esp_netif_config_t cfg = { .base = &base, .stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA };
|
||||
esp_netif_t *netif = esp_netif_new(&cfg);
|
||||
|
||||
Event data for these events is the same as the standard ones: :cpp:type:`ip_event_got_ip_t` is posted for “got IP”, and :cpp:type:`ip_event_got_ip_t` with :cpp:member:`ip_event_got_ip_t::ip_changed` set accordingly for updates. For lost IP, an empty :cpp:type:`ip_event_got_ip_t` with only :cpp:member:`ip_event_got_ip_t::esp_netif` set is posted.
|
||||
|
||||
.. _esp_netif_set_dhcp:
|
||||
|
||||
Configure DHCP options
|
||||
----------------------
|
||||
|
||||
Some network interfaces are pre-configured to use either a DHCP client (commonly for Ethernet interfaces) or a DHCP server (typically for Wi-Fi software access points). When manually creating a custom network interface, the configuration flags :cpp:type:`esp_netif_flags_t` are used to specify the behavior of the interface. Adding :cpp:enumerator:`ESP_NETIF_DHCP_CLIENT` or :cpp:enumerator:`ESP_NETIF_DHCP_SERVER` will enable the DHCP client or server, respectively.
|
||||
|
||||
It is important to note that these two options are mutually exclusive and cannot be changed at runtime. If an interface is configured as a DHCP client upon creation, it cannot later be used as a DHCP server. The only option is to destroy the existing network interface and create a new one with the desired configuration.
|
||||
|
||||
To set or get a specific DHCP option, the common type :cpp:type:`esp_netif_dhcp_option_id_t` is used for both the DHCP server and client. However, not all options are supported for both. For details on the available options for the DHCP client, refer to the API documentation for :cpp:func:`esp_netif_dhcpc_option()`. Similarly, for the options available for the DHCP server, consult the API documentation for :cpp:func:`esp_netif_dhcps_option()`.
|
||||
|
||||
.. _esp_netif-sntp-api:
|
||||
|
||||
SNTP Service
|
||||
------------
|
||||
|
||||
A brief introduction to SNTP, its initialization code, and basic modes can be found in Section :ref:`system-time-sntp-sync` in :doc:`System Time </api-reference/system/system_time>`.
|
||||
|
||||
This section provides more details on specific use cases for the SNTP service, such as using statically configured servers, DHCP-provided servers, or both. The workflow is typically straightforward:
|
||||
|
||||
1. Initialize and configure the service using :cpp:func:`esp_netif_sntp_init()`. This function can only be called once unless the SNTP service has been destroyed using :cpp:func:`esp_netif_sntp_deinit()`.
|
||||
2. Start the service with :cpp:func:`esp_netif_sntp_start()`. This step is not necessary if the service was auto-started in the previous step (default behavior). However, it can be useful to start the service explicitly after connecting if DHCP-provided NTP servers are being used. Note that this option needs to be enabled before connecting, but the SNTP service should only be started afterward.
|
||||
3. Wait for the system time to synchronize using :cpp:func:`esp_netif_sntp_sync_wait()` (if required).
|
||||
4. Stop and destroy the service using :cpp:func:`esp_netif_sntp_deinit()`.
|
||||
|
||||
Events
|
||||
^^^^^^
|
||||
|
||||
The SNTP wrapper posts an event when the system time is synchronized:
|
||||
|
||||
- Event base: ``NETIF_SNTP_EVENT``
|
||||
- Event ID: ``NETIF_SNTP_TIME_SYNC``
|
||||
- Event data: pointer to :cpp:type:`esp_netif_sntp_time_sync_t` with the synchronized ``timeval``
|
||||
|
||||
Register a handler after creating the default event loop:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void sntp_evt_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
const esp_netif_sntp_time_sync_t *evt = (const esp_netif_sntp_time_sync_t *)data;
|
||||
if (evt) {
|
||||
ESP_LOGI("sntp", "time synchronized: %ld.%06ld", (long)evt->tv.tv_sec, (long)evt->tv.tv_usec);
|
||||
// Optionally convert to human-readable time using localtime_r() or gmtime_r()
|
||||
}
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &sntp_evt_handler, NULL));
|
||||
|
||||
|
||||
Basic Mode with Statically Defined Server(s)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Initialize the module with the default configuration after connecting to the network. Note that it is possible to provide multiple NTP servers in the configuration struct:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
|
||||
ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) );
|
||||
esp_netif_sntp_init(&config);
|
||||
|
||||
.. note::
|
||||
|
||||
If you want to configure multiple SNTP servers, update the lwIP configuration option :ref:`CONFIG_LWIP_SNTP_MAX_SERVERS`.
|
||||
|
||||
|
||||
Use DHCP-Obtained SNTP Server(s)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
First, you need to enable the lwIP configuration option :ref:`CONFIG_LWIP_DHCP_GET_NTP_SRV`. Then, initialize the SNTP module with the DHCP option, without specifying an NTP server.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(0, {} );
|
||||
config.start = false; // start the SNTP service explicitly
|
||||
config.server_from_dhcp = true; // accept the NTP offer from the DHCP server
|
||||
esp_netif_sntp_init(&config);
|
||||
|
||||
Once connected, you can start the service using:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_netif_sntp_start();
|
||||
|
||||
.. note::
|
||||
|
||||
It is also possible to start the service during initialization (with the default ``config.start=true``). However, this may cause the initial SNTP request to fail since you are not connected yet, which could result in a back-off period for subsequent requests.
|
||||
|
||||
|
||||
Use Both Static and Dynamic Servers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This scenario is similar to using DHCP-provided SNTP servers. However, in this configuration, you need to ensure that the static server configuration is refreshed when obtaining NTP servers via DHCP. The underlying lwIP code removes the existing list of NTP servers when DHCP-provided information is accepted. Therefore, the ESP-NETIF SNTP module retains the statically configured server(s) and appends them to the list after obtaining a DHCP lease.
|
||||
|
||||
The typical configuration now looks as per below, providing the specific ``IP_EVENT`` to update the config and index of the first server to reconfigure (for example setting ``config.index_of_first_server=1`` would keep the DHCP provided server at index 0, and the statically configured server at index 1).
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
|
||||
config.start = false; // start the SNTP service explicitly (after connecting)
|
||||
config.server_from_dhcp = true; // accept the NTP offers from DHCP server
|
||||
config.renew_servers_after_new_IP = true; // let esp-netif update the configured SNTP server(s) after receiving the DHCP lease
|
||||
config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact
|
||||
config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; // IP event on which you refresh your configuration
|
||||
|
||||
Then you start the service normally with :cpp:func:`esp_netif_sntp_start()`.
|
||||
|
||||
|
||||
.. _esp_netif_l2tap:
|
||||
|
||||
L2 TAP Interface Usage
|
||||
----------------------
|
||||
|
||||
The ESP-NETIF L2 TAP interface is used to access Data Link Layer, please refer to the :ref:`esp-netif structure` diagram to see how L2 TAP interacts with ESP-NETIF and application.
|
||||
|
||||
From a user perspective, the ESP-NETIF L2 TAP interface is accessed using file descriptors of VFS, which provides file-like interfacing (using functions like ``open()``, ``read()``, ``write()``, etc). To learn more, refer to :doc:`/api-reference/storage/vfs`.
|
||||
|
||||
There is only one ESP-NETIF L2 TAP interface device (path name) available, but you can open multiple file descriptors from it, each with its own unique configuration. Think of the ESP-NETIF L2 TAP interface as a general gateway to the Layer 2 network infrastructure. The key point is that each file descriptor can be individually configured, which is crucial. For example, a file descriptor can be set up to access a specific network interface identified by if_key (like ETH_DEF) and to filter specific types of frames (such as filtering by Ethernet type for IEEE 802.3 frames).
|
||||
|
||||
This filtering is essential because the ESP-NETIF L2 TAP works alongside the IP stack, meaning that IP-related traffic (like IP, ARP, etc.) should not be sent directly to your application. Although this option is still possible, it is not recommended in standard use cases. The benefit of filtering is that it allows your application to receive only the frame types it cares about, while other traffic is either routed to different L2 TAP file descriptors or handled by the IP stack.
|
||||
|
||||
|
||||
Initialization
|
||||
^^^^^^^^^^^^^^
|
||||
To be able to use the ESP-NETIF L2 TAP interface, it needs to be enabled in Kconfig by :ref:`CONFIG_ESP_NETIF_L2_TAP` first and then registered by :cpp:func:`esp_vfs_l2tap_intf_register()` prior usage of any VFS function.
|
||||
|
||||
``open()``
|
||||
^^^^^^^^^^
|
||||
Once the ESP-NETIF L2 TAP is registered, it can be opened at path name "/dev/net/tap". The same path name can be opened multiple times up to :ref:`CONFIG_ESP_NETIF_L2_TAP_MAX_FDS` and multiple file descriptors with a different configuration may access the Data Link Layer frames.
|
||||
|
||||
The ESP-NETIF L2 TAP can be opened with the ``O_NONBLOCK`` file status flag to make sure the ``read()`` does not block. Note that the ``write()`` may block in the current implementation when accessing a Network interface since it is a shared resource among multiple ESP-NETIF L2 TAP file descriptors and IP stack, and there is currently no queuing mechanism deployed. The file status flag can be retrieved and modified using ``fcntl()``.
|
||||
|
||||
On success, ``open()`` returns the new file descriptor (a nonnegative integer). On error, -1 is returned, and ``errno`` is set to indicate the error.
|
||||
|
||||
``ioctl()``
|
||||
^^^^^^^^^^^
|
||||
The newly opened ESP-NETIF L2 TAP file descriptor needs to be configured prior to its usage since it is not bounded to any specific Network Interface and no frame type filter is configured. The following configuration options are available to do so:
|
||||
|
||||
* ``L2TAP_S_INTF_DEVICE`` - bounds the file descriptor to a specific Network Interface that is identified by its ``if_key``. ESP-NETIF Network Interface ``if_key`` is passed to ``ioctl()`` as the third parameter. Note that default Network Interfaces ``if_key``'s used in ESP-IDF can be found in :component_file:`esp_netif/include/esp_netif_defaults.h`.
|
||||
* ``L2TAP_S_DEVICE_DRV_HNDL`` - is another way to bound the file descriptor to a specific Network Interface. In this case, the Network interface is identified directly by IO Driver handle (e.g., :cpp:type:`esp_eth_handle_t` in case of Ethernet). The IO Driver handle is passed to ``ioctl()`` as the third parameter.
|
||||
* ``L2TAP_S_RCV_FILTER`` - sets the filter to frames with the type to be passed to the file descriptor. In the case of Ethernet frames, the frames are to be filtered based on the Length and Ethernet type field. In case the filter value is set less than or equal to 0x05DC, the Ethernet type field is considered to represent IEEE802.3 Length Field, and all frames with values in interval <0, 0x05DC> at that field are passed to the file descriptor. The IEEE802.2 logical link control (LLC) resolution is then expected to be performed by the user's application. In case the filter value is set greater than 0x05DC, the Ethernet type field is considered to represent protocol identification and only frames that are equal to the set value are to be passed to the file descriptor.
|
||||
* ``L2TAP_S_TIMESTAMP_EN`` - enables the hardware Time Stamping processing inside the file descriptor. The Time Stamps are retrieved to user space by using :ref:`Extended Buffer <esp_netif_l2tap_ext_buff>` mechanism when accessing the file descriptor by ``read()`` and ``write()`` functions. Hardware time stamping needs to be supported by target and needs to be enabled in IO Driver to this option work as expected.
|
||||
|
||||
All above-set configuration options have a getter counterpart option to read the current settings except for ``L2TAP_S_TIMESTAMP_EN``.
|
||||
|
||||
.. warning::
|
||||
The file descriptor needs to be firstly bounded to a specific Network Interface by ``L2TAP_S_INTF_DEVICE`` or ``L2TAP_S_DEVICE_DRV_HNDL`` to make ``L2TAP_S_RCV_FILTER`` option available.
|
||||
|
||||
.. note::
|
||||
VLAN-tagged frames are currently not recognized. If the user needs to process VLAN-tagged frames, they need a set filter to be equal to the VLAN tag (i.e., 0x8100 or 0x88A8) and process the VLAN-tagged frames in the user application.
|
||||
|
||||
.. note::
|
||||
``L2TAP_S_DEVICE_DRV_HNDL`` is particularly useful when the user's application does not require the usage of an IP stack and so ESP-NETIF is not required to be initialized too. As a result, Network Interface cannot be identified by its ``if_key`` and hence it needs to be identified directly by its IO Driver handle.
|
||||
|
||||
| On success, ``ioctl()`` returns 0. On error, -1 is returned, and ``errno`` is set to indicate the error.
|
||||
| * EBADF - not a valid file descriptor.
|
||||
| * EACCES - options change is denied in this state (e.g., file descriptor has not been bounded to Network interface yet).
|
||||
| * EINVAL - invalid configuration argument. Ethernet type filter is already used by other file descriptors on that same Network interface.
|
||||
| * ENODEV - no such Network Interface which is tried to be assigned to the file descriptor exists.
|
||||
| * ENOSYS - unsupported operation, passed configuration option does not exist.
|
||||
|
||||
``fcntl()``
|
||||
^^^^^^^^^^^
|
||||
The ``fcntl()`` is used to manipulate with properties of opened ESP-NETIF L2 TAP file descriptor.
|
||||
|
||||
The following commands manipulate the status flags associated with the file descriptor:
|
||||
|
||||
* ``F_GETFD`` - the function returns the file descriptor flags, and the third argument is ignored.
|
||||
* ``F_SETFD`` - sets the file descriptor flags to the value specified by the third argument. Zero is returned.
|
||||
|
||||
| On success, ``fcntl()`` returns 0. On error, -1 is returned, and ``errno`` is set to indicate the error.
|
||||
| * EBADF - not a valid file descriptor.
|
||||
| * ENOSYS - unsupported command.
|
||||
|
||||
``read()``
|
||||
^^^^^^^^^^
|
||||
Opened and configured ESP-NETIF L2 TAP file descriptor can be accessed by ``read()`` to get inbound frames. The read operation can be either blocking or non-blocking based on the actual state of the ``O_NONBLOCK`` file status flag. When the file status flag is set to blocking, the read operation waits until a frame is received and the context is switched to other tasks. When the file status flag is set to non-blocking, the read operation returns immediately. In such case, either a frame is returned if it was already queued or the function indicates the queue is empty. The number of queued frames associated with one file descriptor is limited by :ref:`CONFIG_ESP_NETIF_L2_TAP_RX_QUEUE_SIZE` Kconfig option. Once the number of queued frames reached a configured threshold, the newly arrived frames are dropped until the queue has enough room to accept incoming traffic (Tail Drop queue management).
|
||||
|
||||
| On success, ``read()`` returns the number of bytes read. Zero is returned when the size of the destination buffer is 0. On error, -1 is returned, and ``errno`` is set to indicate the error.
|
||||
| * EBADF - not a valid file descriptor.
|
||||
| * EAGAIN - the file descriptor has been marked non-blocking (``O_NONBLOCK``), and the read would block.
|
||||
|
||||
.. note::
|
||||
ESP-NETIF L2 TAP ``read()`` implementation extends the standard and offers Extended Buffer mechanism to retrieve additional information about received frame. See :ref:`Extended Buffer <esp_netif_l2tap_ext_buff>` section for more information.
|
||||
|
||||
``write()``
|
||||
^^^^^^^^^^^
|
||||
A raw Data Link Layer frame can be sent to Network Interface via opened and configured ESP-NETIF L2 TAP file descriptor. The user's application is responsible to construct the whole frame except for fields which are added automatically by the physical interface device. The following fields need to be constructed by the user's application in case of an Ethernet link: source/destination MAC addresses, Ethernet type, actual protocol header, and user data. The length of these fields is as follows:
|
||||
|
||||
.. packetdiag::
|
||||
|
||||
packetdiag {
|
||||
colwidth = 16;
|
||||
node_width = 38;
|
||||
0-5: Destination MAC (6B) [color = "#ffcccc"];
|
||||
6-11: Source MAC Port (6B) [color = "#ffcccc"];
|
||||
12-13: Type/Length (2B) [color = "#ccccff"];
|
||||
14-15: [color = "#ffffcc"];
|
||||
16-31: Payload (protocol header/data - 1486B) [color = "#ffffcc", colheight = 3];
|
||||
}
|
||||
|
||||
In other words, there is no additional frame processing performed by the ESP-NETIF L2 TAP interface. It only checks the Ethernet type of the frame is the same as the filter configured in the file descriptor. If the Ethernet type is different, an error is returned and the frame is not sent. Note that the ``write()`` may block in the current implementation when accessing a Network interface since it is a shared resource among multiple ESP-NETIF L2 TAP file descriptors and IP stack, and there is currently no queuing mechanism deployed.
|
||||
|
||||
| On success, ``write()`` returns the number of bytes written. Zero is returned when the size of the input buffer is 0. On error, -1 is returned, and ``errno`` is set to indicate the error.
|
||||
| * EBADF - not a valid file descriptor.
|
||||
| * EBADMSG - The Ethernet type of the frame is different from the file descriptor configured filter.
|
||||
| * EIO - Network interface not available or busy.
|
||||
|
||||
.. note::
|
||||
ESP-NETIF L2 TAP ``write()`` implementation extends the standard and offers Extended Buffer mechanism to retrieve additional information about transmitted frame. See :ref:`Extended Buffer <esp_netif_l2tap_ext_buff>` section for more information.
|
||||
|
||||
``close()``
|
||||
^^^^^^^^^^^
|
||||
Opened ESP-NETIF L2 TAP file descriptor can be closed by the ``close()`` to free its allocated resources. The ESP-NETIF L2 TAP implementation of ``close()`` may block. On the other hand, it is thread-safe and can be called from a different task than the file descriptor is actually used. If such a situation occurs and one task is blocked in the I/O operation and another task tries to close the file descriptor, the first task is unblocked. The first's task ``read`` operation then ends with returning `0` bytes was read.
|
||||
|
||||
| On success, ``close()`` returns zero. On error, -1 is returned, and ``errno`` is set to indicate the error.
|
||||
| * EBADF - not a valid file descriptor.
|
||||
|
||||
``select()``
|
||||
^^^^^^^^^^^^
|
||||
Select is used in a standard way, just :ref:`CONFIG_VFS_SUPPORT_SELECT` needs to be enabled to make the ``select()`` function available.
|
||||
|
||||
.. _esp_netif_l2tap_ext_buff:
|
||||
|
||||
Extended Buffer
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The Extended Buffer is ESP-NETIF L2 TAP's mechanism of how to retrieve additional information about transmitted or received IO frame via ``write()`` or ``read()`` functions. The Extended Buffer must be only used when specific functionality is enabled in the file descriptor (such as ``L2TAP_S_TIMESTAMP_EN``) and you want to access the additional data (such as Time Stamp) or control the frame processing.
|
||||
|
||||
The **Extended Buffer** is a structure with fields which serve as arguments to drive underlying functionality in the ESP-NETIF L2 TAP file descriptor. The structure is defined as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef struct {
|
||||
size_t info_recs_len; /*!< Length of Information Records buffer */
|
||||
void *info_recs_buff; /*!< Buffer holding extended information (IRECs) related to IO frames */
|
||||
size_t buff_len; /*!< Length of the actual IO Frame buffer */
|
||||
void *buff; /*!< Pointer to the IO Frame buffer */
|
||||
} l2tap_extended_buff_t;
|
||||
|
||||
One Extended buffer may hold multiple **Information Records** (IRECs). These are variable data typed (and sized) records which may hold any datatype of additional information associated with the IO frame. The IREC structure is defined as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t len; /*!< Length of the record including header and data*/
|
||||
l2tap_irec_type_t type; /*!< Type of the record */
|
||||
alignas(long long) uint8_t data[]; /*!< Records Data aligned to double word */
|
||||
} l2tap_irec_hdr_t;
|
||||
|
||||
Currently implement and used IREC data types are defined in :cpp:type:`l2tap_irec_type_t`.
|
||||
|
||||
Since the flexible array to hold data is used, proper memory alignment of multiple IRECs in the records buffer is required to correctly access memory. Improper alignment can result in slower memory access due to misaligned read/write operations, or in the worst case, cause undefined behavior on certain architectures. Therefore it is strictly recommended to use the below macros when manipulating with IRECs:
|
||||
|
||||
* ``L2TAP_IREC_SPACE()`` - determines the space required for an IREC, ensuring that it is properly aligned.
|
||||
* ``L2TAP_IREC_LEN()`` - calculates the total length of one IREC, including the header and the data section of the record.
|
||||
* ``L2TAP_IREC_FIRST()`` - retrieves the first IREC from the :cpp:member:`l2tap_extended_buff_t::info_recs_buff` pool of Extended Buffer. If the :cpp:member:`l2tap_extended_buff_t::info_recs_len` is smaller than the size of a record header, it returns NULL.
|
||||
* ``L2TAP_IREC_NEXT()`` - retrieves the next IREC in the Extended Buffer after the current record. If the current record is NULL, it returns the first record.
|
||||
|
||||
Extended Buffer Usage
|
||||
"""""""""""""""""""""
|
||||
|
||||
Prior any Extended Buffer IO operation (either ``write()`` or ``read()``), you first need to fully populate the Extended Buffer and its IREC fields. For example, when you want to retrieve Time Stamp, you need to set type of the IREC to :cpp:enumerator:`L2TAP_IREC_TIME_STAMP` and configure appropriate length. If you don't set the type correctly, the frame is still received or transmitted but information to be retrieved is lost. Similarly, when the IREC length is less than expected length, the frame is still received or transmitted but the type of affected IREC is marked to :cpp:enumerator:`L2TAP_IREC_INVALID` by the ESP-NETIF L2 TAP and information to be retrieved is lost.
|
||||
|
||||
When accessing the file descriptor using Extended Buffer, ``size`` parameter of ``write()`` or ``read()`` function must be set equal to ``0``. Failing to do so (i.e. accessing such file descriptor in a standard way with ``size`` parameter set to data length) will result in an -1 error and ``errno`` set to EINVAL.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// wrap "Info Records Buffer" into union to ensure proper alignment of data (this is typically needed when
|
||||
// accessing double word variables or structs containing double word variables)
|
||||
union {
|
||||
uint8_t info_recs_buff[L2TAP_IREC_SPACE(sizeof(struct timespec))];
|
||||
l2tap_irec_hdr_t align;
|
||||
} u;
|
||||
|
||||
l2tap_extended_buff_t ptp_msg_ext_buff;
|
||||
|
||||
ptp_msg_ext_buff.info_recs_len = sizeof(u.info_recs_buff);
|
||||
ptp_msg_ext_buff.info_recs_buff = u.info_recs_buff;
|
||||
ptp_msg_ext_buff.buff = eth_frame;
|
||||
ptp_msg_ext_buff.buff_len = sizeof(eth_frame);
|
||||
|
||||
l2tap_irec_hdr_t *ts_info = L2TAP_IREC_FIRST(&ptp_msg_ext_buff);
|
||||
ts_info->len = L2TAP_IREC_LEN(sizeof(struct timespec));
|
||||
ts_info->type = L2TAP_IREC_TIME_STAMP;
|
||||
|
||||
int ret = write(state->ptp_socket, &ptp_msg_ext_buff, 0);
|
||||
|
||||
// check if write was successful and ts_info is valid
|
||||
if (ret > 0 && ts_info->type == L2TAP_IREC_TIME_STAMP) {
|
||||
*ts = *(struct timespec *)ts_info->data;
|
||||
}
|
||||
|
||||
.. _esp_netif_other_events:
|
||||
|
||||
IP Event: Transmit/Receive Packet
|
||||
---------------------------------
|
||||
|
||||
This event, ``IP_EVENT_TX_RX``, is triggered for every transmitted or received IP packet. It provides information about packet transmission or reception, data length, and the ``esp_netif`` handle.
|
||||
|
||||
Enabling the Event
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Compile Time:**
|
||||
|
||||
The feature can be completely disabled during compilation time using the flag :ref:`CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC` in the kconfig.
|
||||
|
||||
**Run Time:**
|
||||
|
||||
At runtime, you can enable or disable this event using the functions :cpp:func:`esp_netif_tx_rx_event_enable()` and :cpp:func:`esp_netif_tx_rx_event_disable()`.
|
||||
|
||||
Event Registration
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To handle this event, you need to register a handler using the following syntax:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void
|
||||
tx_rx_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ip_event_tx_rx_t *event = (ip_event_tx_rx_t *)event_data;
|
||||
|
||||
if (event->dir == ESP_NETIF_TX) {
|
||||
ESP_LOGI(TAG, "Got TX event: Interface \"%s\" data len: %d", esp_netif_get_desc(event->esp_netif), event->len);
|
||||
} else if (event->dir == ESP_NETIF_RX) {
|
||||
ESP_LOGI(TAG, "Got RX event: Interface \"%s\" data len: %d", esp_netif_get_desc(event->esp_netif), event->len);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Got Unknown event: Interface \"%s\"", esp_netif_get_desc(event->esp_netif));
|
||||
}
|
||||
}
|
||||
|
||||
esp_event_handler_register(IP_EVENT, IP_EVENT_TX_RX, &tx_rx_event_handler, NULL);
|
||||
|
||||
Here, ``tx_rx_event_handler`` is the name of the function that will handle the event.
|
||||
|
||||
Event Data Structure
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The event data structure, :cpp:class:`ip_event_tx_rx_t`, contains the following fields:
|
||||
|
||||
- :cpp:member:`ip_event_tx_rx_t::dir`: Indicates whether the packet was transmitted (``ESP_NETIF_TX``) or received (``ESP_NETIF_RX``).
|
||||
- :cpp:member:`ip_event_tx_rx_t::len`: Length of the data frame.
|
||||
- :cpp:member:`ip_event_tx_rx_t::esp_netif`: The network interface on which the packet was sent or received.
|
||||
|
||||
IP Events: Netif Status (Unified)
|
||||
---------------------------------
|
||||
|
||||
ESP-NETIF emits unified status events when an interface becomes usable for L3 traffic or goes down. These are derived from the lwIP extended netif callbacks and posted on ``IP_EVENT``:
|
||||
|
||||
- ``IP_EVENT_NETIF_UP`` / ``IP_EVENT_NETIF_DOWN``
|
||||
|
||||
ESP-IDF normalizes link and administrative state changes into these two events (including PPP). Subscribe as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void netif_status_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
const ip_event_netif_status_t *evt = (const ip_event_netif_status_t *)data;
|
||||
ESP_LOGI("netif", "status %s on %s", (id == IP_EVENT_NETIF_UP) ? "UP" : "DOWN", esp_netif_get_desc(evt->esp_netif));
|
||||
}
|
||||
|
||||
esp_event_handler_register(IP_EVENT, IP_EVENT_NETIF_UP, &netif_status_handler, NULL);
|
||||
esp_event_handler_register(IP_EVENT, IP_EVENT_NETIF_DOWN, &netif_status_handler, NULL);
|
||||
|
||||
Event Data Structure
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The event data structure is :cpp:type:`ip_event_netif_status_t`, which contains the ``esp_netif`` handle of the interface that changed state.
|
||||
|
||||
|
||||
.. _esp_netif_api_reference:
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/esp_netif.inc
|
||||
.. include-build-file:: inc/esp_netif_sntp.inc
|
||||
.. include-build-file:: inc/esp_netif_types.inc
|
||||
.. include-build-file:: inc/esp_netif_ip_addr.inc
|
||||
.. include-build-file:: inc/esp_vfs_l2tap.inc
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
|
||||
Wi-Fi Default API Reference
|
||||
---------------------------
|
||||
|
||||
.. include-build-file:: inc/esp_wifi_default.inc
|
||||
@@ -0,0 +1,154 @@
|
||||
ESP-NOW
|
||||
=======
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP-NOW is a kind of connectionless Wi-Fi communication protocol that is defined by Espressif. In ESP-NOW, application data is encapsulated in a vendor-specific action frame and then transmitted from one Wi-Fi device to another without connection.
|
||||
|
||||
CTR with CBC-MAC Protocol (CCMP) is used to protect the action frame for security. ESP-NOW is widely used in smart light, remote controlling, sensor, etc.
|
||||
|
||||
Frame Format
|
||||
------------
|
||||
|
||||
ESP-NOW uses a vendor-specific action frame to transmit ESP-NOW data. The default ESP-NOW bit rate is 1 Mbps.
|
||||
|
||||
Currently, ESP-NOW supports two versions: v1.0 and v2.0. The maximum packet length supported by v2.0 devices is 1470 (``ESP_NOW_MAX_DATA_LEN_V2``) bytes, while the maximum packet length supported by v1.0 devices is 250 (``ESP_NOW_MAX_DATA_LEN``) bytes.
|
||||
|
||||
The v2.0 devices are capable of receiving packets from both v2.0 and v1.0 devices. In contrast, v1.0 devices can only receive packets from other v1.0 devices.
|
||||
|
||||
However, v1.0 devices can receive v2.0 packets if the packet length is less than or equal to 250 (``ESP_NOW_MAX_IE_DATA_LEN``).For packets exceeding this length, the v1.0 devices will either truncate the data to the first 250 (``ESP_NOW_MAX_IE_DATA_LEN``) bytes or discard the packet entirely.
|
||||
|
||||
For detailed behavior, please refer to the documentation corresponding to the specific IDF version.
|
||||
|
||||
The format of the vendor-specific action frame is as follows:
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
| MAC Header | Category Code | Organization Identifier | Random Values | Vendor Specific Content | FCS |
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
24 bytes 1 byte 3 bytes 4 bytes 7-x bytes 4 bytes
|
||||
|
||||
- Category Code: The Category Code field is set to the value (127) indicating the vendor-specific category.
|
||||
- Organization Identifier: The Organization Identifier contains a unique identifier (0x18fe34), which is the first three bytes of MAC address applied by Espressif.
|
||||
- Random Value: The Random Value filed is used to prevents relay attacks.
|
||||
- Vendor Specific Content: The Vendor Specific Content contains several (at least one) vendor-specific element fields. For version v2.0, x = 1512(1470 + 6*7), for version v1.0, x = 257(250 + 7).
|
||||
|
||||
The format of the vendor-specific element frame is as follows:
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
ESP-NOW v1.0:
|
||||
------------------------------------------------------------------------------------------
|
||||
| Element ID | Length | Organization Identifier | Type | Reserved | Version | Body |
|
||||
------------------------------------------------------------------------------------------
|
||||
7~4 bits | 3~0 bits
|
||||
1 byte 1 byte 3 bytes 1 byte 1 byte 0-250 bytes
|
||||
|
||||
ESP-NOW v2.0:
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
| Element ID | Length | Organization Identifier | Type | Reserved | More data |Version | Body |
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
7~5 bits | 1 bit |3~0 bits
|
||||
1 byte 1 byte 3 bytes 1 byte 1 byte 0-250 bytes
|
||||
|
||||
- Element ID: The Element ID field is set to the value (221), indicating the vendor-specific element.
|
||||
- Length: The length is the total length of Organization Identifier, Type, Version and Body, the maximum value is 255.
|
||||
- Organization Identifier: The Organization Identifier contains a unique identifier (0x18fe34), which is the first three bytes of MAC address applied by Espressif.
|
||||
- Type: The Type field is set to the value (4) indicating ESP-NOW.
|
||||
- Version: The Version field is set to the version of ESP-NOW.
|
||||
- Body: The Body contains the actual ESP-NOW data to be transmitted.
|
||||
|
||||
As ESP-NOW is connectionless, the MAC header is a little different from that of standard frames. The FromDS and ToDS bits of FrameControl field are both 0. The first address field is set to the destination address. The second address field is set to the source address. The third address field is set to broadcast address (0xff:0xff:0xff:0xff:0xff:0xff).
|
||||
|
||||
Security
|
||||
--------
|
||||
|
||||
ESP-NOW uses the CCMP method, which is described in IEEE Std. 802.11-2012, to protect the vendor-specific action frame. The Wi-Fi device maintains a Primary Master Key (PMK) and several Local Master Keys (LMKs, each paired device has one LMK). The lengths of both PMK and LMK are 16 bytes.
|
||||
|
||||
* PMK is used to encrypt LMK with the AES-128 algorithm. Call :cpp:func:`esp_now_set_pmk()` to set PMK. If PMK is not set, a default PMK will be used.
|
||||
* LMK of the paired device is used to encrypt the vendor-specific action frame with the CCMP method. If the LMK of the paired device is not set, the vendor-specific action frame will not be encrypted.
|
||||
|
||||
Encrypting multicast vendor-specific action frame is not supported.
|
||||
|
||||
Initialization and Deinitialization
|
||||
------------------------------------
|
||||
|
||||
Call :cpp:func:`esp_now_init()` to initialize ESP-NOW and :cpp:func:`esp_now_deinit()` to de-initialize ESP-NOW. ESP-NOW data must be transmitted after Wi-Fi is started, so it is recommended to start Wi-Fi before initializing ESP-NOW and stop Wi-Fi after de-initializing ESP-NOW.
|
||||
|
||||
When :cpp:func:`esp_now_deinit()` is called, all of the information of paired devices are deleted.
|
||||
|
||||
Add Paired Device
|
||||
-----------------
|
||||
|
||||
Call :cpp:func:`esp_now_add_peer()` to add the device to the paired device list before you send data to this device. If security is enabled, the LMK must be set. A device with a broadcast MAC address must be added before sending broadcast data.
|
||||
|
||||
You can send ESP-NOW data via both the Station and the SoftAP interface. Make sure that the interface is enabled before sending ESP-NOW data.
|
||||
|
||||
.. only:: esp32 or esp32c2 or esp32s2 or esp32s3 or esp32c3 or esp32c6
|
||||
|
||||
The range of the channel of paired devices is from 0 to 14. If the channel is set to 0, data will be sent on the current channel. Otherwise, the channel must be set as the channel that the local device is on.
|
||||
|
||||
.. only:: esp32c5
|
||||
|
||||
The channel range for paired devices in the 2.4 GHz band is from 1 to 14. The channel range for paired devices in the 5 GHz band includes the following channels: [36, 40, 44, 48, 52, 56, 60, 64, 100, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177].
|
||||
|
||||
If the channel is set to 0, data will be transmitted on the current channel. Otherwise, the channel must correspond to the local device's current channel.
|
||||
|
||||
For the receiving device, calling :cpp:func:`esp_now_add_peer()` is not required. If no paired device is added, it can only receive broadcast packets and unencrypted unicast packets. To receive encrypted unicast packets, a paired device must be added, and the same LMK must be set.
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
The maximum number of paired devices is 20, and the paired encryption devices are no more than 4, the default is 2. If you want to change the number of paired encryption devices, set :ref:`CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM` in the Wi-Fi component configuration menu.
|
||||
|
||||
.. only:: esp32 or esp32s2 or esp32s3 or esp32c3 or esp32c6 or esp32c5
|
||||
|
||||
The maximum number of paired devices is 20, and the paired encryption devices are no more than 17, the default is 7. If you want to change the number of paired encryption devices, set :ref:`CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM` in the Wi-Fi component configuration menu.
|
||||
|
||||
Send ESP-NOW Data
|
||||
-----------------
|
||||
|
||||
Call :cpp:func:`esp_now_send()` to send ESP-NOW data and :cpp:func:`esp_now_register_send_cb()` to register sending callback function. It will return `ESP_NOW_SEND_SUCCESS` in sending callback function if the data is received successfully on the MAC layer. Otherwise, it will return `ESP_NOW_SEND_FAIL`. Several reasons can lead to ESP-NOW fails to send data. For example, the destination device does not exist; the channels of the devices are not the same; the action frame is lost when transmitting on the air, etc. It is not guaranteed that application layer can receive the data. If necessary, send back ack data when receiving ESP-NOW data. If receiving ack data timeouts, retransmit the ESP-NOW data. A sequence number can also be assigned to ESP-NOW data to drop the duplicate data.
|
||||
|
||||
If there is a lot of ESP-NOW data to send, call :cpp:func:`esp_now_send()` to send less than or equal to the maximum packet length (v1.0 is 250 bytes, v2.0 is 1470 bytes) of data once a time. Note that too short interval between sending two ESP-NOW data may lead to disorder of sending callback function. So, it is recommended that sending the next ESP-NOW data after the sending callback function of the previous sending has returned. The sending callback function runs from a high-priority Wi-Fi task. So, do not do lengthy operations in the callback function. Instead, post the necessary data to a queue and handle it from a lower priority task.
|
||||
|
||||
Receiving ESP-NOW Data
|
||||
----------------------
|
||||
|
||||
Call :cpp:func:`esp_now_register_recv_cb()` to register receiving callback function. Call the receiving callback function when receiving ESP-NOW. The receiving callback function also runs from the Wi-Fi task. So, do not do lengthy operations in the callback function.
|
||||
Instead, post the necessary data to a queue and handle it from a lower priority task.
|
||||
|
||||
Config ESP-NOW Rate
|
||||
-------------------
|
||||
|
||||
Call :cpp:func:`esp_now_set_peer_rate_config()` to configure ESP-NOW rate of each peer. Make sure that the peer is added before configuring the rate. This API should be called after :cpp:func:`esp_wifi_start()` and :cpp:func:`esp_now_add_peer()`.
|
||||
|
||||
Config ESP-NOW Power-saving Parameter
|
||||
--------------------------------------------
|
||||
|
||||
Sleep is supported only when {IDF_TARGET_NAME} is configured as station.
|
||||
|
||||
Call :cpp:func:`esp_now_set_wake_window()` to configure Window for ESP-NOW RX at sleep. The default value is the maximum, which allowing RX all the time.
|
||||
|
||||
If Power-saving is needed for ESP-NOW, call :cpp:func:`esp_wifi_connectionless_module_set_wake_interval()` to configure Interval as well.
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
|
||||
Please refer to :ref:`connectionless module power save <connectionless-module-power-save>` to get more detail.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`wifi/espnow` demonstrates how to use the ESPNOW feature of {IDF_TARGET_NAME}'s Wi-Fi, including starting Wi-Fi, initializing ESP-NOW, registering ESP-NOW sending or receiving callback function, adding ESP-NOW peer information, and sending and receiving ESP-NOW data between two devices.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/esp_now.inc
|
||||
@@ -0,0 +1,37 @@
|
||||
Thread
|
||||
==========
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
`Thread <https://www.threadgroup.org>`_ is an IP-based mesh networking protocol. It is based on the 802.15.4 physical and MAC layer.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`openthread/ot_br` demonstrates how to set up a Thread border router on {IDF_TARGET_NAME}, enabling functionalities such as bidirectional IPv6 connectivity, service discovery, etc.
|
||||
|
||||
- :example:`openthread/ot_cli` demonstrates how to use the OpenThread Command Line Interface with additional features such as TCP, UDP, and Iperf. This requires a board equipped with an IEEE 802.15.4 module. This example provides instructions on how to set up a network using at least two 802.15.4 boards.
|
||||
|
||||
- :example:`openthread/ot_rcp` demonstrates how to work with a Host Processor to perform as a Thread border router and function as a Thread sniffer, using a board with an IEEE 802.15.4 module.
|
||||
|
||||
- :example:`openthread/ot_trel` demonstrates Thread Radio Encapsulation Link (TREL) function. This requires a board equipped with a Wi-Fi module.
|
||||
|
||||
- :example:`openthread/ot_sleepy_device/deep_sleep` demonstrates Thread Deep-sleep function.
|
||||
|
||||
- :example:`openthread/ot_sleepy_device/light_sleep` demonstrates Thread Light-sleep function.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
For manipulating the Thread network, the OpenThread API shall be used. The OpenThread API docs can be found at the `OpenThread API docs <https://openthread.io/reference>`_.
|
||||
|
||||
ESP-IDF provides extra APIs for launching and managing the OpenThread stack, binding to network interfaces and border routing features.
|
||||
|
||||
.. include-build-file:: inc/esp_openthread.inc
|
||||
.. include-build-file:: inc/esp_openthread_types.inc
|
||||
.. include-build-file:: inc/esp_openthread_lock.inc
|
||||
.. include-build-file:: inc/esp_openthread_netif_glue.inc
|
||||
.. include-build-file:: inc/esp_openthread_border_router.inc
|
||||
@@ -0,0 +1,29 @@
|
||||
SmartConfig
|
||||
===========
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The SmartConfig\ :sup:`TM` is a provisioning technology developed by TI to connect a new Wi-Fi device to a Wi-Fi network. It uses a mobile application to broadcast the network credentials from a smartphone, or a tablet, to an un-provisioned Wi-Fi device.
|
||||
|
||||
The advantage of this technology is that the device does not need to directly know SSID or password of an Access Point (AP). This information is provided using the smartphone. This is particularly important to headless device and systems, due to their lack of a user interface.
|
||||
|
||||
Currently, {IDF_TARGET_NAME} support three types of SmartConfig: Airkiss, ESPTouch, and ESPTouch v2. ESPTouch v2 has been supported since SmartConfig v3.0 (the version of SmartConfig can be get from :cpp:func:`esp_smartconfig_get_version()`), and it employs a completely different algorithm compared to ESPTouch, resulting in faster setup times. Additionally, ESPTouch v2 introduces AES encryption and custom data fields.
|
||||
|
||||
Starting from SmartConfig v3.0.2, ESPTouch v2 introduces support for random IV in AES encryption. On the application side, when the option for random IV is disabled, the default IV is set to 0, maintaining consistency with previous versions. When the random IV option is enabled, the IV will be a random value. It is important to note that when AES encryption is enabled with a random IV, the provision time will be extended due to the need of transmitting the IV to the provisioning device. On the provisioning device side, the device will identify whether the random IV for AES is enabled based on the flag in the provisioning packet.
|
||||
|
||||
If you are looking for other options to provision your {IDF_TARGET_NAME} devices, check :doc:`../provisioning/index`.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Connect {IDF_TARGET_NAME} to the target AP using SmartConfig: :example:`wifi/smart_config`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/esp_smartconfig.inc
|
||||
@@ -0,0 +1,36 @@
|
||||
Wi-Fi
|
||||
=====
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The Wi-Fi libraries provide support for configuring and monitoring the {IDF_TARGET_NAME} Wi-Fi networking functionality. This includes configuration for:
|
||||
|
||||
- Station mode (aka STA mode or Wi-Fi client mode). {IDF_TARGET_NAME} connects to an access point.
|
||||
- AP mode (aka Soft-AP mode or Access Point mode). Stations connect to the {IDF_TARGET_NAME}.
|
||||
- Station/AP-coexistence mode ({IDF_TARGET_NAME} is concurrently an access point and a station connected to another access point).
|
||||
|
||||
- Various security modes for the above (WPA, WPA2, WPA3, etc.)
|
||||
- Scanning for access points (active & passive scanning).
|
||||
- Promiscuous mode for monitoring of IEEE802.11 Wi-Fi packets.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
Several application examples demonstrating the functionality of Wi-Fi library are provided in :example:`wifi` directory of ESP-IDF repository. Please check the :example_file:`README <wifi/README.md>` for more details.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/esp_wifi.inc
|
||||
.. include-build-file:: inc/esp_wifi_types.inc
|
||||
.. include-build-file:: inc/esp_wifi_types_generic.inc
|
||||
.. include-build-file:: inc/esp_eap_client.inc
|
||||
.. include-build-file:: inc/esp_wps.inc
|
||||
.. include-build-file:: inc/esp_rrm.inc
|
||||
.. include-build-file:: inc/esp_wnm.inc
|
||||
.. include-build-file:: inc/esp_mbo.inc
|
||||
@@ -0,0 +1,73 @@
|
||||
Networking APIs
|
||||
***************
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
|
||||
Wi-Fi
|
||||
=====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
esp_now
|
||||
:SOC_WIFI_MESH_SUPPORT: esp-wifi-mesh
|
||||
esp_smartconfig
|
||||
esp_wifi
|
||||
esp_dpp
|
||||
:SOC_WIFI_NAN_SUPPORT: esp_nan
|
||||
|
||||
Code examples for the Wi-Fi API are provided in the :example:`wifi` directory of ESP-IDF examples.
|
||||
|
||||
.. only:: SOC_WIFI_MESH_SUPPORT
|
||||
|
||||
Code examples for ESP-WIFI-MESH are provided in the :example:`mesh` directory of ESP-IDF examples.
|
||||
|
||||
|
||||
|
||||
Ethernet
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
esp_eth
|
||||
|
||||
Code examples for the Ethernet API are provided in the :example:`ethernet` directory of ESP-IDF examples.
|
||||
|
||||
Thread
|
||||
==========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
esp_openthread
|
||||
|
||||
Thread is an IPv6-based mesh networking technology for IoT.
|
||||
|
||||
Code examples for the Thread API are provided in the :example:`openthread` directory of ESP-IDF examples.
|
||||
|
||||
ESP-NETIF
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
esp_netif
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
esp_netif_programming
|
||||
esp_netif_driver
|
||||
|
||||
IP Network Layer
|
||||
================
|
||||
|
||||
Code examples for TCP/IP socket APIs are provided in the :example:`protocols/sockets` directory of ESP-IDF examples.
|
||||
|
||||
Application Layer
|
||||
=================
|
||||
|
||||
Documentation for Application layer network protocols (above the IP Network layer) are provided in :doc:`../protocols/index`.
|
||||
Reference in New Issue
Block a user