diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 259cf22c845..ae6ddab13f0 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -18,6 +18,12 @@ config ARCH_CHIP_ESP32 select ARCH_HAVE_SDRAM select ARCH_HAVE_RESET select ARCH_TOOLCHAIN_GNU + select LIBC_ARCH_MEMCPY + select LIBC_ARCH_MEMCHR + select LIBC_ARCH_MEMCMP + select LIBC_ARCH_MEMCCMP + select LIBC_ARCH_MEMMOVE + select LIBC_ARCH_MEMSET ---help--- The ESP32 is a dual-core system from Espressif with two Harvard architecture Xtensa LX6 CPUs. All embedded memory, external memory diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index cf7e4049a38..6ca1e6f8eea 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -256,6 +256,9 @@ config ESP32_WIRELESS bool "Wireless" default n depends on EXPERIMENTAL + select NET + select ARCH_PHY_INTERRUPT + select ESP32_RNG ---help--- No yet implemented @@ -628,4 +631,38 @@ config ESP32_ETH_PHY_ADDR endmenu # ESP32_EMAC +menu "WiFi configuration" + depends on ESP32_WIRELESS + +config ESP32_WIFI_CONNECT_TIMEOUT + int "Connect timeout by second" + default 10 + help + Max waiting time of connecting to AP. + +config ESP32_WIFI_SAVE_PARAM + bool "Save WiFi Parameters" + default n + help + If you enable this option, WiFi adapter parameters will be saved + into the file system instead of computing them each time. + + These parameters mainly contains: + - SSID + - Password + - BSSID + - PMK(compute when connecting) + - Author mode + - MAC address + - WiFi hardware configuration parameters + +config ESP32_WIFI_FS_MOUNTPT + string "Save WiFi Parameters" + default "/mnt/esp/wifi" + depends on ESP32_WIFI_SAVE_PARAM + help + Mount point of WiFi storage file system. + +endmenu # ESP32_WIRELESS + endif # ARCH_CHIP_ESP32 diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index 10c7d1b187f..b2090daa0a0 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -150,8 +150,10 @@ CHIP_CSRCS += esp32_modtext.c CMN_ASRCS += xtensa_loadstore.S endif +ifeq ($(CONFIG_ESP32_WIRELESS),y) WIRELESS_DRV_UNPACK = esp-wireless-drivers-3rdparty -WIRELESS_DRV_ZIP = master.zip +WIRELESS_DRV_ID = 5cb6561 +WIRELESS_DRV_ZIP = $(WIRELESS_DRV_ID).zip WIRELESS_DRV_URL = https://github.com/espressif/esp-wireless-drivers-3rdparty/archive $(WIRELESS_DRV_ZIP): @@ -161,7 +163,7 @@ $(WIRELESS_DRV_ZIP): chip/$(WIRELESS_DRV_UNPACK): $(WIRELESS_DRV_ZIP) $(Q) echo "Unpacking: ESP Wireless Drivers" $(Q) unzip -oqq chip/$(WIRELESS_DRV_ZIP) -d chip/ - $(Q) mv chip/$(WIRELESS_DRV_UNPACK)-master chip/$(WIRELESS_DRV_UNPACK) + $(Q) mv chip/$(WIRELESS_DRV_UNPACK)-$(WIRELESS_DRV_ID)* chip/$(WIRELESS_DRV_UNPACK) $(Q) touch chip/$(WIRELESS_DRV_UNPACK) context:: chip/$(WIRELESS_DRV_UNPACK) @@ -170,3 +172,14 @@ clean_context:: $(call DELFILE, chip/$(WIRELESS_DRV_ZIP)) $(call DELDIR, chip/$(WIRELESS_DRV_UNPACK)) +INCLUDES += $(shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip$(DELIM)esp-wireless-drivers-3rdparty$(DELIM)include) +CHIP_CSRCS += esp32_wlan.c esp32_wifi_adapter.c + +EXTRA_LIBPATHS += -L $(ARCH_SRCDIR)$(DELIM)chip$(DELIM)esp-wireless-drivers-3rdparty$(DELIM)libs +EXTRA_LIBS += -lcore -lrtc -lnet80211 -lpp -lsmartconfig -lcoexist -lespnow -lphy -lwpa_supplicant + +# Due to some Wi-Fi related libraries, the option is need to avoid linking too much +# unused functions. + +LDFLAGS += --gc-sections +endif diff --git a/arch/xtensa/src/esp32/esp32_wifi_adapter.c b/arch/xtensa/src/esp32/esp32_wifi_adapter.c new file mode 100644 index 00000000000..f4c98593c2d --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wifi_adapter.c @@ -0,0 +1,4430 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wifi_adapter.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nuttx/kmalloc.h" +#include "nuttx/spinlock.h" +#include +#include +#include +#include +#include +#include +#include + +#include "xtensa.h" +#include "xtensa_attr.h" +#include "hardware/esp32_dport.h" +#include "hardware/esp32_emac.h" +#include "esp32_cpuint.h" +#include "esp32_wifi_adapter.h" + +#include "espidf_wifi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PHY_RF_MASK ((1 << PHY_BT_MODULE) | (1 << PHY_WIFI_MODULE)) + +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM +# define NVS_FS_PREFIX CONFIG_ESP32_WIFI_FS_MOUNTPT +# define NVS_DIR_BASE NVS_FS_PREFIX"/wifi." +# define NVS_FILE_MODE 0777 +#endif + +#define WIFI_CONNECT_TIMEOUT CONFIG_ESP32_WIFI_CONNECT_TIMEOUT + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* WiFi interrupt adapter private data */ + +struct irq_adpt +{ + void (*func)(void *arg); /* Interrupt callback function */ + void *arg; /* Interrupt private data */ +}; + +/* WiFi message queue private data */ + +struct mq_adpt +{ + mqd_t mq; /* Message queue handle */ + uint32_t msgsize; /* Message size */ + char name[16]; /* Message queue name */ +}; + +/* WiFi time private data */ + +struct time_adpt +{ + time_t sec; /* Second value */ + suseconds_t usec; /* Micro second value */ +}; + +/* WiFi timer private data */ + +struct timer_adpt +{ + struct wdog_s wdog; /* Timer handle */ + struct work_s work; /* Work private data */ + bool repeat; /* Flags indicate if it is cycle */ + uint32_t delay; /* Timeout ticks */ + + /* Timer callback function */ + + void (*func)(void *priv); + void *priv; /* Timer private data */ +}; + +/* WiFi event private data */ + +struct evt_adpt +{ + sq_entry_t entry; /* Sequence entry */ + int32_t id; /* Event ID */ + uint8_t buf[0]; /* Event private data */ +}; + +/* WiFi event notification private data */ + +struct wifi_notify +{ + bool assigned; /* Flag indicate if it is used */ + pid_t pid; /* Signal's target thread PID */ + struct sigevent event; /* Signal event private data */ + struct sigwork_s work; /* Signal work private data */ +}; + +/* WiFi NVS private data */ + +struct nvs_adpt +{ + char *index_name; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void esp_set_isr(int32_t n, void *f, void *arg); +static void esp32_ints_on(uint32_t mask); +static void esp32_ints_off(uint32_t mask); +static void *esp_spin_lock_create(void); +static void esp_spin_lock_delete(void *lock); +static uint32_t esp_wifi_int_disable(void *wifi_int_mux); +static void esp_wifi_int_restore(void *wifi_int_mux, uint32_t tmp); +static void IRAM_ATTR esp_task_yield_from_isr(void); +static void *esp_semphr_create(uint32_t max, uint32_t init); +static void esp_semphr_delete(void *semphr); +static int32_t esp_semphr_take(void *semphr, uint32_t block_time_tick); +static int32_t esp_semphr_give(void *semphr); +static void *esp_thread_semphr_get(void); +static void *esp_mutex_create(void); +static void *esp_recursive_mutex_create(void); +static void esp_mutex_delete(void *mutex_data); +static int32_t esp_mutex_lock(void *mutex_data); +static int32_t esp_mutex_unlock(void *mutex_data); +static void *esp_queue_create(uint32_t queue_len, uint32_t item_size); +static void esp_queue_delete(void *queue); +static int32_t esp_queue_send(void *queue, void *item, + uint32_t block_time_tick); +static int32_t esp_queue_send_from_isr(void *queue, void *item, void *hptw); +static int32_t esp_queue_send_to_back(void *queue, void *item, + uint32_t block_time_tick); +static int32_t esp_queue_send_to_front(void *queue, void *item, + uint32_t block_time_tick); +static int32_t esp_queue_recv(void *queue, void *item, + uint32_t block_time_tick); +static uint32_t esp_queue_msg_waiting(void *queue); +static void *esp_event_group_create(void); +static void esp_event_group_delete(void *event); +static uint32_t esp_event_group_set_bits(void *event, uint32_t bits); +static uint32_t esp_event_group_clear_bits(void *event, uint32_t bits); +static uint32_t esp_event_group_wait_bits(void *event, + uint32_t bits_to_wait_for, + int32_t clear_on_exit, + int32_t wait_for_all_bits, + uint32_t block_time_tick); +static int32_t esp_task_create_pinned_to_core(void *task_func, + const char *name, + uint32_t stack_depth, + void *param, + uint32_t prio, + void *task_handle, + uint32_t core_id); +static int32_t esp_task_create(void *task_func, const char *name, + uint32_t stack_depth, void *param, + uint32_t prio, void *task_handle); +static void esp_task_delete(void *task_handle); +static void esp_task_delay(uint32_t tick); +static int32_t esp_task_ms_to_tick(uint32_t ms); +static void *esp_task_get_current_task(void); +static int32_t esp_task_get_max_priority(void); +static void *esp_malloc(uint32_t size); +static uint32_t esp_rand(void); +static void esp_dport_access_stall_other_cpu_start(void); +static void esp_dport_access_stall_other_cpu_end(void); +static int32_t esp_phy_deinit_rf(uint32_t module); +static void esp_phy_init(uint32_t module); +static void esp_phy_enable_clock(void); +static void esp_phy_disable_clock(void); +static int32_t esp_wifi_read_mac(uint8_t *mac, uint32_t type); +static void esp_timer_arm(void *timer, uint32_t tmout, bool repeat); +static void esp_timer_disarm(void *timer); +static void esp32_timer_done(void *timer); +static void esp_timer_setfn(void *timer, void *pfunction, void *parg); +static void esp_timer_cb(wdparm_t parm); +static void esp_timer_arm_us(void *timer, uint32_t us, bool repeat); +static void esp_periph_module_enable(uint32_t periph); +static void esp_periph_module_disable(uint32_t periph); +static int32_t esp_nvs_set_i8(uint32_t handle, const char *key, + int8_t value); +static int32_t esp_nvs_get_i8(uint32_t handle, const char *key, + int8_t *out_value); +static int32_t esp_nvs_set_u8(uint32_t handle, const char *key, + uint8_t value); +static int32_t esp_nvs_get_u8(uint32_t handle, const char *key, + uint8_t *out_value); +static int32_t esp_nvs_set_u16(uint32_t handle, const char *key, + uint16_t value); +static int32_t esp_nvs_get_u16(uint32_t handle, const char *key, + uint16_t *out_value); +static int32_t esp_nvs_open(const char *name, uint32_t open_mode, + uint32_t *out_handle); +static void esp_nvs_close(uint32_t handle); +static int32_t esp_nvs_commit(uint32_t handle); +static int32_t esp_nvs_set_blob(uint32_t handle, const char *key, + const void *value, size_t length); +static int32_t esp_nvs_get_blob(uint32_t handle, const char *key, + void *out_value, size_t *length); +static int32_t esp_nvs_erase_key(uint32_t handle, const char *key); +static int32_t esp_get_random(uint8_t *buf, size_t len); +static int32_t esp_get_time(void *t); +static void esp_log_writev(uint32_t level, const char *tag, + const char *format, va_list args); +static void *esp_malloc_internal(size_t size); +static void *esp_realloc_internal(void *ptr, size_t size); +static void *esp_calloc_internal(size_t n, size_t size); +static void *esp_zalloc_internal(size_t size); +static void *esp_wifi_malloc(size_t size); +static void *esp_wifi_realloc(void *ptr, size_t size); +static void *esp_wifi_calloc(size_t n, size_t size); +static void *esp_wifi_zalloc(size_t size); +static int32_t esp_modem_enter_sleep(uint32_t module); +static int32_t esp_modem_exit_sleep(uint32_t module); +static int32_t esp_modem_register_sleep(uint32_t module); +static int32_t esp_modem_deregister_sleep(uint32_t module); +static void *esp_wifi_create_queue(int32_t queue_len, int32_t item_size); +static void esp_wifi_delete_queue(void *queue); +static uint32_t esp_coex_status_get(void); +static void esp_coex_condition_set(uint32_t type, bool dissatisfy); +static int32_t esp_coex_wifi_request(uint32_t event, uint32_t latency, + uint32_t duration); +static int32_t esp_coex_wifi_release(uint32_t event); + +/**************************************************************************** + * Public Functions declaration + ****************************************************************************/ + +int64_t esp_timer_get_time(void); +void esp_fill_random(void *buf, size_t len); +void esp_log_write(uint32_t level, const char *tag, const char *format, ...); +uint32_t esp_log_timestamp(void); +uint8_t esp_crc8(const uint8_t *p, uint32_t len); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* WiFi interrupt private data */ + +static int s_wifi_irq; + +/* WiFi thread private data */ + +static pthread_key_t s_wifi_thread_key; +static bool s_wifi_tkey_init; + +/* WiFi sleep private data */ + +static uint32_t s_esp32_module_mask; +static uint32_t s_esp32_module_sleep; +static bool s_esp32_sleep; +static uint32_t s_phy_clk_en_cnt = 0; +static bool s_esp23_phy_en; +static uint32_t s_esp32_phy_init_mask; +static int64_t s_esp32_phy_rf_stop_tm; + +/* WiFi event private data */ + +static struct work_s s_wifi_evt_work; +static sq_queue_t s_wifi_evt_queue; +static struct wifi_notify s_wifi_notify[WIFI_ADPT_EVT_MAX]; +static sem_t s_connect_sem; +static bool s_connected; + +static uint8_t s_ssid[32]; +static uint8_t s_password[64]; +static uint8_t s_ssid_len; +static uint8_t s_password_len; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* WiFi OS adapter data */ + +wifi_osi_funcs_t g_wifi_osi_funcs = +{ + ._version = ESP_WIFI_OS_ADAPTER_VERSION, + ._set_isr = esp_set_isr, + ._ints_on = esp32_ints_on, + ._ints_off = esp32_ints_off, + ._spin_lock_create = esp_spin_lock_create, + ._spin_lock_delete = esp_spin_lock_delete, + ._wifi_int_disable = esp_wifi_int_disable, + ._wifi_int_restore = esp_wifi_int_restore, + ._task_yield_from_isr = esp_task_yield_from_isr, + ._semphr_create = esp_semphr_create, + ._semphr_delete = esp_semphr_delete, + ._semphr_take = esp_semphr_take, + ._semphr_give = esp_semphr_give, + ._wifi_thread_semphr_get = esp_thread_semphr_get, + ._mutex_create = esp_mutex_create, + ._recursive_mutex_create = esp_recursive_mutex_create, + ._mutex_delete = esp_mutex_delete, + ._mutex_lock = esp_mutex_lock, + ._mutex_unlock = esp_mutex_unlock, + ._queue_create = esp_queue_create, + ._queue_delete = esp_queue_delete, + ._queue_send = esp_queue_send, + ._queue_send_from_isr = esp_queue_send_from_isr, + ._queue_send_to_back = esp_queue_send_to_back, + ._queue_send_to_front = esp_queue_send_to_front, + ._queue_recv = esp_queue_recv, + ._queue_msg_waiting = esp_queue_msg_waiting, + ._event_group_create = esp_event_group_create, + ._event_group_delete = esp_event_group_delete, + ._event_group_set_bits = esp_event_group_set_bits, + ._event_group_clear_bits = esp_event_group_clear_bits, + ._event_group_wait_bits = esp_event_group_wait_bits, + ._task_create_pinned_to_core = esp_task_create_pinned_to_core, + ._task_create = esp_task_create, + ._task_delete = esp_task_delete, + ._task_delay = esp_task_delay, + ._task_ms_to_tick = esp_task_ms_to_tick, + ._task_get_current_task = esp_task_get_current_task, + ._task_get_max_priority = esp_task_get_max_priority, + ._malloc = esp_malloc, + ._free = free, + ._event_post = esp_event_post, + ._get_free_heap_size = esp_get_free_heap_size, + ._rand = esp_rand, + ._dport_access_stall_other_cpu_start_wrap = + esp_dport_access_stall_other_cpu_start, + ._dport_access_stall_other_cpu_end_wrap = + esp_dport_access_stall_other_cpu_end, + ._phy_rf_deinit = esp_phy_deinit_rf, + ._phy_load_cal_and_init = esp_phy_init, + ._phy_common_clock_enable = esp_phy_enable_clock, + ._phy_common_clock_disable = esp_phy_disable_clock, + ._read_mac = esp_wifi_read_mac, + ._timer_arm = esp_timer_arm, + ._timer_disarm = esp_timer_disarm, + ._timer_done = esp32_timer_done, + ._timer_setfn = esp_timer_setfn, + ._timer_arm_us = esp_timer_arm_us, + ._periph_module_enable = esp_periph_module_enable, + ._periph_module_disable = esp_periph_module_disable, + ._esp_timer_get_time = esp_timer_get_time, + ._nvs_set_i8 = esp_nvs_set_i8, + ._nvs_get_i8 = esp_nvs_get_i8, + ._nvs_set_u8 = esp_nvs_set_u8, + ._nvs_get_u8 = esp_nvs_get_u8, + ._nvs_set_u16 = esp_nvs_set_u16, + ._nvs_get_u16 = esp_nvs_get_u16, + ._nvs_open = esp_nvs_open, + ._nvs_close = esp_nvs_close, + ._nvs_commit = esp_nvs_commit, + ._nvs_set_blob = esp_nvs_set_blob, + ._nvs_get_blob = esp_nvs_get_blob, + ._nvs_erase_key = esp_nvs_erase_key, + ._get_random = esp_get_random, + ._get_time = esp_get_time, + ._random = esp_random, + ._log_write = esp_log_write, + ._log_writev = esp_log_writev, + ._log_timestamp = esp_log_timestamp, + ._malloc_internal = esp_malloc_internal, + ._realloc_internal = esp_realloc_internal, + ._calloc_internal = esp_calloc_internal, + ._zalloc_internal = esp_zalloc_internal, + ._wifi_malloc = esp_wifi_malloc, + ._wifi_realloc = esp_wifi_realloc, + ._wifi_calloc = esp_wifi_calloc, + ._wifi_zalloc = esp_wifi_zalloc, + ._wifi_create_queue = esp_wifi_create_queue, + ._wifi_delete_queue = esp_wifi_delete_queue, + ._modem_sleep_enter = esp_modem_enter_sleep, + ._modem_sleep_exit = esp_modem_exit_sleep, + ._modem_sleep_register = esp_modem_register_sleep, + ._modem_sleep_deregister = esp_modem_deregister_sleep, + ._coex_status_get = esp_coex_status_get, + ._coex_condition_set = esp_coex_condition_set, + ._coex_wifi_request = esp_coex_wifi_request, + ._coex_wifi_release = esp_coex_wifi_release, + ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, +}; + +/* WiFi feature capacity data */ + +uint64_t g_wifi_feature_caps; + +/* WiFi TAG string data */ + +ESP_EVENT_DEFINE_BASE(WIFI_EVENT); + +/**************************************************************************** + * Private Functions and Public Functions only used by libraries + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_errno_trans + * + * Description: + * Transform from nuttx error code to WiFi adapter error code + * + * Input Parameters: + * ret - Nuttx error code + * + * Returned Value: + * WiFi adapter error code + * + ****************************************************************************/ + +static inline int32_t esp_errno_trans(int ret) +{ + if (!ret) + { + return true; + } + else + { + return false; + } +} + +/**************************************************************************** + * Name: esp_int_adpt_cb + * + * Description: + * WiFi interrupt adapter callback function + * + * Input Parameters: + * arg - interrupt adapter private data + * + * Returned Value: + * 0 on success + * + ****************************************************************************/ + +static int esp_int_adpt_cb(int irq, void *context, FAR void *arg) +{ + struct irq_adpt *adapter = (struct irq_adpt *)arg; + + adapter->func(adapter->arg); + + return 0; +} + +/**************************************************************************** + * Name: esp_thread_semphr_free + * + * Description: + * Delete thread self's semaphore + * + * Input Parameters: + * semphr - Semphore data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_thread_semphr_free(void *semphr) +{ + if (semphr) + { + esp_semphr_delete(semphr); + } +} + +/**************************************************************************** + * Name: esp_update_time + * + * Description: + * Transform ticks to time and add this time to timespec value + * + * Input Parameters: + * timespec - Input timespec data pointer + * ticks - System ticks + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_update_time(struct timespec *timespec, uint32_t ticks) +{ + uint32_t tmp; + + tmp = TICK2SEC(ticks); + timespec->tv_sec += tmp; + + ticks -= SEC2TICK(tmp); + tmp = TICK2NSEC(ticks); + + timespec->tv_nsec += tmp; +} + +/**************************************************************************** + * Name: esp_set_isr + * + * Description: + * Register interrupt function + * + * Input Parameters: + * n - Interrupt ID + * f - Interrupt function + * arg - Function private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_set_isr(int32_t n, void *f, void *arg) +{ + int ret; + struct irq_adpt *adapter; + int irq; + int cpu = 0; + int tmp; + + irq = esp32_alloc_levelint(1); + if (irq < 0) + { + wlerr("ERROR: Failed to alloc interrupt\n"); + assert(0); + return ; + } + + up_disable_irq(irq); + + tmp = sizeof(struct irq_adpt); + adapter = kmm_malloc(tmp); + if (!adapter) + { + wlerr("ERROR: Failed to alloc %d memory\n", tmp); + assert(0); + return ; + } + + adapter->func = f; + adapter->arg = arg; + + tmp = n + XTENSA_IRQ_FIRSTPERIPH; + ret = irq_attach(tmp, esp_int_adpt_cb, adapter); + if (ret) + { + wlerr("ERROR: Failed to attach IRQ %d\n", tmp); + assert(0); + return ; + } + + esp32_attach_peripheral(cpu, n, irq); + + s_wifi_irq = irq; +} + +/**************************************************************************** + * Name: esp32_ints_on + * + * Description: + * Enable WiFi interrupt + * + * Input Parameters: + * mask - No mean + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_ints_on(uint32_t mask) +{ + up_enable_irq(s_wifi_irq); +} + +/**************************************************************************** + * Name: esp32_ints_on + * + * Description: + * Disable WiFi interrupt + * + * Input Parameters: + * mask - No mean + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_ints_off(uint32_t mask) +{ + up_disable_irq(s_wifi_irq); +} + +/**************************************************************************** + * Name: esp_spin_lock_create + * + * Description: + * Create spin lock in SMP mode + * + * Input Parameters: + * None + * + * Returned Value: + * Spin lock data pointer + * + ****************************************************************************/ + +static void *esp_spin_lock_create(void) +{ +#ifdef CONFIG_SMP + spinlock_t *lock; + int tmp; + + tmp = sizeof(struct spinlock_t); + lock = kmm_malloc(tmp); + if (!lock) + { + wlerr("ERROR: Failed to alloc %d memory\n", tmp); + DEBUGASSERT(0); + } + + spin_initialize(lock, SP_UNLOCKED); + + return lock; +#else + /* If return NULL, code may check fail */ + + return (void *)1; +#endif +} + +/**************************************************************************** + * Name: esp_spin_lock_delete + * + * Description: + * Delete spin lock + * + * Input Parameters: + * lock - Spin lock data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_spin_lock_delete(void *lock) +{ +#ifdef CONFIG_SMP + kmm_free(lock); +#else + DEBUGASSERT((int)lock == 1); +#endif +} + +/**************************************************************************** + * Name: esp_wifi_int_disable + * + * Description: + * Enter critical by disable interrup, and take spin lock if + * in SMP mode + * + * Input Parameters: + * wifi_int_mux - Spin lock data pointer + * + * Returned Value: + * CPU PS value. + * + ****************************************************************************/ + +static uint32_t IRAM_ATTR esp_wifi_int_disable(void *wifi_int_mux) +{ + irqstate_t flags; + + flags = enter_critical_section(); + +#ifdef CONFIG_SMP + spin_lock((volatile spinlock_t *)wifi_int_mux); +#endif + + return (uint32_t)flags; +} + +/**************************************************************************** + * Name: esp_wifi_int_restore + * + * Description: + * Exit from critical by enable interrup, and release spin + * lock if in SMP mode + * + * Input Parameters: + * wifi_int_mux - Spin lock data pointer + * tmp - CPU PS value. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void IRAM_ATTR esp_wifi_int_restore(void *wifi_int_mux, uint32_t tmp) +{ + irqstate_t flags = (irqstate_t)tmp; + +#ifdef CONFIG_SMP + spin_unlock((volatile spinlock_t *)wifi_int_mux); +#endif + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: esp_task_yield_from_isr + * + * Description: + * Do nothing in Nuttx + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void IRAM_ATTR esp_task_yield_from_isr(void) +{ + /* Do nothing */ +} + +/**************************************************************************** + * Name: esp_semphr_create + * + * Description: + * Create and initialize semaphore + * + * Input Parameters: + * max - No mean + * init - semaphore initialization value + * + * Returned Value: + * Semphore data pointer + * + ****************************************************************************/ + +static void *esp_semphr_create(uint32_t max, uint32_t init) +{ + int ret; + sem_t *sem; + int tmp; + + tmp = sizeof(sem_t); + sem = kmm_malloc(tmp); + if (!sem) + { + wlerr("ERROR: Failed to alloc %d memory\n", tmp); + return NULL; + } + + ret = sem_init(sem, 0, init); + if (ret) + { + wlerr("ERROR: Failed to initialize sem error=%d\n", ret); + kmm_free(sem); + return NULL; + } + + return sem; +} + +/**************************************************************************** + * Name: esp_semphr_delete + * + * Description: + * Delete semaphore + * + * Input Parameters: + * semphr - Semphore data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_semphr_delete(void *semphr) +{ + sem_t *sem = (sem_t *)semphr; + + sem_destroy(sem); + kmm_free(sem); +} + +/**************************************************************************** + * Name: esp_semphr_take + * + * Description: + * Wait semaphore within a certain period of time + * + * Input Parameters: + * semphr - Semphore data pointer + * ticks - Wait system ticks + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_semphr_take(void *semphr, uint32_t ticks) +{ + int ret; + struct timespec timeout; + sem_t *sem = (sem_t *)semphr; + + if (ticks == OSI_FUNCS_TIME_BLOCKING) + { + ret = sem_wait(sem); + if (ret) + { + wlerr("ERROR: Failed to wait sem\n"); + } + } + else + { + ret = clock_gettime(CLOCK_REALTIME, &timeout); + if (ret < 0) + { + wlerr("ERROR: Failed to get time\n"); + return false; + } + + if (ticks) + { + esp_update_time(&timeout, ticks); + } + + ret = sem_timedwait(sem, &timeout); + if (ret) + { + wlerr("ERROR: Failed to wait sem in %d ticks\n", ticks); + } + } + + return esp_errno_trans(ret); +} + +/**************************************************************************** + * Name: esp_semphr_give + * + * Description: + * Post semaphore + * + * Input Parameters: + * semphr - Semphore data pointer + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_semphr_give(void *semphr) +{ + int ret; + sem_t *sem = (sem_t *)semphr; + + ret = sem_post(sem); + if (ret) + { + wlerr("ERROR: Failed to post sem error=%d\n", ret); + } + + return esp_errno_trans(ret); +} + +/**************************************************************************** + * Name: esp_thread_semphr_get + * + * Description: + * Get thread self's semaphore + * + * Input Parameters: + * None + * + * Returned Value: + * Semphore data pointer + * + ****************************************************************************/ + +static void *esp_thread_semphr_get(void) +{ + int ret; + void *sem; + + if (s_wifi_tkey_init) + { + ret = pthread_key_create(&s_wifi_thread_key, esp_thread_semphr_free); + if (ret) + { + wlerr("ERROR: Failed to create pthread key\n"); + return NULL; + } + + s_wifi_tkey_init = true; + } + + sem = pthread_getspecific(s_wifi_thread_key); + if (!sem) + { + sem = esp_semphr_create(1, 0); + if (!sem) + { + wlerr("ERROR: Failed to create semaphore\n"); + return NULL; + } + + ret = pthread_setspecific(s_wifi_thread_key, sem); + if (ret) + { + wlerr("ERROR: Failed to set specific\n"); + esp_semphr_delete(sem); + return NULL; + } + } + + return sem; +} + +/**************************************************************************** + * Name: esp_mutex_create + * + * Description: + * Create mutex + * + * Input Parameters: + * None + * + * Returned Value: + * Mutex data pointer + * + ****************************************************************************/ + +static void *esp_mutex_create(void) +{ + int ret; + pthread_mutex_t *mutex; + int tmp; + + tmp = sizeof(pthread_mutex_t); + mutex = kmm_malloc(tmp); + if (!mutex) + { + wlerr("ERROR: Failed to alloc %d memory\n", tmp); + return NULL; + } + + ret = pthread_mutex_init(mutex, NULL); + if (ret) + { + wlerr("ERROR: Failed to initialize mutex error=%d\n", ret); + kmm_free(mutex); + return NULL; + } + + return mutex; +} + +/**************************************************************************** + * Name: esp_recursive_mutex_create + * + * Description: + * Create recursive mutex + * + * Input Parameters: + * None + * + * Returned Value: + * Recursive mutex data pointer + * + ****************************************************************************/ + +static void *esp_recursive_mutex_create(void) +{ + int ret; + pthread_mutex_t *mutex; + pthread_mutexattr_t attr; + int tmp; + + ret = pthread_mutexattr_init(&attr); + if (ret) + { + wlerr("ERROR: Failed to initialize attr error=%d\n", ret); + return NULL; + } + + ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + if (ret) + { + wlerr("ERROR: Failed to set attr type error=%d\n", ret); + return NULL; + } + + tmp = sizeof(pthread_mutex_t); + mutex = kmm_malloc(tmp); + if (!mutex) + { + wlerr("ERROR: Failed to alloc %d memory\n", tmp); + return NULL; + } + + ret = pthread_mutex_init(mutex, &attr); + if (ret) + { + wlerr("ERROR: Failed to initialize mutex error=%d\n", ret); + kmm_free(mutex); + return NULL; + } + + return mutex; +} + +/**************************************************************************** + * Name: esp_mutex_delete + * + * Description: + * Delete mutex + * + * Input Parameters: + * mutex_data - mutex data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_mutex_delete(void *mutex_data) +{ + pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data; + + pthread_mutex_destroy(mutex); + kmm_free(mutex); +} + +/**************************************************************************** + * Name: esp_mutex_lock + * + * Description: + * Lock mutex + * + * Input Parameters: + * mutex_data - mutex data pointer + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_mutex_lock(void *mutex_data) +{ + int ret; + pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data; + + ret = pthread_mutex_lock(mutex); + if (ret) + { + wlerr("ERROR: Failed to lock mutex error=%d\n", ret); + } + + return esp_errno_trans(ret); +} + +/**************************************************************************** + * Name: esp_mutex_unlock + * + * Description: + * Unlock mutex + * + * Input Parameters: + * mutex_data - mutex data pointer + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_mutex_unlock(void *mutex_data) +{ + int ret; + pthread_mutex_t *mutex = (pthread_mutex_t *)mutex_data; + + ret = pthread_mutex_unlock(mutex); + if (ret) + { + wlerr("ERROR: Failed to unlock mutex error=%d\n", ret); + } + + return esp_errno_trans(ret); +} + +/**************************************************************************** + * Name: esp_queue_create + * + * Description: + * Create message queue + * + * Input Parameters: + * queue_len - queue message number + * item_size - message size + * + * Returned Value: + * Message queue data pointer + * + ****************************************************************************/ + +static void *esp_queue_create(uint32_t queue_len, uint32_t item_size) +{ + struct mq_attr attr; + mqd_t mq; + struct mq_adpt *mq_adpt; + + mq_adpt = kmm_malloc(sizeof(struct mq_adpt)); + if (!mq_adpt) + { + wlerr("ERROR: Failed to malloc\n"); + return NULL; + } + + snprintf(mq_adpt->name, sizeof(mq_adpt->name), + "/tmp/%X", mq_adpt); + + attr.mq_maxmsg = queue_len; + attr.mq_msgsize = item_size; + attr.mq_curmsgs = 0; + attr.mq_flags = 0; + + mq = mq_open(mq_adpt->name, O_RDWR | O_CREAT, 0644, &attr); + if (!mq) + { + wlerr("ERROR: Failed to create mqueue\n"); + kmm_free(mq_adpt); + return NULL; + } + + mq_adpt->mq = mq; + mq_adpt->msgsize = item_size; + + return (void *)mq_adpt; +} + +/**************************************************************************** + * Name: esp_queue_delete + * + * Description: + * Delete message queue + * + * Input Parameters: + * queue - Message queue data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_queue_delete(void *queue) +{ + struct mq_adpt *mq_adpt = (struct mq_adpt *)queue; + + mq_close(mq_adpt->mq); + mq_unlink(mq_adpt->name); + kmm_free(mq_adpt); +} + +/**************************************************************************** + * Name: esp_queue_send_generic + * + * Description: + * Generic send message to queue within a certain period of time + * + * Input Parameters: + * queue - Message queue data pointer + * item - Message data pointer + * ticks - Wait ticks + * prio - Message priority + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_queue_send_generic(void *queue, void *item, + uint32_t ticks, int prio) +{ + int ret; + struct timespec timeout; + struct mq_adpt *mq_adpt = (struct mq_adpt *)queue; + + if (ticks == OSI_FUNCS_TIME_BLOCKING || ticks == 0) + { + /** + * WiFi interrupt function will call this adapter function to send + * message to message queue, so here we should call kernel API + * instead of application API + */ + + ret = nxmq_send(mq_adpt->mq, (const char *)item, + mq_adpt->msgsize, prio); + if (ret < 0) + { + wlerr("ERROR: Failed to send message to mqueue error=%d\n", + ret); + } + } + else + { + ret = clock_gettime(CLOCK_REALTIME, &timeout); + if (ret < 0) + { + wlerr("ERROR: Failed to get time\n"); + return false; + } + + if (ticks) + { + esp_update_time(&timeout, ticks); + } + + ret = mq_timedsend(mq_adpt->mq, (const char *)item, + mq_adpt->msgsize, prio, &timeout); + if (ret < 0) + { + wlerr("ERROR: Failed to timedsend message to mqueue error=%d\n", + ret); + } + } + + return esp_errno_trans(ret); +} + +/**************************************************************************** + * Name: esp_queue_send + * + * Description: + * Send message of low priority to queue within a certain period of time + * + * Input Parameters: + * queue - Message queue data pointer + * item - Message data pointer + * ticks - Wait ticks + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_queue_send(void *queue, void *item, uint32_t ticks) +{ + return esp_queue_send_generic(queue, item, ticks, 0); +} + +/**************************************************************************** + * Name: esp_queue_send_from_isr + * + * Description: + * Send message of low priority to queue in ISR within + * a certain period of time + * + * Input Parameters: + * queue - Message queue data pointer + * item - Message data pointer + * hptw - No mean + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_queue_send_from_isr(void *queue, void *item, void *hptw) +{ + /* Force to set the value to be false */ + + *((int *)hptw) = false; + + return esp_queue_send_generic(queue, item, 0, 0); +} + +/**************************************************************************** + * Name: esp_queue_send_to_back + * + * Description: + * Send message of low priority to queue within a certain period of time + * + * Input Parameters: + * queue - Message queue data pointer + * item - Message data pointer + * ticks - Wait ticks + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_queue_send_to_back(void *queue, void *item, + uint32_t ticks) +{ + return esp_queue_send_generic(queue, item, ticks, 0); +} + +/**************************************************************************** + * Name: esp_queue_send_from_isr + * + * Description: + * Send message of high priority to queue within a certain period of time + * + * Input Parameters: + * queue - Message queue data pointer + * item - Message data pointer + * ticks - Wait ticks + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_queue_send_to_front(void *queue, void *item, + uint32_t ticks) +{ + return esp_queue_send_generic(queue, item, ticks, 1); +} + +/**************************************************************************** + * Name: esp_queue_recv + * + * Description: + * Receive message from queue within a certain period of time + * + * Input Parameters: + * queue - Message queue data pointer + * item - Message data pointer + * ticks - Wait ticks + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_queue_recv(void *queue, void *item, uint32_t ticks) +{ + ssize_t ret; + struct timespec timeout; + unsigned int prio; + struct mq_adpt *mq_adpt = (struct mq_adpt *)queue; + + if (ticks == OSI_FUNCS_TIME_BLOCKING) + { + ret = mq_receive(mq_adpt->mq, (char *)item, + mq_adpt->msgsize, &prio); + if (ret < 0) + { + wlerr("ERROR: Failed to receive from mqueue error=%d\n", ret); + } + } + else + { + ret = clock_gettime(CLOCK_REALTIME, &timeout); + if (ret < 0) + { + wlerr("ERROR: Failed to get time\n"); + return false; + } + + if (ticks) + { + esp_update_time(&timeout, ticks); + } + + ret = mq_timedreceive(mq_adpt->mq, (char *)item, + mq_adpt->msgsize, &prio, &timeout); + if (ret < 0) + { + wlerr("ERROR: Failed to timedreceive from mqueue error=%d\n", + ret); + } + } + + return ret > 0 ? true : false; +} + +/**************************************************************************** + * Name: esp_queue_msg_waiting + * + * Description: + * Get message number in the message queue + * + * Input Parameters: + * queue - Message queue data pointer + * + * Returned Value: + * Message number + * + ****************************************************************************/ + +static uint32_t esp_queue_msg_waiting(void *queue) +{ + int ret; + struct mq_attr attr; + struct mq_adpt *mq_adpt = (struct mq_adpt *)queue; + + ret = mq_getattr(mq_adpt->mq, &attr); + if (ret < 0) + { + wlerr("ERROR: Failed to get attr from mqueue error=%d\n", ret); + return 0; + } + + return attr.mq_curmsgs; +} + +/**************************************************************************** + * Name: esp_event_group_create + * + * Description: + * Don't support + * + ****************************************************************************/ + +static void *esp_event_group_create(void) +{ + DEBUGASSERT(0); + + return NULL; +} + +/**************************************************************************** + * Name: esp_event_group_delete + * + * Description: + * Don't support + * + ****************************************************************************/ + +static void esp_event_group_delete(void *event) +{ + DEBUGASSERT(0); +} + +/**************************************************************************** + * Name: esp_event_group_set_bits + * + * Description: + * Don't support + * + ****************************************************************************/ + +static uint32_t esp_event_group_set_bits(void *event, uint32_t bits) +{ + DEBUGASSERT(0); + + return false; +} + +/**************************************************************************** + * Name: esp_event_group_clear_bits + * + * Description: + * Don't support + * + ****************************************************************************/ + +static uint32_t esp_event_group_clear_bits(void *event, uint32_t bits) +{ + DEBUGASSERT(0); + + return false; +} + +/**************************************************************************** + * Name: esp_event_group_wait_bits + * + * Description: + * Don't support + * + ****************************************************************************/ + +static uint32_t esp_event_group_wait_bits(void *event, + uint32_t bits_to_wait_for, + int32_t clear_on_exit, + int32_t wait_for_all_bits, + uint32_t block_time_tick) +{ + DEBUGASSERT(0); + + return false; +} + +/**************************************************************************** + * Name: esp_task_create_pinned_to_core + * + * Description: + * Create task and bind it to target CPU, the task will run when it + * is created + * + * Input Parameters: + * entry - Task entry + * name - Task name + * stack_depth - Task stack size + * param - Task private data + * prio - Task priority + * task_handle - Task handle pointer which is used to pause, resume + * and delete the task + * core_id - CPU which the task runs in + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_task_create_pinned_to_core(void *entry, + const char *name, + uint32_t stack_depth, + void *param, + uint32_t prio, + void *task_handle, + uint32_t core_id) +{ + int pid; +#ifdef CONFIG_SMP + int ret; + cpu_set_t cpuset; +#endif + + pid = kthread_create(name, prio, stack_depth, entry, + (char * const *)param); + if (pid > 0) + { + *((int *)task_handle) = pid; + +#ifdef CONFIG_SMP + if (core_id < CONFIG_SMP_NCPUS) + { + CPU_ZERO(&cpuset); + CPU_SET(core_id, &cpuset); + ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset); + if (ret) + { + wlerr("ERROR: Failed to set affinity error=%d\n", ret); + return false; + } + } +#endif + } + else + { + wlerr("ERROR: Failed to create task\n"); + } + + return pid > 0 ? true : false; +} + +/**************************************************************************** + * Name: esp_task_create + * + * Description: + * Create task and the task will run when it is created + * + * Input Parameters: + * entry - Task entry + * name - Task name + * stack_depth - Task stack size + * param - Task private data + * prio - Task priority + * task_handle - Task handle pointer which is used to pause, resume + * and delete the task + * + * Returned Value: + * True if success or false if fail + * + ****************************************************************************/ + +static int32_t esp_task_create(void *entry, const char *name, + uint32_t stack_depth, void *param, + uint32_t prio, void *task_handle) +{ + return esp_task_create_pinned_to_core(entry, name, stack_depth, param, + prio, task_handle, UINT32_MAX); +} + +/**************************************************************************** + * Name: esp_task_delete + * + * Description: + * Delete the target task + * + * Input Parameters: + * task_handle - Task handle pointer which is used to pause, resume + * and delete the task + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_task_delete(void *task_handle) +{ + pid_t pid = (pid_t)((uintptr_t)task_handle); + + kthread_delete(pid); +} + +/**************************************************************************** + * Name: esp_task_delay + * + * Description: + * Current task wait for some ticks + * + * Input Parameters: + * tick - Waiting ticks + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_task_delay(uint32_t tick) +{ + useconds_t us = TICK2USEC(tick); + + usleep(us); +} + +/**************************************************************************** + * Name: esp_task_ms_to_tick + * + * Description: + * Transform from millim seconds to system ticks + * + * Input Parameters: + * ms - Millim seconds + * + * Returned Value: + * System ticks + * + ****************************************************************************/ + +static int32_t esp_task_ms_to_tick(uint32_t ms) +{ + return MSEC2TICK(ms); +} + +/**************************************************************************** + * Name: esp_task_get_current_task + * + * Description: + * Transform from millim seconds to system ticks + * + * Input Parameters: + * ms - Millim seconds + * + * Returned Value: + * System ticks + * + ****************************************************************************/ + +static void *esp_task_get_current_task(void) +{ + pid_t pid = getpid(); + + return (void *)((uintptr_t)pid); +} + +/**************************************************************************** + * Name: esp_task_get_current_task + * + * Description: + * Get OS task maxium priority + * + * Input Parameters: + * None + * + * Returned Value: + * Task maxium priority + * + ****************************************************************************/ + +static int32_t esp_task_get_max_priority(void) +{ + return SCHED_PRIORITY_MAX; +} + +/**************************************************************************** + * Name: esp_malloc_internal + * + * Description: + * Allocate a block of memory + * + * Input Parameters: + * size - memory size + * + * Returned Value: + * Memory pointer + * + ****************************************************************************/ + +static void *esp_malloc(uint32_t size) +{ + return malloc(size); +} + +/**************************************************************************** + * Name: esp_event_id_map + * + * Description: + * Transform from esp-idf event ID to WiFi adapter event ID + * + * Input Parameters: + * event_id - esp-idf event ID + * + * Returned Value: + * WiFi adapter event ID + * + ****************************************************************************/ + +static int esp_event_id_map(int event_id) +{ + int id; + + switch (event_id) + { + case WIFI_EVENT_STA_START: + id = WIFI_ADPT_EVT_STA_START; + break; + case WIFI_EVENT_STA_CONNECTED: + id = WIFI_ADPT_EVT_STA_CONNECT; + break; + case WIFI_EVENT_STA_DISCONNECTED: + id = WIFI_ADPT_EVT_STA_DISCONNECT; + break; + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + id = WIFI_ADPT_EVT_STA_AUTHMODE_CHANGE; + break; + case WIFI_EVENT_STA_STOP: + id = WIFI_ADPT_EVT_STA_STOP; + break; + default: + return -1; + } + + return id; +} + +/**************************************************************************** + * Name: esp_evt_work_cb + * + * Description: + * Process the cached event + * + * Input Parameters: + * arg - No mean + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_evt_work_cb(FAR void *arg) +{ + int ret; + irqstate_t flags; + struct evt_adpt *evt_adpt; + struct wifi_notify *notify; + + while (1) + { + flags = enter_critical_section(); + evt_adpt = (struct evt_adpt *)sq_remfirst(&s_wifi_evt_queue); + leave_critical_section(flags); + if (!evt_adpt) + { + break; + } + + switch (evt_adpt->id) + { + case WIFI_ADPT_EVT_STA_START: + ret = esp_wifi_connect(); + if (ret) + { + wlerr("ERROR: Failed to connect\n"); + } + break; + case WIFI_ADPT_EVT_STA_CONNECT: + s_connected = true; + ret = sem_post(&s_connect_sem); + if (ret) + { + wlerr("ERROR: Failed to post sem error=%d\n", errno); + } + break; + case WIFI_ADPT_EVT_STA_DISCONNECT: + s_connected = false; + ret = esp_wifi_connect(); + if (ret) + { + wlerr("ERROR: Failed to connect\n"); + } + break; + default: + break; + } + + notify = &s_wifi_notify[evt_adpt->id]; + if (notify->assigned) + { + notify->event.sigev_value.sival_ptr = evt_adpt->buf; + + ret = nxsig_notification(notify->pid, ¬ify->event, + SI_QUEUE, ¬ify->work); + if (ret < 0) + { + wlwarn("ERROR: nxsig_notification event ID=%d failed: %d\n", + evt_adpt->id, ret); + } + } + + free(evt_adpt); + } +} + +/**************************************************************************** + * Name: esp_event_post + * + * Description: + * Active work queue and let the work to process the cached event + * + * Input Parameters: + * event_base - Event set name + * event_id - Event ID + * event_data - Event private data + * event_data_size - Event data size + * ticks - Waiting system ticks + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_event_post(esp_event_base_t event_base, + int32_t event_id, + void *event_data, + size_t event_data_size, + uint32_t ticks) +{ + size_t size; + int32_t id; + irqstate_t flags; + struct evt_adpt *evt_adpt; + + wlinfo("Event: base=%s id=%d data=%p data_size=%d ticks=%u\n", event_base, + event_id, event_data, event_data_size, ticks); + + id = esp_event_id_map(event_id); + if (id < 0) + { + wlerr("ERROR: No process event %d\n", event_id); + return -1; + } + + size = event_data_size + sizeof(struct evt_adpt); + evt_adpt = malloc(size); + if (!evt_adpt) + { + wlerr("ERROR: Failed to alloc %d memory\n", size); + return -1; + } + + evt_adpt->id = id; + memcpy(evt_adpt->buf, event_data, event_data_size); + + flags = enter_critical_section(); + sq_addlast(&evt_adpt->entry, &s_wifi_evt_queue); + leave_critical_section(flags); + + work_queue(LPWORK, &s_wifi_evt_work, esp_evt_work_cb, NULL, 0); + + return 0; +} + +/**************************************************************************** + * Name: esp_task_get_current_task + * + * Description: + * Get free heap size by byte + * + * Input Parameters: + * None + * + * Returned Value: + * Free heap size + * + ****************************************************************************/ + +uint32_t esp_get_free_heap_size(void) +{ + int ret; + struct mallinfo info; + + ret = mm_mallinfo(&g_mmheap, &info); + if (ret) + { + wlerr("ERROR: Failed to create task\n"); + return 0; + } + + return info.fordblks; +} + +/**************************************************************************** + * Name: esp_dport_access_stall_other_cpu_start + * + * Description: + * Don't support + * + ****************************************************************************/ + +static void esp_dport_access_stall_other_cpu_start(void) +{ +#ifdef CONFIG_SMP + DEBUGASSERT(0); +#endif +} + +/**************************************************************************** + * Name: esp_dport_access_stall_other_cpu_end + * + * Description: + * Don't support + * + ****************************************************************************/ + +static void esp_dport_access_stall_other_cpu_end(void) +{ +#ifdef CONFIG_SMP + DEBUGASSERT(0); +#endif +} + +/**************************************************************************** + * Name: esp_phy_rf_init + * + * Description: + * Initialize PHY hardware with given parameters + * + * Input Parameters: + * init_data - PHY hardware initialization parameters + * mode - PHY RF calculation mode + * calibration_data - PHY RF calculation parameters + * module - PHY mode which is to be initialized + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_phy_rf_init(const esp_phy_init_data_t *init_data, + esp_phy_calibration_mode_t mode, + esp_phy_calibration_data_t *calibration_data, + phy_rf_module_t module) +{ + irqstate_t flags; + int64_t time; + bool enable = false; + + if (module >= PHY_MODULE_COUNT) + { + return -1; + } + + flags = enter_critical_section(); + + s_esp32_phy_init_mask |= 1 << module; + + if (s_esp23_phy_en) + { + leave_critical_section(flags); + return 0; + } + + if (module == PHY_MODEM_MODULE) + { + if (s_esp32_phy_init_mask & PHY_RF_MASK) + { + enable = true; + } + } + else if (module == PHY_WIFI_MODULE || module == PHY_BT_MODULE) + { + enable = true; + } + + if (enable) + { + if (s_esp32_phy_rf_stop_tm) + { + time = esp_timer_get_time() - s_esp32_phy_rf_stop_tm; + esp_wifi_internal_update_mac_time((uint32_t)time); + s_esp32_phy_rf_stop_tm = 0; + } + + esp_phy_enable_clock(); + + phy_set_wifi_mode_only(0); + + register_chipv7_phy(init_data, calibration_data, mode); + + s_esp23_phy_en = true; + } + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: esp_phy_deinit_rf + * + * Description: + * Deinitialize PHY hardware + * + * Input Parameters: + * module - PHY mode which is to be deinitialized + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_phy_deinit_rf(uint32_t module) +{ + irqstate_t flags; + bool disable = false; + + if (module >= PHY_MODULE_COUNT) + { + return -1; + } + + flags = enter_critical_section(); + + s_esp32_phy_init_mask |= ~(1 << module); + + if (!s_esp23_phy_en) + { + leave_critical_section(flags); + return 0; + } + + if (module == PHY_MODEM_MODULE) + { + disable = true; + } + else if (module == PHY_WIFI_MODULE || module == PHY_BT_MODULE) + { + if (!(s_esp32_phy_init_mask & PHY_RF_MASK)) + { + disable = true; + } + } + + if (disable) + { + phy_close_rf(); + + s_esp32_phy_rf_stop_tm = esp_timer_get_time(); + + esp_phy_disable_clock(); + + s_esp23_phy_en = false; + } + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: esp_phy_init + * + * Description: + * Initialize PHY hardware + * + * Input Parameters: + * module - PHY mode which is to be initialized + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_phy_init(uint32_t module) +{ + int ret; + esp_phy_calibration_data_t *cal_data; + + cal_data = kmm_zalloc(sizeof(esp_phy_calibration_data_t)); + if (!cal_data) + { + wlerr("ERROR: Failed to malloc"); + DEBUGASSERT(0); + } + + ret = esp_phy_rf_init(&phy_init_data, PHY_RF_CAL_FULL, cal_data, module); + if (ret) + { + wlerr("ERROR: Failed to initialize RF"); + DEBUGASSERT(0); + } + + kmm_free(cal_data); +} + +/**************************************************************************** + * Name: esp_phy_enable_clock + * + * Description: + * Enable PHY hardware clock + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_phy_enable_clock(void) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + if (s_phy_clk_en_cnt == 0) + { + modifyreg32(DPORT_WIFI_CLK_EN_REG, 0, + DPORT_WIFI_CLK_WIFI_BT_COMMON_M); + } + + s_phy_clk_en_cnt++; + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: esp_phy_disable_clock + * + * Description: + * Disable PHY hardware clock + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_phy_disable_clock(void) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + if (s_phy_clk_en_cnt) + { + s_phy_clk_en_cnt--; + if (!s_phy_clk_en_cnt) + { + modifyreg32(DPORT_WIFI_CLK_EN_REG, + DPORT_WIFI_CLK_WIFI_BT_COMMON_M, + 0); + } + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: esp_read_mac + * + * Description: + * Read MAC address from efuse + * + * Input Parameters: + * mac - MAC address buffer pointer + * type - MAC address type + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_read_mac(uint8_t *mac, esp_mac_type_t type) +{ + uint32_t regval[2]; + uint8_t tmp; + uint8_t *data = (uint8_t *)regval; + uint8_t crc; + int i; + + if (type > ESP_MAC_WIFI_SOFTAP) + { + wlerr("ERROR: Input type is error=%d\n", type); + return -1; + } + + regval[0] = getreg32(MAC_ADDR0_REG); + regval[1] = getreg32(MAC_ADDR1_REG); + + crc = data[6]; + for (i = 0; i < 6; i++) + { + mac[i] = data[5 - i]; + } + + if (crc != esp_crc8(mac, 6)) + { + wlerr("ERROR: Failed to check MAC address CRC\n"); + return -1; + } + + if (type == ESP_MAC_WIFI_SOFTAP) + { + tmp = mac[0]; + for (i = 0; i < 64; i++) + { + mac[0] = tmp | 0x02; + mac[0] ^= i << 2; + + if (mac[0] != tmp) + { + break; + } + } + + if (i >= 64) + { + wlerr("ERROR: Failed to generate softAP MAC\n"); + return -1; + } + } + + return 0; +} + +/**************************************************************************** + * Name: esp_wifi_read_mac + * + * Description: + * Read MAC address from efuse + * + * Input Parameters: + * mac - MAC address buffer pointer + * type - MAC address type + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_wifi_read_mac(uint8_t *mac, uint32_t type) +{ + return esp_read_mac(mac, type); +} + +/**************************************************************************** + * Name: esp_timer_arm + * + * Description: + * Set timer timeout period and repeat flag + * + * Input Parameters: + * ptimer - timer data pointer + * ms - millim seconds + * repeat - true: run cycle, false: run once + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_timer_arm(void *ptimer, uint32_t ms, bool repeat) +{ + esp_timer_arm_us(ptimer, ms * 1000, repeat); +} + +/**************************************************************************** + * Name: esp_timer_disarm + * + * Description: + * Disable timer + * + * Input Parameters: + * ptimer - timer data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_timer_disarm(void *ptimer) +{ + struct timer_adpt *timer_adpt; + struct ets_timer *ets_timer = (struct ets_timer *)ptimer; + + if (ets_timer->priv) + { + timer_adpt = (struct timer_adpt *)ets_timer->priv; + + wd_cancel(&timer_adpt->wdog); + work_cancel(LPWORK, &timer_adpt->work); + } +} + +/**************************************************************************** + * Name: esp32_timer_done + * + * Description: + * Disable and free timer + * + * Input Parameters: + * ptimer - timer data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_timer_done(void *ptimer) +{ + struct timer_adpt *timer_adpt; + struct ets_timer *ets_timer = (struct ets_timer *)ptimer; + + if (ets_timer->priv) + { + timer_adpt = (struct timer_adpt *)ets_timer->priv; + + wd_cancel(&timer_adpt->wdog); + work_cancel(LPWORK, &timer_adpt->work); + + kmm_free(timer_adpt); + + ets_timer->priv = NULL; + } +} + +/**************************************************************************** + * Name: esp_timer_setfn + * + * Description: + * Set timer callback function and private data + * + * Input Parameters: + * ptimer - Timer data pointer + * pfunction - Callback function + * parg - Callback function private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_timer_setfn(void *ptimer, void *pfunction, void *parg) +{ + struct timer_adpt *timer_adpt; + struct ets_timer *ets_timer = (struct ets_timer *)ptimer; + + if (ets_timer->priv) + { + return ; + } + + timer_adpt = kmm_zalloc(sizeof(struct timer_adpt)); + if (!timer_adpt) + { + wlerr("ERROR: Failed to malloc\n"); + return ; + } + + timer_adpt->func = pfunction; + timer_adpt->priv = parg; + + ets_timer->priv = timer_adpt; +} + +/**************************************************************************** + * Name: esp_timer_work_cb + * + * Description: + * Process timer callback function in workqueue and active + * it if it has repeat flag + * + * Input Parameters: + * arg - Timer data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_timer_work_cb(FAR void *arg) +{ + struct ets_timer *ets_timer = (struct ets_timer *)arg; + struct timer_adpt *timer_adpt = + (struct timer_adpt *)ets_timer->priv; + + timer_adpt->func(timer_adpt->priv); + if (timer_adpt->repeat) + { + wd_start(&timer_adpt->wdog, timer_adpt->delay, + esp_timer_cb, (wdparm_t)ets_timer); + } +} + +/**************************************************************************** + * Name: esp_timer_cb + * + * Description: + * Post event to work queue and let work queue to process the timer's + * real callback function + * + * Input Parameters: + * parm - Timer data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_timer_cb(wdparm_t parm) +{ + struct ets_timer *ets_timer = (struct ets_timer *)parm; + struct timer_adpt *timer_adpt = + (struct timer_adpt *)ets_timer->priv; + + work_queue(LPWORK, &timer_adpt->work, + esp_timer_work_cb, ets_timer, 0); +} + +/**************************************************************************** + * Name: esp_timer_arm_us + * + * Description: + * Set timer timeout period and repeat flag + * + * Input Parameters: + * ptimer - timer data pointer + * us - micro seconds + * repeat - true: run cycle, false: run once + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_timer_arm_us(void *ptimer, uint32_t us, bool repeat) +{ + uint32_t delay; + struct timer_adpt *timer_adpt; + struct ets_timer *ets_timer = (struct ets_timer *)ptimer; + + if (ets_timer->priv) + { + timer_adpt = (struct timer_adpt *)ets_timer->priv; + + wd_cancel(&timer_adpt->wdog); + work_cancel(LPWORK, &timer_adpt->work); + + delay = USEC2TICK(us); + timer_adpt->repeat = (uint32_t)repeat; + timer_adpt->delay = delay; + + wd_start(&timer_adpt->wdog, delay, + esp_timer_cb, (wdparm_t)ets_timer); + } +} + +/**************************************************************************** + * Name: esp_periph_module_enable + * + * Description: + * Enable WiFi module clock + * + * Input Parameters: + * periph - No mean + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_periph_module_enable(uint32_t periph) +{ + modifyreg32(DPORT_WIFI_CLK_EN_REG, 0, DPORT_WIFI_CLK_WIFI_EN_M); +} + +/**************************************************************************** + * Name: esp_periph_module_enable + * + * Description: + * Disable WiFi module clock + * + * Input Parameters: + * periph - No mean + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_periph_module_disable(uint32_t periph) +{ + modifyreg32(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M, 0); +} + +/**************************************************************************** + * Name: esp_timer_get_time + * + * Description: + * Get system time of type int64_t + * + * Input Parameters: + * periph - No mean + * + * Returned Value: + * System time + * + ****************************************************************************/ + +int64_t esp_timer_get_time(void) +{ + int64_t us; + struct timeval tv; + int ret; + + ret = gettimeofday(&tv, NULL); + if (!ret) + { + us = tv.tv_sec * (1000 * 1000) + tv.tv_usec; + } + else + { + us = 0; + wlerr("ERROR: Failed to get time of day\n"); + } + + return us; +} + +/**************************************************************************** + * Name: esp_nvs_set_i8 + * + * Description: + * Save data of type int8_t into file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * value - Stored data + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_set_i8(uint32_t handle, + const char *key, + int8_t value) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + return esp_nvs_set_blob(handle, key, &value, sizeof(int8_t)); +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_get_i8 + * + * Description: + * Read data of type int8_t from file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * out_value - Read buffer pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_get_i8(uint32_t handle, + const char *key, + int8_t *out_value) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + size_t len = sizeof(int8_t); + + return esp_nvs_get_blob(handle, key, out_value, &len); +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_set_u8 + * + * Description: + * Save data of type uint8_t into file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * value - Stored data + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_set_u8(uint32_t handle, + const char *key, + uint8_t value) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + return esp_nvs_set_blob(handle, key, &value, sizeof(uint8_t)); +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_get_u8 + * + * Description: + * Read data of type uint8_t from file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * out_value - Read buffer pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_get_u8(uint32_t handle, + const char *key, + uint8_t *out_value) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + size_t len = sizeof(uint8_t); + + return esp_nvs_get_blob(handle, key, out_value, &len); +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_set_u16 + * + * Description: + * Save data of type uint16_t into file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * value - Stored data + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_set_u16(uint32_t handle, + const char *key, + uint16_t value) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + return esp_nvs_set_blob(handle, key, &value, sizeof(uint16_t)); +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_get_u16 + * + * Description: + * Read data of type uint16_t from file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * out_value - Read buffer pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_get_u16(uint32_t handle, + const char *key, + uint16_t *out_value) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + size_t len = sizeof(uint16_t); + + return esp_nvs_get_blob(handle, key, out_value, &len); +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_open + * + * Description: + * Create a file system storage data object + * + * Input Parameters: + * name - Storage index + * open_mode - Storage mode + * out_handle - Storage handle + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_open(const char *name, + uint32_t open_mode, + uint32_t *out_handle) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + int ret; + struct nvs_adpt *nvs_adpt; + int tmp; + char *index_name; + + tmp = sizeof(struct nvs_adpt); + nvs_adpt = kmm_malloc(tmp); + if (!nvs_adpt) + { + wlerr("ERROR: Failed to alloc %d memory\n", tmp); + return -1; + } + + ret = asprintf(&index_name, "%s", name); + if (ret < 0) + { + wlerr("ERROR: Failed to create NVS index_name string\n"); + kmm_free(nvs_adpt); + return -1; + } + + nvs_adpt->index_name = index_name; + *out_handle = (uint32_t)nvs_adpt; + + return 0; +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_close + * + * Description: + * Close storage data object and free resource + * + * Input Parameters: + * handle - NVS handle + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static void esp_nvs_close(uint32_t handle) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle; + + kmm_free(nvs_adpt->index_name); + kmm_free(nvs_adpt); +#else + DEBUGASSERT(0); +#endif +} + +/**************************************************************************** + * Name: esp_nvs_commit + * + * Description: + * This function has no practical effect + * + ****************************************************************************/ + +static int32_t esp_nvs_commit(uint32_t handle) +{ + return 0; +} + +/**************************************************************************** + * Name: esp_nvs_set_blob + * + * Description: + * Save a block of data into file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * value - Stored buffer pointer + * length - Buffer length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_set_blob(uint32_t handle, + const char *key, + const void *value, + size_t length) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + int fd; + int ret; + char *dir; + struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle; + char *index_name = nvs_adpt->index_name; + + ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key); + if (ret < 0) + { + wlerr("ERROR: Failed to create NVS dir string\n"); + return -1; + } + + ret = unlink(dir); + if (ret) + { + if (errno != ENOENT) + { + wlerr("ERROR: Failed to unlink %s error=%d\n", dir, errno); + free(dir); + return -1; + } + } + + fd = open(dir, O_WRONLY | O_CREAT, NVS_FILE_MODE); + if (fd < 0) + { + wlerr("ERROR: Failed to set open %s\n", dir); + free(dir); + return -1; + } + + ret = write(fd, value, length); + if (ret < 0) + { + wlerr("ERROR: Failed to write to %s\n", dir); + free(dir); + close(fd); + return -1; + } + + free(dir); + close(fd); + + return 0; +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_get_blob + * + * Description: + * Read a block of data from file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * out_value - Read buffer pointer + * length - Buffer length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_get_blob(uint32_t handle, + const char *key, + void *out_value, + size_t *length) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + int fd; + int ret; + char *dir; + struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle; + char *index_name = nvs_adpt->index_name; + + ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key); + if (ret < 0) + { + wlerr("ERROR: Failed to create NVS dir string\n"); + return -1; + } + + fd = open(dir, O_RDONLY, NVS_FILE_MODE); + if (fd < 0) + { + free(dir); + if (errno == ENOENT) + { + wlinfo("INFO: No file %s\n", dir); + return ESP_ERR_NVS_NOT_FOUND; + } + wlerr("ERROR: Failed to get open %s\n", dir); + return -1; + } + + ret = read(fd, out_value, *length); + if (ret <= 0) + { + wlerr("ERROR: Failed to write to %s\n", dir); + free(dir); + close(fd); + return -1; + } + else + { + *length = ret; + } + + free(dir); + close(fd); + + return 0; +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_nvs_erase_key + * + * Description: + * Read a block of data from file system + * + * Input Parameters: + * handle - NVS handle + * key - Data index + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_nvs_erase_key(uint32_t handle, const char *key) +{ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + int ret; + char *dir; + struct nvs_adpt *nvs_adpt = (struct nvs_adpt *)handle; + char *index_name = nvs_adpt->index_name; + + ret = asprintf(&dir, NVS_DIR_BASE"%s.%s", index_name, key); + if (ret < 0) + { + wlerr("ERROR: Failed to create NVS dir string\n"); + return -1; + } + + ret = unlink(dir); + if (ret < 0) + { + wlerr("ERROR: Failed to delete NVS file %s\n", dir); + free(dir); + return -1; + } + + free(dir); + + return 0; +#else + DEBUGASSERT(0); + + return -1; +#endif +} + +/**************************************************************************** + * Name: esp_fill_random + * + * Description: + * Fill random data int given buffer of given length + * + * Input Parameters: + * buf - buffer pointer + * len - buffer length + * + * Returned Value: + * + ****************************************************************************/ + +void esp_fill_random(void *buf, size_t len) +{ + uint8_t *p = (uint8_t *)buf; + uint32_t tmp; + uint32_t n; + + while (len > 0) + { + tmp = random(); + n = len < 4 ? len : 4; + + memcpy(p, &tmp, n); + + p += n; + len -= n; + } +} + +/**************************************************************************** + * Name: esp_get_random + * + * Description: + * Fill random data int given buffer of given length + * + * Input Parameters: + * buf - buffer pointer + * len - buffer length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_get_random(uint8_t *buf, size_t len) +{ + esp_fill_random(buf, len); + + return 0; +} + +/**************************************************************************** + * Name: esp_get_time + * + * Description: + * Get std C time + * + * Input Parameters: + * t - buffer to store time of type timeval + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_get_time(void *t) +{ + int ret; + struct timeval tv; + struct time_adpt *time_adpt = (struct time_adpt *)t; + + ret = gettimeofday(&tv, NULL); + if (!ret) + { + time_adpt->sec = (time_t)tv.tv_sec; + time_adpt->usec = (suseconds_t)tv.tv_usec; + } + else + { + wlerr("ERROR: Failed to get time of day\n"); + } + + return ret; +} + +/**************************************************************************** + * Name: esp_rand + * + * Description: + * Get random data of type uint32_t + * + * Input Parameters: + * None + * + * Returned Value: + * Random data + * + ****************************************************************************/ + +static uint32_t esp_rand(void) +{ + return esp_random(); +} + +/**************************************************************************** + * Name: esp_log_writev + * + * Description: + * Output log with by format string and its arguments + * + * Input Parameters: + * level - log level, no mean here + * tag - log TAG, no mean here + * format - format string + * args - arguments list + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_log_writev(uint32_t level, const char *tag, + const char *format, va_list args) +{ + int pri; + + switch (level) + { + case ESP_LOG_ERROR: + pri = LOG_ERR; + break; + case ESP_LOG_WARN: + pri = LOG_WARNING; + break; + case ESP_LOG_INFO: + pri = LOG_INFO; + break; + default: + pri = LOG_DEBUG; + break; + } + + vsyslog(pri, format, args); +} + +/**************************************************************************** + * Name: esp_log_write + * + * Description: + * Output log with by format string and its arguments + * + * Input Parameters: + * level - log level, no mean here + * tag - log TAG, no mean here + * format - format string + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_log_write(uint32_t level, + const char *tag, + const char *format, ...) +{ + va_list list; + va_start(list, format); + esp_log_writev(level, tag, format, list); + va_end(list); +} + +/**************************************************************************** + * Name: esp_log_timestamp + * + * Description: + * Get system time by millim second + * + * Input Parameters: + * None + * + * Returned Value: + * System time + * + ****************************************************************************/ + +uint32_t esp_log_timestamp(void) +{ + return (uint32_t)(esp_timer_get_time() / 1000); +} + +/**************************************************************************** + * Name: esp_malloc_internal + * + * Description: + * Drivers allocate a block of memory + * + * Input Parameters: + * size - memory size + * + * Returned Value: + * Memory pointer + * + ****************************************************************************/ + +static void *esp_malloc_internal(size_t size) +{ + return kmm_malloc(size); +} + +/**************************************************************************** + * Name: esp_realloc_internal + * + * Description: + * Drivers allocate a block of memory by old memory block + * + * Input Parameters: + * ptr - old memory pointer + * size - memory size + * + * Returned Value: + * New memory pointer + * + ****************************************************************************/ + +static void *esp_realloc_internal(void *ptr, size_t size) +{ + return kmm_realloc(ptr, size); +} + +/**************************************************************************** + * Name: esp_calloc_internal + * + * Description: + * Drivers allocate some continuous blocks of memory + * + * Input Parameters: + * n - memory block number + * size - memory block size + * + * Returned Value: + * New memory pointer + * + ****************************************************************************/ + +static void *esp_calloc_internal(size_t n, size_t size) +{ + return kmm_calloc(n, size); +} + +/**************************************************************************** + * Name: esp_zalloc_internal + * + * Description: + * Drivers allocate a block of memory and clear it with 0 + * + * Input Parameters: + * size - memory size + * + * Returned Value: + * New memory pointer + * + ****************************************************************************/ + +static void *esp_zalloc_internal(size_t size) +{ + return kmm_zalloc(size); +} + +/**************************************************************************** + * Name: esp_malloc_internal + * + * Description: + * Applications allocate a block of memory + * + * Input Parameters: + * size - memory size + * + * Returned Value: + * Memory pointer + * + ****************************************************************************/ + +static void *esp_wifi_malloc(size_t size) +{ + return malloc(size); +} + +/**************************************************************************** + * Name: esp_realloc_internal + * + * Description: + * Applications allocate a block of memory by old memory block + * + * Input Parameters: + * ptr - old memory pointer + * size - memory size + * + * Returned Value: + * New memory pointer + * + ****************************************************************************/ + +static void *esp_wifi_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +/**************************************************************************** + * Name: esp_calloc_internal + * + * Description: + * Applications allocate some continuous blocks of memory + * + * Input Parameters: + * n - memory block number + * size - memory block size + * + * Returned Value: + * New memory pointer + * + ****************************************************************************/ + +static void *esp_wifi_calloc(size_t n, size_t size) +{ + return calloc(n, size); +} + +/**************************************************************************** + * Name: esp_zalloc_internal + * + * Description: + * Applications allocate a block of memory and clear it with 0 + * + * Input Parameters: + * size - memory size + * + * Returned Value: + * New memory pointer + * + ****************************************************************************/ + +static void *esp_wifi_zalloc(size_t size) +{ + return zalloc(size); +} + +/**************************************************************************** + * Name: esp_wifi_create_queue + * + * Description: + * Create WiFi static message queue + * + * Input Parameters: + * queue_len - queue message number + * item_size - message size + * + * Returned Value: + * WiFi static message queue data pointer + * + ****************************************************************************/ + +static void *esp_wifi_create_queue(int32_t queue_len, int32_t item_size) +{ + wifi_static_queue_t *wifi_queue; + + wifi_queue = kmm_malloc(sizeof(wifi_static_queue_t)); + if (!wifi_queue) + { + wlerr("ERROR: Failed to malloc\n"); + return NULL; + } + + wifi_queue->handle = esp_queue_create(queue_len, item_size); + if (!wifi_queue->handle) + { + wlerr("ERROR: Failed to create queue\n"); + kmm_free(wifi_queue); + return NULL; + } + + return wifi_queue; +} + +/**************************************************************************** + * Name: esp_wifi_delete_queue + * + * Description: + * Delete WiFi static message queue + * + * Input Parameters: + * queue - WiFi static message queue data pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_wifi_delete_queue(void *queue) +{ + wifi_static_queue_t *wifi_queue = (wifi_static_queue_t *)queue; + + esp_queue_delete(wifi_queue->handle); + kmm_free(wifi_queue); +} + +/**************************************************************************** + * Name: esp_modem_enter_sleep + * + * Description: + * Let given module to enter sleep mode + * + * Input Parameters: + * module - hardware module ID + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_modem_enter_sleep(uint32_t module) +{ + int ret = 0; + irqstate_t flags; + uint32_t bit; + + if (module >= (uint32_t)MODEM_MODULE_COUNT) + { + return -1; + } + + bit = 1 << module; + + if (!(s_esp32_module_mask & bit)) + { + return -1; + } + + flags = enter_critical_section(); + + s_esp32_module_sleep |= bit; + if (!s_esp32_sleep && (s_esp32_module_sleep == s_esp32_module_mask)) + { + ret = esp_phy_deinit_rf(PHY_MODEM_MODULE); + if (ret) + { + wlerr("ERROR: Failed to close RF\n"); + } + else + { + s_esp32_sleep = true; + } + } + + leave_critical_section(flags); + + return ret; +} + +/**************************************************************************** + * Name: esp_modem_enter_sleep + * + * Description: + * Let given module to exit from sleep mode + * + * Input Parameters: + * module - hardware module ID + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_modem_exit_sleep(uint32_t module) +{ + int ret = 0; + irqstate_t flags; + uint32_t bit; + + if (module >= (uint32_t)MODEM_MODULE_COUNT) + { + return -1; + } + + bit = 1 << module; + + if (!(s_esp32_module_mask & bit)) + { + return -1; + } + + flags = enter_critical_section(); + + s_esp32_module_sleep &= ~bit; + if (s_esp32_sleep) + { + ret = esp_phy_rf_init(NULL, PHY_RF_CAL_NONE, + NULL, PHY_MODEM_MODULE); + if (ret) + { + wlerr("ERROR: Failed to open RF\n"); + } + else + { + s_esp32_sleep = false; + } + } + + leave_critical_section(flags); + + return ret; +} + +/**************************************************************************** + * Name: esp_modem_register_sleep + * + * Description: + * Regitser given module so that it can enter sleep mode + * + * Input Parameters: + * module - hardware module ID + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_modem_register_sleep(uint32_t module) +{ + irqstate_t flags; + uint32_t bit; + + if (module >= (uint32_t)MODEM_MODULE_COUNT) + { + return -1; + } + + bit = 1 << module; + + flags = enter_critical_section(); + + if (s_esp32_module_mask & bit) + { + /* Has registered and return success */ + + return 0; + } + + s_esp32_module_mask |= bit; + s_esp32_module_sleep |= bit; + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: esp_modem_deregister_sleep + * + * Description: + * Deregitser given module so that it can't enter sleep mode + * + * Input Parameters: + * module - hardware module ID + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +static int32_t esp_modem_deregister_sleep(uint32_t module) +{ + int ret; + irqstate_t flags; + uint32_t bit; + + if (module >= (uint32_t)MODEM_MODULE_COUNT) + { + return -1; + } + + bit = 1 << module; + + flags = enter_critical_section(); + + if (!(s_esp32_module_mask & bit)) + { + /* Has deregistered and return success */ + + return 0; + } + + s_esp32_module_mask &= ~bit; + s_esp32_module_sleep &= ~bit; + if (!s_esp32_module_mask) + { + s_esp32_module_mask = 0; + if (s_esp32_sleep) + { + s_esp32_sleep = false; + ret = esp_phy_rf_init(NULL, PHY_RF_CAL_NONE, + NULL, PHY_MODEM_MODULE); + if (ret) + { + wlerr("ERROR: Failed to open RF\n"); + } + } + } + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: esp_coex_status_get + * + * Description: + * Don't support + * + ****************************************************************************/ + +static uint32_t esp_coex_status_get(void) +{ + return 0; +} + +/**************************************************************************** + * Name: esp_coex_condition_set + * + * Description: + * Don't support + * + ****************************************************************************/ + +static void esp_coex_condition_set(uint32_t type, bool dissatisfy) +{ +} + +/**************************************************************************** + * Name: esp_coex_wifi_request + * + * Description: + * Don't support + * + ****************************************************************************/ + +static int32_t esp_coex_wifi_request(uint32_t event, uint32_t latency, + uint32_t duration) +{ + return 0; +} + +/**************************************************************************** + * Name: esp_coex_wifi_release + * + * Description: + * Don't support + * + ****************************************************************************/ + +static int32_t esp_coex_wifi_release(uint32_t event) +{ + return 0; +} + +/**************************************************************************** + * Functions needed by libphy.a + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_dport_access_reg_read + * + * Description: + * Read regitser value safely in SMP + * + * Input Parameters: + * reg - Regitser address + * + * Returned Value: + * Regitser value + * + ****************************************************************************/ + +uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) +{ +#ifdef CONFIG_SMP + DEBUGASSERT(0); +#else + return getreg32(reg); +#endif +} + +/**************************************************************************** + * Name: phy_enter_critical + * + * Description: + * Enter critical state + * + * Input Parameters: + * None + * + * Returned Value: + * CPU PS value + * + ****************************************************************************/ + +uint32_t IRAM_ATTR phy_enter_critical(void) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + return flags; +} + +/**************************************************************************** + * Name: phy_exit_critical + * + * Description: + * Exit from critical state + * + * Input Parameters: + * level - CPU PS value + * + * Returned Value: + * None + * + ****************************************************************************/ + +void IRAM_ATTR phy_exit_critical(uint32_t level) +{ + leave_critical_section(level); +} + +/**************************************************************************** + * Name: phy_printf + * + * Description: + * Output format string and its arguments + * + * Input Parameters: + * format - format string + * + * Returned Value: + * 0 + * + ****************************************************************************/ + +int phy_printf(const char *format, ...) +{ + va_list arg; + + va_start(arg, format); + wlinfo(format, arg); + va_end(arg); + + return 0; +} + +/**************************************************************************** + * Functions needed by libnet80211.a + ****************************************************************************/ + +/**************************************************************************** + * Name: net80211_printf + * + * Description: + * Output format string and its arguments + * + * Input Parameters: + * format - format string + * + * Returned Value: + * 0 + * + ****************************************************************************/ + +int net80211_printf(const char *format, ...) +{ + va_list arg; + + va_start(arg, format); + vsyslog(LOG_INFO, format, arg); + va_end(arg); + + return 0; +} + +/**************************************************************************** + * Functions needed by libwpa_supplicant.a + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_timer_create + * + * Description: + * Create timer with given arguments + * + * Input Parameters: + * create_args - Timer arguments data pointer + * out_handle - Timer handle pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_timer_create(const esp_timer_create_args_t *create_args, + esp_timer_handle_t *out_handle) +{ + struct ets_timer *ets_timer; + + ets_timer = kmm_zalloc(sizeof(struct ets_timer)); + if (!ets_timer) + { + wlerr("ERROR: Failed to malloc\n"); + return -1; + } + + esp_timer_setfn(ets_timer, create_args->callback, create_args->arg); + if (!ets_timer->priv) + { + wlerr("ERROR: Failed to set timer func\n"); + return -1; + } + + *out_handle = (esp_timer_handle_t)ets_timer; + + return 0; +} + +/**************************************************************************** + * Name: esp_timer_start_once + * + * Description: + * Start timer with one shot mode + * + * Input Parameters: + * timer - Timer handle pointer + * timeout_us - Timeout value by micro second + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us) +{ + struct ets_timer *ets_timer = (struct ets_timer *)timer; + + esp_timer_arm_us(ets_timer, timeout_us, false); + + return 0; +} + +/**************************************************************************** + * Name: esp_timer_start_periodic + * + * Description: + * Start timer with periodic mode + * + * Input Parameters: + * timer - Timer handle pointer + * period - Timeout value by micro second + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period) +{ + struct ets_timer *ets_timer = (struct ets_timer *)timer; + + esp_timer_arm_us(ets_timer, period, true); + + return 0; +} + +/**************************************************************************** + * Name: esp_timer_stop + * + * Description: + * Stop timer + * + * Input Parameters: + * timer - Timer handle pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_timer_stop(esp_timer_handle_t timer) +{ + struct ets_timer *ets_timer = (struct ets_timer *)timer; + + esp_timer_disarm(ets_timer); + + return 0; +} + +/**************************************************************************** + * Name: esp_timer_delete + * + * Description: + * Delete timer and free recource + * + * Input Parameters: + * timer - Timer handle pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int32_t esp_timer_delete(esp_timer_handle_t timer) +{ + struct ets_timer *ets_timer = (struct ets_timer *)timer; + + esp32_timer_done(ets_timer); + kmm_free(ets_timer); + + return 0; +} + +/**************************************************************************** + * Name: __assert_func + * + * Description: + * Delete timer and free recource + * + * Input Parameters: + * file - assert file + * line - assert line + * func - assert function + * expr - assert condition + * + * Returned Value: + * None + * + ****************************************************************************/ + +void __assert_func(const char *file, int line, + const char *func, const char *expr) +{ + wlerr("ERROR: Assert failed in %s, %s:%d (%s)", + func, file, line, expr); + abort(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_event_send_internal + * + * Description: + * Post event message to queue + * + * Input Parameters: + * event_base - Event set name + * event_id - Event ID + * event_data - Event private data + * event_data_size - Event data size + * ticks_to_wait - Waiting system ticks + * + * Returned Value: + * Task maxium priority + * + ****************************************************************************/ + +int32_t esp_event_send_internal(esp_event_base_t event_base, + int32_t event_id, + void *event_data, + size_t event_data_size, + uint32_t ticks_to_wait) +{ + int32_t ret; + + ret = esp_event_post(event_base, event_id, event_data, + event_data_size, ticks_to_wait); + + return ret; +} + +/**************************************************************************** + * Name: esp_wifi_init + * + * Description: + * Initialize WiFi + * + * Input Parameters: + * config - Initialization config parameters + * + * Returned Value: + * 0 if success or others if fail + * + ****************************************************************************/ + +int32_t esp_wifi_init(const wifi_init_config_t *config) +{ + int32_t ret; + + ret = esp_wifi_init_internal(config); + if (ret) + { + wlerr("ERROR: Failed to initialize WiFi error=%d\n", ret); + return -1; + } + + ret = esp_supplicant_init(); + if (ret) + { + wlerr("ERROR: Failed to initialize WPA supplicant error=%d\n", ret); + esp_wifi_deinit_internal(); + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: esp_wifi_deinit + * + * Description: + * Deinitialize WiFi and free resource + * + * Input Parameters: + * None + * + * Returned Value: + * 0 if success or others if fail + * + ****************************************************************************/ + +int32_t esp_wifi_deinit(void) +{ + int ret; + + ret = esp_supplicant_deinit(); + if (ret) + { + wlerr("ERROR: Failed to deinitialize supplicant\n"); + return ret; + } + + ret = esp_wifi_deinit_internal(); + if (ret != 0) + { + wlerr("ERROR: Failed to deinitialize WiFi\n"); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: esp_wifi_sta_send_data + * + * Description: + * Use WiFi station interface to send 802.3 frame + * + * Input Parameters: + * pbuf - Packet buffer pointer + * len - Packet length + * + * Returned Value: + * 0 if success or others if fail + * + ****************************************************************************/ + +int esp_wifi_sta_send_data(void *pbuf, uint32_t len) +{ + int ret; + + ret = esp_wifi_internal_tx(WIFI_IF_STA, pbuf, len); + + return ret; +} + +/**************************************************************************** + * Name: esp_wifi_sta_register_recv_cb + * + * Description: + * Regitser WiFi receive packet callback function + * + * Input Parameters: + * input_cb - Receive callback function + * + * Returned Value: + * 0 if success or others if fail + * + ****************************************************************************/ + +int esp_wifi_sta_register_recv_cb(int (*recv_cb)(void *buffer, + uint16_t len, + void *eb)) +{ + int ret; + + ret = esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, (wifi_rxcb_t)recv_cb); + + return ret; +} + +/**************************************************************************** + * Name: esp_wifi_sta_read_mac + * + * Description: + * Read station interface MAC address from efuse + * + * Input Parameters: + * mac - MAC address buffer pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_sta_read_mac(uint8_t *mac) +{ + return esp_read_mac(mac, ESP_MAC_WIFI_STA); +} + +/**************************************************************************** + * Name: esp_wifi_free_eb + * + * Description: + * Free WiFi receive callback input eb pointer + * + * Input Parameters: + * eb - WiFi receive callback input eb pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_wifi_free_eb(void *eb) +{ + esp_wifi_internal_free_rx_buffer(eb); +} + +/**************************************************************************** + * Name: esp_wifi_notify_subscribe + * + * Description: + * Enable event notification + * + * Input Parameters: + * pid - Task PID + * event - Signal event data pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_notify_subscribe(pid_t pid, FAR struct sigevent *event) +{ + int id; + struct wifi_notify *notify; + int ret = -1; + + wlinfo("PID=%d event=%p\n", pid, event); + + if (event->sigev_notify != SIGEV_SIGNAL) + { + wlerr("ERROR: sigev_notify %d is invalid\n", event->sigev_signo); + return -1; + } + + id = esp_event_id_map(event->sigev_signo); + if (id < 0) + { + wlerr("ERROR: No process event %d\n", event->sigev_signo); + } + else + { + notify = &s_wifi_notify[id]; + + if (notify->assigned) + { + wlerr("ERROR: sigev_signo %d has subscribed\n", + event->sigev_signo); + } + else + { + if (pid == 0) + { + pid = getpid(); + wlinfo("Actual PID=%d\n", pid); + } + + notify->pid = pid; + notify->event = *event; + notify->assigned = true; + + ret = 0; + } + } + + return ret; +} + +/**************************************************************************** + * Name: esp_wifi_adapter_init + * + * Description: + * Initialize ESP32 WiFi adapter + * + * Input Parameters: + * None + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_adapter_init(void) +{ + int ret; + wifi_init_config_t init_cfg = WIFI_INIT_CONFIG_DEFAULT(); + + ret = sem_init(&s_connect_sem, 0, 0); + if (ret) + { + wlerr("ERROR: Failed to initialize sem error=%d\n", errno); + return -1; + } + +#ifndef CONFIG_ESP32_WIFI_SAVE_PARAM + init_cfg.nvs_enable = 0; +#endif + + ret = esp_wifi_init(&init_cfg); + if (ret) + { + wlerr("ERROR: Failed to initialize WiFi error=%d\n", ret); + sem_destroy(&s_connect_sem); + return -1; + } + + ret = esp_wifi_set_ps(WIFI_PS_NONE); + if (ret) + { + wlerr("ERROR: Failed to close power save, error=%d\n", ret); + esp_wifi_deinit(); + sem_destroy(&s_connect_sem); + return -1; + } + + sq_init(&s_wifi_evt_queue); + + return 0; +} + +/**************************************************************************** + * Name: esp_wifi_set_password + * + * Description: + * Set WiFi password + * + * Input Parameters: + * pdata - Password buffer pointer + * len - Password length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_set_password(const uint8_t *pdata, uint8_t len) +{ + memcpy(s_password, pdata, len); + s_password_len = len; + + return 0; +} + +/**************************************************************************** + * Name: esp_wifi_set_ssid + * + * Description: + * Set WiFi SSID + * + * Input Parameters: + * pdata - SSID buffer pointer + * len - SSID length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_set_ssid(const uint8_t *pdata, uint8_t len) +{ + memcpy(s_ssid, pdata, len); + s_ssid_len = len; + + return 0; +} + +/**************************************************************************** + * Name: esp_wifi_connect_internal + * + * Description: + * Trigger WiFi connection action + * + * Input Parameters: + * None + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_connect_internal(void) +{ + int ret; + wifi_config_t wifi_cfg; + struct timespec timeout; + + if (s_connected) + { + wlinfo("INFO: WiFi has connected AP\n"); + return 0; + } + + ret = esp_wifi_set_mode(WIFI_MODE_STA); + if (ret) + { + wlerr("ERROR: Failed to set station mode error=%d\n", ret); + esp_wifi_deinit(); + return -1; + } + + memset(&wifi_cfg, 0, sizeof(wifi_config_t)); + memcpy((char *)wifi_cfg.sta.ssid, s_ssid, s_ssid_len); + memcpy((char *)wifi_cfg.sta.password, s_password, s_password_len); + + ret = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg); + if (ret) + { + wlerr("ERROR: Failed to set WiFi config error=%d\n", ret); + return -1; + } + + ret = esp_wifi_start(); + if (ret) + { + wlerr("ERROR: Failed to set start config error=%d\n", ret); + return -1; + } + + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += WIFI_CONNECT_TIMEOUT; + + ret = sem_timedwait(&s_connect_sem, &timeout); + if (ret) + { + wlerr("ERROR: Failed to wait sem error=%d\n", errno); + esp_wifi_stop(); + return -1; + } + + if (!s_connected) + { + wlerr("ERROR: Process connection error\n"); + esp_wifi_stop(); + return -1; + } + + return 0; +} diff --git a/arch/xtensa/src/esp32/esp32_wifi_adapter.h b/arch/xtensa/src/esp32/esp32_wifi_adapter.h new file mode 100644 index 00000000000..33ccbfeabbc --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wifi_adapter.h @@ -0,0 +1,223 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wifi_adapter.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32_ESP32_WIFI_ADAPTER_H +#define __ARCH_XTENSA_SRC_ESP32_ESP32_WIFI_ADAPTER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* WiFi event ID */ + +enum wifi_adpt_evt_e +{ + WIFI_ADPT_EVT_STA_START = 0, + WIFI_ADPT_EVT_STA_CONNECT, + WIFI_ADPT_EVT_STA_DISCONNECT, + WIFI_ADPT_EVT_STA_AUTHMODE_CHANGE, + WIFI_ADPT_EVT_STA_STOP, + WIFI_ADPT_EVT_MAX, +}; + +/* WiFi event callback function */ + +typedef void (*wifi_evt_cb_t)(void *p); + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_wifi_adapter_init + * + * Description: + * Initialize ESP32 WiFi adapter + * + * Input Parameters: + * None + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_adapter_init(void); + +/**************************************************************************** + * Name: esp_wifi_notify_subscribe + * + * Description: + * Enable event notification + * + * Input Parameters: + * pid - Task PID + * event - Signal event data pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_notify_subscribe(pid_t pid, FAR struct sigevent *event); + +/**************************************************************************** + * Name: esp_wifi_sta_send_data + * + * Description: + * Use WiFi station interface to send 802.3 frame + * + * Input Parameters: + * pbuf - Packet buffer pointer + * len - Packet length + * + * Returned Value: + * 0 if success or others if fail + * + ****************************************************************************/ + +int esp_wifi_sta_send_data(void *pbuf, uint32_t len); + +/**************************************************************************** + * Name: esp_wifi_sta_register_recv_cb + * + * Description: + * Regitser WiFi receive packet callback function + * + * Input Parameters: + * input_cb - Receive callback function + * + * Returned Value: + * 0 if success or others if fail + * + ****************************************************************************/ + +int esp_wifi_sta_register_recv_cb(int (*recv_cb)(void *buffer, + uint16_t len, + void *eb)); + +/**************************************************************************** + * Name: esp_wifi_sta_read_mac + * + * Description: + * Read station interface MAC address from efuse + * + * Input Parameters: + * mac - MAC address buffer pointer + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_sta_read_mac(uint8_t *mac); + +/**************************************************************************** + * Name: esp_wifi_free_eb + * + * Description: + * Free WiFi receive callback input eb pointer + * + * Input Parameters: + * eb - WiFi receive callback input eb pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_wifi_free_eb(void *eb); + +/**************************************************************************** + * Name: esp_wifi_set_password + * + * Description: + * Set WiFi password + * + * Input Parameters: + * pdata - Password buffer pointer + * len - Password length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_set_password(const uint8_t *pdata, uint8_t len); + +/**************************************************************************** + * Name: esp_wifi_set_ssid + * + * Description: + * Set WiFi SSID + * + * Input Parameters: + * pdata - SSID buffer pointer + * len - SSID length + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_set_ssid(const uint8_t *pdata, uint8_t len); + +/**************************************************************************** + * Name: esp_wifi_connect_internal + * + * Description: + * Trigger WiFi connection action + * + * Input Parameters: + * None + * + * Returned Value: + * 0 if success or -1 if fail + * + ****************************************************************************/ + +int esp_wifi_connect_internal(void); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_WIFI_ADAPTER_H */ diff --git a/arch/xtensa/src/esp32/esp32_wlan.c b/arch/xtensa/src/esp32/esp32_wlan.c new file mode 100644 index 00000000000..105b029a593 --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wlan.c @@ -0,0 +1,1431 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wlan.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_NET_PKT) +# include +#endif + +#include +#include +#include + +#include "esp32_wifi_adapter.h" + +#include + +#ifdef CONFIG_ESP32_WIRELESS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STA_DEVNO 0 + +/* TX poll delay = 1 seconds. + * CLK_TCK is the number of clock ticks per second + */ + +#define ESP_WDDELAY (1*CLK_TCK) +#define ESPWORK LPWORK + +/* TX timeout = 1 minute */ + +#define ESP_TXTIMEOUT (60*CLK_TCK) +#define DEFAULT_SCAN_LIST_SIZE 2 + +/* Add 4 to the configured buffer size to account for the 2 byte checksum + * memory needed at the end of the maximum size packet. Buffer sizes must + * be an even multiple of 4, 8, or 16 bytes (depending on buswidth). We + * will use the 16-byte alignment in all cases. + */ + +#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15) + +#ifndef CONFIG_ESP_ETH_BUFSIZE +# define CONFIG_ESP_ETH_BUFSIZE OPTIMAL_ETH_BUFSIZE +#endif + +#ifndef CONFIG_ESP_ETH_NTXDESC +# define CONFIG_ESP_ETH_NTXDESC 4 +#endif + +/* We need at least one more free buffer than transmit buffers */ + +#define ESP_ETH_NFREEBUFFERS (CONFIG_ESP_ETH_NTXDESC+1) +#define ETH_MAX_LEN 1518 + +/* This is a helper pointer for accessing the contents of wlan header */ + +#define BUF ((struct eth_hdr_s *)priv->esp_dev.d_buf) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The esp_dev_s encapsulates all state information for a single + * hardware interface + */ + +struct esp_dev_s +{ + bool ifup; /* true:ifup false:ifdown */ + struct wdog_s esp_txpoll; /* TX poll timer */ + struct wdog_s esp_txtimeout; /* TX timeout timer */ + struct work_s esp_irqwork; /* For deferring interrupt work to the work queue */ + struct work_s esp_pollwork; /* For deferring poll work to the work queue */ + + /* This holds the information visible to the NuttX network */ + + struct net_driver_s esp_dev; + sq_queue_t freeb; /* The free buffer list */ + + /* Buffer allocations */ + + uint8_t alloc[CONFIG_ESP_ETH_NTXDESC*CONFIG_ESP_ETH_BUFSIZE]; + uint8_t rxbuf[ETH_MAX_LEN]; + uint32_t rx_len; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct esp_dev_s s_esp32_dev; +static bool g_tx_ready = false; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Free buffer management */ + +static void esp_initbuffer(FAR struct esp_dev_s *priv); +static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv); +static inline void esp_freebuffer(FAR struct esp_dev_s *priv, + uint8_t *buffer); +static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv); + +/* Common TX logic */ + +static int esp_transmit(FAR struct esp_dev_s *priv); +static void esp_receive(FAR struct esp_dev_s *priv); +static int esp_txpoll(FAR struct net_driver_s *dev); +static void esp_rxpoll(FAR void *arg); +static void esp_dopoll(FAR struct esp_dev_s *priv); +static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv, + void *buffer, uint16_t len); +static int esp_sta_input(void *buffer, uint16_t len, void *eb); + +/* Watchdog timer expirations */ + +static void esp_txtimeout_work(FAR void *arg); +static void esp_txtimeout_expiry(wdparm_t arg); + +static void esp_poll_work(FAR void *arg); +static void esp_poll_expiry(wdparm_t arg); + +/* NuttX callback functions */ + +static int esp_ifup(struct net_driver_s *dev); +static int esp_ifdown(struct net_driver_s *dev); + +static void esp_txavail_work(FAR void *arg); +static int esp_txavail(struct net_driver_s *dev); + +#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6) +static int esp_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); +#endif +#ifdef CONFIG_NET_MCASTGROUP +static int esp_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); +#endif +#ifdef CONFIG_NETDEV_IOCTL +static int esp_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif +static int esp32_net_initialize(unsigned int devno); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/** + * Note: + * All TX done/RX done/Error trigger functions are not called from + * interrupts, this is much different from ethernet driver, including: + * * esp_sta_input + * + * These functions are called in a WiFi private thread. So we just use + * mutex/semaphore instead of disable interrupt, if necessary. + */ + +/**************************************************************************** + * Function: esp_initbuffer + * + * Description: + * Initialize the free buffer list. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_initbuffer(FAR struct esp_dev_s *priv) +{ + uint8_t *buffer; + int i; + + /* Initialize the head of the free buffer list */ + + sq_init(&priv->freeb); + + /* Add all of the pre-allocated buffers to the free buffer list */ + + for (i = 0, buffer = priv->alloc; i < ESP_ETH_NFREEBUFFERS; + i++, buffer += CONFIG_ESP_ETH_BUFSIZE) + { + sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb); + } +} + +/**************************************************************************** + * Function: esp_allocbuffer + * + * Description: + * Allocate one buffer from the free buffer list. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * Pointer to the allocated buffer on success; NULL on failure + * + ****************************************************************************/ + +static inline uint8_t *esp_allocbuffer(FAR struct esp_dev_s *priv) +{ + /* Allocate a buffer by returning the head of the free buffer list */ + + return (uint8_t *)sq_remfirst(&priv->freeb); +} + +/**************************************************************************** + * Function: esp_freebuffer + * + * Description: + * Return a buffer to the free buffer list. + * + * Input Parameters: + * priv - Reference to the driver state structure + * buffer - A pointer to the buffer to be freed + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void esp_freebuffer(FAR struct esp_dev_s *priv, + uint8_t *buffer) +{ + /* Free the buffer by adding it to the end of the free buffer list */ + + sq_addlast((FAR sq_entry_t *)buffer, &priv->freeb); +} + +/**************************************************************************** + * Function: esp_isfreebuffer + * + * Description: + * Return TRUE if the free buffer list is not empty. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * True if there are one or more buffers in the free buffer list; + * false if the free buffer list is empty + * + ****************************************************************************/ + +static inline bool esp_isfreebuffer(FAR struct esp_dev_s *priv) +{ + /* Return TRUE if the free buffer list is not empty */ + + return !sq_empty(&priv->freeb); +} + +/**************************************************************************** + * Name: esp_transmit + * + * Description: + * Start hardware transmission. Called either from TX process or + * from watchdog based polling. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +static int esp_transmit(FAR struct esp_dev_s *priv) +{ + int ret = 0; + uint8_t *buffer; + uint32_t buffer_len; + + /* Set up all but the last TX descriptor */ + + buffer = priv->esp_dev.d_buf; + buffer_len = priv->esp_dev.d_len; + ret = esp_wifi_sta_send_data(buffer, buffer_len); + + if (ret != 0) + { + wlerr("ERROR: Failed to transmit frame\n"); + (void)wd_start(&priv->esp_txtimeout, ESP_TXTIMEOUT, + esp_txtimeout_expiry, (uint32_t)priv); + return -EIO; + } + + return OK; +} + +/**************************************************************************** + * Function: esp_recvframe + * + * Description: + * It scans the RX descriptors of the received frame. + * + * NOTE: This function will silently discard any packets containing errors. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * OK if a packet was successfully returned; -EAGAIN if there are no + * further packets available + * + ****************************************************************************/ + +static int esp_recvframe(FAR struct esp_dev_s *priv) +{ + struct net_driver_s *dev = &priv->esp_dev; + uint8_t *buffer; + uint32_t buffer_len = 0; + buffer = dev->d_buf; + buffer_len = dev->d_len; + + /* Check if there are free buffers. We cannot receive new frames in this + * design unless there is at least one free buffer. + */ + + if (!esp_isfreebuffer(priv)) + { + wlerr("ERROR: No free buffers\n"); + return -ENOMEM; + } + + /* Check if any errors are reported in the frame */ + + if (buffer == NULL || buffer_len == 0) + { + return -EAGAIN; + } + + return OK; +} + +/**************************************************************************** + * Function: esp_receive + * + * Description: + * An event was received indicating the availability of a new RX packet + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_receive(FAR struct esp_dev_s *priv) +{ + struct net_driver_s *dev = &priv->esp_dev; + + /* Loop while while esp_recvframe() successfully retrieves valid + * Ethernet frames. + */ + + while (esp_recvframe(priv) == OK) + { +#ifdef CONFIG_NET_PKT + + /* When packet sockets are enabled, + * feed the frame into the packet tap. + */ + + pkt_input(&priv->esp_dev); +#endif + + /* Check if the packet is a valid size for the network + * buffer configuration (this should not happen) + */ + + if (dev->d_len > CONFIG_NET_ETH_PKTSIZE) + { + wlwarn("WARNING: DROPPED Too big: %d\n", dev->d_len); + + /* Free dropped packet buffer */ + + if (dev->d_buf) + { + esp_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + dev->d_len = 0; + } + + continue; + } + + /* We only accept IP packets of the configured type and ARP packets */ + +#ifdef CONFIG_NET_IPv4 + if (BUF->type == HTONS(ETHTYPE_IP)) + { + wlinfo("IPv4 frame\n"); + + /* Handle ARP on input then give the IPv4 packet to the network + * layer + */ + + arp_ipin(&priv->esp_dev); + ipv4_input(&priv->esp_dev); + + /* If the above function invocation resulted in data + * that should be sent out on the network, + * the field d_len will set to a value > 0. + */ + + if (priv->esp_dev.d_len > 0) + { + /* Update the Ethernet header with the correct MAC address */ + +#ifdef CONFIG_NET_IPv6 + if (IFF_IS_IPv4(priv->esp_dev.d_flags)) +#endif + { + arp_out(&priv->esp_dev); + } +#ifdef CONFIG_NET_IPv6 + else + { + neighbor_out(&priv->esp_dev); + } +#endif + + /* And send the packet */ + + esp_transmit(priv); + } + } + else +#endif +#ifdef CONFIG_NET_IPv6 + if (BUF->type == HTONS(ETHTYPE_IP6)) + { + wlinfo("Iv6 frame\n"); + + /* Give the IPv6 packet to the network layer */ + + ipv6_input(&priv->esp_dev); + + /* If the above function invocation resulted in data + * that should be sent out on the network, the field + * d_len will set to a value > 0. + */ + + if (priv->esp_dev.d_len > 0) + { + /* Update the Ethernet header with the correct MAC address */ + +#ifdef CONFIG_NET_IPv4 + if (IFF_IS_IPv4(priv->esp_dev.d_flags)) + { + arp_out(&priv->esp_dev); + } + else +#endif +#ifdef CONFIG_NET_IPv6 + { + neighbor_out(&priv->esp_dev); + } +#endif + + /* And send the packet */ + + esp_transmit(priv); + } + } + else +#endif +#ifdef CONFIG_NET_ARP + if (BUF->type == htons(ETHTYPE_ARP)) + { + wlinfo("ARP frame\n"); + + /* Handle ARP packet */ + + arp_arpin(&priv->esp_dev); + + /* If the above function invocation resulted in data + * that should be sent out on the network, the field + * d_len will set to a value > 0. + */ + + if (priv->esp_dev.d_len > 0) + { + esp_transmit(priv); + } + } + else +#endif + { + wlinfo("INFO: Dropped, Unknown type: %04x\n", BUF->type); + } + + /* We are finished with the RX buffer. NOTE: If the buffer is + * re-used for transmission, the dev->d_buf field will have been + * nullified. + */ + + if (dev->d_buf) + { + /* Free the receive packet buffer */ + + esp_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + dev->d_len = 0; + } + } +} + +/**************************************************************************** + * Name: esp_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send times out and the interface is + * reset + * 2. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +static int esp_txpoll(FAR struct net_driver_s *dev) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private; + + DEBUGASSERT(priv->esp_dev.d_buf != NULL); + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->esp_dev.d_len > 0) + { + /* Look up the destination MAC address and add it to the Ethernet + * header. + */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (IFF_IS_IPv4(priv->esp_dev.d_flags)) +#endif + { + arp_out(&priv->esp_dev); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + neighbor_out(&priv->esp_dev); + } +#endif /* CONFIG_NET_IPv6 */ + + if (!devif_loopback(&priv->esp_dev)) + { + /* Send the packet */ + + int ret = esp_transmit(priv); + if (ret != OK) + { + wlerr("TX failed\r\n"); + return -EBUSY; + } + } + } + + /* If zero is returned, the polling will continue until + * all connections have been examined. + */ + + return OK; +} + +/**************************************************************************** + * Name: esp_rxpoll + * + * Description: + * Process RX frames + * + * Input Parameters: + * arg - context of device to use + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void esp_rxpoll(FAR void *arg) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg; + + if (priv->esp_dev.d_buf == NULL) + { + priv->esp_dev.d_buf = priv->rxbuf; + priv->esp_dev.d_len = priv->rx_len; + } + else + { + wlinfo("priv->esp_dev.d_buf != NULL"); + return; + } + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + + esp_receive(priv); + + if (priv->esp_dev.d_buf) + { + priv->esp_dev.d_buf = NULL; + memset(priv->rxbuf, 0x0, sizeof(priv->rxbuf)); + priv->rx_len = 0; + } + + net_unlock(); +} + +/**************************************************************************** + * Function: esp_dopoll + * + * Description: + * The function is called in order to perform an out-of-sequence TX poll. + * This is done: + * + * 1. When new TX data is available (esp_txavail), and + * 2. After a TX timeout to restart the sending process + * (esp_txtimeout_expiry). + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_dopoll(FAR struct esp_dev_s *priv) +{ + FAR struct net_driver_s *dev = &priv->esp_dev; + + if (g_tx_ready == true) + { + /* Check if there is room in the hardware to + * hold another outgoing packet. + */ + + dev->d_buf = esp_allocbuffer(priv); + + /* We can't poll if we have no buffers */ + + if (dev->d_buf) + { + /* If so, then poll the network for new XMIT data */ + + (void)devif_poll(dev, esp_txpoll); + + /* We will, most likely end up with a buffer to be freed. + * But it might not be the same one that we allocated above. + */ + + if (dev->d_buf) + { + esp_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + } + } + else + { + wlerr("Alloc buffer error"); + } + } + else + { + wlwarn("Tx is not ready"); + } +} + +/**************************************************************************** + * Name: esp_netdev_notify_rx + * + * Description: + * Notify callback called when RX frame is available + * + * Input Parameters: + * priv - Reference to the driver state structure + * buffer - Receive buffer + * len - Length of receive buffer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_netdev_notify_rx(FAR struct esp_dev_s *priv, + void *buffer, uint16_t len) +{ + struct esp_dev_s *priv_dev = priv; + + memcpy(priv_dev->rxbuf, buffer, len); + priv_dev->rx_len = len; + work_queue(ESPWORK, &priv_dev->esp_irqwork, esp_rxpoll, priv_dev, 0); +} + +/**************************************************************************** + * Function: esp_sta_input + * + * Description: + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * Input Parameters: + * buffer - WiFi receive buffer + * len - Length of receive buffer + * eb - WiFi receive callback input eb pointer + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +static int esp_sta_input(void *buffer, uint16_t len, void *eb) +{ + FAR struct esp_dev_s *priv = &s_esp32_dev; + + if (!buffer || (priv->ifup == false)) + { + if (eb) + { + esp_wifi_free_eb(eb); + } + + return -1; + } + else + { + esp_netdev_notify_rx(priv, buffer, len); + } + + esp_wifi_free_eb(eb); + return 0; +} + +/**************************************************************************** + * Function: esp_txtimeout_work + * + * Description: + * Perform TX timeout related work from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + ****************************************************************************/ + +static void esp_txtimeout_work(void *arg) +{ + struct esp_dev_s *priv = (struct esp_dev_s *)arg; + + /* Reset the hardware. Just take the interface down, then back up again. */ + + net_lock(); + esp_ifdown(&priv->esp_dev); + esp_ifup(&priv->esp_dev); + + /* Then poll for new XMIT data */ + + esp_dopoll(priv); + net_unlock(); +} + +/**************************************************************************** + * Function: esp_txtimeout_expiry + * + * Description: + * Our TX watchdog timed out. Called from the timer callback handler. + * The last TX never completed. Reset the hardware and start again. + * + * Input Parameters: + * argc - The number of available arguments + * arg - The first argument + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_txtimeout_expiry(wdparm_t arg) +{ + struct esp_dev_s *priv = (struct esp_dev_s *)arg; + wlinfo("Timeout!\n"); + + /* Schedule to perform the TX timeout processing on the worker thread. */ + + DEBUGASSERT(work_available(&priv->esp_irqwork)); + work_queue(ESPWORK, &priv->esp_irqwork, esp_txtimeout_work, priv, 0); +} + +/**************************************************************************** + * Name: esp_poll_work + * + * Description: + * Perform periodic polling from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void esp_poll_work(FAR void *arg) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg; + struct net_driver_s *dev = &priv->esp_dev; + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + + /* Check if there is room in the send another TX packet. We cannot perform + * the TX poll if he are unable to accept another packet for transmission. + */ + + if (g_tx_ready == true) + { + dev->d_buf = esp_allocbuffer(priv); + + /* We can't poll if we have no buffers */ + + if (dev->d_buf) + { + /* Update TCP timing states and poll + * the network for new XMIT data. + */ + + (void)devif_timer(&priv->esp_dev, ESP_WDDELAY, esp_txpoll); + + /* We will, most likely end up with a buffer to be freed. + * But it might not be the same one that we allocated above. + */ + + if (dev->d_buf) + { + esp_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + } + } + else + { + wlerr("ERROR: Failed to TX pkt"); + } + } + + wd_start(&priv->esp_txpoll, ESP_WDDELAY, esp_poll_expiry, + (wdparm_t)priv); + net_unlock(); +} + +/**************************************************************************** + * Name: esp_poll_expiry + * + * Description: + * Periodic timer handler. Called from the timer callback handler. + * + * Input Parameters: + * argc - The number of available arguments + * arg - The first argument + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp_poll_expiry(wdparm_t arg) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg; + + work_queue(ESPWORK, &priv->esp_pollwork, esp_poll_work, priv, 0); +} + +/**************************************************************************** + * Name: esp_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int esp_ifup(FAR struct net_driver_s *dev) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private; + +#ifdef CONFIG_NET_IPv4 + wlinfo("Bringing up: %d.%d.%d.%d\n", + dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, + (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); +#endif +#ifdef CONFIG_NET_IPv6 + winfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2], + dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5], + dev->d_ipv6addr[6], dev->d_ipv6addr[7]); +#endif + +#ifdef CONFIG_NET_ICMPv6 + + /* Set up IPv6 multicast address filtering */ + + esp_ipv6multicast(priv); +#endif + + /* Initialize the free buffer list */ + + esp_initbuffer(priv); + + /* Set and activate a timer process */ + + (void)wd_start(&priv->esp_txpoll, ESP_WDDELAY, esp_poll_expiry, + (wdparm_t)priv); + + priv->ifup = true; + + return OK; +} + +/**************************************************************************** + * Name: esp_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int esp_ifdown(FAR struct net_driver_s *dev) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Cancel the TX poll timer and TX timeout timers */ + + wd_cancel(&priv->esp_txpoll); + wd_cancel(&priv->esp_txtimeout); + + /* Mark the device "down" */ + + priv->ifup = false; + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: esp_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void esp_txavail_work(FAR void *arg) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)arg; + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + + /* Ignore the notification if the interface is not yet up */ + + if (priv->ifup) + { + /* Poll the network for new XMIT data */ + + esp_dopoll(priv); + } + + net_unlock(); +} + +/**************************************************************************** + * Name: esp_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int esp_txavail(FAR struct net_driver_s *dev) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private; + + if (work_available(&priv->esp_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(ESPWORK, &priv->esp_pollwork, esp_txavail_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: esp_addmac + * + * Description: + * NuttX Callback: Add the specified MAC address to the hardware multicast + * address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be added + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6) +static int esp_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private; + + /* Add the MAC address to the hardware multicast routing table */ + + return OK; +} +#endif + +/**************************************************************************** + * Name: esp_rmmac + * + * Description: + * NuttX Callback: Remove the specified MAC address from the + * hardware multicast address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be removed + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_MCASTGROUP +static int esp_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + FAR struct esp_dev_s *priv = (FAR struct esp_dev_s *)dev->d_private; + + /* Add the MAC address to the hardware multicast routing table */ + + return OK; +} +#endif + +/**************************************************************************** + * Name: esp_ipv6multicast + * + * Description: + * Configure the IPv6 multicast MAC address. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ICMPv6 +static void esp_ipv6multicast(FAR struct esp_dev_s *priv) +{ + FAR struct net_driver_s *dev; + uint16_t tmp16; + uint8_t mac[6]; + + /* For ICMPv6, we need to add the IPv6 multicast address + * + * For IPv6 multicast addresses, the Ethernet MAC is derived by + * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00, + * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map + * to the Ethernet MAC address 33:33:00:01:00:03. + * + * NOTES: This appears correct for the ICMPv6 Router Solicitation + * Message, but the ICMPv6 Neighbor Solicitation message seems to + * use 33:33:ff:01:00:03. + */ + + mac[0] = 0x33; + mac[1] = 0x33; + + dev = &priv->esp_dev; + tmp16 = dev->d_ipv6addr[6]; + mac[2] = 0xff; + mac[3] = tmp16 >> 8; + + tmp16 = dev->d_ipv6addr[7]; + mac[4] = tmp16 & 0xff; + mac[5] = tmp16 >> 8; + + wlinfo("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + esp_addmac(dev, mac); + +#ifdef CONFIG_NET_ICMPv6_AUTOCONF + /* Add the IPv6 all link-local nodes Ethernet address. This is the + * address that we expect to receive ICMPv6 Router Advertisement + * packets. + */ + + esp_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet); +#endif /* CONFIG_NET_ICMPv6_AUTOCONF */ + +#ifdef CONFIG_NET_ICMPv6_ROUTER + /* Add the IPv6 all link-local routers Ethernet address. This is the + * address that we expect to receive ICMPv6 Router Solicitation + * packets. + */ + + esp_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet); +#endif /* CONFIG_NET_ICMPv6_ROUTER */ +} +#endif /* CONFIG_NET_ICMPv6 */ + +/**************************************************************************** + * Name: esp_ioctl + * + * Description: + * Handle network IOCTL commands directed to this device. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int esp_ioctl(FAR struct net_driver_s *dev, + int cmd, unsigned long arg) +{ + int ret; + struct iw_point *essid; + struct iw_encode_ext *ext; + struct mii_ioctl_notify_s *req; + struct iwreq *iwr = (struct iwreq *)arg; + + /* Decode and dispatch the driver-specific IOCTL command */ + + switch (cmd) + { +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ + { + req = (struct mii_ioctl_notify_s *)arg; + ret = esp_wifi_notify_subscribe(req->pid, &req->event); + if (ret) + { + wlerr("ERROR: Failed to subscribe event\n"); + } + } + break; +#endif +#endif + + case SIOCSIWENCODEEXT: + { + ext = iwr->u.encoding.pointer; + ret = esp_wifi_set_password(ext->key, ext->key_len); + if (ret) + { + wlerr("ERROR: Failed to set password\n"); + } + } + break; + case SIOCSIWESSID: + { + iwr = (struct iwreq *)arg; + essid = &iwr->u.essid; + ret = esp_wifi_set_ssid(essid->pointer, essid->length); + if (ret) + { + wlerr("ERROR: Failed to set SSID\n"); + break; + } + + ret = esp_wifi_connect_internal(); + if (ret) + { + wlerr("ERROR: Failed to start connecting\n"); + break; + } + else + { + g_tx_ready = true; + } + } + break; + case SIOCSIWMODE: + ret = OK; + break; + case SIOCSIWAUTH: + ret = OK; + break; + default: + wlerr("ERROR: Unrecognized IOCTL command: %d\n", cmd); + ret = -ENOTTY; /* Special return value for this case */ + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Name: esp32_net_initialize + * + * Description: + * Initialize the esp32 driver + * + * Input Parameters: + * devno - The device number. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +static int esp32_net_initialize(unsigned int devno) +{ + int ret; + uint8_t eth_mac[6]; + FAR struct esp_dev_s *priv; + + /* Get the interface structure associated with this interface number. */ + + priv = &s_esp32_dev; + + /* Initialize the driver structure */ + + memset(priv, 0, sizeof(struct esp_dev_s)); + + priv->esp_dev.d_ifup = esp_ifup; /* I/F down callback */ + priv->esp_dev.d_ifdown = esp_ifdown; /* I/F up (new IP address) callback */ + priv->esp_dev.d_txavail = esp_txavail; /* New TX data callback */ +#ifdef CONFIG_NET_MCASTGROUP + priv->esp_dev.d_addmac = esp_addmac; /* Add multicast MAC address */ + priv->esp_dev.d_rmmac = esp_rmmac; /* Remove multicast MAC address */ +#endif +#ifdef CONFIG_NETDEV_IOCTL + priv->esp_dev.d_ioctl = esp_ioctl; /* Handle network IOCTL commands */ +#endif + + /* Used to recover private state from dev */ + + priv->esp_dev.d_private = (void *)&s_esp32_dev; + + /* Create a watchdog for timing polling for and timing of transmissions */ + + /* Initialize network stack interface buffer */ + + priv->esp_dev.d_buf = NULL; + g_tx_ready = false; + + assert(esp_wifi_adapter_init() == 0); + esp_wifi_sta_register_recv_cb(esp_sta_input); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + esp_wifi_sta_read_mac(priv->esp_dev.d_mac.ether.ether_addr_octet); + memcpy(eth_mac, priv->esp_dev.d_mac.ether.ether_addr_octet, + sizeof(eth_mac)); + wlinfo("%02X:%02X:%02X:%02X:%02X:%02X \r\n", eth_mac[0], eth_mac[1], + eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]); + + /* Put the interface in the down state. */ + + ret = esp_ifdown(&priv->esp_dev); + if (ret < 0) + { + wlerr("ERROR: Initialization of Ethernet block failed: %d\n", ret); + return ret; + } + + (void)netdev_register(&s_esp32_dev.esp_dev, NET_LL_IEEE80211); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_wlan_initialize + * + * Description: + * Initialize the esp32 wlan driver + * + * Input Parameters: + * None + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int esp32_wlan_initialize(void) +{ + return esp32_net_initialize(STA_DEVNO); +} + +#endif /* CONFIG_ESP32_WIRELESS */ diff --git a/arch/xtensa/src/esp32/esp32_wlan.h b/arch/xtensa/src/esp32/esp32_wlan.h new file mode 100644 index 00000000000..a18f294ca17 --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wlan.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wlan.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32_ESP32_WLAN_H +#define __ARCH_XTENSA_SRC_ESP32_ESP32_WLAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifdef CONFIG_ESP32_WIRELESS + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_wlan_initialize + * + * Description: + * Initialize the esp32 wlan driver + * + * Input Parameters: + * None + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int esp32_wlan_initialize(void); + +#endif /* CONFIG_ESP32_SPI */ +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_WLAN_H */ diff --git a/arch/xtensa/src/esp32/hardware/esp32_dport.h b/arch/xtensa/src/esp32/hardware/esp32_dport.h index 47989fa24da..f81b6dea815 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_dport.h +++ b/arch/xtensa/src/esp32/hardware/esp32_dport.h @@ -1193,6 +1193,31 @@ #define DPORT_WIFI_CLK_EN_V 0xFFFFFFFF #define DPORT_WIFI_CLK_EN_S 0 +/* Mask for all Wifi clock bits - 1, 2, 10 */ + +#define DPORT_WIFI_CLK_WIFI_EN 0x00000406 +#define DPORT_WIFI_CLK_WIFI_EN_M ((DPORT_WIFI_CLK_WIFI_EN_V)<<(DPORT_WIFI_CLK_WIFI_EN_S)) +#define DPORT_WIFI_CLK_WIFI_EN_V 0x406 +#define DPORT_WIFI_CLK_WIFI_EN_S 0 + +/* Mask for all Bluetooth clock bits - 11, 16, 17 */ + +#define DPORT_WIFI_CLK_BT_EN 0x61 +#define DPORT_WIFI_CLK_BT_EN_M ((DPORT_WIFI_CLK_BT_EN_V)<<(DPORT_WIFI_CLK_BT_EN_S)) +#define DPORT_WIFI_CLK_BT_EN_V 0x61 +#define DPORT_WIFI_CLK_BT_EN_S 11 + +/* Mask for clock bits used by both WIFI and Bluetooth */ + +#define DPORT_WIFI_CLK_WIFI_BT_COMMON_M 0x000003c9 + +/* bluetooth baseband bit11 */ + +#define DPORT_BT_BASEBAND_EN BIT(11) + +/* bluetooth LC bit16 and bit17 */ +#define DPORT_BT_LC_EN (BIT(16)|BIT(17)) + #define DPORT_WIFI_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) /* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ diff --git a/boards/xtensa/esp32/esp32-core/configs/wapi/defconfig b/boards/xtensa/esp32/esp32-core/configs/wapi/defconfig new file mode 100644 index 00000000000..f982ac03163 --- /dev/null +++ b/boards/xtensa/esp32/esp32-core/configs/wapi/defconfig @@ -0,0 +1,82 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +CONFIG_ARCH="xtensa" +CONFIG_ARCH_BOARD="esp32-core" +CONFIG_ARCH_BOARD_ESP32CORE=y +CONFIG_ARCH_CHIP="esp32" +CONFIG_ARCH_CHIP_ESP32=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_XTENSA=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_WARN=y +CONFIG_DEBUG_WIRELESS=y +CONFIG_DEBUG_WIRELESS_ERROR=y +CONFIG_DEBUG_WIRELESS_WARN=y +CONFIG_DRIVERS_IEEE80211=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_ESP32_MTD_SIZE=0x80000 +CONFIG_ESP32_SPIFLASH=y +CONFIG_ESP32_UART0=y +CONFIG_ESP32_WIFI_SAVE_PARAM=y +CONFIG_ESP32_WIRELESS=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_SPIFFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_MAX_TASKS=16 +CONFIG_MM_REGIONS=2 +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_PHY_IOCTL=y +CONFIG_NETDEV_WIRELESS_IOCTL=y +CONFIG_NETUTILS_DHCPC=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_TCP=y +CONFIG_NET_UDP=y +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PTHREAD_MUTEX_TYPES=y +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SIG_DEFAULT=y +CONFIG_SPI=y +CONFIG_SPIFFS_NAME_MAX=48 +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_WIRELESS=y +CONFIG_WIRELESS_WAPI=y +CONFIG_WIRELESS_WAPI_CMDTOOL=y +CONFIG_WIRELESS_WAPI_STACKSIZE=4096 diff --git a/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld b/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld index 16345097948..f6db2e99fc0 100644 --- a/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld +++ b/boards/xtensa/esp32/esp32-core/scripts/esp32_flash.ld @@ -59,6 +59,8 @@ SECTIONS *libpp.a:(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) *libarch.a:esp32_spiflash.*(.literal .text .literal.* .text.*) + *(.wifirxiram .wifirxiram.*) + *(.wifirxiram .wifi0iram.*) _iram_text_end = ABSOLUTE(.); /* Module text area starts at the end of iram0_0_seg */ diff --git a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld index d9278d1352c..479d1181c0b 100644 --- a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld @@ -1850,3 +1850,6 @@ PROVIDE ( g_rom_spiflash_dummy_len_plus = 0x3ffae290 ); PROVIDE ( esp_rom_spiflash_read_user_cmd = 0x400621b0 ); PROVIDE ( esp_rom_spiflash_write_encrypted_enable = 0x40062df4 ); PROVIDE ( esp_rom_spiflash_prepare_encrypted_data = 0x40062e1c ); + +PROVIDE ( esp_rom_printf = ets_printf ); +PROVIDE ( esp_rom_delay_us = ets_delay_us ); diff --git a/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c b/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c index 567d3829565..fd505f964e5 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c +++ b/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c @@ -39,6 +39,12 @@ #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -47,9 +53,14 @@ #ifdef CONFIG_TIMER # include #endif +#include +#include #include "esp32-core.h" +#include "esp32_wlan.h" +#include "esp32_spiflash.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -88,6 +99,38 @@ * ****************************************************************************/ +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM +static int esp32_init_wifi_storage(void) +{ + int ret; + const char *path = "/dev/mtdblock1"; + FAR struct mtd_dev_s *mtd_part; + + mtd_part = esp32_spiflash_alloc_mtdpart(); + if (!mtd_part) + { + syslog(LOG_ERR, "ERROR: Failed to alloc MTD partition of SPI Flash\n"); + return -1; + } + + ret = register_mtddriver(path, mtd_part, 0777, NULL); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to regitser MTD: %d\n", ret); + return -1; + } + + ret = mount(path, CONFIG_ESP32_WIFI_FS_MOUNTPT, "spiffs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", errno); + return ret; + } + + return 0; +} +#endif + int esp32_bringup(void) { int ret; @@ -113,6 +156,33 @@ int esp32_bringup(void) #ifdef CONFIG_ESP32_SPIFLASH ret = esp32_spiflash_init(); + if (ret) + { + syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n"); + return ret; + } +#endif + +#ifdef CONFIG_ESP32_WIRELESS + +#ifdef CONFIG_ESP32_WIFI_SAVE_PARAM + ret = esp32_init_wifi_storage(); + if (ret) + { + syslog(LOG_ERR, "ERROR: Failed to initialize WiFi storage\n"); + return ret; + } +#endif + +#ifdef CONFIG_NET + ret = esp32_wlan_initialize(); + if (ret) + { + syslog(LOG_ERR, "ERROR: Failed to initialize WiFi\n"); + return ret; + } +#endif + #endif #ifdef CONFIG_TIMER