diff --git a/components/esp32/esp_adapter.c b/components/esp32/esp_adapter.c index 2c34588a6a..b86b50b5ab 100644 --- a/components/esp32/esp_adapter.c +++ b/components/esp32/esp_adapter.c @@ -38,6 +38,9 @@ #include "esp_private/wifi_os_adapter.h" #include "esp_private/wifi.h" #include "esp_phy_init.h" +#include "soc/dport_reg.h" +#include "soc/syscon_reg.h" +#include "phy_init_data.h" #include "driver/periph_ctrl.h" #include "nvs.h" #include "os.h" @@ -568,6 +571,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._phy_load_cal_and_init = esp_phy_load_cal_and_init, ._phy_common_clock_enable = esp_phy_common_clock_enable, ._phy_common_clock_disable = esp_phy_common_clock_disable, + ._phy_update_country_info = esp_phy_update_country_info, ._read_mac = esp_read_mac, ._timer_arm = timer_arm_wrapper, ._timer_disarm = timer_disarm_wrapper, diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 1d239ed115..0b508c5ab6 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -38,22 +38,38 @@ endif() if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) idf_component_get_property(esp_common_dir esp_common COMPONENT_DIR) partition_table_get_partition_info(phy_partition_offset "--partition-type data --partition-subtype phy" "offset") - set(phy_init_data_bin "${build_dir}/phy_init_data.bin") + + if(CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN) + set(phy_init_data_bin "${CMAKE_CURRENT_SOURCE_DIR}/phy_multiple_init_data.bin") + else() + set(phy_init_data_bin "${build_dir}/phy_init_data.bin") - # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy - # the object file to a raw binary - idf_build_get_property(config_dir CONFIG_DIR) - add_custom_command( - OUTPUT ${phy_init_data_bin} - DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h - COMMAND ${CMAKE_C_COMPILER} -x c -c - -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${config_dir} - -o phy_init_data.obj - ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h - COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} - ) - add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) - add_dependencies(flash phy_init_data) + # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy + # the object file to a raw binary + idf_build_get_property(config_dir CONFIG_DIR) + add_custom_command( + OUTPUT ${phy_init_data_bin} + DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h + COMMAND ${CMAKE_C_COMPILER} -x c -c + -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${config_dir} + -o phy_init_data.obj + ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h + COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} + ) + add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) + add_dependencies(flash phy_init_data) + + idf_component_get_property(main_args esptool_py FLASH_ARGS) + idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) + endif() + + # ToDo: remove once MP chip is supported + if(CONFIG_IDF_TARGET_ESP32) + set(phy_name "phy") + endif() esptool_py_flash_project_args(phy ${phy_partition_offset} ${phy_init_data_bin} FLASH_IN_PROJECT) + # esptool_py_flash_target(${phy_name}-flash "${main_args}" "${sub_args}") + # esptool_py_flash_target_image(${phy_name}-flash ${phy_name} "${phy_partition_offset}" "${phy_init_data_bin}") + # esptool_py_flash_target_image(flash ${phy_name} "${phy_partition_offset}" "${phy_init_data_bin}") endif() diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 79b13109b2..51bb965b0f 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -334,7 +334,7 @@ menu "PHY" 2.Because of your board design, each time when you do calibration, the result are too unstable. If unsure, choose 'y'. - config ESP32_PHY_INIT_DATA_IN_PARTITION + menuconfig ESP32_PHY_INIT_DATA_IN_PARTITION bool "Use a partition to store PHY init data" default n help @@ -350,6 +350,32 @@ menu "PHY" If unsure, choose 'n'. + if ESP32_PHY_INIT_DATA_IN_PARTITION + config ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + bool "Support multiple PHY init data bin" + depends on ESP32_PHY_INIT_DATA_IN_PARTITION + default n + help + If enabled, the corresponding PHY init data type can be automatically switched + according to the country code. China's PHY init data bin is used by default. + Can be modified by country information in API esp_wifi_set_country(). + The priority of switching the PHY init data type is: + 1. Country configured by API esp_wifi_set_country() + and the parameter policy is WIFI_COUNTRY_POLICY_MANUAL. + 2. Country notified by the connected AP. + 3. Country configured by API esp_wifi_set_country() + and the parameter policy is WIFI_COUNTRY_POLICY_AUTO. + + config ESP32_PHY_INIT_DATA_ERROR + bool "Terminate operation when PHY init data error" + depends on ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + default n + help + If enabled, when an error occurs while the PHY init data is updated, + the program will terminate and restart. + If not enabled, the PHY init data will not be updated when an error occurs. + endif + config ESP32_PHY_MAX_WIFI_TX_POWER int "Max WiFi TX power (dBm)" range 10 20 diff --git a/components/esp_wifi/esp32/esp_adapter.c b/components/esp_wifi/esp32/esp_adapter.c new file mode 100644 index 0000000000..010fde884b --- /dev/null +++ b/components/esp_wifi/esp32/esp_adapter.c @@ -0,0 +1,663 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed 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. + +#include +#include +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/event_groups.h" +#include "freertos/xtensa_api.h" +#include "freertos/portmacro.h" +#include "freertos/xtensa_api.h" +#include "esp_types.h" +#include "esp_system.h" +#include "esp_task.h" +#include "esp_intr_alloc.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_event.h" +#include "esp_heap_caps.h" +#include "esp_private/wifi_os_adapter.h" +#include "esp_private/wifi.h" +#include "esp_phy_init.h" +#include "soc/dport_reg.h" +#include "soc/syscon_reg.h" +#include "phy_init_data.h" +#include "driver/periph_ctrl.h" +#include "nvs.h" +#include "os.h" +#include "esp_smartconfig.h" +#include "esp_coexist_internal.h" +#include "esp_coexist_adapter.h" +#include "esp32/dport_access.h" + +#define TAG "esp_adapter" + +static void IRAM_ATTR s_esp_dport_access_stall_other_cpu_start(void) +{ + DPORT_STALL_OTHER_CPU_START(); +} + +static void IRAM_ATTR s_esp_dport_access_stall_other_cpu_end(void) +{ + DPORT_STALL_OTHER_CPU_END(); +} + +/* + If CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is enabled. Prefer to allocate a chunk of memory in SPIRAM firstly. + If failed, try to allocate it in internal memory then. + */ +IRAM_ATTR void *wifi_malloc( size_t size ) +{ +#if CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP + return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); +#else + return malloc(size); +#endif +} + +/* + If CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is enabled. Prefer to allocate a chunk of memory in SPIRAM firstly. + If failed, try to allocate it in internal memory then. + */ +IRAM_ATTR void *wifi_realloc( void *ptr, size_t size ) +{ +#if CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP + return heap_caps_realloc_prefer(ptr, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); +#else + return realloc(ptr, size); +#endif +} + +/* + If CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is enabled. Prefer to allocate a chunk of memory in SPIRAM firstly. + If failed, try to allocate it in internal memory then. + */ +IRAM_ATTR void *wifi_calloc( size_t n, size_t size ) +{ +#if CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP + return heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); +#else + return calloc(n, size); +#endif +} + +static void * IRAM_ATTR wifi_zalloc_wrapper(size_t size) +{ + void *ptr = wifi_calloc(1, size); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +} + +wifi_static_queue_t* wifi_create_queue( int queue_len, int item_size) +{ + wifi_static_queue_t *queue = NULL; + + queue = (wifi_static_queue_t*)heap_caps_malloc(sizeof(wifi_static_queue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue) { + return NULL; + } + +#if CONFIG_SPIRAM_USE_MALLOC + + queue->storage = heap_caps_calloc(1, sizeof(StaticQueue_t) + (queue_len*item_size), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue->storage) { + goto _error; + } + + queue->handle = xQueueCreateStatic( queue_len, item_size, ((uint8_t*)(queue->storage)) + sizeof(StaticQueue_t), (StaticQueue_t*)(queue->storage)); + + if (!queue->handle) { + goto _error; + } + + return queue; + +_error: + if (queue) { + if (queue->storage) { + free(queue->storage); + } + + free(queue); + } + + return NULL; +#else + queue->handle = xQueueCreate( queue_len, item_size); + return queue; +#endif +} + +void wifi_delete_queue(wifi_static_queue_t *queue) +{ + if (queue) { + vQueueDelete(queue->handle); + +#if CONFIG_SPIRAM_USE_MALLOC + if (queue->storage) { + free(queue->storage); + } +#endif + + free(queue); + } +} + +static void * wifi_create_queue_wrapper(int queue_len, int item_size) +{ + return wifi_create_queue(queue_len, item_size); +} + +static void wifi_delete_queue_wrapper(void *queue) +{ + wifi_delete_queue(queue); +} + +static void set_isr_wrapper(int32_t n, void *f, void *arg) +{ + xt_set_interrupt_handler(n, (xt_handler)f, arg); +} + +static void * spin_lock_create_wrapper(void) +{ + portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED; + void *mux = malloc(sizeof(portMUX_TYPE)); + + if (mux) { + memcpy(mux,&tmp,sizeof(portMUX_TYPE)); + return mux; + } + return NULL; +} + +static uint32_t IRAM_ATTR wifi_int_disable_wrapper(void *wifi_int_mux) +{ + if (xPortInIsrContext()) { + portENTER_CRITICAL_ISR(wifi_int_mux); + } else { + portENTER_CRITICAL(wifi_int_mux); + } + + return 0; +} + +static void IRAM_ATTR wifi_int_restore_wrapper(void *wifi_int_mux, uint32_t tmp) +{ + if (xPortInIsrContext()) { + portEXIT_CRITICAL_ISR(wifi_int_mux); + } else { + portEXIT_CRITICAL(wifi_int_mux); + } +} + +static void IRAM_ATTR task_yield_from_isr_wrapper(void) +{ + portYIELD_FROM_ISR(); +} + +static void * semphr_create_wrapper(uint32_t max, uint32_t init) +{ + return (void *)xSemaphoreCreateCounting(max, init); +} + +static void semphr_delete_wrapper(void *semphr) +{ + vSemaphoreDelete(semphr); +} + +static void wifi_thread_semphr_free(void* data) +{ + xSemaphoreHandle *sem = (xSemaphoreHandle*)(data); + + if (sem) { + vSemaphoreDelete(sem); + } +} + +static void * wifi_thread_semphr_get_wrapper(void) +{ + static bool s_wifi_thread_sem_key_init = false; + static pthread_key_t s_wifi_thread_sem_key; + xSemaphoreHandle sem = NULL; + + if (s_wifi_thread_sem_key_init == false) { + if (0 != pthread_key_create(&s_wifi_thread_sem_key, wifi_thread_semphr_free)) { + return NULL; + } + s_wifi_thread_sem_key_init = true; + } + + sem = pthread_getspecific(s_wifi_thread_sem_key); + if (!sem) { + sem = xSemaphoreCreateCounting(1, 0); + if (sem) { + pthread_setspecific(s_wifi_thread_sem_key, sem); + ESP_LOGV(TAG, "thread sem create: sem=%p", sem); + } + } + + ESP_LOGV(TAG, "thread sem get: sem=%p", sem); + return (void*)sem; +} + +static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) +{ + return (int32_t)xSemaphoreTakeFromISR(semphr, hptw); +} + +static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw) +{ + return (int32_t)xSemaphoreGiveFromISR(semphr, hptw); +} + +static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_tick) +{ + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY); + } else { + return (int32_t)xSemaphoreTake(semphr, block_time_tick); + } +} + +static int32_t semphr_give_wrapper(void *semphr) +{ + return (int32_t)xSemaphoreGive(semphr); +} + +static void * recursive_mutex_create_wrapper(void) +{ + return (void *)xSemaphoreCreateRecursiveMutex(); +} + +static void * mutex_create_wrapper(void) +{ + return (void *)xSemaphoreCreateMutex(); +} + +static void mutex_delete_wrapper(void *mutex) +{ + vSemaphoreDelete(mutex); +} + +static int32_t IRAM_ATTR mutex_lock_wrapper(void *mutex) +{ + return (int32_t)xSemaphoreTakeRecursive(mutex, portMAX_DELAY); +} + +static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex) +{ + return (int32_t)xSemaphoreGiveRecursive(mutex); +} + +static void * queue_create_wrapper(uint32_t queue_len, uint32_t item_size) +{ + return (void *)xQueueCreate(queue_len, item_size); +} + +static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_tick) +{ + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)xQueueSend(queue, item, portMAX_DELAY); + } else { + return (int32_t)xQueueSend(queue, item, block_time_tick); + } +} + +static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw) +{ + return (int32_t)xQueueSendFromISR(queue, item, hptw); +} + +static int32_t queue_send_to_back_wrapper(void *queue, void *item, uint32_t block_time_tick) +{ + return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_BACK); +} + +static int32_t queue_send_to_front_wrapper(void *queue, void *item, uint32_t block_time_tick) +{ + return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_FRONT); +} + +static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_tick) +{ + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)xQueueReceive(queue, item, portMAX_DELAY); + } else { + return (int32_t)xQueueReceive(queue, item, block_time_tick); + } +} + +static uint32_t event_group_wait_bits_wrapper(void *event, uint32_t bits_to_wait_for, int clear_on_exit, int wait_for_all_bits, uint32_t block_time_tick) +{ + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + return (uint32_t)xEventGroupWaitBits(event, bits_to_wait_for, clear_on_exit, wait_for_all_bits, portMAX_DELAY); + } else { + return (uint32_t)xEventGroupWaitBits(event, bits_to_wait_for, clear_on_exit, wait_for_all_bits, block_time_tick); + } +} + +static int32_t task_create_pinned_to_core_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) +{ + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); +} + +static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle) +{ + return (uint32_t)xTaskCreate(task_func, name, stack_depth, param, prio, task_handle); +} + +static int32_t IRAM_ATTR task_ms_to_tick_wrapper(uint32_t ms) +{ + return (int32_t)(ms / portTICK_PERIOD_MS); +} + +static int32_t task_get_max_priority_wrapper(void) +{ + return (int32_t)(configMAX_PRIORITIES); +} + +static int32_t esp_event_post_wrapper(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait) +{ + if (ticks_to_wait == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)esp_event_post(event_base, event_id, event_data, event_data_size, portMAX_DELAY); + } else { + return (int32_t)esp_event_post(event_base, event_id, event_data, event_data_size, ticks_to_wait); + } +} + +static void IRAM_ATTR timer_arm_wrapper(void *timer, uint32_t tmout, bool repeat) +{ + ets_timer_arm(timer, tmout, repeat); +} + +static void IRAM_ATTR timer_disarm_wrapper(void *timer) +{ + ets_timer_disarm(timer); +} + +static void timer_done_wrapper(void *ptimer) +{ + ets_timer_done(ptimer); +} + +static void timer_setfn_wrapper(void *ptimer, void *pfunction, void *parg) +{ + ets_timer_setfn(ptimer, pfunction, parg); +} + +static void IRAM_ATTR timer_arm_us_wrapper(void *ptimer, uint32_t us, bool repeat) +{ + ets_timer_arm_us(ptimer, us, repeat); +} + +static void wifi_reset_mac_wrapper(void) +{ + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); +} + +static void wifi_clock_enable_wrapper(void) +{ + periph_module_enable(PERIPH_WIFI_MODULE); +} + +static void wifi_clock_disable_wrapper(void) +{ + periph_module_disable(PERIPH_WIFI_MODULE); +} + +static int get_time_wrapper(void *t) +{ + return os_get_time(t); +} + +static void * IRAM_ATTR malloc_internal_wrapper(size_t size) +{ + return heap_caps_malloc(size, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); +} + +static void * IRAM_ATTR realloc_internal_wrapper(void *ptr, size_t size) +{ + return heap_caps_realloc(ptr, size, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); +} + +static void * IRAM_ATTR calloc_internal_wrapper(size_t n, size_t size) +{ + return heap_caps_calloc(n, size, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); +} + +static void * IRAM_ATTR zalloc_internal_wrapper(size_t size) +{ + void *ptr = heap_caps_calloc(1, size, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +} + +static uint32_t coex_status_get_wrapper(void) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_status_get(); +#else + return 0; +#endif +} + +static void coex_condition_set_wrapper(uint32_t type, bool dissatisfy) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_condition_set(type, dissatisfy); +#endif +} + +static int coex_wifi_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_wifi_request(event, latency, duration); +#else + return 0; +#endif +} + +static int coex_wifi_release_wrapper(uint32_t event) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_wifi_release(event); +#else + return 0; +#endif +} + +int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_bt_request(event, latency, duration); +#else + return 0; +#endif +} + +int IRAM_ATTR coex_bt_release_wrapper(uint32_t event) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_bt_release(event); +#else + return 0; +#endif +} + +int coex_register_bt_cb_wrapper(coex_func_cb_t cb) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_register_bt_cb(cb); +#else + return 0; +#endif +} + +uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + return coex_bb_reset_lock(); +#else + return 0; +#endif +} + +void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore) +{ +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + coex_bb_reset_unlock(restore); +#endif +} + +int32_t IRAM_ATTR coex_is_in_isr_wrapper(void) +{ + return !xPortCanYield(); +} + +wifi_osi_funcs_t g_wifi_osi_funcs = { + ._version = ESP_WIFI_OS_ADAPTER_VERSION, + ._set_isr = set_isr_wrapper, + ._ints_on = xt_ints_on, + ._ints_off = xt_ints_off, + ._spin_lock_create = spin_lock_create_wrapper, + ._spin_lock_delete = free, + ._wifi_int_disable = wifi_int_disable_wrapper, + ._wifi_int_restore = wifi_int_restore_wrapper, + ._task_yield_from_isr = task_yield_from_isr_wrapper, + ._semphr_create = semphr_create_wrapper, + ._semphr_delete = semphr_delete_wrapper, + ._semphr_take = semphr_take_wrapper, + ._semphr_give = semphr_give_wrapper, + ._wifi_thread_semphr_get = wifi_thread_semphr_get_wrapper, + ._mutex_create = mutex_create_wrapper, + ._recursive_mutex_create = recursive_mutex_create_wrapper, + ._mutex_delete = mutex_delete_wrapper, + ._mutex_lock = mutex_lock_wrapper, + ._mutex_unlock = mutex_unlock_wrapper, + ._queue_create = queue_create_wrapper, + ._queue_delete = (void(*)(void *))vQueueDelete, + ._queue_send = queue_send_wrapper, + ._queue_send_from_isr = queue_send_from_isr_wrapper, + ._queue_send_to_back = queue_send_to_back_wrapper, + ._queue_send_to_front = queue_send_to_front_wrapper, + ._queue_recv = queue_recv_wrapper, + ._queue_msg_waiting = (uint32_t(*)(void *))uxQueueMessagesWaiting, + ._event_group_create = (void *(*)(void))xEventGroupCreate, + ._event_group_delete = (void(*)(void *))vEventGroupDelete, + ._event_group_set_bits = (uint32_t(*)(void *,uint32_t))xEventGroupSetBits, + ._event_group_clear_bits = (uint32_t(*)(void *,uint32_t))xEventGroupClearBits, + ._event_group_wait_bits = event_group_wait_bits_wrapper, + ._task_create_pinned_to_core = task_create_pinned_to_core_wrapper, + ._task_create = task_create_wrapper, + ._task_delete = (void(*)(void *))vTaskDelete, + ._task_delay = vTaskDelay, + ._task_ms_to_tick = task_ms_to_tick_wrapper, + ._task_get_current_task = (void *(*)(void))xTaskGetCurrentTaskHandle, + ._task_get_max_priority = task_get_max_priority_wrapper, + ._malloc = malloc, + ._free = free, + ._event_post = esp_event_post_wrapper, + ._get_free_heap_size = esp_get_free_heap_size, + ._rand = esp_random, + ._dport_access_stall_other_cpu_start_wrap = s_esp_dport_access_stall_other_cpu_start, + ._dport_access_stall_other_cpu_end_wrap = s_esp_dport_access_stall_other_cpu_end, + ._phy_rf_deinit = esp_phy_rf_deinit, + ._phy_load_cal_and_init = esp_phy_load_cal_and_init, + ._phy_common_clock_enable = esp_phy_common_clock_enable, + ._phy_common_clock_disable = esp_phy_common_clock_disable, + ._phy_update_country_info = esp_phy_update_country_info, + ._read_mac = esp_read_mac, + ._timer_arm = timer_arm_wrapper, + ._timer_disarm = timer_disarm_wrapper, + ._timer_done = timer_done_wrapper, + ._timer_setfn = timer_setfn_wrapper, + ._timer_arm_us = timer_arm_us_wrapper, + ._wifi_reset_mac = wifi_reset_mac_wrapper, + ._wifi_clock_enable = wifi_clock_enable_wrapper, + ._wifi_clock_disable = wifi_clock_disable_wrapper, + ._esp_timer_get_time = esp_timer_get_time, + ._nvs_set_i8 = nvs_set_i8, + ._nvs_get_i8 = nvs_get_i8, + ._nvs_set_u8 = nvs_set_u8, + ._nvs_get_u8 = nvs_get_u8, + ._nvs_set_u16 = nvs_set_u16, + ._nvs_get_u16 = nvs_get_u16, + ._nvs_open = nvs_open, + ._nvs_close = nvs_close, + ._nvs_commit = nvs_commit, + ._nvs_set_blob = nvs_set_blob, + ._nvs_get_blob = nvs_get_blob, + ._nvs_erase_key = nvs_erase_key, + ._get_random = os_get_random, + ._get_time = get_time_wrapper, + ._random = os_random, + ._log_write = esp_log_write, + ._log_timestamp = esp_log_timestamp, + ._malloc_internal = malloc_internal_wrapper, + ._realloc_internal = realloc_internal_wrapper, + ._calloc_internal = calloc_internal_wrapper, + ._zalloc_internal = zalloc_internal_wrapper, + ._wifi_malloc = wifi_malloc, + ._wifi_realloc = wifi_realloc, + ._wifi_calloc = wifi_calloc, + ._wifi_zalloc = wifi_zalloc_wrapper, + ._wifi_create_queue = wifi_create_queue_wrapper, + ._wifi_delete_queue = wifi_delete_queue_wrapper, + ._modem_sleep_enter = esp_modem_sleep_enter, + ._modem_sleep_exit = esp_modem_sleep_exit, + ._modem_sleep_register = esp_modem_sleep_register, + ._modem_sleep_deregister = esp_modem_sleep_deregister, + ._coex_status_get = coex_status_get_wrapper, + ._coex_condition_set = coex_condition_set_wrapper, + ._coex_wifi_request = coex_wifi_request_wrapper, + ._coex_wifi_release = coex_wifi_release_wrapper, + ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, +}; + +coex_adapter_funcs_t g_coex_adapter_funcs = { + ._version = COEX_ADAPTER_VERSION, + ._spin_lock_create = spin_lock_create_wrapper, + ._spin_lock_delete = free, + ._int_disable = wifi_int_disable_wrapper, + ._int_enable = wifi_int_restore_wrapper, + ._task_yield_from_isr = task_yield_from_isr_wrapper, + ._semphr_create = semphr_create_wrapper, + ._semphr_delete = semphr_delete_wrapper, + ._semphr_take_from_isr = semphr_take_from_isr_wrapper, + ._semphr_give_from_isr = semphr_give_from_isr_wrapper, + ._semphr_take = semphr_take_wrapper, + ._semphr_give = semphr_give_wrapper, + ._is_in_isr = coex_is_in_isr_wrapper, + ._malloc_internal = malloc_internal_wrapper, + ._free = free, + ._timer_disarm = timer_disarm_wrapper, + ._timer_done = timer_done_wrapper, + ._timer_setfn = timer_setfn_wrapper, + ._timer_arm_us = timer_arm_us_wrapper, + ._esp_timer_get_time = esp_timer_get_time, + ._magic = COEX_ADAPTER_MAGIC, +}; diff --git a/components/esp_wifi/esp32/include/phy_init_data.h b/components/esp_wifi/esp32/include/phy_init_data.h index 031813f5b7..f227138f27 100644 --- a/components/esp_wifi/esp32/include/phy_init_data.h +++ b/components/esp_wifi/esp32/include/phy_init_data.h @@ -27,6 +27,12 @@ #define PHY_TX_POWER_OFFSET 44 #define PHY_TX_POWER_NUM 5 +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +#define PHY_CRC_ALGORITHM 1 +#define PHY_COUNTRY_CODE_LEN 2 +#define PHY_INIT_DATA_TYPE_OFFSET 126 +#define PHY_SUPPORT_MULTIPLE_BIN_OFFSET 125 +#endif static const char phy_init_magic_pre[] = PHY_INIT_MAGIC; /** @@ -144,5 +150,27 @@ static const esp_phy_init_data_t phy_init_data= { { static const char phy_init_magic_post[] = PHY_INIT_MAGIC; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief PHY init data control infomation structure + */ +typedef struct { + uint8_t control_info_checksum[4]; /*!< 4-byte control infomation checksum */ + uint8_t multiple_bin_checksum[4]; /*!< 4-byte multiple bin checksum */ + uint8_t check_algorithm; /*!< check algorithm */ + uint8_t version; /*!< PHY init data bin version */ + uint8_t number; /*!< PHY init data bin number */ + uint8_t length[2]; /*!< Length of each PHY init data bin */ + uint8_t reserved[19]; /*!< 19-byte reserved */ +} __attribute__ ((packed)) phy_control_info_data_t; + +/** + * @brief Country corresponds to PHY init data type structure + */ +typedef struct { + char cc[PHY_COUNTRY_CODE_LEN]; + uint8_t type; +} phy_country_to_bin_type_t; +#endif #endif /* PHY_INIT_DATA_H */ diff --git a/components/esp_wifi/include/esp_phy_init.h b/components/esp_wifi/include/esp_phy_init.h index 70b55cbeb0..84163c7f47 100644 --- a/components/esp_wifi/include/esp_phy_init.h +++ b/components/esp_wifi/include/esp_phy_init.h @@ -63,6 +63,30 @@ typedef enum{ MODEM_MODULE_COUNT //!< Number of items }modem_sleep_module_t; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief PHY init data type + */ +typedef enum { + ESP_PHY_INIT_DATA_TYPE_DEFAULT = 0, + ESP_PHY_INIT_DATA_TYPE_SRRC, + ESP_PHY_INIT_DATA_TYPE_FCC, + ESP_PHY_INIT_DATA_TYPE_CE, + ESP_PHY_INIT_DATA_TYPE_NCC, + ESP_PHY_INIT_DATA_TYPE_KCC, + ESP_PHY_INIT_DATA_TYPE_MIC, + ESP_PHY_INIT_DATA_TYPE_IC, + ESP_PHY_INIT_DATA_TYPE_ACMA, + ESP_PHY_INIT_DATA_TYPE_ANATEL, + ESP_PHY_INIT_DATA_TYPE_ISED, + ESP_PHY_INIT_DATA_TYPE_WPC, + ESP_PHY_INIT_DATA_TYPE_OFCA, + ESP_PHY_INIT_DATA_TYPE_IFETEL, + ESP_PHY_INIT_DATA_TYPE_RCM, + ESP_PHY_INIT_DATA_TYPE_NUMBER, +} phy_init_data_type_t; +#endif + /** * @brief Module WIFI mask for medem sleep */ @@ -251,6 +275,20 @@ int64_t esp_phy_rf_get_on_ts(void); */ char * get_phy_version_str(void); +/** + * @brief Update the corresponding PHY init type according to the country code of Wi-Fi. + */ +esp_err_t esp_phy_update_country_info(const char *country); + +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief Apply PHY init bin to PHY + * @return ESP_OK on success. + * @return ESP_FAIL on fail. + */ +esp_err_t esp_phy_apply_phy_init_data(uint8_t *init_data); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_private/wifi_os_adapter.h b/components/esp_wifi/include/esp_private/wifi_os_adapter.h index 286b8093e1..cc283a4b7c 100644 --- a/components/esp_wifi/include/esp_private/wifi_os_adapter.h +++ b/components/esp_wifi/include/esp_private/wifi_os_adapter.h @@ -21,7 +21,7 @@ extern "C" { #endif -#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000005 +#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000006 #define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF #define OSI_FUNCS_TIME_BLOCKING 0xffffffff @@ -81,6 +81,7 @@ typedef struct { void (* _phy_load_cal_and_init)(uint32_t module); void (* _phy_common_clock_enable)(void); void (* _phy_common_clock_disable)(void); + int32_t (* _phy_update_country_info)(const char* country); int32_t (* _read_mac)(uint8_t* mac, uint32_t type); void (* _timer_arm)(void *timer, uint32_t tmout, bool repeat); void (* _timer_disarm)(void *timer); diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 304aec4183..b81001f2d4 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -596,9 +596,11 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); * @attention 3. When the country policy is WIFI_COUNTRY_POLICY_MANUAL, always use the configured country info. * @attention 4. When the country info is changed because of configuration or because the station connects to a different * external AP, the country IE in probe response/beacon of the soft-AP is changed also. - * @attention 5. The country configuration is not stored into flash + * @attention 5. The country configuration is stored into flash. * @attention 6. This API doesn't validate the per-country rules, it's up to the user to fill in all fields according to * local regulations. + * @attention 7. When this API is called, the PHY init data will switch to the PHY init data type corresponding to the + * country info. * * @param country the configured country info * diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib new file mode 160000 index 0000000000..51e2668fd4 --- /dev/null +++ b/components/esp_wifi/lib @@ -0,0 +1 @@ +Subproject commit 51e2668fd4e6416f8ad6292e846e177e7d3859bd diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 63df20cc99..4c46338b90 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 63df20cc99da2226bd94c20853d5dee467304a93 +Subproject commit 4c46338b90a4f7aa2dc6a14736be1fe63f8a2e10 diff --git a/components/esp_wifi/phy_multiple_init_data.bin b/components/esp_wifi/phy_multiple_init_data.bin new file mode 100644 index 0000000000..61ce8eb8e9 Binary files /dev/null and b/components/esp_wifi/phy_multiple_init_data.bin differ diff --git a/components/esp_wifi/src/phy_init.c b/components/esp_wifi/src/phy_init.c index a0421ac4a8..e38eb20f17 100644 --- a/components/esp_wifi/src/phy_init.c +++ b/components/esp_wifi/src/phy_init.c @@ -39,6 +39,13 @@ #include "driver/periph_ctrl.h" #include "esp_private/wifi.h" + +#include "esp32/rom/ets_sys.h" +#include "esp32/rom/rtc.h" +#include "esp32/rom/crc.h" + + +//#if CONFIG_IDF_TARGET_ESP32 extern wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb; static const char* TAG = "phy_init"; @@ -69,6 +76,69 @@ static int64_t s_phy_rf_en_ts = 0; static DRAM_ATTR portMUX_TYPE s_phy_int_mux = portMUX_INITIALIZER_UNLOCKED; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/* The following static variables are only used by Wi-Fi tasks, so they can be handled without lock */ +static phy_init_data_type_t s_phy_init_data_type = 0; + +static phy_init_data_type_t s_current_apply_phy_init_data = 0; + +static char s_phy_current_country[PHY_COUNTRY_CODE_LEN] = {0}; + +/* Whether it is a new bin */ +static bool s_multiple_phy_init_data_bin = false; + +/* PHY init data type array */ +static char* s_phy_type[ESP_PHY_INIT_DATA_TYPE_NUMBER] = {"DEFAULT", "SRRC", "FCC", "CE", "NCC", "KCC", "MIC", "IC", + "ACMA", "ANATEL", "ISED", "WPC", "OFCA", "IFETEL", "RCM"}; + +/* Country and PHY init data type map */ +static phy_country_to_bin_type_t s_country_code_map_type_table[] = { + {"AT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"AU", ESP_PHY_INIT_DATA_TYPE_ACMA}, + {"BE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"BG", ESP_PHY_INIT_DATA_TYPE_CE}, + {"BR", ESP_PHY_INIT_DATA_TYPE_ANATEL}, + {"CA", ESP_PHY_INIT_DATA_TYPE_ISED}, + {"CH", ESP_PHY_INIT_DATA_TYPE_CE}, + {"CN", ESP_PHY_INIT_DATA_TYPE_SRRC}, + {"CY", ESP_PHY_INIT_DATA_TYPE_CE}, + {"CZ", ESP_PHY_INIT_DATA_TYPE_CE}, + {"DE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"DK", ESP_PHY_INIT_DATA_TYPE_CE}, + {"EE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"ES", ESP_PHY_INIT_DATA_TYPE_CE}, + {"FI", ESP_PHY_INIT_DATA_TYPE_CE}, + {"FR", ESP_PHY_INIT_DATA_TYPE_CE}, + {"GB", ESP_PHY_INIT_DATA_TYPE_CE}, + {"GR", ESP_PHY_INIT_DATA_TYPE_CE}, + {"HK", ESP_PHY_INIT_DATA_TYPE_OFCA}, + {"HR", ESP_PHY_INIT_DATA_TYPE_CE}, + {"HU", ESP_PHY_INIT_DATA_TYPE_CE}, + {"IE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"IN", ESP_PHY_INIT_DATA_TYPE_WPC}, + {"IS", ESP_PHY_INIT_DATA_TYPE_CE}, + {"IT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"JP", ESP_PHY_INIT_DATA_TYPE_MIC}, + {"KR", ESP_PHY_INIT_DATA_TYPE_KCC}, + {"LI", ESP_PHY_INIT_DATA_TYPE_CE}, + {"LT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"LU", ESP_PHY_INIT_DATA_TYPE_CE}, + {"LV", ESP_PHY_INIT_DATA_TYPE_CE}, + {"MT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"MX", ESP_PHY_INIT_DATA_TYPE_IFETEL}, + {"NL", ESP_PHY_INIT_DATA_TYPE_CE}, + {"NO", ESP_PHY_INIT_DATA_TYPE_CE}, + {"NZ", ESP_PHY_INIT_DATA_TYPE_RCM}, + {"PL", ESP_PHY_INIT_DATA_TYPE_CE}, + {"PT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"RO", ESP_PHY_INIT_DATA_TYPE_CE}, + {"SE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"SI", ESP_PHY_INIT_DATA_TYPE_CE}, + {"SK", ESP_PHY_INIT_DATA_TYPE_CE}, + {"TW", ESP_PHY_INIT_DATA_TYPE_NCC}, + {"US", ESP_PHY_INIT_DATA_TYPE_FCC}, +}; +#endif uint32_t IRAM_ATTR phy_enter_critical(void) { if (xPortInIsrContext()) { @@ -425,6 +495,14 @@ const esp_phy_init_data_t* esp_phy_get_init_data() ESP_LOGE(TAG, "failed to validate PHY data partition"); return NULL; } +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + if ((*(init_data_store + (sizeof(phy_init_magic_pre) + PHY_SUPPORT_MULTIPLE_BIN_OFFSET)))) { + s_multiple_phy_init_data_bin = true; + ESP_LOGI(TAG, "Support multiple PHY init data bins"); + } else { + ESP_LOGW(TAG, "Does not support multiple PHY init data bins"); + } +#endif ESP_LOGD(TAG, "PHY data partition validated"); return (const esp_phy_init_data_t*) (init_data_store + sizeof(phy_init_magic_pre)); } @@ -524,6 +602,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle_t handle, { esp_err_t err; uint32_t cal_data_version; + err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to get cal_version (0x%x)", __func__, err); @@ -687,3 +766,227 @@ void esp_phy_load_cal_and_init(phy_rf_module_t module) free(cal_data); // PHY maintains a copy of calibration data, so we can free this } +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +static esp_err_t phy_crc_check_init_data(uint8_t* init_data, const uint8_t* checksum, size_t init_data_length) +{ + uint32_t crc_data = 0; + crc_data = crc32_le(crc_data, init_data, init_data_length); + uint32_t crc_size_conversion = htonl(crc_data); + + if (crc_size_conversion != *(uint32_t*)(checksum)) { + return ESP_FAIL; + } + return ESP_OK; +} + +static uint8_t phy_find_bin_type_according_country(const char* country) +{ + uint32_t i = 0; + uint8_t phy_init_data_type = 0; + + for (i = 0; i < sizeof(s_country_code_map_type_table)/sizeof(phy_country_to_bin_type_t); i++) + { + if (!memcmp(country, s_country_code_map_type_table[i].cc, sizeof(s_phy_current_country))) { + phy_init_data_type = s_country_code_map_type_table[i].type; + ESP_LOGD(TAG, "Current country is %c%c, PHY init data type is %s\n", s_country_code_map_type_table[i].cc[0], + s_country_code_map_type_table[i].cc[1], s_phy_type[s_country_code_map_type_table[i].type]); + break; + } + } + + if (i == sizeof(s_country_code_map_type_table)/sizeof(phy_country_to_bin_type_t)) { + phy_init_data_type = ESP_PHY_INIT_DATA_TYPE_DEFAULT; + ESP_LOGW(TAG, "Use the default certification code beacuse %c%c doesn't have a certificate", country[0], country[1]); + } + + return phy_init_data_type; +} + +static esp_err_t phy_find_bin_data_according_type(uint8_t* out_init_data_store, + const phy_control_info_data_t* init_data_control_info, + const uint8_t* init_data_multiple, + phy_init_data_type_t init_data_type) +{ + int i = 0; + for (i = 0; i < init_data_control_info->number; i++) { + if (init_data_type == *(init_data_multiple + (i * sizeof(esp_phy_init_data_t)) + PHY_INIT_DATA_TYPE_OFFSET)) { + memcpy(out_init_data_store + sizeof(phy_init_magic_pre), + init_data_multiple + (i * sizeof(esp_phy_init_data_t)), sizeof(esp_phy_init_data_t)); + break; + } + } + + if (i == init_data_control_info->number) { + return ESP_FAIL; + } + return ESP_OK; +} + +static esp_err_t phy_get_multiple_init_data(const esp_partition_t* partition, + uint8_t* init_data_store, + size_t init_data_store_length, + phy_init_data_type_t init_data_type) +{ + phy_control_info_data_t* init_data_control_info = (phy_control_info_data_t*) malloc(sizeof(phy_control_info_data_t)); + if (init_data_control_info == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for PHY init data control info"); + return ESP_FAIL; + } + + esp_err_t err = esp_partition_read(partition, init_data_store_length, init_data_control_info, sizeof(phy_control_info_data_t)); + if (err != ESP_OK) { + free(init_data_control_info); + ESP_LOGE(TAG, "failed to read PHY control info data partition (0x%x)", err); + return ESP_FAIL; + } + + if ((init_data_control_info->check_algorithm) == PHY_CRC_ALGORITHM) { + err = phy_crc_check_init_data(init_data_control_info->multiple_bin_checksum, init_data_control_info->control_info_checksum, + sizeof(phy_control_info_data_t) - sizeof(init_data_control_info->control_info_checksum)); + if (err != ESP_OK) { + free(init_data_control_info); + ESP_LOGE(TAG, "PHY init data control info check error"); + return ESP_FAIL; + } + } else { + free(init_data_control_info); + ESP_LOGE(TAG, "Check algorithm not CRC, PHY init data update failed"); + return ESP_FAIL; + } + + uint8_t* init_data_multiple = (uint8_t*) malloc(sizeof(esp_phy_init_data_t) * init_data_control_info->number); + if (init_data_multiple == NULL) { + free(init_data_control_info); + ESP_LOGE(TAG, "failed to allocate memory for PHY init data multiple bin"); + return ESP_FAIL; + } + + err = esp_partition_read(partition, init_data_store_length + sizeof(phy_control_info_data_t), + init_data_multiple, sizeof(esp_phy_init_data_t) * init_data_control_info->number); + if (err != ESP_OK) { + free(init_data_multiple); + free(init_data_control_info); + ESP_LOGE(TAG, "failed to read PHY init data multiple bin partition (0x%x)", err); + return ESP_FAIL; + } + + if ((init_data_control_info->check_algorithm) == PHY_CRC_ALGORITHM) { + err = phy_crc_check_init_data(init_data_multiple, init_data_control_info->multiple_bin_checksum, + sizeof(esp_phy_init_data_t) * init_data_control_info->number); + if (err != ESP_OK) { + free(init_data_multiple); + free(init_data_control_info); + ESP_LOGE(TAG, "PHY init data multiple bin check error"); + return ESP_FAIL; + } + } else { + free(init_data_multiple); + free(init_data_control_info); + ESP_LOGE(TAG, "Check algorithm not CRC, PHY init data update failed"); + return ESP_FAIL; + } + + err = phy_find_bin_data_according_type(init_data_store, init_data_control_info, init_data_multiple, init_data_type); + if (err != ESP_OK) { + ESP_LOGW(TAG, "%s has not been certified, use DEFAULT PHY init data", s_phy_type[init_data_type]); + s_phy_init_data_type = ESP_PHY_INIT_DATA_TYPE_DEFAULT; + } else { + s_phy_init_data_type = init_data_type; + } + + free(init_data_multiple); + free(init_data_control_info); + return ESP_OK; +} + +esp_err_t esp_phy_update_init_data(phy_init_data_type_t init_data_type) +{ + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL); + if (partition == NULL) { + ESP_LOGE(TAG, "Updated country code PHY data partition not found"); + return ESP_FAIL; + } + size_t init_data_store_length = sizeof(phy_init_magic_pre) + + sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post); + uint8_t* init_data_store = (uint8_t*) malloc(init_data_store_length); + if (init_data_store == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for updated country code PHY init data"); + return ESP_ERR_NO_MEM; + } + + esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length); + if (err != ESP_OK) { + free(init_data_store); + ESP_LOGE(TAG, "failed to read updated country code PHY data partition (0x%x)", err); + return ESP_FAIL; + } + if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 || + memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post), + PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) { + free(init_data_store); + ESP_LOGE(TAG, "failed to validate updated country code PHY data partition"); + return ESP_FAIL; + } + + //find init data bin according init data type + if (init_data_type != ESP_PHY_INIT_DATA_TYPE_DEFAULT) { + err = phy_get_multiple_init_data(partition, init_data_store, init_data_store_length, init_data_type); + if (err != ESP_OK) { + free(init_data_store); +#if CONFIG_ESP32_PHY_INIT_DATA_ERROR + abort(); +#else + return ESP_FAIL; +#endif + } + } else { + s_phy_init_data_type = ESP_PHY_INIT_DATA_TYPE_DEFAULT; + } + + if (s_current_apply_phy_init_data != s_phy_init_data_type) { + err = esp_phy_apply_phy_init_data(init_data_store + sizeof(phy_init_magic_pre)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "PHY init data failed to load"); + free(init_data_store); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "PHY init data type updated from %s to %s", + s_phy_type[s_current_apply_phy_init_data], s_phy_type[s_phy_init_data_type]); + s_current_apply_phy_init_data = s_phy_init_data_type; + } + + free(init_data_store); + return ESP_OK; +} +#endif + +esp_err_t esp_phy_update_country_info(const char *country) +{ +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + uint8_t phy_init_data_type_map = 0; + //if country equal s_phy_current_country, return; + if (!memcmp(country, s_phy_current_country, sizeof(s_phy_current_country))) { + return ESP_OK; + } + + memcpy(s_phy_current_country, country, sizeof(s_phy_current_country)); + + if (!s_multiple_phy_init_data_bin) { + ESP_LOGD(TAG, "Does not support multiple PHY init data bins"); + return ESP_FAIL; + } + + phy_init_data_type_map = phy_find_bin_type_according_country(country); + if (phy_init_data_type_map == s_phy_init_data_type) { + return ESP_OK; + } + + esp_err_t err = esp_phy_update_init_data(phy_init_data_type_map); + if (err != ESP_OK) { + return err; + } +#endif + return ESP_OK; +} diff --git a/tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data b/tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data new file mode 100644 index 0000000000..b4d3f63c85 --- /dev/null +++ b/tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data @@ -0,0 +1,3 @@ +CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y +CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN=y +CONFIG_IDF_TARGET="esp32"