<commit_before>/*
 * Copyright (C) 2018 <NAME>
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @ingroup     cpu_esp32_esp_wifi
 * @{
 *
 * @file
 * @brief       Network device driver for the ESP32 WiFi interface
 *
 * @author      <NAME> <<EMAIL>>
 */

#ifdef MODULE_ESP_WIFI

#define ENABLE_DEBUG (0)
#include "debug.h"
#include "log.h"
#include "tools.h"

#include <string.h>
#include <assert.h>
#include <errno.h>

#include "net/gnrc/netif/ethernet.h"
#include "net/gnrc/netif/raw.h"
#include "net/gnrc.h"
#include "net/ethernet.h"
#include "net/netdev/eth.h"

#include "xtimer.h"

#include "esp_common.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "esp_now.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_internal.h"
#include "irq_arch.h"

#include "nvs_flash/include/nvs_flash.h"

#include "esp_wifi_params.h"
#include "esp_wifi_netdev.h"

#include "net/ipv6/hdr.h"
#include "net/gnrc/ipv6/nib.h"

#define SYSTEM_EVENT_WIFI_RX_DONE    (SYSTEM_EVENT_MAX + 3)
#define SYSTEM_EVENT_WIFI_TX_DONE    (SYSTEM_EVENT_MAX + 4)

/**
 * There is only one ESP WiFi device. We define it as static device variable
 * to have accesss to the device inside ESP WiFi interrupt routines which do
 * not provide an argument that could be used as pointer to the ESP WiFi
 * device which triggers the interrupt.
 */
static esp_wifi_netdev_t _esp_wifi_dev;
static const netdev_driver_t _esp_wifi_driver;

/* device thread stack */
static char _esp_wifi_stack[ESP_WIFI_STACKSIZE];

extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler,
                                               void *arg);

esp_err_t _esp_wifi_rx_cb(void *buffer, uint16_t len, void *eb)
{
    /*
     * This callback function is executed in interrupt context but in the
     * context of the wifi thread. That is, mutex_lock or msg_send can block.
     */

    DEBUG("%s: buf=%p len=%d eb=%p\n", __func__, buffer, len, eb);

    if ((buffer == NULL) || (len >= ETHERNET_MAX_LEN)) {
        if (eb != NULL) {
            esp_wifi_internal_free_rx_buffer(eb);
        }
        return ESP_ERR_INVALID_ARG;
    }

    mutex_lock(&_esp_wifi_dev.dev_lock);
    critical_enter();

    /* copy the buffer and free WiFi driver buffer */
    memcpy(_esp_wifi_dev.rx_buf, buffer, len);
    if (eb) {
        esp_wifi_internal_free_rx_buffer(eb);
    }

    /*
     * Because this function is not executed in interrupt context but in thread
     * context, following msg_send could block on heavy network load, if frames
     * are coming in faster than the ISR events can be handled. To avoid
     * blocking during msg_send, we pretend we are in an ISR by incrementing
     * the IRQ nesting counter. If IRQ nesting counter is greater 0, function
     * irq_is_in returns true and the non-blocking version of msg_send is used.
     */
    irq_interrupt_nesting++;

    /* trigger netdev event to read the data */
    _esp_wifi_dev.rx_len = len;
    _esp_wifi_dev.event = SYSTEM_EVENT_WIFI_RX_DONE;
    _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);

    /* reset IRQ nesting counter */
    irq_interrupt_nesting--;

    critical_exit();
    mutex_unlock(&_esp_wifi_dev.dev_lock);

    return ESP_OK;
}

/*
 * Event handler for esp system events.
 */
static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event)
{
    esp_err_t result;

    switch(event->event_id) {
        case SYSTEM_EVENT_STA_START:
            DEBUG("%s WiFi started\n", __func__);
            result = esp_wifi_connect();
            if (result != ESP_OK) {
                LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with return "
                              "value %d\n", result);
            }
            break;

        case SYSTEM_EVENT_SCAN_DONE:
            DEBUG("%s WiFi scan done\n", __func__);
            break;

        case SYSTEM_EVENT_STA_CONNECTED:
            DEBUG("%s WiFi connected\n", __func__);

            /* register RX callback function */
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb);

            _esp_wifi_dev.connected = true;
            _esp_wifi_dev.event = SYSTEM_EVENT_STA_CONNECTED;
            _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);

            break;

        case SYSTEM_EVENT_STA_DISCONNECTED:
            DEBUG("%s WiFi disconnected from ssid %s, reason %d\n", __func__,
                  event->event_info.disconnected.ssid,
                  event->event_info.disconnected.reason);

            /* unregister RX callback function */
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);

            _esp_wifi_dev.connected = false;
            _esp_wifi_dev.event = SYSTEM_EVENT_STA_DISCONNECTED;
            _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);

            /* call disconnect to reset internal state */
            result = esp_wifi_disconnect();
            if (result != ESP_OK) {
                LOG_TAG_ERROR("esp_wifi", "esp_wifi_disconnect failed with "
                             "return value %d\n", result);
                return result;
            }

            /* try to reconnect */
            result = esp_wifi_connect();
            if (result != ESP_OK) {
               LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with "
                             "return value %d\n", result);
            }

            break;

        default:
            DEBUG("%s event %d\n", __func__, event->event_id);
            break;
    }
    return ESP_OK;
}

/* we use predefined station configuration */
static wifi_config_t wifi_config_sta = {
    .sta = {
        .ssid = ESP_WIFI_SSID,
        .password = <PASSWORD>,
        .channel = 0,
        .scan_method = WIFI_ALL_CHANNEL_SCAN,
        .sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
        .threshold.rssi = -127,
        .threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK
    }
};

static void esp_wifi_setup (esp_wifi_netdev_t* dev)
{
    DEBUG("%s: %p\n", __func__, dev);

    /*
     * Init the WiFi driver. TODO It is not only required before ESP_WIFI is
     * initialized but also before other WiFi functions are used. Once other
     * WiFi functions are realized it has to be moved to a more common place.
     */
    extern portMUX_TYPE g_intr_lock_mux;
    mutex_init(&g_intr_lock_mux);

    esp_system_event_add_handler (_esp_system_event_handler, NULL);

    esp_err_t result;
    #if CONFIG_ESP32_WIFI_NVS_ENABLED
    result = nvs_flash_init();
    if (result != ESP_OK) {
       LOG_TAG_ERROR("esp_wifi", "nfs_flash_init failed with return value %d\n", result);
        return;
    }
    #endif

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    result = esp_wifi_init(&cfg);
    if (result != ESP_OK) {
       LOG_TAG_ERROR("esp_wifi", "esp_wifi_init failed with return value %d\n", result);
        return;
    }

    #ifdef CONFIG_WIFI_COUNTRY
    /* TODO */
    #endif

    result = esp_wifi_set_mode(WIFI_MODE_STA);
    if (result != ESP_OK) {
       LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_mode failed with return value %d\n", result);
        return;
    }

    /* set the Station and SoftAP configuration */
    result = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta);
    if (result != ESP_OK) {
       LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_config station failed with return value %d\n", result);
        return;
    }

    /* start the WiFi driver */
    result = esp_wifi_start();
    if (result != ESP_OK) {
       LOG_TAG_ERROR("esp_wifi", "esp_wifi_start failed with return value %d\n", result);
        return;
    }

    /* register RX callback function */
    esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb);

    /* set the netdev driver */
    dev->netdev.driver = &_esp_wifi_driver;<commit_msg>cpu/esp32: cleanup comments/messages in esp_wifi<commit_after>/*
 * Copyright (C) 2018 <NAME>
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @ingroup     cpu_esp32_esp_wifi
 * @{
 *
 * @file
 * @brief       Network device driver for the ESP32 WiFi interface
 *
 * @author      <NAME> <<EMAIL>>
 */

#ifdef MODULE_ESP_WIFI

#define ENABLE_DEBUG (0)
#include "debug.h"
#include "log.h"
#include "tools.h"

#include <string.h>
#include <assert.h>
#include <errno.h>

#include "net/gnrc/netif/ethernet.h"
#include "net/gnrc/netif/raw.h"
#include "net/gnrc.h"
#include "net/ethernet.h"
#include "net/netdev/eth.h"

#include "xtimer.h"

#include "esp_common.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "esp_now.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_internal.h"
#include "irq_arch.h"

#include "nvs_flash/include/nvs_flash.h"

#include "esp_wifi_params.h"
#include "esp_wifi_netdev.h"

#include "net/ipv6/hdr.h"
#include "net/gnrc/ipv6/nib.h"

#define SYSTEM_EVENT_WIFI_RX_DONE    (SYSTEM_EVENT_MAX + 3)
#define SYSTEM_EVENT_WIFI_TX_DONE    (SYSTEM_EVENT_MAX + 4)

/**
 * There is only one ESP WiFi device. We define it as static device variable
 * to have accesss to the device inside ESP WiFi interrupt routines which do
 * not provide an argument that could be used as pointer to the ESP WiFi
 * device which triggers the interrupt.
 */
static esp_wifi_netdev_t _esp_wifi_dev;
static const netdev_driver_t _esp_wifi_driver;

/* device thread stack */
static char _esp_wifi_stack[ESP_WIFI_STACKSIZE];

extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler,
                                               void *arg);

esp_err_t _esp_wifi_rx_cb(void *buffer, uint16_t len, void *eb)
{
    /*
     * This callback function is executed in interrupt context but in the
     * context of the wifi thread. That is, mutex_lock or msg_send can block.
     */

    DEBUG("%s: buf=%p len=%d eb=%p\n", __func__, buffer, len, eb);

    if ((buffer == NULL) || (len >= ETHERNET_MAX_LEN)) {
        if (eb != NULL) {
            esp_wifi_internal_free_rx_buffer(eb);
        }
        return ESP_ERR_INVALID_ARG;
    }

    mutex_lock(&_esp_wifi_dev.dev_lock);
    critical_enter();

    /* copy the buffer and free WiFi driver buffer */
    memcpy(_esp_wifi_dev.rx_buf, buffer, len);
    if (eb) {
        esp_wifi_internal_free_rx_buffer(eb);
    }

    /*
     * Because this function is not executed in interrupt context but in thread
     * context, following msg_send could block on heavy network load, if frames
     * are coming in faster than the ISR events can be handled. To avoid
     * blocking during msg_send, we pretend we are in an ISR by incrementing
     * the IRQ nesting counter. If IRQ nesting counter is greater 0, function
     * irq_is_in returns true and the non-blocking version of msg_send is used.
     */
    irq_interrupt_nesting++;

    /* trigger netdev event to read the data */
    _esp_wifi_dev.rx_len = len;
    _esp_wifi_dev.event = SYSTEM_EVENT_WIFI_RX_DONE;
    _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);

    /* reset IRQ nesting counter */
    irq_interrupt_nesting--;

    critical_exit();
    mutex_unlock(&_esp_wifi_dev.dev_lock);

    return ESP_OK;
}

/*
 * Event handler for esp system events.
 */
static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event)
{
    esp_err_t result;

    switch(event->event_id) {
        case SYSTEM_EVENT_STA_START:
            DEBUG("%s WiFi started\n", __func__);
            result = esp_wifi_connect();
            if (result != ESP_OK) {
                LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with return "
                              "value %d\n", result);
            }
            break;

        case SYSTEM_EVENT_SCAN_DONE:
            DEBUG("%s WiFi scan done\n", __func__);
            break;

        case SYSTEM_EVENT_STA_CONNECTED:
            DEBUG("%s WiFi connected\n", __func__);

            /* register RX callback function */
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb);

            _esp_wifi_dev.connected = true;
            _esp_wifi_dev.event = SYSTEM_EVENT_STA_CONNECTED;
            _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);

            break;

        case SYSTEM_EVENT_STA_DISCONNECTED:
            DEBUG("%s WiFi disconnected from ssid %s, reason %d\n", __func__,
                  event->event_info.disconnected.ssid,
                  event->event_info.disconnected.reason);

            /* unregister RX callback function */
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);

            _esp_wifi_dev.connected = false;
            _esp_wifi_dev.event = SYSTEM_EVENT_STA_DISCONNECTED;
            _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);

            /* call disconnect to reset internal state */
            result = esp_wifi_disconnect();
            if (result != ESP_OK) {
                LOG_TAG_ERROR("esp_wifi", "esp_wifi_disconnect failed with "
                             "return value %d\n", result);
                return result;
            }

            /* try to reconnect */
            result = esp_wifi_connect();
            if (result != ESP_OK) {
               LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with "
                             "return value %d\n", result);
            }

            break;

        default:
            DEBUG("%s event %d\n", __func__, event->event_id);
            break;
    }
    return ESP_OK;
}

/* we use predefined station configuration */
static wifi_config_t wifi_config_sta = {
    .sta = {
        .ssid = ESP_WIFI_SSID,
        .password = <PASSWORD>,
        .channel = 0,
        .scan_method = WIFI_ALL_CHANNEL_SCAN,
        .sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
        .threshold.rssi = -127,
        .threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK
    }
};

static void esp_wifi_setup (esp_wifi_netdev_t* dev)
{
    DEBUG("%s: %p\n", __func__, dev);

    /*
     * Init the WiFi driver. TODO It is not only required before ESP_WIFI is
     * initialized but also before other WiFi functions are used. Once other
     * WiFi functions are realized it has to be moved to a more common place.
     */
    extern portMUX_TYPE g_intr_lock_mux;
    mutex_init(&g_intr_lock_mux);

    esp_system_event_add_handler (_esp_system_event_handler, NULL);

    esp_err_t result;
    #if CONFIG_ESP32_WIFI_NVS_ENABLED
    result = nvs_flash_init();
    if (result != ESP_OK) {
        LOG_TAG_ERROR("esp_wifi", "nfs_flash_init failed "
                      "with return value %d\n", result);
        return;
    }
    #endif

    /* initialize the WiFi driver with default configuration */
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    result = esp_wifi_init(&cfg);
    if (result != ESP_OK) {
        LOG_TAG_ERROR("esp_wifi", "esp_wifi_init failed "
                      "with return value %d\n", result);
        return;
    }

    #ifdef CONFIG_WIFI_COUNTRY
    /* TODO */
    #endif

    result = esp_wifi_set_mode(WIFI_MODE_STA);
    if (result != ESP_OK) {
        LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_mode failed "
                      "with return value %d\n", result);
        return;
    }

    /* set the Station configuration */
    result = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta);
    if (result != ESP_OK) {
        LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_config station failed "
                      "with return value %d\n", result);
        return;
    }

    /* start the WiFi driver */
    result = esp_wifi_start();
    if (result != ESP_OK) {
        LOG_TAG_ERROR("esp_wifi", "esp_wifi_start failed "
                      "with return value %d\n", result);
        return;
    }

    /* register RX callback function */
    esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb);

    /* set the netdev driver */
    dev->netdev.driver = &_esp_wifi_driver;
{'fraction_non_alphanumeric': 0.09623715806411684, 'fraction_numerical': 0.003218220076742171, 'mean_word_length': 2.5956831330663106, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1867435', 'n_tokens_mistral': 5493, 'n_tokens_neox': 5358, 'n_words': 1318}