ESP-MESH Programming Guide
==========================

This is a programming guide for ESP-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-application-examples`

4. :ref:`mesh-api-reference`

For documentation regarding the ESP-MESH protocol, please see the 
:doc:`ESP-MESH API Guide<../../api-guides/mesh>`.


.. ---------------------- ESP-MESH Programming Model --------------------------

.. _mesh-programming-model:

ESP-MESH Programming Model
--------------------------

Software Stack
^^^^^^^^^^^^^^

The ESP-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-MESH software stack.

.. _mesh-going-to-software-stack:

.. figure:: ../../../_static/mesh-software-stack.png
    :align: center
    :alt: ESP-MESH Software Stack
    :figclass: align-center

    ESP-MESH Software Stack

System Events
^^^^^^^^^^^^^

An application interfaces with ESP-MESH via **ESP-MESH Events**. Since ESP-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-MESH application.

.. figure:: ../../../_static/mesh-events-delivery.png
    :align: center
    :alt: ESP-MESH System Events Delivery
    :figclass: align-center

    ESP-MESH System Events Delivery

The :cpp:type:`mesh_event_id_t` defines all possible ESP-MESH system events and
can indicate events such as the connection/disconnection of parent/child. Before 
ESP-MESH system events can be used, the application must register a **Mesh Event 
Callback** via :cpp:func:`esp_mesh_set_config`. The callback is used to receive 
events from the ESP-MESH stack as well as the LwIP Stack and should contain handlers 
for each event relevant to the application.

Typical use cases of system 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:`MESH_EVENT_ROOT_GOT_IP` and :cpp:enumerator:`MESH_EVENT_ROOT_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-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-MESH's self-organizing behavior**. 
    Therefore, user's 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-MESH
^^^^^^^^^^^^^^^

The application can access the ESP-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 is required to initialize LwIP by calling** :cpp:func:`tcpip_adapter_init`. 
In order to prevent non-root node access to LwIP, the application should stop the 
following services after LwIP initialization:

    - DHCP server service on the softAP interface.
    - DHCP client service on the station interface.

The following code snippet demonstrates how to initialize LwIP for ESP-MESH applications.

.. code-block:: c

    /*  tcpip initialization */
    tcpip_adapter_init();
    /*
     * for mesh
     * stop DHCP server on softAP interface by default
     * stop DHCP client on station interface by default
     */
    ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
    ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
    /* do not specify system event callback, use NULL instead. */
    ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));

.. note::

    ESP-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-MESH Application 
-------------------------------

The prerequisites for starting ESP-MESH is to initialize LwIP and Wi-Fi, The 
following code snippet demonstrates the necessary prerequisite steps before 
ESP-MESH itself can be initialized.

.. code-block:: c

    tcpip_adapter_init();
    /*
     * for mesh
     * stop DHCP server on softAP interface by default
     * stop DHCP client on station interface by default
     */
    ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
    ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
    /* do not specify system event callback, use NULL instead. */
    ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));

    /*  Wi-Fi initialization */
    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&config));
    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-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-MESH

.. code-block:: c

    /*  mesh initialization */
    ESP_ERROR_CHECK(esp_mesh_init());

.. _mesh-configuring-mesh:

Configuring an ESP-MESH Network
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. todo - Add note about unified configuration

ESP-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-MESH:

+------------------+-------------------------------------+
| Parameter        | Description                         |
+==================+=====================================+
| Channel          | Range from 1 to 14                  |
+------------------+-------------------------------------+
| Event Callback   | Callback for Mesh Events,           |
|                  | see :cpp:type:`mesh_event_cb_t`     |
+------------------+-------------------------------------+
| Mesh ID          | ID of ESP-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-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);
    /* mesh event callback */
    cfg.event_cb = &mesh_event_handler;
    /* 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-MESH.

.. code-block:: c

    /* mesh start */
    ESP_ERROR_CHECK(esp_mesh_start());

After starting ESP-MESH, the application should check for ESP-MESH events to determine 
when it has connected to the network. After connecting, the application can start 
transmitting and receiving packets over the ESP-MESH network using 
:cpp:func:`esp_mesh_send` and :cpp:func:`esp_mesh_recv`.

.. --------------------- ESP-MESH Application Examples ------------------------

.. _mesh-application-examples:

Application Examples
--------------------

ESP-IDF contains these ESP-MESH example projects:

:example:`The Internal Communication Example<mesh/internal_communication>` demonstrates
how to setup a ESP-MESH network and have the root node send a data packet to 
every node within the network.

:example:`The Manual Networking Example<mesh/manual_networking>` demonstrates
how to use ESP-MESH without the self-organizing features. This example shows how
to program a node to manually scan for a list of potential parent nodes and select 
a parent node based on custom criteria.


.. ------------------------- ESP-MESH API Reference ---------------------------

.. _mesh-api-reference:

API Reference
--------------

.. include:: /_build/inc/esp_mesh.inc
