mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
component/bt: implement classic Bluetooth profiles A2DP(sink) and AVRCP(controller)
This commit is contained in:
commit
ccfe4fefeb
@ -105,9 +105,8 @@ build_esp_idf_tests:
|
||||
|
||||
script:
|
||||
- cd tools/unit-test-app
|
||||
- git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..."
|
||||
- make TESTS_ALL=1
|
||||
- python UnitTestParser.py
|
||||
- python tools/UnitTestParser.py
|
||||
|
||||
build_examples:
|
||||
<<: *build_template
|
||||
@ -143,7 +142,6 @@ build_docs:
|
||||
- docs/_build/html
|
||||
expire_in: 1 mos
|
||||
|
||||
|
||||
test_nvs_on_host:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
@ -294,6 +292,21 @@ check_doc_links:
|
||||
- docs/_build/linkcheck
|
||||
expire_in: 1 mos
|
||||
|
||||
check_commit_msg:
|
||||
stage: deploy
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
- build
|
||||
except:
|
||||
- master
|
||||
- /^release\/v/
|
||||
- /^v\d+\.\d+(\.\d+)?($|-)/
|
||||
before_script:
|
||||
- echo "skip update submodule"
|
||||
script:
|
||||
- git checkout ${CI_BUILD_REF_NAME}
|
||||
# commit start with "WIP: " need to be squashed before merge
|
||||
- 'git log --pretty=%s master..${CI_BUILD_REF_NAME} | grep "^WIP: " || exit 0 && exit 1'
|
||||
|
||||
# AUTO GENERATED PART START, DO NOT MODIFY CONTENT BELOW
|
||||
# template for test jobs
|
||||
@ -380,7 +393,7 @@ check_doc_links:
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||
APP_NAME: "ut"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/unit_test"
|
||||
MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/tools/unit-test-app/ModuleDefinition.yml"
|
||||
MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/tools/unit-test-app/tools/ModuleDefinition.yml"
|
||||
|
||||
dependencies:
|
||||
- build_esp_idf_tests
|
||||
|
@ -38,6 +38,44 @@ config BT_DRAM_RELEASE
|
||||
Enabling this option will release about 30K DRAM from Classic BT.
|
||||
The released DRAM will be used as system heap memory.
|
||||
|
||||
#disable now for app cpu due to a known issue
|
||||
config BTDM_CONTROLLER_RUN_APP_CPU
|
||||
bool "Run controller on APP CPU"
|
||||
depends on BT_ENABLED && !FREERTOS_UNICORE && 0
|
||||
default n
|
||||
help
|
||||
Run controller on APP CPU.
|
||||
|
||||
config BTDM_CONTROLLER_RUN_CPU
|
||||
int
|
||||
depends on BT_ENABLED
|
||||
default 1 if BTDM_CONTROLLER_RUN_APP_CPU
|
||||
default 0
|
||||
|
||||
menuconfig BT_HCI_UART
|
||||
bool "HCI use UART as IO"
|
||||
depends on BT_ENABLED && !BLUEDROID_ENABLED
|
||||
default n
|
||||
help
|
||||
Default HCI use VHCI, if this option choose, HCI will use UART(0/1/2) as IO.
|
||||
Besides, it can set uart number and uart baudrate.
|
||||
|
||||
config BT_HCI_UART_NO
|
||||
int "UART Number for HCI"
|
||||
depends on BT_HCI_UART
|
||||
range 1 2
|
||||
default 1
|
||||
help
|
||||
Uart number for HCI.
|
||||
|
||||
config BT_HCI_UART_BAUDRATE
|
||||
int "UART Baudrate for HCI"
|
||||
depends on BT_HCI_UART
|
||||
range 115200 921600
|
||||
default 921600
|
||||
help
|
||||
UART Baudrate for HCI. Please use standard baudrate.
|
||||
|
||||
# Memory reserved at start of DRAM for Bluetooth stack
|
||||
config BT_RESERVE_DRAM
|
||||
hex
|
||||
|
@ -43,23 +43,23 @@ enum {
|
||||
};
|
||||
|
||||
#define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE)
|
||||
#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 2)
|
||||
#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 3)
|
||||
#define HCI_HOST_TASK_NAME "hciHostT"
|
||||
#define HCI_HOST_QUEUE_NUM 40
|
||||
|
||||
#define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE)
|
||||
#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 3)
|
||||
#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 4)
|
||||
#define HCI_H4_TASK_NAME "hciH4T"
|
||||
#define HCI_H4_QUEUE_NUM 60
|
||||
|
||||
#define BTU_TASK_STACK_SIZE (3584 + BT_TASK_EXTRA_STACK_SIZE)
|
||||
#define BTU_TASK_PRIO (configMAX_PRIORITIES - 4)
|
||||
#define BTU_TASK_PRIO (configMAX_PRIORITIES - 5)
|
||||
#define BTU_TASK_NAME "btuT"
|
||||
#define BTU_QUEUE_NUM 50
|
||||
|
||||
#define BTC_TASK_STACK_SIZE (CONFIG_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig
|
||||
#define BTC_TASK_NAME "btcT"
|
||||
#define BTC_TASK_PRIO (configMAX_PRIORITIES - 5)
|
||||
#define BTC_TASK_PRIO (configMAX_PRIORITIES - 6)
|
||||
#define BTC_TASK_QUEUE_NUM 20
|
||||
|
||||
void btu_task_post(uint32_t sig);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@ -33,13 +34,15 @@
|
||||
#if CONFIG_BT_ENABLED
|
||||
|
||||
/* Bluetooth system and controller config */
|
||||
#define BTDM_CFG_BT_EM_RELEASE (1<<0)
|
||||
#define BTDM_CFG_BT_DATA_RELEASE (1<<1)
|
||||
#define BTDM_CFG_BT_EM_RELEASE (1<<0)
|
||||
#define BTDM_CFG_BT_DATA_RELEASE (1<<1)
|
||||
#define BTDM_CFG_HCI_UART (1<<2)
|
||||
#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<3)
|
||||
/* Other reserved for future */
|
||||
|
||||
/* not for user call, so don't put to include file */
|
||||
extern void btdm_osi_funcs_register(void *osi_funcs);
|
||||
extern void btdm_controller_init(uint32_t config_mask);
|
||||
extern void btdm_controller_init(uint32_t config_mask, esp_bt_controller_config_t *config_opts);
|
||||
extern void btdm_controller_schedule(void);
|
||||
extern void btdm_controller_deinit(void);
|
||||
extern int btdm_controller_enable(esp_bt_mode_t mode);
|
||||
@ -79,12 +82,14 @@ struct osi_funcs_t {
|
||||
int32_t (*_mutex_lock)(void *mutex);
|
||||
int32_t (*_mutex_unlock)(void *mutex);
|
||||
int32_t (* _read_efuse_mac)(uint8_t mac[6]);
|
||||
void (* _srand)(unsigned int seed);
|
||||
int (* _rand)(void);
|
||||
};
|
||||
|
||||
/* Static variable declare */
|
||||
static bool btdm_bb_init_flag = false;
|
||||
static esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
|
||||
|
||||
static esp_bt_controller_config_t btdm_cfg_opts;
|
||||
static xTaskHandle btControllerTaskHandle;
|
||||
|
||||
static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
@ -134,6 +139,16 @@ static int32_t IRAM_ATTR read_mac_wrapper(uint8_t mac[6])
|
||||
return esp_read_mac(mac, ESP_MAC_BT);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR srand_wrapper(unsigned int seed)
|
||||
{
|
||||
/* empty function */
|
||||
}
|
||||
|
||||
static int IRAM_ATTR rand_wrapper(void)
|
||||
{
|
||||
return (int)esp_random();
|
||||
}
|
||||
|
||||
static struct osi_funcs_t osi_funcs = {
|
||||
._set_isr = xt_set_interrupt_handler,
|
||||
._ints_on = xt_ints_on,
|
||||
@ -146,7 +161,9 @@ static struct osi_funcs_t osi_funcs = {
|
||||
._mutex_create = mutex_create_wrapper,
|
||||
._mutex_lock = mutex_lock_wrapper,
|
||||
._mutex_unlock = mutex_unlock_wrapper,
|
||||
._read_efuse_mac = read_mac_wrapper
|
||||
._read_efuse_mac = read_mac_wrapper,
|
||||
._srand = srand_wrapper,
|
||||
._rand = rand_wrapper,
|
||||
};
|
||||
|
||||
bool esp_vhci_host_check_send_available(void)
|
||||
@ -170,6 +187,12 @@ static uint32_t btdm_config_mask_load(void)
|
||||
|
||||
#ifdef CONFIG_BT_DRAM_RELEASE
|
||||
mask |= (BTDM_CFG_BT_EM_RELEASE | BTDM_CFG_BT_DATA_RELEASE);
|
||||
#endif
|
||||
#ifdef CONFIG_BT_HCI_UART
|
||||
mask |= BTDM_CFG_HCI_UART;
|
||||
#endif
|
||||
#ifdef CONFIG_BTDM_CONTROLLER_RUN_APP_CPU
|
||||
mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU;
|
||||
#endif
|
||||
return mask;
|
||||
}
|
||||
@ -178,30 +201,46 @@ static void bt_controller_task(void *pvParam)
|
||||
{
|
||||
uint32_t btdm_cfg_mask = 0;
|
||||
|
||||
btdm_cfg_mask = btdm_config_mask_load();
|
||||
|
||||
btdm_osi_funcs_register(&osi_funcs);
|
||||
|
||||
btdm_cfg_mask = btdm_config_mask_load();
|
||||
btdm_controller_init(btdm_cfg_mask);
|
||||
btdm_controller_init(btdm_cfg_mask, &btdm_cfg_opts);
|
||||
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
|
||||
|
||||
/* Loop */
|
||||
btdm_controller_schedule();
|
||||
}
|
||||
|
||||
void esp_bt_controller_init()
|
||||
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
{
|
||||
BaseType_t ret;
|
||||
|
||||
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
|
||||
return;
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
xTaskCreatePinnedToCore(bt_controller_task, "btController",
|
||||
if (cfg == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
memcpy(&btdm_cfg_opts, cfg, sizeof(esp_bt_controller_config_t));
|
||||
|
||||
ret = xTaskCreatePinnedToCore(bt_controller_task, "btController",
|
||||
ESP_TASK_BT_CONTROLLER_STACK, NULL,
|
||||
ESP_TASK_BT_CONTROLLER_PRIO, &btControllerTaskHandle, 0);
|
||||
ESP_TASK_BT_CONTROLLER_PRIO, &btControllerTaskHandle, CONFIG_BTDM_CONTROLLER_RUN_CPU);
|
||||
|
||||
if (ret != pdPASS) {
|
||||
memset(&btdm_cfg_opts, 0x0, sizeof(esp_bt_controller_config_t));
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_bt_controller_deinit(void)
|
||||
{
|
||||
memset(&btdm_cfg_opts, 0x0, sizeof(esp_bt_controller_config_t));
|
||||
vTaskDelete(btControllerTaskHandle);
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
|
||||
}
|
||||
|
@ -18,11 +18,44 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Controller config options, depend on config mask.
|
||||
* Config mask indicate which functions enabled, this means
|
||||
* some options or parameters of some functions enabled by config mask.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */
|
||||
uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
|
||||
} esp_bt_controller_config_t;
|
||||
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
|
||||
#ifdef CONFIG_BT_HCI_UART_NO
|
||||
#define BT_HCI_UART_NO_DEFAULT CONFIG_BT_HCI_UART_NO
|
||||
#else
|
||||
#define BT_HCI_UART_NO_DEFAULT 1
|
||||
#endif /* BT_HCI_UART_NO_DEFAULT */
|
||||
|
||||
#ifdef CONFIG_BT_HCI_UART_BAUDRATE
|
||||
#define BT_HCI_UART_BAUDRATE_DEFAULT CONFIG_BT_HCI_UART_BAUDRATE
|
||||
#else
|
||||
#define BT_HCI_UART_BAUDRATE_DEFAULT 921600
|
||||
#endif /* BT_HCI_UART_BAUDRATE_DEFAULT */
|
||||
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
|
||||
.hci_uart_no = BT_HCI_UART_NO_DEFAULT,\
|
||||
.hci_uart_baudrate = BT_HCI_UART_BAUDRATE_DEFAULT,\
|
||||
};
|
||||
#else
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() {0}; _Static_assert(0, "please enable bluetooth in menuconfig to use bt.h");
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Bluetooth mode for controller enable/disable
|
||||
*/
|
||||
@ -45,10 +78,11 @@ typedef enum {
|
||||
|
||||
/**
|
||||
* @brief Initialize BT controller to allocate task and other resource.
|
||||
*
|
||||
* @param cfg: Initial configuration of BT controller.
|
||||
* This function should be called only once, before any other BT functions are called.
|
||||
* @return ESP_OK - success, other - failed
|
||||
*/
|
||||
void esp_bt_controller_init(void);
|
||||
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief De-initialize BT controller to free resource and delete task.
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9a4bb1d5287572664f170f9df4dbfd71babdfc68
|
||||
Subproject commit 0986936c6d21a009d7d4249cbae8a23b0f3bd20b
|
@ -55,6 +55,7 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_coexist.h"
|
||||
#include "esp_panic.h"
|
||||
#include "esp_core_dump.h"
|
||||
#include "trax.h"
|
||||
|
||||
@ -92,6 +93,11 @@ static const char* TAG = "cpu_start";
|
||||
|
||||
void IRAM_ATTR call_start_cpu0()
|
||||
{
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
RESET_REASON rst_reas[1];
|
||||
#else
|
||||
RESET_REASON rst_reas[2];
|
||||
#endif
|
||||
cpu_configure_region_protection();
|
||||
|
||||
//Move exception vectors to IRAM
|
||||
@ -99,10 +105,25 @@ void IRAM_ATTR call_start_cpu0()
|
||||
"wsr %0, vecbase\n" \
|
||||
::"r"(&_init_start));
|
||||
|
||||
rst_reas[0] = rtc_get_reset_reason(0);
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
rst_reas[1] = rtc_get_reset_reason(1);
|
||||
#endif
|
||||
// from panic handler we can be reset by RWDT or TG0WDT
|
||||
if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
|| rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
|
||||
#endif
|
||||
) {
|
||||
// stop wdt in case of any
|
||||
ESP_EARLY_LOGI(TAG, "Stop panic WDT");
|
||||
esp_panic_wdt_stop();
|
||||
}
|
||||
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
/* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */
|
||||
if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) {
|
||||
if (rst_reas[0] != DEEPSLEEP_RESET) {
|
||||
memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
|
||||
}
|
||||
|
||||
@ -206,9 +227,7 @@ void start_cpu0_default(void)
|
||||
#if CONFIG_TASK_WDT
|
||||
esp_task_wdt_init();
|
||||
#endif
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
esp_crosscore_int_init();
|
||||
#endif
|
||||
esp_ipc_init();
|
||||
spi_flash_init();
|
||||
/* init default OS-aware flash access critical section */
|
||||
|
@ -61,7 +61,10 @@ void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const cha
|
||||
* Disabled if assertions are disabled.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#define ESP_ERROR_CHECK(x) do { (x); } while (0)
|
||||
#define ESP_ERROR_CHECK(x) do { \
|
||||
esp_err_t rc = (x); \
|
||||
(void) sizeof(rc); \
|
||||
} while(0);
|
||||
#else
|
||||
#define ESP_ERROR_CHECK(x) do { \
|
||||
esp_err_t rc = (x); \
|
||||
|
@ -61,6 +61,11 @@ esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
|
||||
void esp_clear_watchpoint(int no);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stops panic WDT
|
||||
*/
|
||||
void esp_panic_wdt_stop(void);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1650,6 +1650,12 @@
|
||||
#define RTC_CNTL_WDT_PAUSE_IN_SLP_M (BIT(7))
|
||||
#define RTC_CNTL_WDT_PAUSE_IN_SLP_V 0x1
|
||||
#define RTC_CNTL_WDT_PAUSE_IN_SLP_S 7
|
||||
/* RTC_CNTL_WDT_STGX : */
|
||||
/*description: stage action selection values */
|
||||
#define RTC_WDT_STG_SEL_OFF 0
|
||||
#define RTC_WDT_STG_SEL_INT 1
|
||||
#define RTC_WDT_STG_SEL_RESET_CPU 2
|
||||
#define RTC_WDT_STG_SEL_RESET_SYSTEM 3
|
||||
|
||||
#define RTC_CNTL_WDTCONFIG1_REG (DR_REG_RTCCNTL_BASE + 0x90)
|
||||
/* RTC_CNTL_WDT_STG0_HOLD : R/W ;bitpos:[31:0] ;default: 32'd128000 ; */
|
||||
|
@ -284,11 +284,37 @@ static void disableAllWdts()
|
||||
TIMERG0.wdt_wprotect = 0;
|
||||
TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.en = 0;
|
||||
TIMERG0.wdt_wprotect = 0;
|
||||
TIMERG1.wdt_wprotect = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void esp_panic_wdt_start()
|
||||
{
|
||||
if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) {
|
||||
return;
|
||||
}
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
|
||||
// 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
|
||||
// @ 115200 UART speed it will take more than 6 sec to print them out.
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, RTC_CNTL_SLOWCLK_FREQ*7);
|
||||
REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
|
||||
}
|
||||
|
||||
void esp_panic_wdt_stop()
|
||||
{
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
|
||||
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
|
||||
}
|
||||
|
||||
static inline bool stackPointerIsSane(uint32_t sp)
|
||||
{
|
||||
return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
|
||||
@ -343,6 +369,9 @@ static void commonErrorHandler(XtExcFrame *frame)
|
||||
"A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
|
||||
};
|
||||
|
||||
// start panic WDT to restart system if we hang in this handler
|
||||
esp_panic_wdt_start();
|
||||
|
||||
//Feed the watchdogs, so they will give us time to print out debug info
|
||||
reconfigureAllWdts();
|
||||
|
||||
@ -370,6 +399,7 @@ static void commonErrorHandler(XtExcFrame *frame)
|
||||
|
||||
#if CONFIG_ESP32_PANIC_GDBSTUB
|
||||
disableAllWdts();
|
||||
esp_panic_wdt_stop();
|
||||
panicPutStr("Entering gdb stub now.\r\n");
|
||||
esp_gdbstub_panic_handler(frame);
|
||||
#else
|
||||
@ -383,6 +413,7 @@ static void commonErrorHandler(XtExcFrame *frame)
|
||||
#endif
|
||||
reconfigureAllWdts();
|
||||
#endif
|
||||
esp_panic_wdt_stop();
|
||||
#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
panicPutStr("Rebooting...\r\n");
|
||||
esp_restart_noos();
|
||||
|
@ -2935,12 +2935,18 @@ initial condition:
|
||||
test script: InitCondBase
|
||||
- check cmd set:
|
||||
- ''
|
||||
- - FREBOOT UT1
|
||||
- ['']
|
||||
- - DELAY 3
|
||||
- ['']
|
||||
- - UT UT1 -
|
||||
- [R UT1 C Tests C Failures C Ignored]
|
||||
force restore cmd set:
|
||||
- ''
|
||||
- - FREBOOT UT1
|
||||
- ['']
|
||||
- - DELAY 3
|
||||
- ['']
|
||||
- - UT UT1 -
|
||||
- [R UT1 C Tests C Failures C Ignored]
|
||||
initial condition detail: At UT menu page
|
||||
@ -2948,6 +2954,8 @@ initial condition:
|
||||
- ''
|
||||
- - FREBOOT UT1
|
||||
- ['']
|
||||
- - DELAY 3
|
||||
- ['']
|
||||
- - UT UT1 -
|
||||
- [R UT1 C Tests C Failures C Ignored]
|
||||
restore post cmd set:
|
||||
|
@ -18,7 +18,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MDNS_TEST_MODE
|
||||
#include <tcpip_adapter.h>
|
||||
#else
|
||||
#include "esp32_compat.h"
|
||||
#endif
|
||||
|
||||
struct mdns_server_s;
|
||||
typedef struct mdns_server_s mdns_server_t;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mdns.h"
|
||||
|
||||
#include <string.h>
|
||||
#ifndef MDNS_TEST_MODE
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
@ -23,6 +24,7 @@
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "esp_wifi.h"
|
||||
#endif
|
||||
|
||||
#define MDNS_FLAGS_AUTHORITATIVE 0x8400
|
||||
|
||||
@ -162,6 +164,9 @@ static const char * MDNS_DEFAULT_DOMAIN = "local";
|
||||
static const char * MDNS_SUB_STR = "_sub";
|
||||
|
||||
static mdns_server_t * _mdns_servers[TCPIP_ADAPTER_IF_MAX] = {0,0,0};
|
||||
|
||||
#ifndef MDNS_TEST_MODE
|
||||
|
||||
static TaskHandle_t _mdns_service_task_handle = NULL;
|
||||
static QueueSetHandle_t _mdns_queue_set = NULL;
|
||||
|
||||
@ -257,6 +262,7 @@ esp_err_t _mdns_server_deinit(mdns_server_t * server)
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief send packet over UDP
|
||||
@ -269,25 +275,28 @@ esp_err_t _mdns_server_deinit(mdns_server_t * server)
|
||||
*/
|
||||
static size_t _mdns_server_write(mdns_server_t * server, uint8_t * data, size_t len)
|
||||
{
|
||||
#ifndef MDNS_TEST_MODE
|
||||
struct pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if (pbt != NULL) {
|
||||
uint8_t* dst = (uint8_t *)pbt->payload;
|
||||
memcpy(dst, data, len);
|
||||
err_t err = udp_sendto(server->pcb, pbt, &(server->pcb->remote_ip), server->pcb->remote_port);
|
||||
pbuf_free(pbt);
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
if (pbt == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
uint8_t* dst = (uint8_t *)pbt->payload;
|
||||
memcpy(dst, data, len);
|
||||
err_t err = udp_sendto(server->pcb, pbt, &(server->pcb->remote_ip), server->pcb->remote_port);
|
||||
pbuf_free(pbt);
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* MDNS Servers
|
||||
* */
|
||||
|
||||
static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len);
|
||||
#ifndef MDNS_TEST_MODE
|
||||
void mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief the main MDNS service task. Packets are received and parsed here
|
||||
@ -305,7 +314,7 @@ static void _mdns_service_task(void *pvParameters)
|
||||
mdns_server_t * server = _mdns_servers[i];
|
||||
if (server && server->queue == queue) {
|
||||
MDNS_MUTEX_LOCK();
|
||||
_mdns_parse_packet(server, (uint8_t*)pb->payload, pb->len);
|
||||
mdns_parse_packet(server, (uint8_t*)pb->payload, pb->len);
|
||||
MDNS_MUTEX_UNLOCK();
|
||||
break;
|
||||
}
|
||||
@ -314,6 +323,7 @@ static void _mdns_service_task(void *pvParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief get the server assigned to particular interface
|
||||
@ -342,6 +352,7 @@ static mdns_server_t * _mdns_server_get(tcpip_adapter_if_t tcpip_if)
|
||||
*/
|
||||
static esp_err_t _mdns_server_add(mdns_server_t * server)
|
||||
{
|
||||
#ifndef MDNS_TEST_MODE
|
||||
if (!_mdns_service_semaphore) {
|
||||
_mdns_service_semaphore = xSemaphoreCreateMutex();
|
||||
if (!_mdns_service_semaphore) {
|
||||
@ -374,7 +385,7 @@ static esp_err_t _mdns_server_add(mdns_server_t * server)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
_mdns_servers[server->tcpip_if] = server;
|
||||
|
||||
return ESP_OK;
|
||||
@ -391,11 +402,11 @@ static esp_err_t _mdns_server_add(mdns_server_t * server)
|
||||
*/
|
||||
static esp_err_t _mdns_server_remove(mdns_server_t * server)
|
||||
{
|
||||
_mdns_servers[server->tcpip_if] = NULL;
|
||||
#ifndef MDNS_TEST_MODE
|
||||
//stop UDP
|
||||
_mdns_server_deinit(server);
|
||||
|
||||
_mdns_servers[server->tcpip_if] = NULL;
|
||||
|
||||
if (xQueueRemoveFromSet(server->queue, _mdns_queue_set) != pdPASS) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@ -417,7 +428,7 @@ static esp_err_t _mdns_server_remove(mdns_server_t * server)
|
||||
}
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
}
|
||||
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -1294,7 +1305,7 @@ static inline uint16_t _mdns_read_u16(const uint8_t * packet, uint16_t index)
|
||||
* @param data byte array holding the packet data
|
||||
* @param len length of the byte array
|
||||
*/
|
||||
static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len)
|
||||
void mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len)
|
||||
{
|
||||
static mdns_name_t n;
|
||||
static mdns_result_temp_t a;
|
||||
@ -1309,11 +1320,13 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
|
||||
if (questions) {
|
||||
uint8_t qs = questions;
|
||||
mdns_answer_item_t * answers = NULL;
|
||||
mdns_answer_item_t * answer_items = NULL;
|
||||
|
||||
while(qs--) {
|
||||
content = _mdns_parse_fqdn(data, content, name);
|
||||
if (!content) {
|
||||
answers = 0;
|
||||
additional = 0;
|
||||
break;//error
|
||||
}
|
||||
|
||||
@ -1323,7 +1336,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
if (!name->service[0] || !name->proto[0]) {
|
||||
if (type == MDNS_TYPE_A || type == MDNS_TYPE_AAAA || type == MDNS_TYPE_ANY) {//send A + AAAA
|
||||
if (name->host[0] && server->hostname && server->hostname[0] && !strcmp(name->host, server->hostname)) {
|
||||
answers = _mdns_add_answer(answers, NULL, MDNS_ANSWER_A);
|
||||
answer_items = _mdns_add_answer(answer_items, NULL, MDNS_ANSWER_A);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@ -1336,7 +1349,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
mdns_srv_item_t * s = server->services;
|
||||
while(s) {
|
||||
if (s->service->service && s->service->proto) {
|
||||
answers = _mdns_add_answer(answers, s->service, MDNS_ANSWER_SDPTR);
|
||||
answer_items = _mdns_add_answer(answer_items, s->service, MDNS_ANSWER_SDPTR);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
@ -1354,7 +1367,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
}
|
||||
|
||||
if (type == MDNS_TYPE_PTR) {
|
||||
answers = _mdns_add_answer(answers, si->service, MDNS_ANSWER_ALL);
|
||||
answer_items = _mdns_add_answer(answer_items, si->service, MDNS_ANSWER_ALL);
|
||||
} else if (type == MDNS_TYPE_TXT) {
|
||||
//match instance/host
|
||||
const char * host = (si->service->instance)?si->service->instance
|
||||
@ -1363,7 +1376,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
if (!host || !host[0] || !name->host[0] || strcmp(name->host, host)) {
|
||||
continue;
|
||||
}
|
||||
answers = _mdns_add_answer(answers, si->service, MDNS_ANSWER_TXT);
|
||||
answer_items = _mdns_add_answer(answer_items, si->service, MDNS_ANSWER_TXT);
|
||||
} else if (type == MDNS_TYPE_SRV) {
|
||||
//match instance/host
|
||||
const char * host = (si->service->instance)?si->service->instance
|
||||
@ -1372,16 +1385,16 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
if (!host || !host[0] || !name->host[0] || strcmp(name->host, host)) {
|
||||
continue;
|
||||
}
|
||||
answers = _mdns_add_answer(answers, si->service, MDNS_ANSWER_SRV | MDNS_ANSWER_A);
|
||||
answer_items = _mdns_add_answer(answer_items, si->service, MDNS_ANSWER_SRV | MDNS_ANSWER_A);
|
||||
} else if (type == MDNS_TYPE_ANY) {//send all
|
||||
//match host
|
||||
if (!name->host[0] || !server->hostname || !server->hostname[0] || strcmp(name->host, server->hostname)) {
|
||||
answers = _mdns_add_answer(answers, si->service, MDNS_ANSWER_ALL);
|
||||
answer_items = _mdns_add_answer(answer_items, si->service, MDNS_ANSWER_ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (answers) {
|
||||
_mdns_send_answers(server, answers);
|
||||
if (answer_items) {
|
||||
_mdns_send_answers(server, answer_items);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1392,30 +1405,37 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
while(content < (data + len)) {
|
||||
content = _mdns_parse_fqdn(data, content, name);
|
||||
if (!content) {
|
||||
break;//error
|
||||
return;//error
|
||||
}
|
||||
uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET);
|
||||
uint16_t data_len = _mdns_read_u16(content, MDNS_LEN_OFFSET);
|
||||
const uint8_t * data_ptr = content + MDNS_DATA_OFFSET;
|
||||
|
||||
content = data_ptr + data_len;
|
||||
if(content > (data + len)){
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == MDNS_TYPE_PTR) {
|
||||
if (!_mdns_parse_fqdn(data, data_ptr, name)) {
|
||||
continue;//error
|
||||
}
|
||||
#ifndef MDNS_TEST_MODE
|
||||
if (server->search.host[0] ||
|
||||
(strcmp(name->service, server->search.service) != 0) ||
|
||||
(strcmp(name->proto, server->search.proto) != 0)) {
|
||||
continue;//not searching for service or wrong service/proto
|
||||
}
|
||||
#endif
|
||||
strlcpy(answer->instance, name->host, MDNS_NAME_BUF_LEN);
|
||||
} else if (type == MDNS_TYPE_SRV) {
|
||||
#ifndef MDNS_TEST_MODE
|
||||
if (server->search.host[0] ||
|
||||
(strcmp(name->service, server->search.service) != 0) ||
|
||||
(strcmp(name->proto, server->search.proto) != 0)) {
|
||||
continue;//not searching for service or wrong service/proto
|
||||
}
|
||||
#endif
|
||||
if (answer->instance[0]) {
|
||||
if (strcmp(answer->instance, name->host) != 0) {
|
||||
continue;//instance name is not the same as the one in the PTR record
|
||||
@ -1444,6 +1464,9 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
uint16_t i=0,b=0, y;
|
||||
while(i < data_len) {
|
||||
uint8_t partLen = data_ptr[i++];
|
||||
if((i+partLen) > data_len){
|
||||
break;//error
|
||||
}
|
||||
//check if partLen will fit in the buffer
|
||||
if (partLen > (MDNS_TXT_MAX_LEN - b - 1)) {
|
||||
break;
|
||||
@ -1459,9 +1482,11 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
answer->txt[b] = 0;
|
||||
} else if (type == MDNS_TYPE_AAAA) {
|
||||
if (server->search.host[0]) {
|
||||
#ifndef MDNS_TEST_MODE
|
||||
if (strcmp(name->host, server->search.host) != 0) {
|
||||
continue;//wrong host
|
||||
}
|
||||
#endif
|
||||
} else if (!answer->ptr) {
|
||||
strlcpy(answer->host, name->host, MDNS_NAME_BUF_LEN);
|
||||
} else if (strcmp(answer->host, name->host) != 0) {
|
||||
@ -1470,9 +1495,11 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||
memcpy(answer->addrv6, data_ptr, sizeof(ip6_addr_t));
|
||||
} else if (type == MDNS_TYPE_A) {
|
||||
if (server->search.host[0]) {
|
||||
#ifndef MDNS_TEST_MODE
|
||||
if (strcmp(name->host, server->search.host) != 0) {
|
||||
continue;//wrong host
|
||||
}
|
||||
#endif
|
||||
} else if (!answer->ptr) {
|
||||
strlcpy(answer->host, name->host, MDNS_NAME_BUF_LEN);
|
||||
} else if (strcmp(answer->host, name->host) != 0) {
|
||||
@ -1611,12 +1638,11 @@ esp_err_t mdns_set_hostname(mdns_server_t * server, const char * hostname)
|
||||
}
|
||||
MDNS_MUTEX_LOCK();
|
||||
free((char*)server->hostname);
|
||||
server->hostname = (char *)malloc(strlen(hostname)+1);
|
||||
server->hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!server->hostname) {
|
||||
MDNS_MUTEX_UNLOCK();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
strlcpy((char *)server->hostname, hostname, MDNS_NAME_BUF_LEN);
|
||||
MDNS_MUTEX_UNLOCK();
|
||||
return ERR_OK;
|
||||
}
|
||||
@ -1631,12 +1657,11 @@ esp_err_t mdns_set_instance(mdns_server_t * server, const char * instance)
|
||||
}
|
||||
MDNS_MUTEX_LOCK();
|
||||
free((char*)server->instance);
|
||||
server->instance = (char *)malloc(strlen(instance)+1);
|
||||
server->instance = strndup(instance, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!server->instance) {
|
||||
MDNS_MUTEX_UNLOCK();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
strlcpy((char *)server->instance, instance, MDNS_NAME_BUF_LEN);
|
||||
MDNS_MUTEX_UNLOCK();
|
||||
return ERR_OK;
|
||||
}
|
||||
@ -1812,7 +1837,7 @@ esp_err_t mdns_service_remove_all(mdns_server_t * server)
|
||||
* MDNS QUERY
|
||||
* */
|
||||
|
||||
uint32_t mdns_query(mdns_server_t * server, const char * service, const char * proto, uint32_t timeout)
|
||||
size_t mdns_query(mdns_server_t * server, const char * service, const char * proto, uint32_t timeout)
|
||||
{
|
||||
if (!server || !service) {
|
||||
return 0;
|
||||
|
35
components/mdns/test_afl_fuzz_host/Makefile
Normal file
35
components/mdns/test_afl_fuzz_host/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
TEST_NAME=test
|
||||
FUZZ=afl-fuzz
|
||||
CC=afl-clang-fast
|
||||
CPP=$(CC)
|
||||
LD=$(CC)
|
||||
OBJECTS=mdns.o test.o
|
||||
CFLAGS=-DMDNS_TEST_MODE -I. -I../include
|
||||
|
||||
OS := $(shell uname)
|
||||
ifeq ($(OS),Darwin)
|
||||
LDLIBS=
|
||||
else
|
||||
LDLIBS=-lbsd
|
||||
CFLAGS+=-DUSE_BSD_STRING
|
||||
endif
|
||||
|
||||
all: $(TEST_NAME)
|
||||
|
||||
%.o: %.c
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
mdns.o: ../mdns.c
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TEST_NAME): $(OBJECTS)
|
||||
@echo "[LD] $@"
|
||||
@$(LD) $(LDLIBS) $(OBJECTS) -o $@
|
||||
|
||||
fuzz: $(TEST_NAME)
|
||||
@$(FUZZ) -i "in" -o "out" -- ./$(TEST_NAME)
|
||||
|
||||
clean:
|
||||
@rm -rf *.o *.SYM $(TEST_NAME) out
|
58
components/mdns/test_afl_fuzz_host/README.md
Normal file
58
components/mdns/test_afl_fuzz_host/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
## Introduction
|
||||
This test uses [american fuzzy lop](http://lcamtuf.coredump.cx/afl/) to mangle real mdns packets and look for exceptions caused by the parser.
|
||||
|
||||
A few actuall packets are collected and exported as bins in the ```in``` folder, which is then passed as input to AFL when testing. The setup procedure for the test includes all possible services and scenarios that could be used with the given input packets. Output of the parser before fuzzing can be found in [input_packets.txt](input_packets.txt)
|
||||
|
||||
## Installing AFL
|
||||
To run the test yourself, you need to dounload the [latest afl archive](http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz) and extract it to a folder on your computer.
|
||||
|
||||
The rest of the document will refer to that folder as ```PATH_TO_AFL```.
|
||||
|
||||
### Preparation
|
||||
- On Mac, you will need to insall the latest Xcode and llvm support from [Homebrew](https://brew.sh)
|
||||
|
||||
```bash
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
brew install --with-clang --with-lld --HEAD llvm
|
||||
export PATH="/usr/local/opt/llvm/bin:$PATH"
|
||||
```
|
||||
|
||||
- On Ubuntu you need the following packages:
|
||||
|
||||
```bash
|
||||
sudo apt-get install make clang llvm libbsd-dev
|
||||
```
|
||||
|
||||
### Compile AFL
|
||||
Compiling AFL is as easy as running make:
|
||||
|
||||
```bash
|
||||
cd [PATH_TO_AFL]
|
||||
make
|
||||
cd llvm_mode/
|
||||
make
|
||||
```
|
||||
|
||||
After successful compilation, you can export the following variables to your shell (you can also add them to your profile if you want to use afl in other projects)
|
||||
|
||||
```bash
|
||||
export AFL_PATH=[PATH_TO_AFL]
|
||||
export PATH="$AFL_PATH:$PATH"
|
||||
```
|
||||
|
||||
## Running the test
|
||||
Apple has a crash reporting service that could interfere with AFLs normal operation. To turn that off, run the following command:
|
||||
|
||||
```bash
|
||||
launchctl unload -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist
|
||||
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist
|
||||
```
|
||||
|
||||
Ubuntu has a similar service. To turn that off, run as root:
|
||||
|
||||
```bash
|
||||
echo core >/proc/sys/kernel/core_pattern
|
||||
```
|
||||
|
||||
After going through all of the requirements above, you can ```cd``` into this test's folder and simply run ```make fuzz```.
|
||||
|
129
components/mdns/test_afl_fuzz_host/esp32_compat.h
Normal file
129
components/mdns/test_afl_fuzz_host/esp32_compat.h
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright 2015-2016 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.
|
||||
|
||||
#ifndef _ESP32_COMPAT_H_
|
||||
#define _ESP32_COMPAT_H_
|
||||
|
||||
#ifdef MDNS_TEST_MODE
|
||||
|
||||
#ifdef USE_BSD_STRING
|
||||
#include <bsd/string.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ERR_OK 0
|
||||
#define ESP_OK 0
|
||||
#define ESP_FAIL -1
|
||||
|
||||
#define ESP_ERR_NO_MEM 0x101
|
||||
#define ESP_ERR_INVALID_ARG 0x102
|
||||
#define ESP_ERR_INVALID_STATE 0x103
|
||||
#define ESP_ERR_INVALID_SIZE 0x104
|
||||
#define ESP_ERR_NOT_FOUND 0x105
|
||||
#define ESP_ERR_NOT_SUPPORTED 0x106
|
||||
#define ESP_ERR_TIMEOUT 0x107
|
||||
#define ESP_ERR_INVALID_RESPONSE 0x108
|
||||
#define ESP_ERR_INVALID_CRC 0x109
|
||||
|
||||
#define pdTRUE true
|
||||
#define pdFALSE false
|
||||
|
||||
#define portMAX_DELAY 0xFFFFFFFF
|
||||
#define portTICK_PERIOD_MS 1
|
||||
|
||||
#define xSemaphoreTake(s,d)
|
||||
#define xSemaphoreGive(s)
|
||||
#define xSemaphoreCreateMutex() malloc(1)
|
||||
#define vSemaphoreDelete(s) free(s)
|
||||
#define xQueueCreate(n,s) malloc((n)*(s))
|
||||
#define vQueueDelete(q) free(q)
|
||||
#define xQueueReceive(q, d, t) (ESP_OK)
|
||||
#define vTaskDelay(m) usleep((m)*1000)
|
||||
#define pbuf_free(p) free(p)
|
||||
|
||||
#define tcpip_adapter_get_ip_info(i,d)
|
||||
#define tcpip_adapter_get_ip6_linklocal(i,d) (ESP_OK)
|
||||
#define tcpip_adapter_get_hostname(i, n) *(n) = "esp32-0123456789AB"
|
||||
|
||||
#define IP4_ADDR(ipaddr, a,b,c,d) \
|
||||
(ipaddr)->addr = ((uint32_t)((d) & 0xff) << 24) | \
|
||||
((uint32_t)((c) & 0xff) << 16) | \
|
||||
((uint32_t)((b) & 0xff) << 8) | \
|
||||
(uint32_t)((a) & 0xff)
|
||||
|
||||
typedef uint32_t esp_err_t;
|
||||
|
||||
typedef void * xSemaphoreHandle;
|
||||
typedef void * xQueueHandle;
|
||||
|
||||
typedef enum {
|
||||
TCPIP_ADAPTER_IF_STA = 0, /**< ESP32 station interface */
|
||||
TCPIP_ADAPTER_IF_AP, /**< ESP32 soft-AP interface */
|
||||
TCPIP_ADAPTER_IF_ETH, /**< ESP32 ethernet interface */
|
||||
TCPIP_ADAPTER_IF_MAX
|
||||
} tcpip_adapter_if_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_MODE_NULL = 0, /**< null mode */
|
||||
WIFI_MODE_STA, /**< WiFi station mode */
|
||||
WIFI_MODE_AP, /**< WiFi soft-AP mode */
|
||||
WIFI_MODE_APSTA, /**< WiFi station + soft-AP mode */
|
||||
WIFI_MODE_MAX
|
||||
} wifi_mode_t;
|
||||
|
||||
struct udp_pcb {
|
||||
uint8_t dummy;
|
||||
};
|
||||
|
||||
struct ip4_addr {
|
||||
uint32_t addr;
|
||||
};
|
||||
typedef struct ip4_addr ip4_addr_t;
|
||||
|
||||
struct ip6_addr {
|
||||
uint32_t addr[4];
|
||||
};
|
||||
typedef struct ip6_addr ip6_addr_t;
|
||||
|
||||
typedef struct {
|
||||
ip4_addr_t ip;
|
||||
ip4_addr_t netmask;
|
||||
ip4_addr_t gw;
|
||||
} tcpip_adapter_ip_info_t;
|
||||
|
||||
inline esp_err_t esp_wifi_get_mode(wifi_mode_t * mode)
|
||||
{
|
||||
*mode = WIFI_MODE_APSTA;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
inline uint32_t xTaskGetTickCount()
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
if (gettimeofday(&tv, &tz) == 0) {
|
||||
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif //MDNS_TEST_MODE
|
||||
|
||||
#endif //_ESP32_COMPAT_H_
|
BIN
components/mdns/test_afl_fuzz_host/in/test-14.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-14.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-15.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-15.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-16.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-16.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-28.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-28.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-29.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-29.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-31.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-31.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-53.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-53.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-56.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-56.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-63.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-63.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-83.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-83.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-88.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-88.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-89.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-89.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-95.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-95.bin
Executable file
Binary file not shown.
BIN
components/mdns/test_afl_fuzz_host/in/test-96.bin
Executable file
BIN
components/mdns/test_afl_fuzz_host/in/test-96.bin
Executable file
Binary file not shown.
166
components/mdns/test_afl_fuzz_host/input_packets.txt
Normal file
166
components/mdns/test_afl_fuzz_host/input_packets.txt
Normal file
@ -0,0 +1,166 @@
|
||||
Input: in/test-14.bin
|
||||
Packet Length: 568
|
||||
Questions: 18
|
||||
Q: _airport._tcp.local. PTR IN
|
||||
Q: _http._tcp.local. PTR IN
|
||||
Q: _printer._tcp.local. PTR IN
|
||||
Q: _sub._http._tcp.local. PTR IN
|
||||
Q: _airplay._tcp.local. PTR IN
|
||||
Q: _raop._tcp.local. PTR IN
|
||||
Q: _uscan._tcp.local. PTR IN
|
||||
Q: _uscans._tcp.local. PTR IN
|
||||
Q: _ippusb._tcp.local. PTR IN
|
||||
Q: _scanner._tcp.local. PTR IN
|
||||
Q: _ipp._tcp.local. PTR IN
|
||||
Q: _ipps._tcp.local. PTR IN
|
||||
Q: _pdl-datastream._tcp.local. PTR IN
|
||||
Q: _ptp._tcp.local. PTR IN
|
||||
Q: _sleep-proxy._udp.local. PTR IN
|
||||
Q: 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. TXT IN
|
||||
Q: Hristo's AirPort Express._airport._tcp.local. TXT IN
|
||||
Q: Hristo's Time Capsule._airport._tcp.local. TXT IN
|
||||
Answers: 7 + 0
|
||||
A: _airport._tcp.local. PTR IN 2272 [2] Hristo's AirPort Express._airport._tcp.local.
|
||||
A: _airport._tcp.local. PTR IN 2272 [2] Hristo's Time Capsule._airport._tcp.local.
|
||||
A: _http._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._http._tcp.local.
|
||||
A: _printer._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._printer._tcp.local.
|
||||
A: _ipp._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._ipp._tcp.local.
|
||||
A: _pdl-datastream._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._pdl-datastream._tcp.local.
|
||||
A: _sleep-proxy._udp.local. PTR IN 2535 [38] 50-34-10-70.1 Hristo's Time Capsule._sleep-proxy._udp.local.
|
||||
|
||||
Input: in/test-15.bin
|
||||
Packet Length: 524
|
||||
Answers: 3 + 3
|
||||
A: Hristo's AirPort Express._airport._tcp.local. TXT IN FLUSH 4500 [166] waMA=98-01-A7-E5-8F-A1,raMA=98-01-A7-E8-C2-2E,raM2=98-01-A7-E8-C2-2F,raNm=your-ssid,raCh=1,rCh2=52,raSt=0,raNA=1,syFl=0x8A0C,syAP=115,syVs=7.6.8,srcv=76800.1,bjSd=23
|
||||
A: 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. TXT IN FLUSH 4500 [134] txtvers=1; ch=2; cn=0,1; et=0,4; sv=false; da=true; sr=44100; ss=16; pw=false; vn=65537; tp=TCP,UDP; vs=105.1; am=AirPort10,115; fv=76800.1; sf=0x1
|
||||
A: _raop._tcp.local. PTR IN 4500 [2] 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local.
|
||||
A: 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. SRV IN FLUSH 120 [32] 5000 Hristos-AirPort-Express.local.
|
||||
A: Hristo's AirPort Express.local. NSEC IN FLUSH 4500 [9] Hristo's AirPort Express._airport._tcp.local. 00 05 00 00 80 00 40
|
||||
A: 9801A7E58FA1@Hristo's AirPort Express.local. NSEC IN FLUSH 4500 [9] 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. 00 05 00 00 80 00 40
|
||||
|
||||
Input: in/test-16.bin
|
||||
Packet Length: 254
|
||||
Answers: 1 + 1
|
||||
A: Hristo's Time Capsule._airport._tcp.local. TXT IN FLUSH 4500 [168] waMA=70-73-CB-B4-C9-B3,raMA=70-73-CB-BB-04-E7,raM2=70-73-CB-BB-04-E8,raNm=nbis-test,raCh=11,rCh2=132,raSt=0,raNA=0,syFl=0x820C,syAP=116,syVs=7.6.8,srcv=76800.1,bjSd=30
|
||||
A: Hristo's Time Capsule.local. NSEC IN FLUSH 4500 [9] Hristo's Time Capsule._airport._tcp.local. 00 05 00 00 80 00 40
|
||||
|
||||
Input: in/test-28.bin
|
||||
Packet Length: 62
|
||||
Questions: 1
|
||||
Q: Hristo's Time Capsule._afpovertcp._tcp.local. SRV IN FLUSH
|
||||
|
||||
Input: in/test-29.bin
|
||||
Packet Length: 39
|
||||
Questions: 2
|
||||
Q: minifritz.local. A IN FLUSH
|
||||
Q: minifritz.local. AAAA IN FLUSH
|
||||
|
||||
Input: in/test-31.bin
|
||||
Packet Length: 91
|
||||
Answers: 2 + 1
|
||||
A: minifritz.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:142e:54ff:b8c4:fd09
|
||||
A: minifritz.local. A IN FLUSH 120 [4] 192.168.254.16
|
||||
A: minifritz.local. NSEC IN FLUSH 120 [8] minifritz...local. 00 04 40 00 00 08
|
||||
|
||||
Input: in/test-53.bin
|
||||
Packet Length: 140
|
||||
Questions: 2
|
||||
Q: _smb._tcp.local. PTR IN
|
||||
Q: Sofiya-Ivanovas-MacBook.local. A IN
|
||||
Answers: 2 + 0
|
||||
A: _smb._tcp.local. PTR IN 3061 [29] Sofiya Ivanova’s MacBook._smb._tcp.local.
|
||||
A: _smb._tcp.local. PTR IN 3062 [24] Hristo's Time Capsule._smb._tcp.local.
|
||||
|
||||
Input: in/test-56.bin
|
||||
Packet Length: 262
|
||||
Answers: 2 + 6
|
||||
A: Hristo’s Mac mini._device-info._tcp.local. TXT IN 4500 [28] model=Macmini6,2; osxvers=16
|
||||
A: _smb._tcp.local. PTR IN 4500 [22] Hristo’s Mac mini._smb._tcp.local.
|
||||
A: Hristo’s Mac mini._smb._tcp.local. TXT IN FLUSH 4500 [1]
|
||||
A: Hristo’s Mac mini._smb._tcp.local. SRV IN FLUSH 120 [18] 445 minifritz.local.
|
||||
A: minifritz.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:142e:54ff:b8c4:fd09
|
||||
A: minifritz.local. A IN FLUSH 120 [4] 192.168.254.16
|
||||
A: Hristo’s Mac mini.local. NSEC IN FLUSH 4500 [9] Hristo’s Mac mini._smb._tcp.local. 00 05 00 00 80 00 40
|
||||
A: minifritz.local. NSEC IN FLUSH 120 [8] minifritz...local. 00 04 40 00 00 08
|
||||
|
||||
Input: in/test-63.bin
|
||||
Packet Length: 147
|
||||
Questions: 2
|
||||
Q: _afpovertcp._tcp.local. PTR IN
|
||||
Q: Sofiya-Ivanovas-MacBook.local. A IN
|
||||
Answers: 2 + 0
|
||||
A: _afpovertcp._tcp.local. PTR IN 2881 [29] Sofiya Ivanova’s MacBook._afpovertcp._tcp.local.
|
||||
A: _afpovertcp._tcp.local. PTR IN 2881 [24] Hristo's Time Capsule._afpovertcp._tcp.local.
|
||||
|
||||
Input: in/test-66.bin
|
||||
Packet Length: 269
|
||||
Answers: 2 + 6
|
||||
A: Hristo’s Mac mini._device-info._tcp.local. TXT IN 4500 [28] model=Macmini6,2; osxvers=16
|
||||
A: _afpovertcp._tcp.local. PTR IN 4500 [22] Hristo’s Mac mini._afpovertcp._tcp.local.
|
||||
A: Hristo’s Mac mini._afpovertcp._tcp.local. TXT IN FLUSH 4500 [1]
|
||||
A: Hristo’s Mac mini._afpovertcp._tcp.local. SRV IN FLUSH 120 [18] 548 minifritz.local.
|
||||
A: minifritz.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:142e:54ff:b8c4:fd09
|
||||
A: minifritz.local. A IN FLUSH 120 [4] 192.168.254.16
|
||||
A: Hristo’s Mac mini.local. NSEC IN FLUSH 4500 [9] Hristo’s Mac mini._afpovertcp._tcp.local. 00 05 00 00 80 00 40
|
||||
A: minifritz.local. NSEC IN FLUSH 120 [8] minifritz...local. 00 04 40 00 00 08
|
||||
|
||||
Input: in/test-83.bin
|
||||
Packet Length: 105
|
||||
Answers: 1 + 2
|
||||
A: Sofiya-Ivanovas-MacBook.local. A IN FLUSH 120 [4] 192.168.254.20
|
||||
A: Sofiya-Ivanovas-MacBook.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:021c:b3ff:feb2:72a3
|
||||
A: Sofiya-Ivanovas-MacBook.local. NSEC IN FLUSH 120 [8] Sofiya-Ivanovas-MacBook...local. 00 04 40 00 00 08
|
||||
|
||||
Input: in/test-88.bin
|
||||
Packet Length: 48
|
||||
Questions: 2
|
||||
Q: _rfb._tcp.local. PTR IN
|
||||
Q: _airport._tcp.local. PTR IN
|
||||
|
||||
Input: in/test-89.bin
|
||||
Packet Length: 459
|
||||
Answers: 2 + 7
|
||||
A: _airport._tcp.local. PTR IN 4500 [24] Hristo's Time Capsule._airport._tcp.local.
|
||||
A: Hristo's Time Capsule._device-info._tcp.local. TXT IN 4500 [23] model=TimeCapsule6,116
|
||||
A: Hristos-Time-Capsule.local. A IN FLUSH 120 [4] 192.168.254.49
|
||||
A: Hristo's Time Capsule._airport._tcp.local. TXT IN FLUSH 4500 [168] waMA=70-73-CB-B4-C9-B3,raMA=70-73-CB-BB-04-E7,raM2=70-73-CB-BB-04-E8,raNm=nbis-test,raCh=11,rCh2=132,raSt=0,raNA=0,syFl=0x820C,syAP=116,syVs=7.6.8,srcv=76800.1,bjSd=30
|
||||
A: Hristos-Time-Capsule.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:7273:cbff:feb4:c9b3
|
||||
A: Hristo's Time Capsule._airport._tcp.local. SRV IN FLUSH 120 [8] 5009 Hristos-Time-Capsule.local.
|
||||
A: Hristos-Time-Capsule.local. A IN FLUSH 120 [4] 169.254.23.40
|
||||
A: Hristos-Time-Capsule.local. NSEC IN FLUSH 120 [8] Hristos-Time-Capsule...local. 00 04 40 00 00 08
|
||||
A: Hristo's Time Capsule.local. NSEC IN FLUSH 4500 [9] Hristo's Time Capsule._airport._tcp.local. 00 05 00 00 80 00 40
|
||||
|
||||
Input: in/test-91.bin
|
||||
Packet Length: 279
|
||||
Answers: 2 + 6
|
||||
A: Sofiya Ivanova’s MacBook._device-info._tcp.local. TXT IN 4500 [17] model=Macmini2,1
|
||||
A: _rfb._tcp.local. PTR IN 4500 [29] Sofiya Ivanova’s MacBook._rfb._tcp.local.
|
||||
A: Sofiya Ivanova’s MacBook._rfb._tcp.local. TXT IN FLUSH 4500 [1]
|
||||
A: Sofiya Ivanova’s MacBook._rfb._tcp.local. SRV IN FLUSH 120 [32] 5900 Sofiya-Ivanovas-MacBook.local.
|
||||
A: Sofiya-Ivanovas-MacBook.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:021c:b3ff:feb2:72a3
|
||||
A: Sofiya-Ivanovas-MacBook.local. A IN FLUSH 120 [4] 192.168.254.20
|
||||
A: Sofiya Ivanova’s MacBook.local. NSEC IN FLUSH 4500 [9] Sofiya Ivanova’s MacBook._rfb._tcp.local. 00 05 00 00 80 00 40
|
||||
A: Sofiya-Ivanovas-MacBook.local. NSEC IN FLUSH 120 [8] Sofiya-Ivanovas-MacBook...local. 00 04 40 00 00 08
|
||||
|
||||
Input: in/test-95.bin
|
||||
Packet Length: 286
|
||||
Questions: 3
|
||||
Q: _afpovertcp._tcp.local. PTR IN
|
||||
Q: _smb._tcp.local. PTR IN
|
||||
Q: _adisk._tcp.local. PTR IN
|
||||
Answers: 6 + 0
|
||||
A: _afpovertcp._tcp.local. PTR IN 2353 [29] Sofiya Ivanova’s MacBook._afpovertcp._tcp.local.
|
||||
A: _afpovertcp._tcp.local. PTR IN 3973 [22] Hristo’s Mac mini._afpovertcp._tcp.local.
|
||||
A: _afpovertcp._tcp.local. PTR IN 2353 [24] Hristo's Time Capsule._afpovertcp._tcp.local.
|
||||
A: _smb._tcp.local. PTR IN 2353 [29] Sofiya Ivanova’s MacBook._smb._tcp.local.
|
||||
A: _smb._tcp.local. PTR IN 3792 [22] Hristo’s Mac mini._smb._tcp.local.
|
||||
A: _smb._tcp.local. PTR IN 2353 [24] Hristo's Time Capsule._smb._tcp.local.
|
||||
|
||||
Input: in/test-96.bin
|
||||
Packet Length: 319
|
||||
Answers: 2 + 3
|
||||
A: Hristo's Time Capsule._device-info._tcp.local. TXT IN 4500 [23] model=TimeCapsule6,116
|
||||
A: _adisk._tcp.local. PTR IN 4500 [24] Hristo's Time Capsule._adisk._tcp.local.
|
||||
A: Hristo's Time Capsule._adisk._tcp.local. TXT IN FLUSH 4500 [110] sys=waMA=70:73:CB:B4:C9:B3,adVF=0x1000; dk2=adVF=0x1083,adVN=Capsule,adVU=55fabb8b-a63b-5441-9874-6edb504eb30a
|
||||
A: Hristo's Time Capsule._adisk._tcp.local. SRV IN FLUSH 120 [29] 9 Hristos-Time-Capsule.local.
|
||||
A: Hristo's Time Capsule.local. NSEC IN FLUSH 4500 [9] Hristo's Time Capsule._adisk._tcp.local. 00 05 00 00 80 00 40
|
113
components/mdns/test_afl_fuzz_host/test.c
Normal file
113
components/mdns/test_afl_fuzz_host/test.c
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2015-2016 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.
|
||||
|
||||
#ifdef MDNS_TEST_MODE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mdns.h"
|
||||
|
||||
void mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char * mdns_hostname = "minifritz";
|
||||
const char * mdns_instance = "Hristo's Time Capsule";
|
||||
const char * arduTxtData[4] = {
|
||||
"board=esp32",
|
||||
"tcp_check=no",
|
||||
"ssh_upload=no",
|
||||
"auth_upload=no"
|
||||
};
|
||||
const uint8_t mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x32};
|
||||
|
||||
mdns_server_t * mdns = NULL;
|
||||
uint8_t buf[1460];
|
||||
char winstance[21+strlen(mdns_hostname)];
|
||||
|
||||
sprintf(winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", mdns_hostname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
if (mdns_init(TCPIP_ADAPTER_IF_ETH, &mdns)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_set_hostname(mdns, mdns_hostname)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_set_instance(mdns, mdns_instance)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_add(mdns, "_workstation", "_tcp", 9)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_instance_set(mdns, "_workstation", "_tcp", winstance)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_add(mdns, "_arduino", "_tcp", 3232)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_txt_set(mdns, "_arduino", "_tcp", 4, arduTxtData)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_add(mdns, "_http", "_tcp", 80)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_instance_set(mdns, "_http", "_tcp", "ESP WebServer")) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (
|
||||
mdns_service_add(mdns, "_afpovertcp", "_tcp", 548)
|
||||
|| mdns_service_add(mdns, "_rfb", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_smb", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_adisk", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_airport", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_printer", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_airplay", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_raop", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_uscan", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_uscans", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ippusb", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_scanner", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ipp", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ipps", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_pdl-datastream", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ptp", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_sleep-proxy", "_udp", 885))
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
while (__AFL_LOOP(1000)) {
|
||||
memset(buf, 0, 1460);
|
||||
size_t len = read(0, buf, 1460);
|
||||
mdns_query(mdns, "_afpovertcp", "_tcp", 0);
|
||||
mdns_parse_packet(mdns, buf, len);
|
||||
mdns_query_end(mdns);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -38,6 +38,9 @@ Enumerations
|
||||
Structures
|
||||
^^^^^^^^^^
|
||||
|
||||
.. doxygenstruct:: esp_bt_controller_config_t
|
||||
:members:
|
||||
|
||||
.. doxygenstruct:: esp_vhci_host_callback
|
||||
:members:
|
||||
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define A2DP_SINK_TAG "A2DP_SINK"
|
||||
|
||||
extern void bte_main_boot_entry(void *);
|
||||
extern void bt_app_task_start_up(void);
|
||||
@ -15,11 +18,21 @@ extern void bt_app_core_start(void);
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
nvs_flash_init();
|
||||
esp_bt_controller_init();
|
||||
|
||||
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) {
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(A2DP_SINK_TAG, "%s initialize controller failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (ret) {
|
||||
ESP_LOGE(A2DP_SINK_TAG, "%s enable controller failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_app_task_start_up();
|
||||
}
|
||||
|
@ -13,10 +13,13 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "bt.h"
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *tag = "BLE_ADV";
|
||||
|
||||
#define HCI_H4_CMD_PREAMBLE_SIZE (4)
|
||||
|
||||
@ -214,9 +217,15 @@ void bleAdvtTask(void *pvParameters)
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_bt_controller_init();
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
|
||||
if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
|
||||
ESP_LOGI(tag, "Bluetooth controller initialize failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) {
|
||||
ESP_LOGI(tag, "Bluetooth controller enable failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -315,7 +315,11 @@ void app_main()
|
||||
ESP_ERROR_CHECK( nvs_flash_init() );
|
||||
initialise_wifi();
|
||||
|
||||
esp_bt_controller_init();
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
BLUFI_ERROR("%s initialize bt controller failed\n", __func__);
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (ret) {
|
||||
|
8
examples/bluetooth/controller_hci_uart/Makefile
Normal file
8
examples/bluetooth/controller_hci_uart/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := controller_hci_uart
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
7
examples/bluetooth/controller_hci_uart/README.rst
Normal file
7
examples/bluetooth/controller_hci_uart/README.rst
Normal file
@ -0,0 +1,7 @@
|
||||
ESP-IDF UART HCI Controller
|
||||
===========================
|
||||
|
||||
This is a btdm controller use UART as HCI IO. This require the UART device support RTS/CTS mandatory.
|
||||
It can do the configuration of UART number and UART baudrate by menuconfig.
|
||||
|
||||
|
4
examples/bluetooth/controller_hci_uart/main/component.mk
Normal file
4
examples/bluetooth/controller_hci_uart/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -0,0 +1,53 @@
|
||||
// Copyright 2015-2016 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bt.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *tag = "CONTROLLER_UART_HCI";
|
||||
|
||||
static void uart_gpio_reset(void)
|
||||
{
|
||||
#if CONFIG_BT_HCI_UART_NO
|
||||
ESP_LOGI(tag, "HCI UART%d Pin select: TX 5, RX, 18, CTS 23, RTS 19", CONFIG_BT_HCI_UART_NO);
|
||||
|
||||
uart_set_pin(CONFIG_BT_HCI_UART_NO, 5, 18, 19, 23);
|
||||
#endif
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
/* As the UART1/2 pin conflict with flash pin, so do matrix of the signal and pin */
|
||||
uart_gpio_reset();
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(tag, "Bluetooth Controller initialize failed, ret %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(tag, "Bluetooth Controller initialize failed, ret %d", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
10
examples/bluetooth/controller_hci_uart/sdkconfig.defaults
Normal file
10
examples/bluetooth/controller_hci_uart/sdkconfig.defaults
Normal file
@ -0,0 +1,10 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_HCI_UART=y
|
||||
CONFIG_BT_HCI_UART_NO_DEFAULT=1
|
||||
CONFIG_BT_HCI_UART_BAUDRATE_DEFAULT=921600
|
@ -402,7 +402,8 @@ void gattc_client_test(void)
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_bt_controller_init();
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
esp_bt_controller_init(&bt_cfg);
|
||||
esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
|
||||
gattc_client_test();
|
||||
|
@ -398,7 +398,12 @@ void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
esp_bt_controller_init();
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTS_TAG, "%s initialize controller failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (ret) {
|
||||
|
@ -313,7 +313,12 @@ void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
esp_bt_controller_init();
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (ret) {
|
||||
|
@ -1,170 +0,0 @@
|
||||
import yaml
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
|
||||
MODULE_MAP = yaml.load(open("ModuleDefinition.yml", "r"))
|
||||
|
||||
TEST_CASE_PATTERN = {
|
||||
"initial condition": "UTINIT1",
|
||||
"SDK": "ESP32_IDF",
|
||||
"level": "Unit",
|
||||
"execution time": 0,
|
||||
"Test App": "UT",
|
||||
"auto test": "Yes",
|
||||
"category": "Function",
|
||||
"test point 1": "basic function",
|
||||
"version": "v1 (2016-12-06)",
|
||||
"test environment": "UT_T1_1",
|
||||
"expected result": "1. set succeed"
|
||||
}
|
||||
|
||||
CONFIG_FILE_PATTERN = {
|
||||
"Config": {"execute count": 1, "execute order": "in order"},
|
||||
"DUT": [],
|
||||
"Filter": [{"Add": {"ID": []}}]
|
||||
}
|
||||
|
||||
test_cases = list()
|
||||
test_ids = {}
|
||||
test_ids_by_job = {}
|
||||
unit_jobs = {}
|
||||
|
||||
os.chdir(os.path.join("..", ".."))
|
||||
IDF_PATH = os.getcwd()
|
||||
|
||||
|
||||
class Parser(object):
|
||||
@classmethod
|
||||
def parse_test_folders(cls):
|
||||
test_folder_paths = list()
|
||||
os.chdir(os.path.join(IDF_PATH, "components"))
|
||||
component_dirs = [d for d in os.listdir(".") if os.path.isdir(d)]
|
||||
for dir in component_dirs:
|
||||
os.chdir(dir)
|
||||
if "test" in os.listdir("."):
|
||||
test_folder_paths.append(os.path.join(os.getcwd(), "test"))
|
||||
os.chdir("..")
|
||||
Parser.parse_test_files(test_folder_paths)
|
||||
|
||||
@classmethod
|
||||
def parse_test_files(cls, test_folder_paths):
|
||||
for path in test_folder_paths:
|
||||
os.chdir(path)
|
||||
for file_path in os.listdir("."):
|
||||
if file_path[-2:] == ".c":
|
||||
Parser.read_test_file(os.path.join(os.getcwd(), file_path), len(test_cases)+1)
|
||||
os.chdir(os.path.join("..", ".."))
|
||||
Parser.dump_test_cases(test_cases)
|
||||
|
||||
@classmethod
|
||||
def read_test_file(cls, test_file_path, file_index):
|
||||
test_index = 0
|
||||
with open(test_file_path, "r") as file:
|
||||
for line in file:
|
||||
if re.match("TEST_CASE", line):
|
||||
test_index += 1
|
||||
tags = re.split(r"[\[\]\"]", line)
|
||||
Parser.parse_test_cases(file_index, test_index, tags)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parse_test_cases(cls, file_index, test_index, tags):
|
||||
ci_ready = "Yes"
|
||||
test_env = "UT_T1_1"
|
||||
for tag in tags:
|
||||
if tag == "ignore":
|
||||
ci_ready = "No"
|
||||
if re.match("test_env=", tag):
|
||||
test_env = tag[9:]
|
||||
module_name = tags[4]
|
||||
try:
|
||||
MODULE_MAP[module_name]
|
||||
except KeyError:
|
||||
module_name = "misc"
|
||||
id = "UT_%s_%s_%03d%02d" % (MODULE_MAP[module_name]['module abbr'],
|
||||
MODULE_MAP[module_name]['sub module abbr'],
|
||||
file_index, test_index)
|
||||
test_case = dict(TEST_CASE_PATTERN)
|
||||
test_case.update({"module": MODULE_MAP[module_name]['module'],
|
||||
"CI ready": ci_ready,
|
||||
"cmd set": ["IDFUnitTest/UnitTest", [tags[1]]],
|
||||
"ID": id,
|
||||
"test point 2": module_name,
|
||||
"steps": tags[1],
|
||||
"comment": tags[1],
|
||||
"test environment": test_env,
|
||||
"sub module": MODULE_MAP[module_name]['sub module'],
|
||||
"summary": tags[1]})
|
||||
if test_case["CI ready"] == "Yes":
|
||||
if test_ids.has_key(test_env):
|
||||
test_ids[test_env].append(id)
|
||||
else:
|
||||
test_ids.update({test_env: [id]})
|
||||
test_cases.append(test_case)
|
||||
|
||||
@classmethod
|
||||
def dump_test_cases(cls, test_cases):
|
||||
os.chdir(os.path.join(IDF_PATH, "components", "idf_test", "unit_test"))
|
||||
with open ("TestCaseAll.yml", "wb+") as f:
|
||||
yaml.dump({"test cases": test_cases}, f, allow_unicode=True, default_flow_style=False)
|
||||
|
||||
@classmethod
|
||||
def dump_ci_config(cls):
|
||||
Parser.split_test_cases()
|
||||
os.chdir(os.path.join(IDF_PATH, "components", "idf_test", "unit_test"))
|
||||
if not os.path.exists("CIConfigs"):
|
||||
os.makedirs("CIConfigs")
|
||||
os.chdir("CIConfigs")
|
||||
for unit_job in unit_jobs:
|
||||
job = dict(CONFIG_FILE_PATTERN)
|
||||
job.update({"DUT": ["UT1"]})
|
||||
job.update({"Filter": [{"Add": {"ID": test_ids_by_job[unit_job]}}]})
|
||||
with open (unit_job + ".yml", "wb+") as f:
|
||||
yaml.dump(job, f, allow_unicode=True, default_flow_style=False)
|
||||
|
||||
@classmethod
|
||||
def split_test_cases(cls):
|
||||
for job in unit_jobs:
|
||||
test_ids_by_job.update({job: list()})
|
||||
for test_env in test_ids:
|
||||
available_jobs = list()
|
||||
for job in unit_jobs:
|
||||
if test_env in unit_jobs[job]:
|
||||
available_jobs.append(job)
|
||||
for idx, job in enumerate(available_jobs):
|
||||
test_ids_by_job[job] += (test_ids[test_env][idx*len(test_ids[test_env])/len(available_jobs):(idx+1)*len(test_ids[test_env])/len(available_jobs)])
|
||||
|
||||
@classmethod
|
||||
def parse_gitlab_ci(cls):
|
||||
os.chdir(IDF_PATH)
|
||||
with open(".gitlab-ci.yml", "rb") as f:
|
||||
gitlab_ci = yaml.load(f)
|
||||
keys = gitlab_ci.keys()
|
||||
for key in keys:
|
||||
if re.match("UT_", key):
|
||||
test_env = gitlab_ci[key]["tags"]
|
||||
unit_job = key
|
||||
key = {}
|
||||
key.update({unit_job: test_env})
|
||||
unit_jobs.update(key)
|
||||
|
||||
@classmethod
|
||||
def copy_module_def_file(cls):
|
||||
src = os.path.join(IDF_PATH, "tools", "unit-test-app", "ModuleDefinition.yml")
|
||||
dst = os.path.join(IDF_PATH, "components", "idf_test", "unit_test")
|
||||
shutil.copy(src, dst)
|
||||
|
||||
|
||||
def main():
|
||||
Parser.parse_test_folders()
|
||||
Parser.parse_gitlab_ci()
|
||||
Parser.dump_ci_config()
|
||||
Parser.copy_module_def_file()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
163
tools/unit-test-app/tools/CreateSectionTable.py
Normal file
163
tools/unit-test-app/tools/CreateSectionTable.py
Normal file
@ -0,0 +1,163 @@
|
||||
# This file is used to process section data generated by `objdump -s`
|
||||
import re
|
||||
|
||||
|
||||
class Section(object):
|
||||
"""
|
||||
One Section of section table. contains info about section name, address and raw data
|
||||
"""
|
||||
SECTION_START_PATTERN = re.compile("Contents of section (.+?):")
|
||||
DATA_PATTERN = re.compile("([0-9a-f]{4,8})")
|
||||
|
||||
def __init__(self, name, start_address, data):
|
||||
self.name = name
|
||||
self.start_address = start_address
|
||||
self.data = data
|
||||
|
||||
def __contains__(self, item):
|
||||
""" check if the section name and address match this section """
|
||||
if (item["section"] == self.name or item["section"] == "any") \
|
||||
and (self.start_address <= item["address"] < (self.start_address + len(self.data))):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __getitem__(self, item):
|
||||
"""
|
||||
process slice.
|
||||
convert absolute address to relative address in current section and return slice result
|
||||
"""
|
||||
if isinstance(item, int):
|
||||
return self.data[item - self.start_address]
|
||||
elif isinstance(item, slice):
|
||||
start = item.start if item.start is None else item.start - self.start_address
|
||||
stop = item.stop if item.stop is None else item.stop - self.start_address
|
||||
return self.data[start:stop]
|
||||
return self.data[item]
|
||||
|
||||
def __str__(self):
|
||||
return "%s [%08x - %08x]" % (self.name, self.start_address, self.start_address + len(self.data))
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
@classmethod
|
||||
def parse_raw_data(cls, raw_data):
|
||||
"""
|
||||
process raw data generated by `objdump -s`, create section and return un-processed lines
|
||||
:param raw_data: lines of raw data generated by `objdump -s`
|
||||
:return: one section, un-processed lines
|
||||
"""
|
||||
name = ""
|
||||
data = ""
|
||||
start_address = 0
|
||||
# first find start line
|
||||
for i, line in enumerate(raw_data):
|
||||
if "Contents of section " in line: # do strcmp first to speed up
|
||||
match = cls.SECTION_START_PATTERN.search(line)
|
||||
if match is not None:
|
||||
name = match.group(1)
|
||||
raw_data = raw_data[i + 1:]
|
||||
break
|
||||
else:
|
||||
# do some error handling
|
||||
raw_data = [""] # add a dummy first data line
|
||||
|
||||
def process_data_line(line_to_process):
|
||||
# first remove the ascii part
|
||||
hex_part = line_to_process.split(" ")[0]
|
||||
# process rest part
|
||||
data_list = cls.DATA_PATTERN.findall(hex_part)
|
||||
try:
|
||||
_address = int(data_list[0], base=16)
|
||||
except IndexError:
|
||||
_address = -1
|
||||
|
||||
def hex_to_str(hex_data):
|
||||
if len(hex_data) % 2 == 1:
|
||||
hex_data = "0" + hex_data # append zero at the beginning
|
||||
_length = len(hex_data)
|
||||
return "".join([chr(int(hex_data[_i:_i + 2], base=16))
|
||||
for _i in range(0, _length, 2)])
|
||||
|
||||
return _address, "".join([hex_to_str(x) for x in data_list[1:]])
|
||||
|
||||
# handle first line:
|
||||
address, _data = process_data_line(raw_data[0])
|
||||
if address != -1:
|
||||
start_address = address
|
||||
data += _data
|
||||
raw_data = raw_data[1:]
|
||||
for i, line in enumerate(raw_data):
|
||||
address, _data = process_data_line(line)
|
||||
if address == -1:
|
||||
raw_data = raw_data[i:]
|
||||
break
|
||||
else:
|
||||
data += _data
|
||||
else:
|
||||
# do error handling
|
||||
raw_data = []
|
||||
|
||||
section = cls(name, start_address, data) if start_address != -1 else None
|
||||
unprocessed_data = None if len(raw_data) == 0 else raw_data
|
||||
return section, unprocessed_data
|
||||
|
||||
|
||||
class SectionTable(object):
|
||||
""" elf section table """
|
||||
|
||||
def __init__(self, file_name):
|
||||
with open(file_name, "rb") as f:
|
||||
raw_data = f.readlines()
|
||||
self.table = []
|
||||
while raw_data:
|
||||
section, raw_data = Section.parse_raw_data(raw_data)
|
||||
self.table.append(section)
|
||||
|
||||
def get_unsigned_int(self, section, address, size=4, endian="LE"):
|
||||
"""
|
||||
get unsigned int from section table
|
||||
:param section: section name; use "any" will only match with address
|
||||
:param address: start address
|
||||
:param size: size in bytes
|
||||
:param endian: LE or BE
|
||||
:return: int or None
|
||||
"""
|
||||
if address % 4 != 0 or size % 4 != 0:
|
||||
print("warning: try to access without 4 bytes aligned")
|
||||
key = {"address": address, "section": section}
|
||||
for section in self.table:
|
||||
if key in section:
|
||||
tmp = section[address:address+size]
|
||||
value = 0
|
||||
for i in range(size):
|
||||
if endian == "LE":
|
||||
value += ord(tmp[i]) << (i*8)
|
||||
elif endian == "BE":
|
||||
value += ord(tmp[i]) << ((size - i - 1) * 8)
|
||||
else:
|
||||
print("only support LE or BE for parameter endian")
|
||||
assert False
|
||||
break
|
||||
else:
|
||||
value = None
|
||||
return value
|
||||
|
||||
def get_string(self, section, address):
|
||||
"""
|
||||
get string ('\0' terminated) from section table
|
||||
:param section: section name; use "any" will only match with address
|
||||
:param address: start address
|
||||
:return: string or None
|
||||
"""
|
||||
value = None
|
||||
key = {"address": address, "section": section}
|
||||
for section in self.table:
|
||||
if key in section:
|
||||
value = section[address:]
|
||||
for i, c in enumerate(value):
|
||||
if c == '\0':
|
||||
value = value[:i]
|
||||
break
|
||||
break
|
||||
return value
|
8
tools/unit-test-app/tools/TagDefinition.yml
Normal file
8
tools/unit-test-app/tools/TagDefinition.yml
Normal file
@ -0,0 +1,8 @@
|
||||
ignore:
|
||||
# if the type exist but no value assigned
|
||||
default: "Yes"
|
||||
# if the type is not exist in tag list
|
||||
omitted: "No"
|
||||
test_env:
|
||||
default: "UT_T1_1"
|
||||
omitted: "UT_T1_1"
|
262
tools/unit-test-app/tools/UnitTestParser.py
Normal file
262
tools/unit-test-app/tools/UnitTestParser.py
Normal file
@ -0,0 +1,262 @@
|
||||
import yaml
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from copy import deepcopy
|
||||
import CreateSectionTable
|
||||
|
||||
|
||||
TEST_CASE_PATTERN = {
|
||||
"initial condition": "UTINIT1",
|
||||
"SDK": "ESP32_IDF",
|
||||
"level": "Unit",
|
||||
"execution time": 0,
|
||||
"Test App": "UT",
|
||||
"auto test": "Yes",
|
||||
"category": "Function",
|
||||
"test point 1": "basic function",
|
||||
"version": "v1 (2016-12-06)",
|
||||
"test environment": "UT_T1_1",
|
||||
"expected result": "1. set succeed"
|
||||
}
|
||||
|
||||
CONFIG_FILE_PATTERN = {
|
||||
"Config": {"execute count": 1, "execute order": "in order"},
|
||||
"DUT": [],
|
||||
"Filter": [{"Add": {"ID": []}}]
|
||||
}
|
||||
|
||||
|
||||
class Parser(object):
|
||||
""" parse unit test cases from build files and create files for test bench """
|
||||
|
||||
TAG_PATTERN = re.compile("([^=]+)(=)?(.+)?")
|
||||
DESCRIPTION_PATTERN = re.compile("\[([^]\[]+)\]")
|
||||
|
||||
def __init__(self, idf_path=os.getenv("IDF_PATH")):
|
||||
self.test_env_tags = {}
|
||||
self.unit_jobs = {}
|
||||
self.file_name_cache = {}
|
||||
self.idf_path = idf_path
|
||||
self.tag_def = yaml.load(open(os.path.join(idf_path, "tools", "unit-test-app", "tools",
|
||||
"TagDefinition.yml"), "r"))
|
||||
self.module_map = yaml.load(open(os.path.join(idf_path, "tools", "unit-test-app", "tools",
|
||||
"ModuleDefinition.yml"), "r"))
|
||||
|
||||
def parse_test_cases_from_elf(self, elf_file):
|
||||
"""
|
||||
parse test cases from elf and save test cases to unit test folder
|
||||
:param elf_file: elf file path
|
||||
"""
|
||||
subprocess.check_output('xtensa-esp32-elf-objdump -t {} | grep \ test_desc > case_address.tmp'.format(elf_file),
|
||||
shell=True)
|
||||
subprocess.check_output('xtensa-esp32-elf-objdump -s {} > section_table.tmp'.format(elf_file), shell=True)
|
||||
|
||||
table = CreateSectionTable.SectionTable("section_table.tmp")
|
||||
test_cases = []
|
||||
with open("case_address.tmp", "r") as f:
|
||||
for line in f:
|
||||
# process symbol table like: "3ffb4310 l O .dram0.data 00000018 test_desc_33$5010"
|
||||
line = line.split()
|
||||
test_addr = int(line[0], 16)
|
||||
section = line[3]
|
||||
|
||||
name_addr = table.get_unsigned_int(section, test_addr, 4)
|
||||
desc_addr = table.get_unsigned_int(section, test_addr + 4, 4)
|
||||
file_name_addr = table.get_unsigned_int(section, test_addr + 12, 4)
|
||||
name = table.get_string("any", name_addr)
|
||||
desc = table.get_string("any", desc_addr)
|
||||
file_name = table.get_string("any", file_name_addr)
|
||||
|
||||
tc = self.parse_one_test_case(name, desc, file_name)
|
||||
if tc["CI ready"] == "Yes":
|
||||
# update test env list and the cases of same env list
|
||||
if tc["test environment"] in self.test_env_tags:
|
||||
self.test_env_tags[tc["test environment"]].append(tc["ID"])
|
||||
else:
|
||||
self.test_env_tags.update({tc["test environment"]: [tc]})
|
||||
test_cases.append(tc)
|
||||
|
||||
os.remove("section_table.tmp")
|
||||
os.remove("case_address.tmp")
|
||||
|
||||
self.dump_test_cases(test_cases)
|
||||
|
||||
def parse_case_properities(self, tags_raw):
|
||||
"""
|
||||
parse test case tags (properities) with the following rules:
|
||||
* first tag is always group of test cases, it's mandatory
|
||||
* the rest tags should be [type=value].
|
||||
* if the type have default value, then [type] equal to [type=default_value].
|
||||
* if the type don't don't exist, then equal to [type=omitted_value]
|
||||
default_value and omitted_value are defined in TagDefinition.yml
|
||||
:param tags_raw: raw tag string
|
||||
:return: tag dict
|
||||
"""
|
||||
tags = self.DESCRIPTION_PATTERN.findall(tags_raw)
|
||||
assert len(tags) > 0
|
||||
p = dict([(k, self.tag_def[k]["omitted"]) for k in self.tag_def])
|
||||
p["module"] = tags[0]
|
||||
|
||||
if p["module"] not in self.module_map:
|
||||
p["module"] = "misc"
|
||||
|
||||
# parsing rest tags, [type=value], =value is optional
|
||||
for tag in tags[1:]:
|
||||
match = self.TAG_PATTERN.search(tag)
|
||||
assert match is not None
|
||||
tag_type = match.group(1)
|
||||
tag_value = match.group(3)
|
||||
if match.group(2) == "=" and tag_value is None:
|
||||
# [tag_type=] means tag_value is empty string
|
||||
tag_value = ""
|
||||
if tag_type in p:
|
||||
if tag_value is None:
|
||||
p[tag_type] = self.tag_def[tag_type]["default"]
|
||||
else:
|
||||
p[tag_type] = tag_value
|
||||
else:
|
||||
# ignore not defined tag type
|
||||
pass
|
||||
return p
|
||||
|
||||
def parse_one_test_case(self, name, description, file_name):
|
||||
"""
|
||||
parse one test case
|
||||
:param name: test case name (summary)
|
||||
:param description: test case description (tag string)
|
||||
:param file_name: the file defines this test case
|
||||
:return: parsed test case
|
||||
"""
|
||||
prop = self.parse_case_properities(description)
|
||||
|
||||
if file_name in self.file_name_cache:
|
||||
self.file_name_cache[file_name] += 1
|
||||
else:
|
||||
self.file_name_cache[file_name] = 1
|
||||
|
||||
tc_id = "UT_%s_%s_%03d%02d" % (self.module_map[prop["module"]]['module abbr'],
|
||||
self.module_map[prop["module"]]['sub module abbr'],
|
||||
hash(file_name) % 1000,
|
||||
self.file_name_cache[file_name])
|
||||
test_case = deepcopy(TEST_CASE_PATTERN)
|
||||
test_case.update({"module": self.module_map[prop["module"]]['module'],
|
||||
"CI ready": "No" if prop["ignore"] == "Yes" else "Yes",
|
||||
"cmd set": ["IDFUnitTest/UnitTest", [name]],
|
||||
"ID": tc_id,
|
||||
"test point 2": prop["module"],
|
||||
"steps": name,
|
||||
"test environment": prop["test_env"],
|
||||
"sub module": self.module_map[prop["module"]]['sub module'],
|
||||
"summary": name})
|
||||
return test_case
|
||||
|
||||
def dump_test_cases(self, test_cases):
|
||||
"""
|
||||
dump parsed test cases to YAML file for test bench input
|
||||
:param test_cases: parsed test cases
|
||||
"""
|
||||
with open(os.path.join(self.idf_path, "components", "idf_test", "unit_test", "TestCaseAll.yml"), "wb+") as f:
|
||||
yaml.dump({"test cases": test_cases}, f, allow_unicode=True, default_flow_style=False)
|
||||
|
||||
def dump_ci_config(self):
|
||||
""" assign test cases and dump to config file to test bench """
|
||||
test_cases_by_jobs = self.assign_test_cases()
|
||||
|
||||
ci_config_folder = os.path.join(self.idf_path, "components", "idf_test", "unit_test", "CIConfigs")
|
||||
|
||||
if not os.path.exists(ci_config_folder):
|
||||
os.makedirs(os.path.join(ci_config_folder, "CIConfigs"))
|
||||
|
||||
for unit_job in self.unit_jobs:
|
||||
job = deepcopy(CONFIG_FILE_PATTERN)
|
||||
job.update({"DUT": ["UT1"]})
|
||||
job.update({"Filter": [{"Add": {"ID": test_cases_by_jobs[unit_job]}}]})
|
||||
|
||||
with open(os.path.join(ci_config_folder, unit_job + ".yml"), "wb+") as f:
|
||||
yaml.dump(job, f, allow_unicode=True, default_flow_style=False)
|
||||
|
||||
def assign_test_cases(self):
|
||||
""" assign test cases to jobs """
|
||||
test_cases_by_jobs = {}
|
||||
|
||||
for job in self.unit_jobs:
|
||||
test_cases_by_jobs.update({job: list()})
|
||||
for test_env in self.test_env_tags:
|
||||
available_jobs = list()
|
||||
for job in self.unit_jobs:
|
||||
if test_env in self.unit_jobs[job]:
|
||||
available_jobs.append(job)
|
||||
for idx, job in enumerate(available_jobs):
|
||||
test_cases_by_jobs[job] += (self.test_env_tags[test_env]
|
||||
[idx*len(self.test_env_tags[test_env])/len(available_jobs):
|
||||
(idx+1)*len(self.test_env_tags[test_env])/len(available_jobs)])
|
||||
return test_cases_by_jobs
|
||||
|
||||
def parse_gitlab_ci(self):
|
||||
""" parse gitlab ci config file to get pre-defined unit test jobs """
|
||||
with open(os.path.join(self.idf_path, ".gitlab-ci.yml"), "r") as f:
|
||||
gitlab_ci = yaml.load(f)
|
||||
keys = gitlab_ci.keys()
|
||||
for key in keys:
|
||||
if re.match("UT_", key):
|
||||
test_env = gitlab_ci[key]["tags"]
|
||||
unit_job = key
|
||||
key = {}
|
||||
key.update({unit_job: test_env})
|
||||
self.unit_jobs.update(key)
|
||||
|
||||
def copy_module_def_file(self):
|
||||
""" copy module def file to artifact path """
|
||||
src = os.path.join(self.idf_path, "tools", "unit-test-app", "tools", "ModuleDefinition.yml")
|
||||
dst = os.path.join(self.idf_path, "components", "idf_test", "unit_test")
|
||||
shutil.copy(src, dst)
|
||||
|
||||
|
||||
def test_parser():
|
||||
parser = Parser()
|
||||
# test parsing tags
|
||||
# parsing module only and module in module list
|
||||
prop = parser.parse_case_properities("[esp32]")
|
||||
assert prop["module"] == "esp32"
|
||||
# module not in module list
|
||||
prop = parser.parse_case_properities("[not_in_list]")
|
||||
assert prop["module"] == "misc"
|
||||
# parsing a default tag, a tag with assigned value
|
||||
prop = parser.parse_case_properities("[esp32][ignore][test_env=ABCD][not_support1][not_support2=ABCD]")
|
||||
assert prop["ignore"] == "Yes" and prop["test_env"] == "ABCD" \
|
||||
and "not_support1" not in prop and "not_supported2" not in prop
|
||||
# parsing omitted value
|
||||
prop = parser.parse_case_properities("[esp32]")
|
||||
assert prop["ignore"] == "No" and prop["test_env"] == "UT_T1_1"
|
||||
# parsing with incorrect format
|
||||
try:
|
||||
parser.parse_case_properities("abcd")
|
||||
assert False
|
||||
except AssertionError:
|
||||
pass
|
||||
# skip invalid data parse, [type=] assigns empty string to type
|
||||
prop = parser.parse_case_properities("[esp32]abdc aaaa [ignore=]")
|
||||
assert prop["module"] == "esp32" and prop["ignore"] == ""
|
||||
# skip mis-paired []
|
||||
prop = parser.parse_case_properities("[esp32][[ignore=b]][]][test_env=AAA]]")
|
||||
assert prop["module"] == "esp32" and prop["ignore"] == "b" and prop["test_env"] == "AAA"
|
||||
|
||||
|
||||
def main():
|
||||
test_parser()
|
||||
|
||||
idf_path = os.getenv("IDF_PATH")
|
||||
elf_path = os.path.join(idf_path, "tools", "unit-test-app", "build", "unit-test-app.elf")
|
||||
|
||||
parser = Parser(idf_path)
|
||||
parser.parse_test_cases_from_elf(elf_path)
|
||||
parser.parse_gitlab_ci()
|
||||
parser.dump_ci_config()
|
||||
parser.copy_module_def_file()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user