diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2153a3d4e..09711b6b7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -319,6 +319,17 @@ test_report: - git push origin master - test "${TEST_RESULT}" = "Pass" || exit 1 +test_esp_err_to_name_on_host: + stage: test + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - build + dependencies: [] + script: + - cd tools/ + - ./gen_esp_err_to_name.py + - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || (echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1) + push_master_to_github: stage: deploy image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG diff --git a/components/esp32/esp_err_to_name.c b/components/esp32/esp_err_to_name.c new file mode 100644 index 000000000..a706a68a5 --- /dev/null +++ b/components/esp32/esp_err_to_name.c @@ -0,0 +1,396 @@ +//Do not edit this file because it is autogenerated by gen_esp_err_to_name.py + +#include +#if __has_include("soc/soc.h") +#include "soc/soc.h" +#endif +#if __has_include("esp32/ulp.h") +#include "esp32/ulp.h" +#endif +#if __has_include("esp_err.h") +#include "esp_err.h" +#endif +#if __has_include("esp_image_format.h") +#include "esp_image_format.h" +#endif +#if __has_include("esp_now.h") +#include "esp_now.h" +#endif +#if __has_include("esp_ota_ops.h") +#include "esp_ota_ops.h" +#endif +#if __has_include("esp_ping.h") +#include "esp_ping.h" +#endif +#if __has_include("esp_spi_flash.h") +#include "esp_spi_flash.h" +#endif +#if __has_include("esp_wifi.h") +#include "esp_wifi.h" +#endif +#if __has_include("esp_wps.h") +#include "esp_wps.h" +#endif +#if __has_include("nvs.h") +#include "nvs.h" +#endif +#if __has_include("tcpip_adapter.h") +#include "tcpip_adapter.h" +#endif + +#define ERR_TBL_IT(err) {err, #err} + +typedef struct { + esp_err_t code; + const char *msg; +} esp_err_msg_t; + +static const esp_err_msg_t esp_err_msg_table[] = { + // components/esp32/include/esp_err.h +# ifdef ESP_FAIL + ERR_TBL_IT(ESP_FAIL), /* -1 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_FAIL + ERR_TBL_IT(ESP_ERR_WIFI_FAIL), /* -1 General fail code */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_OK + ERR_TBL_IT(ESP_OK), /* 0 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_OK + ERR_TBL_IT(ESP_ERR_WIFI_OK), /* 0 No error */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_NO_MEM + ERR_TBL_IT(ESP_ERR_NO_MEM), /* 257 0x101 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_NO_MEM + ERR_TBL_IT(ESP_ERR_WIFI_NO_MEM), /* 257 0x101 Out of memory */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_INVALID_ARG + ERR_TBL_IT(ESP_ERR_INVALID_ARG), /* 258 0x102 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_ARG + ERR_TBL_IT(ESP_ERR_WIFI_ARG), /* 258 0x102 Invalid argument */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_INVALID_STATE + ERR_TBL_IT(ESP_ERR_INVALID_STATE), /* 259 0x103 */ +# endif +# ifdef ESP_ERR_INVALID_SIZE + ERR_TBL_IT(ESP_ERR_INVALID_SIZE), /* 260 0x104 */ +# endif +# ifdef ESP_ERR_NOT_FOUND + ERR_TBL_IT(ESP_ERR_NOT_FOUND), /* 261 0x105 */ +# endif +# ifdef ESP_ERR_NOT_SUPPORTED + ERR_TBL_IT(ESP_ERR_NOT_SUPPORTED), /* 262 0x106 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_NOT_SUPPORT + ERR_TBL_IT(ESP_ERR_WIFI_NOT_SUPPORT), /* 262 0x106 Indicates that API is not supported yet */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_TIMEOUT + ERR_TBL_IT(ESP_ERR_TIMEOUT), /* 263 0x107 */ +# endif +# ifdef ESP_ERR_INVALID_RESPONSE + ERR_TBL_IT(ESP_ERR_INVALID_RESPONSE), /* 264 0x108 */ +# endif +# ifdef ESP_ERR_INVALID_CRC + ERR_TBL_IT(ESP_ERR_INVALID_CRC), /* 265 0x109 */ +# endif +# ifdef ESP_ERR_INVALID_VERSION + ERR_TBL_IT(ESP_ERR_INVALID_VERSION), /* 266 0x10a */ +# endif +# ifdef ESP_ERR_INVALID_MAC + ERR_TBL_IT(ESP_ERR_INVALID_MAC), /* 267 0x10b */ +# endif + // components/nvs_flash/include/nvs.h +# ifdef ESP_ERR_NVS_BASE + ERR_TBL_IT(ESP_ERR_NVS_BASE), /* 4352 0x1100 Starting number of error codes */ +# endif +# ifdef ESP_ERR_NVS_NOT_INITIALIZED + ERR_TBL_IT(ESP_ERR_NVS_NOT_INITIALIZED), /* 4353 0x1101 The storage driver is not initialized */ +# endif +# ifdef ESP_ERR_NVS_NOT_FOUND + ERR_TBL_IT(ESP_ERR_NVS_NOT_FOUND), /* 4354 0x1102 Id namespace doesn’t exist yet and mode is + NVS_READONLY */ +# endif +# ifdef ESP_ERR_NVS_TYPE_MISMATCH + ERR_TBL_IT(ESP_ERR_NVS_TYPE_MISMATCH), /* 4355 0x1103 The type of set or get operation doesn't + match the type of value stored in NVS */ +# endif +# ifdef ESP_ERR_NVS_READ_ONLY + ERR_TBL_IT(ESP_ERR_NVS_READ_ONLY), /* 4356 0x1104 Storage handle was opened as read only */ +# endif +# ifdef ESP_ERR_NVS_NOT_ENOUGH_SPACE + ERR_TBL_IT(ESP_ERR_NVS_NOT_ENOUGH_SPACE), /* 4357 0x1105 There is not enough space in the underlying + storage to save the value */ +# endif +# ifdef ESP_ERR_NVS_INVALID_NAME + ERR_TBL_IT(ESP_ERR_NVS_INVALID_NAME), /* 4358 0x1106 Namespace name doesn’t satisfy constraints */ +# endif +# ifdef ESP_ERR_NVS_INVALID_HANDLE + ERR_TBL_IT(ESP_ERR_NVS_INVALID_HANDLE), /* 4359 0x1107 Handle has been closed or is NULL */ +# endif +# ifdef ESP_ERR_NVS_REMOVE_FAILED + ERR_TBL_IT(ESP_ERR_NVS_REMOVE_FAILED), /* 4360 0x1108 The value wasn’t updated because flash + write operation has failed. The value was + written however, and update will be finished + after re-initialization of nvs, provided + that flash operation doesn’t fail again. */ +# endif +# ifdef ESP_ERR_NVS_KEY_TOO_LONG + ERR_TBL_IT(ESP_ERR_NVS_KEY_TOO_LONG), /* 4361 0x1109 Key name is too long */ +# endif +# ifdef ESP_ERR_NVS_PAGE_FULL + ERR_TBL_IT(ESP_ERR_NVS_PAGE_FULL), /* 4362 0x110a Internal error; never returned by nvs_ API + functions */ +# endif +# ifdef ESP_ERR_NVS_INVALID_STATE + ERR_TBL_IT(ESP_ERR_NVS_INVALID_STATE), /* 4363 0x110b NVS is in an inconsistent state due to a + previous error. Call nvs_flash_init and + nvs_open again, then retry. */ +# endif +# ifdef ESP_ERR_NVS_INVALID_LENGTH + ERR_TBL_IT(ESP_ERR_NVS_INVALID_LENGTH), /* 4364 0x110c String or blob length is not sufficient to + store data */ +# endif +# ifdef ESP_ERR_NVS_NO_FREE_PAGES + ERR_TBL_IT(ESP_ERR_NVS_NO_FREE_PAGES), /* 4365 0x110d NVS partition doesn't contain any empty + pages. This may happen if NVS partition was + truncated. Erase the whole partition and + call nvs_flash_init again. */ +# endif +# ifdef ESP_ERR_NVS_VALUE_TOO_LONG + ERR_TBL_IT(ESP_ERR_NVS_VALUE_TOO_LONG), /* 4366 0x110e String or blob length is longer than + supported by the implementation */ +# endif +# ifdef ESP_ERR_NVS_PART_NOT_FOUND + ERR_TBL_IT(ESP_ERR_NVS_PART_NOT_FOUND), /* 4367 0x110f Partition with specified name is not found + in the partition table */ +# endif + // components/ulp/include/esp32/ulp.h +# ifdef ESP_ERR_ULP_BASE + ERR_TBL_IT(ESP_ERR_ULP_BASE), /* 4608 0x1200 Offset for ULP-related error codes */ +# endif +# ifdef ESP_ERR_ULP_SIZE_TOO_BIG + ERR_TBL_IT(ESP_ERR_ULP_SIZE_TOO_BIG), /* 4609 0x1201 Program doesn't fit into RTC memory reserved + for the ULP */ +# endif +# ifdef ESP_ERR_ULP_INVALID_LOAD_ADDR + ERR_TBL_IT(ESP_ERR_ULP_INVALID_LOAD_ADDR), /* 4610 0x1202 Load address is outside of RTC memory + reserved for the ULP */ +# endif +# ifdef ESP_ERR_ULP_DUPLICATE_LABEL + ERR_TBL_IT(ESP_ERR_ULP_DUPLICATE_LABEL), /* 4611 0x1203 More than one label with the same number was + defined */ +# endif +# ifdef ESP_ERR_ULP_UNDEFINED_LABEL + ERR_TBL_IT(ESP_ERR_ULP_UNDEFINED_LABEL), /* 4612 0x1204 Branch instructions references an undefined label */ +# endif +# ifdef ESP_ERR_ULP_BRANCH_OUT_OF_RANGE + ERR_TBL_IT(ESP_ERR_ULP_BRANCH_OUT_OF_RANGE), /* 4613 0x1205 Branch target is out of range of B + instruction (try replacing with BX) */ +# endif + // components/app_update/include/esp_ota_ops.h +# ifdef ESP_ERR_OTA_BASE + ERR_TBL_IT(ESP_ERR_OTA_BASE), /* 5376 0x1500 Base error code for ota_ops api */ +# endif +# ifdef ESP_ERR_OTA_PARTITION_CONFLICT + ERR_TBL_IT(ESP_ERR_OTA_PARTITION_CONFLICT), /* 5377 0x1501 Error if request was to write or erase the + current running partition */ +# endif +# ifdef ESP_ERR_OTA_SELECT_INFO_INVALID + ERR_TBL_IT(ESP_ERR_OTA_SELECT_INFO_INVALID), /* 5378 0x1502 Error if OTA data partition contains invalid + content */ +# endif +# ifdef ESP_ERR_OTA_VALIDATE_FAILED + ERR_TBL_IT(ESP_ERR_OTA_VALIDATE_FAILED), /* 5379 0x1503 Error if OTA app image is invalid */ +# endif + // components/bootloader_support/include/esp_image_format.h +# ifdef ESP_ERR_IMAGE_BASE + ERR_TBL_IT(ESP_ERR_IMAGE_BASE), /* 8192 0x2000 */ +# endif +# ifdef ESP_ERR_IMAGE_FLASH_FAIL + ERR_TBL_IT(ESP_ERR_IMAGE_FLASH_FAIL), /* 8193 0x2001 */ +# endif +# ifdef ESP_ERR_IMAGE_INVALID + ERR_TBL_IT(ESP_ERR_IMAGE_INVALID), /* 8194 0x2002 */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_WIFI_BASE + ERR_TBL_IT(ESP_ERR_WIFI_BASE), /* 12288 0x3000 Starting number of WiFi error codes */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_NOT_INIT + ERR_TBL_IT(ESP_ERR_WIFI_NOT_INIT), /* 12289 0x3001 WiFi driver was not installed by esp_wifi_init */ +# endif +# ifdef ESP_ERR_WIFI_NOT_STARTED + ERR_TBL_IT(ESP_ERR_WIFI_NOT_STARTED), /* 12290 0x3002 WiFi driver was not started by esp_wifi_start */ +# endif +# ifdef ESP_ERR_WIFI_NOT_STOPPED + ERR_TBL_IT(ESP_ERR_WIFI_NOT_STOPPED), /* 12291 0x3003 WiFi driver was not stopped by esp_wifi_stop */ +# endif +# ifdef ESP_ERR_WIFI_IF + ERR_TBL_IT(ESP_ERR_WIFI_IF), /* 12292 0x3004 WiFi interface error */ +# endif +# ifdef ESP_ERR_WIFI_MODE + ERR_TBL_IT(ESP_ERR_WIFI_MODE), /* 12293 0x3005 WiFi mode error */ +# endif +# ifdef ESP_ERR_WIFI_STATE + ERR_TBL_IT(ESP_ERR_WIFI_STATE), /* 12294 0x3006 WiFi internal state error */ +# endif +# ifdef ESP_ERR_WIFI_CONN + ERR_TBL_IT(ESP_ERR_WIFI_CONN), /* 12295 0x3007 WiFi internal control block of station or + soft-AP error */ +# endif +# ifdef ESP_ERR_WIFI_NVS + ERR_TBL_IT(ESP_ERR_WIFI_NVS), /* 12296 0x3008 WiFi internal NVS module error */ +# endif +# ifdef ESP_ERR_WIFI_MAC + ERR_TBL_IT(ESP_ERR_WIFI_MAC), /* 12297 0x3009 MAC address is invalid */ +# endif +# ifdef ESP_ERR_WIFI_SSID + ERR_TBL_IT(ESP_ERR_WIFI_SSID), /* 12298 0x300a SSID is invalid */ +# endif +# ifdef ESP_ERR_WIFI_PASSWORD + ERR_TBL_IT(ESP_ERR_WIFI_PASSWORD), /* 12299 0x300b Password is invalid */ +# endif +# ifdef ESP_ERR_WIFI_TIMEOUT + ERR_TBL_IT(ESP_ERR_WIFI_TIMEOUT), /* 12300 0x300c Timeout error */ +# endif +# ifdef ESP_ERR_WIFI_WAKE_FAIL + ERR_TBL_IT(ESP_ERR_WIFI_WAKE_FAIL), /* 12301 0x300d WiFi is in sleep state(RF closed) and wakeup fail */ +# endif +# ifdef ESP_ERR_WIFI_WOULD_BLOCK + ERR_TBL_IT(ESP_ERR_WIFI_WOULD_BLOCK), /* 12302 0x300e The caller would block */ +# endif +# ifdef ESP_ERR_WIFI_NOT_CONNECT + ERR_TBL_IT(ESP_ERR_WIFI_NOT_CONNECT), /* 12303 0x300f Station still in disconnect status */ +# endif + // components/esp32/include/esp_wps.h +# ifdef ESP_ERR_WIFI_REGISTRAR + ERR_TBL_IT(ESP_ERR_WIFI_REGISTRAR), /* 12339 0x3033 WPS registrar is not supported */ +# endif +# ifdef ESP_ERR_WIFI_WPS_TYPE + ERR_TBL_IT(ESP_ERR_WIFI_WPS_TYPE), /* 12340 0x3034 WPS type error */ +# endif +# ifdef ESP_ERR_WIFI_WPS_SM + ERR_TBL_IT(ESP_ERR_WIFI_WPS_SM), /* 12341 0x3035 WPS state machine is not initialized */ +# endif + // components/esp32/include/esp_now.h +# ifdef ESP_ERR_ESPNOW_NOT_INIT + ERR_TBL_IT(ESP_ERR_ESPNOW_NOT_INIT), /* 12389 0x3065 ESPNOW is not initialized. */ +# endif +# ifdef ESP_ERR_ESPNOW_BASE + ERR_TBL_IT(ESP_ERR_ESPNOW_BASE), /* 12389 0x3065 ESPNOW error number base. */ +# endif +# ifdef ESP_ERR_ESPNOW_ARG + ERR_TBL_IT(ESP_ERR_ESPNOW_ARG), /* 12390 0x3066 Invalid argument */ +# endif +# ifdef ESP_ERR_ESPNOW_NO_MEM + ERR_TBL_IT(ESP_ERR_ESPNOW_NO_MEM), /* 12391 0x3067 Out of memory */ +# endif +# ifdef ESP_ERR_ESPNOW_FULL + ERR_TBL_IT(ESP_ERR_ESPNOW_FULL), /* 12392 0x3068 ESPNOW peer list is full */ +# endif +# ifdef ESP_ERR_ESPNOW_NOT_FOUND + ERR_TBL_IT(ESP_ERR_ESPNOW_NOT_FOUND), /* 12393 0x3069 ESPNOW peer is not found */ +# endif +# ifdef ESP_ERR_ESPNOW_INTERNAL + ERR_TBL_IT(ESP_ERR_ESPNOW_INTERNAL), /* 12394 0x306a Internal error */ +# endif +# ifdef ESP_ERR_ESPNOW_EXIST + ERR_TBL_IT(ESP_ERR_ESPNOW_EXIST), /* 12395 0x306b ESPNOW peer has existed */ +# endif +# ifdef ESP_ERR_ESPNOW_IF + ERR_TBL_IT(ESP_ERR_ESPNOW_IF), /* 12396 0x306c Interface error */ +# endif + // components/tcpip_adapter/include/tcpip_adapter.h +# ifdef ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS), /* 20480 0x5000 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_BASE + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_BASE), /* 20480 0x5000 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY), /* 20481 0x5001 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED), /* 20482 0x5002 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED), /* 20483 0x5003 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED), /* 20484 0x5004 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_NO_MEM + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_NO_MEM), /* 20485 0x5005 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED), /* 20486 0x5006 */ +# endif + // components/lwip/apps/ping/esp_ping.h +# ifdef ESP_ERR_PING_INVALID_PARAMS + ERR_TBL_IT(ESP_ERR_PING_INVALID_PARAMS), /* 24576 0x6000 */ +# endif +# ifdef ESP_ERR_PING_BASE + ERR_TBL_IT(ESP_ERR_PING_BASE), /* 24576 0x6000 */ +# endif +# ifdef ESP_ERR_PING_NO_MEM + ERR_TBL_IT(ESP_ERR_PING_NO_MEM), /* 24577 0x6001 */ +# endif + // components/spi_flash/include/esp_spi_flash.h +# ifdef ESP_ERR_FLASH_BASE + ERR_TBL_IT(ESP_ERR_FLASH_BASE), /* 65552 0x10010 */ +# endif +# ifdef ESP_ERR_FLASH_OP_FAIL + ERR_TBL_IT(ESP_ERR_FLASH_OP_FAIL), /* 65553 0x10011 */ +# endif +# ifdef ESP_ERR_FLASH_OP_TIMEOUT + ERR_TBL_IT(ESP_ERR_FLASH_OP_TIMEOUT), /* 65554 0x10012 */ +# endif +}; + +static const char esp_unknown_msg[] = "UNKNOWN ERROR"; + +const char *esp_err_to_name(esp_err_t code) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + return esp_err_msg_table[i].msg; + } + } + + return esp_unknown_msg; +} + +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + strlcpy(buf, esp_err_msg_table[i].msg, buflen); + return buf; + } + } + + if (strerror_r(code, buf, buflen) == 0) { + return buf; + } + + snprintf(buf, buflen, "Unknown error %d", code); + + return buf; +} diff --git a/components/esp32/esp_err_to_name.c.in b/components/esp32/esp_err_to_name.c.in new file mode 100644 index 000000000..86085bb88 --- /dev/null +++ b/components/esp32/esp_err_to_name.c.in @@ -0,0 +1,53 @@ +@COMMENT@ + +#include +#if __has_include("soc/soc.h") +#include "soc/soc.h" +#endif +@HEADERS@ + +#define ERR_TBL_IT(err) {err, #err} + +typedef struct { + esp_err_t code; + const char *msg; +} esp_err_msg_t; + +static const esp_err_msg_t esp_err_msg_table[] = { +@ERROR_ITEMS@ +}; + +static const char esp_unknown_msg[] = "UNKNOWN ERROR"; + +const char *esp_err_to_name(esp_err_t code) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + return esp_err_msg_table[i].msg; + } + } + + return esp_unknown_msg; +} + +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + strlcpy(buf, esp_err_msg_table[i].msg, buflen); + return buf; + } + } + + if (strerror_r(code, buf, buflen) == 0) { + return buf; + } + + snprintf(buf, buflen, "Unknown error %d", code); + + return buf; +} diff --git a/components/esp32/include/esp_err.h b/components/esp32/include/esp_err.h index 5486b1410..8bed65cd3 100644 --- a/components/esp32/include/esp_err.h +++ b/components/esp32/include/esp_err.h @@ -42,6 +42,39 @@ typedef int32_t esp_err_t; #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ +/** + * @brief Returns string for esp_err_t error codes + * + * This function finds the error code in a pre-generated lookup-table and + * returns its string representation. + * + * The function is generated by the Python script + * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t + * error is modified, created or removed from the IDF project. + * + * @param code esp_err_t error code + * @return string error message + */ +const char *esp_err_to_name(esp_err_t code); + +/** + * @brief Returns string for esp_err_t and system error codes + * + * This function finds the error code in a pre-generated lookup-table of + * esp_err_t errors and returns its string representation. If the error code + * is not found then it is attempted to be found among system errors. + * + * The function is generated by the Python script + * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t + * error is modified, created or removed from the IDF project. + * + * @param code esp_err_t error code + * @param[out] buf buffer where the error message should be written + * @param buflen Size of buffer buf. At most buflen bytes are written into the buf buffer (including the terminating null byte). + * @return buf containing the string error message + */ +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen); + void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn)); #ifndef __ASSERT_FUNC diff --git a/tools/gen_esp_err_to_name.py b/tools/gen_esp_err_to_name.py new file mode 100755 index 000000000..1dfe15bab --- /dev/null +++ b/tools/gen_esp_err_to_name.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python +# +# Copyright 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. + +import os +import argparse +import mmap +import re +import fnmatch +import string +import collections +import textwrap + +# list files here which should not be parsed +ignore_files = [ 'components/mdns/test_afl_fuzz_host/esp32_compat.h' ] + +# macros from here have higher priorities in case of collisions +priority_headers = [ 'components/esp32/include/esp_err.h' ] + +err_dict = collections.defaultdict(list) #identified errors are stored here; mapped by the error code +rev_err_dict = dict() #map of error string to error code +unproc_list = list() #errors with unknown codes which depend on other errors + +class ErrItem: + """ + Contains information about the error: + - name - error string + - file - relative path inside the IDF project to the file which defines this error + - comment - (optional) comment for the error + - rel_str - (optional) error string which is a base for the error + - rel_off - (optional) offset in relation to the base error + """ + def __init__(self, name, file, comment, rel_str = "", rel_off = 0): + self.name = name + self.file = file + self.comment = comment + self.rel_str = rel_str + self.rel_off = rel_off + def __str__(self): + ret = self.name + " from " + self.file + if (self.rel_str != ""): + ret += " is (" + self.rel_str + " + " + str(self.rel_off) + ")" + if self.comment != "": + ret += " // " + self.comment + return ret + def __cmp__(self, other): + if self.file in priority_headers and other.file not in priority_headers: + return -1 + elif self.file not in priority_headers and other.file in priority_headers: + return 1 + + base = "_BASE" + + if self.file == other.file: + if self.name.endswith(base) and not(other.name.endswith(base)): + return 1 + elif not(self.name.endswith(base)) and other.name.endswith(base): + return -1 + + self_key = self.file + self.name + other_key = other.file + other.name + if self_key < other_key: + return -1 + elif self_key > other_key: + return 1 + else: + return 0 + +class InputError(RuntimeError): + """ + Represents and error on the input + """ + def __init__(self, p, e): + super(InputError, self).__init__(p + ": " + e) + +def process(line, idf_path): + """ + Process a line of text from file idf_path (relative to IDF project). + Fills the global list unproc_list and dictionaries err_dict, rev_err_dict + """ + if idf_path.endswith(".c"): + # We would not try to include a C file + raise InputError(idf_path, "This line should be in a header file: %s" % line) + + words = re.split(r' +', line, 2) + # words[1] is the error name + # words[2] is the rest of the line (value, base + value, comment) + if len(words) < 2: + raise InputError(idf_path, "Error at line %s" % line) + + line = "" + todo_str = words[2] + + comment = "" + # identify possible comment + m = re.search(r'/\*!<(.+?(?=\*/))', todo_str) + if m: + comment = string.strip(m.group(1)) + todo_str = string.strip(todo_str[:m.start()]) # keep just the part before the comment + + # identify possible parentheses () + m = re.search(r'\((.+)\)', todo_str) + if m: + todo_str = m.group(1) #keep what is inside the parentheses + + # identify BASE error code, e.g. from the form BASE + 0x01 + m = re.search(r'\s*(\w+)\s*\+(.+)', todo_str) + if m: + related = m.group(1) # BASE + todo_str = m.group(2) # keep and process only what is after "BASE +" + + # try to match a hexadecimal number + m = re.search(r'0x([0-9A-Fa-f]+)', todo_str) + if m: + num = int(m.group(1), 16) + else: + # Try to match a decimal number. Negative value is possible for some numbers, e.g. ESP_FAIL + m = re.search(r'(-?[0-9]+)', todo_str) + if m: + num = int(m.group(1), 10) + elif re.match(r'\w+', todo_str): + # It is possible that there is no number, e.g. #define ERROR BASE + related = todo_str # BASE error + num = 0 # (BASE + 0) + else: + raise InputError(idf_path, "Cannot parse line %s" % line) + + try: + related + except NameError: + # The value of the error is known at this moment because it do not depends on some other BASE error code + err_dict[num].append(ErrItem(words[1], idf_path, comment)) + rev_err_dict[words[1]] = num + else: + # Store the information available now and compute the error code later + unproc_list.append(ErrItem(words[1], idf_path, comment, related, num)) + +def process_remaining_errors(): + """ + Create errors which could not be processed before because the error code + for the BASE error code wasn't known. + This works for sure only if there is no multiple-time dependency, e.g.: + #define BASE1 0 + #define BASE2 (BASE1 + 10) + #define ERROR (BASE2 + 10) - ERROR will be processed successfully only if it processed later than BASE2 + """ + for item in unproc_list: + if item.rel_str in rev_err_dict: + base_num = rev_err_dict[item.rel_str] + base = err_dict[base_num][0] + num = base_num + item.rel_off + err_dict[num].append(ErrItem(item.name, item.file, item.comment)) + rev_err_dict[item.name] = num + else: + print(item.rel_str + " referenced by " + item.name + " in " + item.file + " is unknown") + + del unproc_list[:] + +def path_to_include(path): + """ + Process the path (relative to the IDF project) in a form which can be used + to include in a C file. Using just the filename does not work all the + time because some files are deeper in the tree. This approach tries to + find an 'include' parent directory an include its subdirectories, e.g. + "components/XY/include/esp32/file.h" will be transported into "esp32/file.h" + So this solution works only works when the subdirectory or subdirectories + are inside the "include" directory. Other special cases need to be handled + here when the compiler gives an unknown header file error message. + """ + spl_path = string.split(path, os.sep) + try: + i = spl_path.index('include') + except ValueError: + # no include in the path -> use just the filename + return os.path.basename(path) + else: + return str(os.sep).join(spl_path[i+1:]) # subdirectories and filename in "include" + +def print_warning(error_list, error_code): + """ + Print warning about errors with the same error code + """ + print("[WARNING] The following errors have the same code (%d):" % error_code) + for e in error_list: + print(" " + str(e)) + +def max_string_width(): + max = 0 + for k in err_dict.keys(): + for e in err_dict[k]: + x = len(e.name) + if x > max: + max = x + return max + +def generate_output(fin, fout): + """ + Writes the output to fout based on th error dictionary err_dict and + template file fin. + """ + # make includes unique by using a set + includes = set() + for k in err_dict.keys(): + for e in err_dict[k]: + includes.add(path_to_include(e.file)) + + # The order in a set in non-deterministic therefore it could happen that the + # include order will be different in other machines and false difference + # in the output file could be reported. In order to avoid this, the items + # are sorted in a list. + include_list = list(includes) + include_list.sort() + + max_width = max_string_width() + 17 + 1 # length of " ERR_TBL_IT()," with spaces is 17 + max_decdig = max(len(str(k)) for k in err_dict.keys()) + + for line in fin: + if re.match(r'@COMMENT@', line): + fout.write("//Do not edit this file because it is autogenerated by " + os.path.basename(__file__) + "\n") + + elif re.match(r'@HEADERS@', line): + for i in include_list: + fout.write("#if __has_include(\"" + i + "\")\n#include \"" + i + "\"\n#endif\n") + elif re.match(r'@ERROR_ITEMS@', line): + last_file = "" + for k in sorted(err_dict.keys()): + if len(err_dict[k]) > 1: + err_dict[k].sort() + print_warning(err_dict[k], k) + for e in err_dict[k]: + if e.file != last_file: + last_file = e.file + fout.write(" // %s\n" % last_file) + table_line = (" ERR_TBL_IT(" + e.name + "), ").ljust(max_width) + "/* " + str(k).rjust(max_decdig) + fout.write("# ifdef %s\n" % e.name) + fout.write(table_line) + hexnum_length = 0 + if k > 0: # negative number and zero should be only ESP_FAIL and ESP_OK + hexnum = " 0x%x" % k + hexnum_length = len(hexnum) + fout.write(hexnum) + if e.comment != "": + if len(e.comment) < 50: + fout.write(" %s" % e.comment) + else: + indent = " " * (len(table_line) + hexnum_length + 1) + w = textwrap.wrap(e.comment, width=120, initial_indent = indent, subsequent_indent = indent) + # this couldn't be done with initial_indent because there is no initial_width option + fout.write(" %s" % w[0].strip()) + for i in range(1, len(w)): + fout.write("\n%s" % w[i]) + fout.write(" */\n# endif\n") + else: + fout.write(line) + +def main(): + parser = argparse.ArgumentParser(description='ESP32 esp_err_to_name lookup generator for esp_err_t') + parser.add_argument('input', help='Path to the esp_err_to_name.c.in template input.', default=os.environ['IDF_PATH'] + '/components/esp32/esp_err_to_name.c.in', nargs='?') + parser.add_argument('output', help='Path to the esp_err_to_name.c output.', default=os.environ['IDF_PATH'] + '/components/esp32/esp_err_to_name.c', nargs='?') + args = parser.parse_args() + + for root, dirnames, filenames in os.walk(os.environ['IDF_PATH']): + for filename in fnmatch.filter(filenames, '*.[ch]'): + full_path = os.path.join(root, filename) + idf_path = os.path.relpath(full_path, os.environ['IDF_PATH']) + if idf_path in ignore_files: + continue + with open(full_path, "r+b") as f: + try: + map = mmap.mmap(f.fileno(), 0, prot=mmap.ACCESS_READ) + except ValueError: + pass # An empty file cannot be mmaped + else: + for line in iter(map.readline, ""): + # match also ESP_OK and ESP_FAIL because some of ESP_ERRs are referencing them + if re.match(r"\s*#define\s+(ESP_ERR_|ESP_OK|ESP_FAIL)", line): + try: + process(str.strip(line), idf_path) + except InputError as e: + print (e) + + process_remaining_errors() + + with open(args.input, 'r') as fin, open(args.output, 'w') as fout: + generate_output(fin, fout) + +if __name__ == "__main__": + main()