// Copyright 2018-2019 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 "esp_log.h" #include "esp_system.h" #include "internal/esp_system_internal.h" #include "rom/crc.h" #include "esp8266/eagle_soc.h" #include "esp8266/efuse_register.h" #include "FreeRTOS.h" #include "nvs.h" #include "nvs_flash.h" static const char* TAG = "system_api"; static uint8_t base_mac_addr[6] = { 0 }; uint32_t g_esp_ticks_per_us = 80; // Bootloader can get this information const __attribute__((section(".SystemInfoVector.text"))) esp_sys_info_t g_esp_sys_info = { .version = ESP_IDF_VERSION }; esp_err_t esp_base_mac_addr_set(uint8_t *mac) { if (mac == NULL) { ESP_LOGE(TAG, "Base MAC address is NULL"); return ESP_ERR_INVALID_ARG; } memcpy(base_mac_addr, mac, 6); return ESP_OK; } esp_err_t esp_base_mac_addr_get(uint8_t *mac) { uint8_t null_mac[6] = {0}; if (memcmp(base_mac_addr, null_mac, 6) == 0) { ESP_LOGI(TAG, "Base MAC address is not set, read default base MAC address from EFUSE"); return ESP_ERR_INVALID_MAC; } memcpy(mac, base_mac_addr, 6); return ESP_OK; } esp_err_t esp_efuse_mac_get_default(uint8_t* mac) { uint32_t efuse[4]; uint8_t efuse_crc = 0; uint8_t calc_crc = 0; uint8_t version; uint8_t use_default = 1; efuse[0] = REG_READ(EFUSE_DATA0_REG); efuse[1] = REG_READ(EFUSE_DATA1_REG); efuse[2] = REG_READ(EFUSE_DATA2_REG); efuse[3] = REG_READ(EFUSE_DATA3_REG); mac[3] = efuse[1] >> 8; mac[4] = efuse[1]; mac[5] = efuse[0] >> 24; if (efuse[2] & EFUSE_IS_48BITS_MAC) { uint8_t tmp_mac[4]; mac[0] = efuse[3] >> 16; mac[1] = efuse[3] >> 8; mac[2] = efuse[3]; use_default = 0; tmp_mac[0] = mac[2]; tmp_mac[1] = mac[1]; tmp_mac[2] = mac[0]; efuse_crc = efuse[2] >> 24; calc_crc = esp_crc8(tmp_mac, 3); if (efuse_crc != calc_crc) use_default = 1; if (!use_default) { version = (efuse[1] >> EFUSE_VERSION_S) & EFUSE_VERSION_V; if (version == EFUSE_VERSION_1 || version == EFUSE_VERSION_2) { tmp_mac[0] = mac[5]; tmp_mac[1] = mac[4]; tmp_mac[2] = mac[3]; tmp_mac[3] = efuse[1] >> 16; efuse_crc = efuse[0] >> 16; calc_crc = esp_crc8(tmp_mac, 4); if (efuse_crc != calc_crc) use_default = 1; } } } if (use_default) { mac[0] = 0x18; mac[1] = 0xFE; mac[2] = 0x34; } return ESP_OK; } static const char *BACKUP_MAC_NAMESPACE = "backup_mac"; static const char *BACKUP_MAC_DATA_KEY = "backup_mac_data"; #define MAC_DATA_LEN_WITH_CRC (4*4) static esp_err_t load_backup_mac_data(uint8_t *mac) { esp_err_t err; nvs_handle handle; uint32_t efuse[4]; uint8_t efuse_crc = 0; uint8_t calc_crc = 0; uint8_t version; if (mac == NULL) { ESP_LOGE(TAG, "mac address param is NULL"); return ESP_ERR_INVALID_ARG; } err = nvs_open(BACKUP_MAC_NAMESPACE, NVS_READONLY, &handle); if (err == ESP_ERR_NVS_NOT_INITIALIZED) { ESP_LOGE(TAG, "%s: NVS has not been initialized. " "Call nvs_flash_init before starting WiFi/BT.", __func__); return ESP_ERR_INVALID_MAC; } else if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return ESP_ERR_INVALID_MAC; } size_t length = MAC_DATA_LEN_WITH_CRC; err = nvs_get_blob(handle, BACKUP_MAC_DATA_KEY, efuse, &length); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to get backup mac (0x%x)", __func__, err); return ESP_ERR_INVALID_MAC; } if (length != MAC_DATA_LEN_WITH_CRC) { ESP_LOGD(TAG, "%s: invalid length of backup mac (%d)", __func__, length); return ESP_ERR_INVALID_MAC; } nvs_close(handle); mac[3] = efuse[1] >> 8; mac[4] = efuse[1]; mac[5] = efuse[0] >> 24; if (efuse[2] & EFUSE_IS_48BITS_MAC) { uint8_t tmp_mac[4]; mac[0] = efuse[3] >> 16; mac[1] = efuse[3] >> 8; mac[2] = efuse[3]; tmp_mac[0] = mac[2]; tmp_mac[1] = mac[1]; tmp_mac[2] = mac[0]; efuse_crc = efuse[2] >> 24; calc_crc = esp_crc8(tmp_mac, 3); if (efuse_crc != calc_crc) { ESP_LOGE(TAG, "High MAC CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc); return ESP_ERR_INVALID_MAC; } version = (efuse[1] >> EFUSE_VERSION_S) & EFUSE_VERSION_V; if (version == EFUSE_VERSION_1 || version == EFUSE_VERSION_2) { tmp_mac[0] = mac[5]; tmp_mac[1] = mac[4]; tmp_mac[2] = mac[3]; tmp_mac[3] = efuse[1] >> 16; efuse_crc = efuse[0] >> 16; calc_crc = esp_crc8(tmp_mac, 4); if (efuse_crc != calc_crc) { ESP_LOGE(TAG, "CRC8 error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc); return ESP_ERR_INVALID_MAC; } } } else { mac[0] = 0x18; mac[1] = 0xFE; mac[2] = 0x34; } return ESP_OK; } static esp_err_t store_backup_mac_data() { esp_err_t err; nvs_handle handle; uint32_t efuse[4]; efuse[0] = REG_READ(EFUSE_DATA0_REG); efuse[1] = REG_READ(EFUSE_DATA1_REG); efuse[2] = REG_READ(EFUSE_DATA2_REG); efuse[3] = REG_READ(EFUSE_DATA3_REG); err = nvs_open(BACKUP_MAC_NAMESPACE, NVS_READWRITE, &handle); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } err = nvs_set_blob(handle, BACKUP_MAC_DATA_KEY, efuse, MAC_DATA_LEN_WITH_CRC); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: store backup mac data failed(0x%x)\n", __func__, err); return err; } err = nvs_commit(handle); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: store backup mac data failed(0x%x)\n", __func__, err); } return err; } esp_err_t esp_derive_mac(uint8_t* local_mac, const uint8_t* universal_mac) { uint8_t idx; if (local_mac == NULL || universal_mac == NULL) { ESP_LOGE(TAG, "mac address param is NULL"); return ESP_ERR_INVALID_ARG; } memcpy(local_mac, universal_mac, 6); for (idx = 0; idx < 64; idx++) { local_mac[0] = universal_mac[0] | 0x02; local_mac[0] ^= idx << 2; if (memcmp(local_mac, universal_mac, 6)) { break; } } return ESP_OK; } esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) { uint8_t efuse_mac[6]; if (mac == NULL) { ESP_LOGE(TAG, "mac address param is NULL"); return ESP_ERR_INVALID_ARG; } if (type < ESP_MAC_WIFI_STA || type > ESP_MAC_WIFI_SOFTAP) { ESP_LOGE(TAG, "mac type is incorrect"); return ESP_ERR_INVALID_ARG; } if (esp_base_mac_addr_get(efuse_mac) != ESP_OK) { if (load_backup_mac_data(efuse_mac) != ESP_OK) { if (esp_efuse_mac_get_default(efuse_mac) != ESP_OK) { ESP_LOGE(TAG, "Get mac address error"); abort(); } else { store_backup_mac_data(); } } } switch (type) { case ESP_MAC_WIFI_STA: memcpy(mac, efuse_mac, 6); break; case ESP_MAC_WIFI_SOFTAP: esp_derive_mac(mac, efuse_mac); break; default: ESP_LOGW(TAG, "incorrect mac type"); break; } return ESP_OK; } esp_err_t esp_mac_init(void) { esp_err_t ret; uint8_t efuse_mac[6]; if ((ret = nvs_flash_init()) != ESP_OK) { ESP_LOGE(TAG, "Init NVS error=%d", ret); return ESP_ERR_INVALID_MAC; } if (load_backup_mac_data(efuse_mac) == ESP_OK) { ESP_LOGD(TAG, "Load MAC from NVS error=%d", ret); return ESP_OK; } if ((ret = esp_efuse_mac_get_default(efuse_mac)) != ESP_OK) { ESP_LOGE(TAG, "Get mac address error=%d", ret); return ESP_ERR_INVALID_MAC; } if ((ret = store_backup_mac_data()) != ESP_OK) { ESP_LOGE(TAG, "Store mac address error=%d", ret); return ESP_ERR_INVALID_MAC; } return ESP_OK; } /** * Get IDF version */ const char* esp_get_idf_version(void) { return IDF_VER; } /** * @brief Fill an esp_chip_info_t structure with information about the ESP8266 chip */ static void get_chip_info_esp8266(esp_chip_info_t* out_info) { memset(out_info, 0, sizeof(*out_info)); out_info->model = CHIP_ESP8266; out_info->revision = 1; out_info->cores = 1; out_info->features = CHIP_FEATURE_WIFI_BGN; } /** * @brief Fill an esp_chip_info_t structure with information about the chip */ void esp_chip_info(esp_chip_info_t* out_info) { // Only ESP8266 is supported now, in the future call one of the // chip-specific functions based on sdkconfig choice return get_chip_info_esp8266(out_info); } /** * @brief Get the size of available heap. */ uint32_t esp_get_free_heap_size(void) { return heap_caps_get_free_size(MALLOC_CAP_32BIT); } /** * @brief Get the minimum heap that has ever been available */ uint32_t esp_get_minimum_free_heap_size(void) { return heap_caps_get_minimum_free_size(MALLOC_CAP_32BIT); } /** * @brief Get old SDK configuration parameters base address */ uint32_t esp_get_old_sysconf_addr(void) { return rtc_sys_info.old_sysconf_addr; } void os_update_cpu_frequency(uint32_t ticks_per_us) { extern uint32_t _xt_tick_divisor; if (REG_READ(DPORT_CTL_REG) & DPORT_CTL_DOUBLE_CLK) { g_esp_ticks_per_us = CPU_CLK_FREQ * 2 / 1000000; _xt_tick_divisor = (CPU_CLK_FREQ * 2 / CONFIG_FREERTOS_HZ); } else { g_esp_ticks_per_us = CPU_CLK_FREQ / 1000000;; _xt_tick_divisor = (CPU_CLK_FREQ / CONFIG_FREERTOS_HZ); } } void ets_update_cpu_frequency(uint32_t ticks_per_us) __attribute__((alias("os_update_cpu_frequency")));