diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c index 21a0d55..a9dac2d 100644 --- a/FreeRTOS/Source/portable/esp8266/port.c +++ b/FreeRTOS/Source/portable/esp8266/port.c @@ -73,6 +73,7 @@ #include #include #include +#include #include "FreeRTOS.h" #include "task.h" @@ -87,7 +88,7 @@ char level1_int_disabled; After tasks start, task stacks are all allocated from the heap and FreeRTOS checks for stack overflow. */ -static uint32_t xPortSupervisorStackPointer; +uint32_t xPortSupervisorStackPointer; /* * Stack initialization @@ -220,7 +221,7 @@ size_t xPortGetFreeHeapSize( void ) uint32_t sp = xPortSupervisorStackPointer; if(sp == 0) /* scheduler not started */ - __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp)); + SP(sp); return sp - brk_val + mi.fordblks; } diff --git a/common.mk b/common.mk index 8da70cd..c8fee7a 100644 --- a/common.mk +++ b/common.mk @@ -75,6 +75,9 @@ FLAVOR ?= release # or debug # Compiler names, etc. assume gdb CROSS ?= xtensa-lx106-elf- +# Path to the filteroutput.py tool +FILTEROUTPUT ?= $(ROOT)/utils/filteroutput.py + AR = $(CROSS)ar CC = $(CROSS)gcc CPP = $(CROSS)cpp @@ -385,7 +388,7 @@ size: $(PROGRAM_OUT) $(Q) $(CROSS)size --format=sysv $(PROGRAM_OUT) test: flash - screen $(ESPPORT) 115200 + $(FILTEROUTPUT) --port $(ESPPORT) --baud 115200 --elf $(PROGRAM_OUT) # the rebuild target is written like this so it can be run in a parallel build # environment without causing weird side effects diff --git a/core/app_main.c b/core/app_main.c index 45f7e2f..a38fb5f 100644 --- a/core/app_main.c +++ b/core/app_main.c @@ -39,8 +39,6 @@ void user_init(void); #define RTCMEM_BACKUP_PHY_VER 31 #define RTCMEM_SYSTEM_PP_VER 62 -#define halt() while (1) {} - extern uint32_t _bss_start; extern uint32_t _bss_end; @@ -63,7 +61,6 @@ static void IRAM set_spi0_divisor(uint32_t divisor); static void zero_bss(void); static void init_networking(sdk_phy_info_t *phy_info, uint8_t *mac_addr); static void init_g_ic(void); -static void dump_excinfo(void); static void user_start_phase2(void); static void dump_flash_sector(uint32_t start_sector, uint32_t length); static void dump_flash_config_sectors(uint32_t start_sector); @@ -80,11 +77,11 @@ static void IRAM get_otp_mac_address(uint8_t *buf) { if (!(otp_flags & 0x8000)) { //FIXME: do we really need this check? printf("Firmware ONLY supports ESP8266!!!\n"); - halt(); + abort(); } if (otp_id0 == 0 && otp_id1 == 0) { printf("empty otp\n"); - halt(); + abort(); } if (otp_flags & 0x1000) { // If bit 12 is set, it indicates that the vendor portion of the MAC @@ -125,23 +122,6 @@ static void IRAM set_spi0_divisor(uint32_t divisor) { SPI(0).CTRL0 = SET_FIELD(SPI(0).CTRL0, SPI_CTRL0_CLOCK, clkdiv); } -// .text+0x148 -void IRAM sdk_user_fatal_exception_handler(void) { - if (!sdk_NMIIrqIsOn) { - vPortEnterCritical(); - do { - DPORT.DPORT0 &= 0xffffffe0; - } while (DPORT.DPORT0 & 0x00000001); - } - Cache_Read_Disable(); - Cache_Read_Enable(0, 0, 1); - dump_excinfo(); - uart_flush_txfifo(0); - uart_flush_txfifo(1); - sdk_system_restart_in_nmi(); - halt(); -} - static void IRAM default_putc(char c) { uart_putc(0, c); @@ -255,7 +235,7 @@ static void zero_bss(void) { static void init_networking(sdk_phy_info_t *phy_info, uint8_t *mac_addr) { if (sdk_register_chipv6_phy(phy_info)) { printf("FATAL: sdk_register_chipv6_phy failed"); - halt(); + abort(); } uart_set_baud(0, 74906); uart_set_baud(1, 74906); @@ -311,37 +291,6 @@ static void init_g_ic(void) { } } -// .Lfunc008 -- .irom0.text+0x2a0 -static void dump_excinfo(void) { - uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1; - uint32_t excinfo[8]; - - RSR(exccause, exccause); - printf("Fatal exception (%d): \n", (int)exccause); - RSR(epc1, epc1); - RSR(epc2, epc2); - RSR(epc3, epc3); - RSR(excvaddr, excvaddr); - RSR(depc, depc); - RSR(excsave1, excsave1); - printf("%s=0x%08x\n", "epc1", epc1); - printf("%s=0x%08x\n", "epc2", epc2); - printf("%s=0x%08x\n", "epc3", epc3); - printf("%s=0x%08x\n", "excvaddr", excvaddr); - printf("%s=0x%08x\n", "depc", depc); - printf("%s=0x%08x\n", "excsave1", excsave1); - sdk_system_rtc_mem_read(0, excinfo, 32); // Why? - excinfo[0] = 2; - excinfo[1] = exccause; - excinfo[2] = epc1; - excinfo[3] = epc2; - excinfo[4] = epc3; - excinfo[5] = excvaddr; - excinfo[6] = depc; - excinfo[7] = excsave1; - sdk_system_rtc_mem_write(0, excinfo, 32); -} - // .irom0.text+0x398 void sdk_wdt_init(void) { WDT.CTRL &= ~WDT_CTRL_ENABLE; diff --git a/core/debug_dumps.c b/core/debug_dumps.c new file mode 100644 index 0000000..7f1a1ca --- /dev/null +++ b/core/debug_dumps.c @@ -0,0 +1,231 @@ +/* Code for dumping status/debug output/etc, including fatal + * exception handling & abort implementation. + * + * Part of esp-open-rtos + * + * Partially reverse engineered from MIT licensed Espressif RTOS SDK Copyright (C) Espressif Systems. + * Additions Copyright (C) 2015 Superhouse Automation Pty Ltd + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include +#include + +#include "debug_dumps.h" +#include "common_macros.h" +#include "xtensa_ops.h" +#include "esp/rom.h" +#include "esp/uart.h" +#include "espressif/esp_common.h" +#include "sdk_internal.h" + +/* Forward declarations */ +static void IRAM fatal_handler_prelude(void); +/* Inner parts of crash handlers */ +typedef void __attribute__((noreturn)) (*fatal_exception_handler_fn)(uint32_t *sp, bool registers_saved_on_stack); +static void __attribute__((noreturn)) standard_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack); +static void __attribute__((noreturn)) second_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack); +static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_inner(uint32_t *caller, uint32_t *sp); + +static IRAM_DATA fatal_exception_handler_fn fatal_exception_handler_inner = standard_fatal_exception_handler_inner; + +/* fatal_exception_handler called from any unhandled user exception + * + * (similar to a hard fault on other processor architectures) + * + * This function is run from IRAM, but the majority of the handler + * runs from flash after fatal_handler_prelude ensures it is mapped + * safely. + */ +void IRAM __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp, bool registers_saved_on_stack) { + fatal_handler_prelude(); + fatal_exception_handler_fn inner_fn = fatal_exception_handler_inner; + inner_fn(sp, registers_saved_on_stack); +} + +/* Abort implementation + * + * Replaces the weak-linked abort implementation provided by newlib libc. + * + * Disable interrupts, enable flash mapping, dump stack & caller + * address, restart. + * + * This function is run from IRAM, but the majority of the abort + * handler runs from flash after fatal_handler_prelude ensures it is + * mapped safely. + * + */ +void IRAM abort(void) { + uint32_t *sp, *caller; + RETADDR(caller); + /* abort() caller is one instruction before our return address */ + caller = (uint32_t *)((intptr_t)caller - 3); + SP(sp); + fatal_handler_prelude(); + abort_handler_inner(caller, sp); +} + +/* Dump exception information from special function registers */ +static void dump_excinfo(void) { + uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1; + uint32_t excinfo[8]; + + RSR(exccause, exccause); + printf("Fatal exception (%d): \n", (int)exccause); + RSR(epc1, epc1); + RSR(epc2, epc2); + RSR(epc3, epc3); + RSR(excvaddr, excvaddr); + RSR(depc, depc); + RSR(excsave1, excsave1); + printf("%s=0x%08x\n", "epc1", epc1); + printf("%s=0x%08x\n", "epc2", epc2); + printf("%s=0x%08x\n", "epc3", epc3); + printf("%s=0x%08x\n", "excvaddr", excvaddr); + printf("%s=0x%08x\n", "depc", depc); + printf("%s=0x%08x\n", "excsave1", excsave1); + sdk_system_rtc_mem_read(0, excinfo, 32); // Why? + excinfo[0] = 2; + excinfo[1] = exccause; + excinfo[2] = epc1; + excinfo[3] = epc2; + excinfo[4] = epc3; + excinfo[5] = excvaddr; + excinfo[6] = depc; + excinfo[7] = excsave1; + sdk_system_rtc_mem_write(0, excinfo, 32); +} + +/* dump stack memory (frames above sp) to stdout + + There's a lot of smart stuff we could do while dumping stack + but for now we just dump what looks like our stack region. + + Probably dumps more memory than it needs to, the first instance of + 0xa5a5a5a5 probably constitutes the end of our stack. +*/ +void dump_stack(uint32_t *sp) { + printf("\nStack: SP=%p\n", sp); + for(uint32_t *p = sp; p < sp + 32; p += 4) { + if((intptr_t)p >= 0x3fffc000) { + break; /* approximate end of RAM */ + } + printf("%p: %08x %08x %08x %08x\n", p, p[0], p[1], p[2], p[3]); + if(p[0] == 0xa5a5a5a5 && p[1] == 0xa5a5a5a5 + && p[2] == 0xa5a5a5a5 && p[3] == 0xa5a5a5a5) { + break; /* FreeRTOS uses this pattern to mark untouched stack space */ + } + } +} + +/* Dump normal registers that were stored above 'sp' + by the exception handler preamble +*/ +void dump_registers_in_exception_handler(uint32_t *sp) { + uint32_t excsave1; + uint32_t *saved = sp - (0x50 / sizeof(uint32_t)); + printf("Registers:\n"); + RSR(excsave1, excsave1); + printf("a0 %08x ", excsave1); + printf("a1 %08x ", (intptr_t)sp); + for(int a = 2; a < 14; a++) { + printf("a%-2d %08x%c", a, saved[a+3], a == 3 || a == 7 || a == 11 ? '\n':' '); + } + printf("SAR %08x\n", saved[0x13]); +} + +static void __attribute__((noreturn)) post_crash_reset(void) { + uart_flush_txfifo(0); + uart_flush_txfifo(1); + sdk_system_restart_in_nmi(); + while(1) {} +} + +/* Prelude ensures exceptions/NMI off and flash is mapped, allowing + calls to non-IRAM functions. +*/ +static void IRAM fatal_handler_prelude(void) { + if (!sdk_NMIIrqIsOn) { + vPortEnterCritical(); + do { + DPORT.DPORT0 &= 0xffffffe0; + } while (DPORT.DPORT0 & 0x00000001); + } + Cache_Read_Disable(); + Cache_Read_Enable(0, 0, 1); +} + +/* Main part of fatal exception handler, is run from flash to save + some IRAM. +*/ +static void standard_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack) { + /* Replace the fatal exception handler 'inner' function so we + don't end up in a crash loop if this handler crashes. */ + fatal_exception_handler_inner = second_fatal_exception_handler_inner; + dump_excinfo(); + if (sp) { + if (registers_saved_on_stack) { + dump_registers_in_exception_handler(sp); + } + dump_stack(sp); + } + dump_heapinfo(); + post_crash_reset(); +} + +/* This is the exception handler that gets called if a crash occurs inside the standard handler, + so we don't end up in a crash loop. It doesn't rely on contents of stack or heap. +*/ +static void second_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack) { + dump_excinfo(); + printf("Second fatal exception occured inside fatal exception handler. Can't continue.\n"); + post_crash_reset(); +} + +void dump_heapinfo(void) +{ + extern char _heap_start; + extern uint32_t xPortSupervisorStackPointer; + struct mallinfo mi = mallinfo(); + uint32_t brk_val = (uint32_t) sbrk(0); + uint32_t sp = xPortSupervisorStackPointer; + if(sp == 0) { + SP(sp); + } + + /* Total free heap is all memory that could be allocated via + malloc (assuming fragmentation doesn't become a problem) */ + printf("\nFree Heap: %d\n", sp - brk_val + mi.fordblks); + + /* delta between brk & supervisor sp is the contiguous memory + region that is available to be put into heap space via + brk(). */ + printf("_heap_start %p brk 0x%08x supervisor sp 0x%08x sp-brk %d bytes\n", + &_heap_start, brk_val, sp, sp-brk_val); + + /* arena/fordblks/uordblks determines the amount of free space + inside the heap region already added via brk(). May be + fragmented. + + The values in parentheses are the values used internally by + nano-mallocr.c, the field names outside parentheses are the + POSIX compliant field names of the mallinfo structure. + + "arena" should be equal to brk-_heap_start ie total size available. + */ + printf("arena (total_size) %d fordblks (free_size) %d uordblocks (used_size) %d\n", + mi.arena, mi.fordblks, mi.uordblks); +} + +/* Main part of abort handler, can be run from flash to save some + IRAM. +*/ +static void abort_handler_inner(uint32_t *caller, uint32_t *sp) { + printf("abort() invoked at %p.\n", caller); + dump_stack(sp); + dump_heapinfo(); + post_crash_reset(); +} diff --git a/core/esp_interrupts.c b/core/esp_interrupts.c index 4fd68b7..b3aefff 100644 --- a/core/esp_interrupts.c +++ b/core/esp_interrupts.c @@ -9,6 +9,8 @@ _xt_isr isr[16]; +bool esp_in_isr; + void IRAM _xt_isr_attach(uint8_t i, _xt_isr func) { isr[i] = func; @@ -20,6 +22,8 @@ void IRAM _xt_isr_attach(uint8_t i, _xt_isr func) */ uint16_t IRAM _xt_isr_handler(uint16_t intset) { + esp_in_isr = true; + /* WDT has highest priority (occasional WDT resets otherwise) */ if(intset & BIT(INUM_WDT)) { _xt_clear_ints(BIT(INUM_WDT)); @@ -35,5 +39,7 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset) intset -= mask; } + esp_in_isr = false; + return 0; } diff --git a/core/exception_vectors.S b/core/exception_vectors.S index c1f1761..000e742 100644 --- a/core/exception_vectors.S +++ b/core/exception_vectors.S @@ -68,7 +68,9 @@ DebugExceptionVector: .type DebugExceptionVector, @function wsr a0, excsave2 - call0 sdk_user_fatal_exception_handler + mov a2, a1 + movi a3, 0 + call0 fatal_exception_handler rfi 2 .org VecBase + 0x20 @@ -81,7 +83,9 @@ KernelExceptionVector: .type KernelExceptionVector, @function break 1, 0 - call0 sdk_user_fatal_exception_handler + mov a2, a1 + movi a3, 0 + call0 fatal_exception_handler rfe .org VecBase + 0x50 @@ -98,7 +102,9 @@ DoubleExceptionVector: .type DoubleExceptionVector, @function break 1, 4 - call0 sdk_user_fatal_exception_handler + mov a2, a1 + movi a3, 0 + call0 fatal_exception_handler /* Reset vector at offset 0x80 is unused, as vecbase gets reset to mask ROM * vectors on chip reset. */ @@ -251,11 +257,13 @@ LoadStoreErrorHandler: * will have correct values */ wsr a0, sar l32i a0, sp, 0 - l32i a2, sp, 0x08 + /*l32i a2, sp, 0x08*/ l32i a3, sp, 0x0c l32i a4, sp, 0x10 rsr a1, excsave1 - call0 sdk_user_fatal_exception_handler + mov a2, a1 + movi a3, 0 + call0 fatal_exception_handler .balign 4 .LSE_assign_a1: @@ -515,7 +523,9 @@ UserExceptionHandler: .literal_position .LUserFailOtherExceptionCause: break 1, 1 - call0 sdk_user_fatal_exception_handler + addi a2, a1, 0x50 /* UserExceptionHandler pushes stack down 0x50 */ + movi a3, 1 + call0 fatal_exception_handler /* _xt_user_exit is pushed onto the stack as part of the user exception handler, restores same set registers which were saved there and returns from exception */ diff --git a/core/include/common_macros.h b/core/include/common_macros.h index 7c6dd56..4aa6248 100644 --- a/core/include/common_macros.h +++ b/core/include/common_macros.h @@ -65,18 +65,16 @@ */ #define IRAM __attribute__((section(".iram1.text"))) -/* Use this macro to place read-only data into Instruction RAM (IRAM) +/* Use this macro to place data into Instruction RAM (IRAM) instead of loaded into rodata which resides in DRAM. + (IRAM can also be written to as necessary.) + This may be useful to free up data RAM. However all data read from the instruction space must be 32-bit aligned word reads (non-aligned reads will use an interrupt routine to "fix" them and still work, but are very slow.. */ -#ifdef __cplusplus - #define IRAM_DATA __attribute__((section(".iram1.rodata"))) -#else - #define IRAM_DATA __attribute__((section(".iram1.rodata"))) const -#endif +#define IRAM_DATA __attribute__((section(".iram1.rodata"))) #endif diff --git a/core/include/debug_dumps.h b/core/include/debug_dumps.h new file mode 100644 index 0000000..ab3c972 --- /dev/null +++ b/core/include/debug_dumps.h @@ -0,0 +1,25 @@ +/* Functions for dumping status/debug output/etc, including fatal + * exception handling. + * + * Part of esp-open-rtos + * + * Copyright (C) 2015-2016 Superhouse Automation Pty Ltd + * BSD Licensed as described in the file LICENSE + */ +#ifndef _DEBUG_DUMPS_H +#define _DEBUG_DUMPS_H +#include + +/* Dump stack memory to stdout, starting from stack pointer address sp. */ +void dump_stack(uint32_t *sp); + +/* Dump heap statistics to stdout */ +void dump_heapinfo(void); + +/* Called from exception_vectors.S when a fatal exception occurs. + + Probably not useful to be called in other contexts. +*/ +void __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp, bool registers_saved_on_stack); + +#endif diff --git a/core/include/xtensa_ops.h b/core/include/xtensa_ops.h index 49d1fbe..52eba2a 100644 --- a/core/include/xtensa_ops.h +++ b/core/include/xtensa_ops.h @@ -14,6 +14,20 @@ // GCC macros for reading, writing, and exchanging Xtensa processor special // registers: +/* Read stack pointer to variable. + * + * Note that the compiler will push a stack frame (minimum 16 bytes) + * in the prelude of a C function that calls any other functions. + */ +#define SP(var) asm volatile ("mov %0, a1" : "=r" (var)) + +/* Read the function return address to a variable. + * + * Depends on the containing function being simple enough that a0 is + * being used as a working register. + */ +#define RETADDR(var) asm volatile ("mov %0, a0" : "=r" (var)) + #define RSR(var, reg) asm volatile ("rsr %0, " #reg : "=r" (var)); #define WSR(var, reg) asm volatile ("wsr %0, " #reg : : "r" (var)); #define XSR(var, reg) asm volatile ("xsr %0, " #reg : "+r" (var)); diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c index b414481..0d4b95e 100644 --- a/core/newlib_syscalls.c +++ b/core/newlib_syscalls.c @@ -25,7 +25,7 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr) if (heap_end + incr > stack_ptr) { _write (1, "_sbrk: Heap collided with stack\n", 32); - while(1) {} + abort(); } */ heap_end += incr; diff --git a/examples/experiments/unaligned_load/unaligned_load.c b/examples/experiments/unaligned_load/unaligned_load.c index 258b4d0..4244804 100644 --- a/examples/experiments/unaligned_load/unaligned_load.c +++ b/examples/experiments/unaligned_load/unaligned_load.c @@ -305,7 +305,7 @@ static void test_system_interaction() } uint32_t ticks = xTaskGetTickCount() - start; printf("Timer interaction test PASSED after %dms.\n", ticks*portTICK_RATE_MS); - while(1) {} + abort(); } /* The following "sanity tests" are designed to try to execute every code path diff --git a/examples/http_get_mbedtls/http_get_mbedtls.c b/examples/http_get_mbedtls/http_get_mbedtls.c index 017f8fc..7aad0e3 100644 --- a/examples/http_get_mbedtls/http_get_mbedtls.c +++ b/examples/http_get_mbedtls/http_get_mbedtls.c @@ -115,7 +115,7 @@ void http_get_task(void *pvParameters) strlen(pers))) != 0) { printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); - while(1) {} /* todo: replace with abort() */ + abort(); } printf(" ok\n"); @@ -129,7 +129,7 @@ void http_get_task(void *pvParameters) if(ret < 0) { printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); - while(1) {} /* todo: replace with abort() */ + abort(); } printf(" ok (%d skipped)\n", ret); @@ -138,7 +138,7 @@ void http_get_task(void *pvParameters) if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) { printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); - while(1) {} /* todo: replace with abort() */ + abort(); } /* diff --git a/examples/tls_server/tls_server.c b/examples/tls_server/tls_server.c index d253bc9..9030dc0 100644 --- a/examples/tls_server/tls_server.c +++ b/examples/tls_server/tls_server.c @@ -85,7 +85,7 @@ void tls_server_task(void *pvParameters) strlen(pers))) != 0) { printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); - while(1) {} /* todo: replace with abort() */ + abort(); } printf(" ok\n"); @@ -99,7 +99,7 @@ void tls_server_task(void *pvParameters) if(ret < 0) { printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); - while(1) {} /* todo: replace with abort() */ + abort(); } printf(" ok (%d skipped)\n", ret); @@ -109,7 +109,7 @@ void tls_server_task(void *pvParameters) if(ret != 0) { printf(" failed\n ! mbedtls_pk_parse_key returned - 0x%x\n\n", -ret); - while(1) { } /*todo: replace with abort() */ + abort(); } printf(" ok\n"); @@ -134,7 +134,7 @@ void tls_server_task(void *pvParameters) if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) { printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); - while(1) { } + abort(); } mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); diff --git a/libc/xtensa-lx106-elf/lib/libc.a b/libc/xtensa-lx106-elf/lib/libc.a index 6a256cd..a43b5ed 100644 Binary files a/libc/xtensa-lx106-elf/lib/libc.a and b/libc/xtensa-lx106-elf/lib/libc.a differ diff --git a/libc/xtensa-lx106-elf/lib/libg.a b/libc/xtensa-lx106-elf/lib/libg.a index 6a256cd..4d3d50a 100644 Binary files a/libc/xtensa-lx106-elf/lib/libg.a and b/libc/xtensa-lx106-elf/lib/libg.a differ diff --git a/libc/xtensa-lx106-elf/lib/libm.a b/libc/xtensa-lx106-elf/lib/libm.a index 7d96963..2e9a859 100644 Binary files a/libc/xtensa-lx106-elf/lib/libm.a and b/libc/xtensa-lx106-elf/lib/libm.a differ diff --git a/lwip/include/arch/cc.h b/lwip/include/arch/cc.h index a09ea0c..04dab26 100644 --- a/lwip/include/arch/cc.h +++ b/lwip/include/arch/cc.h @@ -94,7 +94,7 @@ typedef int sys_prot_t; _Pragma("GCC diagnostic pop") \ } while(0) #define LWIP_PLATFORM_ASSERT(x) do { printf("Assertion \"%s\" failed at line %d in %s\n", \ - x, __LINE__, __FILE__); while(1) {} } while(0) + x, __LINE__, __FILE__); abort(); } while(0) #define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \ diff --git a/lwip/sys_arch.c b/lwip/sys_arch.c index f625fc6..ad936e4 100644 --- a/lwip/sys_arch.c +++ b/lwip/sys_arch.c @@ -1,585 +1,592 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -//***************************************************************************** -// -// Include OS functionality. -// -//***************************************************************************** - -/* ------------------------ System architecture includes ----------------------------- */ -#include "arch/sys_arch.h" - -/* ------------------------ lwIP includes --------------------------------- */ -#include "lwip/opt.h" - -#include "lwip/err.h" -#include "lwip/debug.h" -#include "lwip/def.h" -#include "lwip/sys.h" -#include "lwip/mem.h" -#include "lwip/stats.h" - -/* Very crude mechanism used to determine if the critical section handling -functions are being called from an interrupt context or not. This relies on -the interrupt handler setting this variable manually. */ -portBASE_TYPE xInsideISR = pdFALSE; - -/*---------------------------------------------------------------------------* - * Routine: sys_mbox_new - *---------------------------------------------------------------------------* - * Description: - * Creates a new mailbox - * Inputs: - * int size -- Size of elements in the mailbox - * Outputs: - * sys_mbox_t -- Handle to new mailbox - *---------------------------------------------------------------------------*/ -err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize ) -{ -err_t xReturn = ERR_MEM; - - *pxMailBox = xQueueCreate( iSize, sizeof( void * ) ); - - if( *pxMailBox != NULL ) - { - xReturn = ERR_OK; - SYS_STATS_INC_USED( mbox ); - } - - return xReturn; -} - - -/*---------------------------------------------------------------------------* - * Routine: sys_mbox_free - *---------------------------------------------------------------------------* - * Description: - * Deallocates a mailbox. If there are messages still present in the - * mailbox when the mailbox is deallocated, it is an indication of a - * programming error in lwIP and the developer should be notified. - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * Outputs: - * sys_mbox_t -- Handle to new mailbox - *---------------------------------------------------------------------------*/ -void sys_mbox_free( sys_mbox_t *pxMailBox ) -{ -unsigned long ulMessagesWaiting; - - ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox ); - configASSERT( ( ulMessagesWaiting == 0 ) ); - - #if SYS_STATS - { - if( ulMessagesWaiting != 0UL ) - { - SYS_STATS_INC( mbox.err ); - } - - SYS_STATS_DEC( mbox.used ); - } - #endif /* SYS_STATS */ - - vQueueDelete( *pxMailBox ); -} - -/*---------------------------------------------------------------------------* - * Routine: sys_mbox_post - *---------------------------------------------------------------------------* - * Description: - * Post the "msg" to the mailbox. - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * void *data -- Pointer to data to post - *---------------------------------------------------------------------------*/ -void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost ) -{ - while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE ); -} - -/*---------------------------------------------------------------------------* - * Routine: sys_mbox_trypost - *---------------------------------------------------------------------------* - * Description: - * Try to post the "msg" to the mailbox. Returns immediately with - * error if cannot. - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * void *msg -- Pointer to data to post - * Outputs: - * err_t -- ERR_OK if message posted, else ERR_MEM - * if not. - *---------------------------------------------------------------------------*/ -err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost ) -{ -err_t xReturn; -portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - - if( xInsideISR != pdFALSE ) - { - xReturn = xQueueSendFromISR( *pxMailBox, &pxMessageToPost, &xHigherPriorityTaskWoken ); - } - else - { - xReturn = xQueueSend( *pxMailBox, &pxMessageToPost, ( portTickType ) 0 ); - } - - if( xReturn == pdPASS ) - { - xReturn = ERR_OK; - } - else - { - /* The queue was already full. */ - xReturn = ERR_MEM; - SYS_STATS_INC( mbox.err ); - } - - return xReturn; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_arch_mbox_fetch - *---------------------------------------------------------------------------* - * Description: - * Blocks the thread until a message arrives in the mailbox, but does - * not block the thread longer than "timeout" milliseconds (similar to - * the sys_arch_sem_wait() function). The "msg" argument is a result - * parameter that is set by the function (i.e., by doing "*msg = - * ptr"). The "msg" parameter maybe NULL to indicate that the message - * should be dropped. - * - * The return values are the same as for the sys_arch_sem_wait() function: - * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a - * timeout. - * - * Note that a function with a similar name, sys_mbox_fetch(), is - * implemented by lwIP. - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * void **msg -- Pointer to pointer to msg received - * u32_t timeout -- Number of milliseconds until timeout - * Outputs: - * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number - * of milliseconds until received. - *---------------------------------------------------------------------------*/ -u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut ) -{ -void *pvDummy; -portTickType xStartTime, xEndTime, xElapsed; -unsigned long ulReturn; - - xStartTime = xTaskGetTickCount(); - - if( NULL == ppvBuffer ) - { - ppvBuffer = &pvDummy; - } - - if( ulTimeOut != 0UL ) - { - configASSERT( xInsideISR == ( portBASE_TYPE ) 0 ); - - if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_RATE_MS ) ) - { - xEndTime = xTaskGetTickCount(); - xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS; - - ulReturn = xElapsed; - } - else - { - /* Timed out. */ - *ppvBuffer = NULL; - ulReturn = SYS_ARCH_TIMEOUT; - } - } - else - { - while( pdTRUE != xQueueReceive( *pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) ); - xEndTime = xTaskGetTickCount(); - xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS; - - if( xElapsed == 0UL ) - { - xElapsed = 1UL; - } - - ulReturn = xElapsed; - } - - return ulReturn; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_arch_mbox_tryfetch - *---------------------------------------------------------------------------* - * Description: - * Similar to sys_arch_mbox_fetch, but if message is not ready - * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is - * returned. - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * void **msg -- Pointer to pointer to msg received - * Outputs: - * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise, - * return ERR_OK. - *---------------------------------------------------------------------------*/ -u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer ) -{ -void *pvDummy; -unsigned long ulReturn; -long lResult; -portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - - if( ppvBuffer== NULL ) - { - ppvBuffer = &pvDummy; - } - - if( xInsideISR != pdFALSE ) - { - lResult = xQueueReceiveFromISR( *pxMailBox, &( *ppvBuffer ), &xHigherPriorityTaskWoken ); - } - else - { - lResult = xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL ); - } - - if( lResult == pdPASS ) - { - ulReturn = ERR_OK; - } - else - { - ulReturn = SYS_MBOX_EMPTY; - } - - return ulReturn; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_sem_new - *---------------------------------------------------------------------------* - * Description: - * Creates and returns a new semaphore. The "ucCount" argument specifies - * the initial state of the semaphore. - * NOTE: Currently this routine only creates counts of 1 or 0 - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * u8_t ucCount -- Initial ucCount of semaphore (1 or 0) - * Outputs: - * sys_sem_t -- Created semaphore or 0 if could not create. - *---------------------------------------------------------------------------*/ -err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount ) -{ -err_t xReturn = ERR_MEM; - - vSemaphoreCreateBinary( ( *pxSemaphore ) ); - - if( *pxSemaphore != NULL ) - { - if( ucCount == 0U ) - { - xSemaphoreTake( *pxSemaphore, 1UL ); - } - - xReturn = ERR_OK; - SYS_STATS_INC_USED( sem ); - } - else - { - SYS_STATS_INC( sem.err ); - } - - return xReturn; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_arch_sem_wait - *---------------------------------------------------------------------------* - * Description: - * Blocks the thread while waiting for the semaphore to be - * signaled. If the "timeout" argument is non-zero, the thread should - * only be blocked for the specified time (measured in - * milliseconds). - * - * If the timeout argument is non-zero, the return value is the number of - * milliseconds spent waiting for the semaphore to be signaled. If the - * semaphore wasn't signaled within the specified time, the return value is - * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore - * (i.e., it was already signaled), the function may return zero. - * - * Notice that lwIP implements a function with a similar name, - * sys_sem_wait(), that uses the sys_arch_sem_wait() function. - * Inputs: - * sys_sem_t sem -- Semaphore to wait on - * u32_t timeout -- Number of milliseconds until timeout - * Outputs: - * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT. - *---------------------------------------------------------------------------*/ -u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout ) -{ -portTickType xStartTime, xEndTime, xElapsed; -unsigned long ulReturn; - - xStartTime = xTaskGetTickCount(); - - if( ulTimeout != 0UL ) - { - if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_RATE_MS ) == pdTRUE ) - { - xEndTime = xTaskGetTickCount(); - xElapsed = (xEndTime - xStartTime) * portTICK_RATE_MS; - ulReturn = xElapsed; - } - else - { - ulReturn = SYS_ARCH_TIMEOUT; - } - } - else - { - while( xSemaphoreTake( *pxSemaphore, portMAX_DELAY ) != pdTRUE ); - xEndTime = xTaskGetTickCount(); - xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS; - - if( xElapsed == 0UL ) - { - xElapsed = 1UL; - } - - ulReturn = xElapsed; - } - - return ulReturn; -} - -/** Create a new mutex - * @param mutex pointer to the mutex to create - * @return a new mutex */ -err_t sys_mutex_new( sys_mutex_t *pxMutex ) -{ -err_t xReturn = ERR_MEM; - - *pxMutex = xSemaphoreCreateMutex(); - - if( *pxMutex != NULL ) - { - xReturn = ERR_OK; - SYS_STATS_INC_USED( mutex ); - } - else - { - SYS_STATS_INC( mutex.err ); - } - - return xReturn; -} - -/** Lock a mutex - * @param mutex the mutex to lock */ -void sys_mutex_lock( sys_mutex_t *pxMutex ) -{ - while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS ); -} - -/** Unlock a mutex - * @param mutex the mutex to unlock */ -void sys_mutex_unlock(sys_mutex_t *pxMutex ) -{ - xSemaphoreGive( *pxMutex ); -} - - -/** Delete a semaphore - * @param mutex the mutex to delete */ -void sys_mutex_free( sys_mutex_t *pxMutex ) -{ - SYS_STATS_DEC( mutex.used ); - vQueueDelete( *pxMutex ); -} - - -/*---------------------------------------------------------------------------* - * Routine: sys_sem_signal - *---------------------------------------------------------------------------* - * Description: - * Signals (releases) a semaphore - * Inputs: - * sys_sem_t sem -- Semaphore to signal - *---------------------------------------------------------------------------*/ -void sys_sem_signal( sys_sem_t *pxSemaphore ) -{ -portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - - if( xInsideISR != pdFALSE ) - { - xSemaphoreGiveFromISR( *pxSemaphore, &xHigherPriorityTaskWoken ); - } - else - { - xSemaphoreGive( *pxSemaphore ); - } -} - -/*---------------------------------------------------------------------------* - * Routine: sys_sem_free - *---------------------------------------------------------------------------* - * Description: - * Deallocates a semaphore - * Inputs: - * sys_sem_t sem -- Semaphore to free - *---------------------------------------------------------------------------*/ -void sys_sem_free( sys_sem_t *pxSemaphore ) -{ - SYS_STATS_DEC(sem.used); - vQueueDelete( *pxSemaphore ); -} - -/*---------------------------------------------------------------------------* - * Routine: sys_init - *---------------------------------------------------------------------------* - * Description: - * Initialize sys arch - *---------------------------------------------------------------------------*/ -void sys_init(void) -{ -} - -u32_t sys_now(void) -{ - return xTaskGetTickCount(); -} - -/*---------------------------------------------------------------------------* - * Routine: sys_thread_new - *---------------------------------------------------------------------------* - * Description: - * Starts a new thread with priority "prio" that will begin its - * execution in the function "thread()". The "arg" argument will be - * passed as an argument to the thread() function. The id of the new - * thread is returned. Both the id and the priority are system - * dependent. - * Inputs: - * char *name -- Name of thread - * void (* thread)(void *arg) -- Pointer to function to run. - * void *arg -- Argument passed into function - * int stacksize -- Required stack amount in bytes - * int prio -- Thread priority - * Outputs: - * sys_thread_t -- Pointer to per-thread timeouts. - *---------------------------------------------------------------------------*/ -sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority ) -{ -xTaskHandle xCreatedTask; -portBASE_TYPE xResult; -sys_thread_t xReturn; - - xResult = xTaskCreate( pxThread, ( signed char * ) pcName, iStackSize, pvArg, iPriority, &xCreatedTask ); - - if( xResult == pdPASS ) - { - xReturn = xCreatedTask; - } - else - { - xReturn = NULL; - } - - return xReturn; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_arch_protect - *---------------------------------------------------------------------------* - * Description: - * This optional function does a "fast" critical region protection and - * returns the previous protection level. This function is only called - * during very short critical regions. An embedded system which supports - * ISR-based drivers might want to implement this function by disabling - * interrupts. Task-based systems might want to implement this by using - * a mutex or disabling tasking. This function should support recursive - * calls from the same task or interrupt. In other words, - * sys_arch_protect() could be called while already protected. In - * that case the return value indicates that it is already protected. - * - * sys_arch_protect() is only required if your port is supporting an - * operating system. - * Outputs: - * sys_prot_t -- Previous protection level (not used here) - *---------------------------------------------------------------------------*/ -sys_prot_t sys_arch_protect( void ) -{ - if( xInsideISR == pdFALSE ) - { - taskENTER_CRITICAL(); - } - return ( sys_prot_t ) 1; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_arch_unprotect - *---------------------------------------------------------------------------* - * Description: - * This optional function does a "fast" set of critical region - * protection to the value specified by pval. See the documentation for - * sys_arch_protect() for more information. This function is only - * required if your port is supporting an operating system. - * Inputs: - * sys_prot_t -- Previous protection level (not used here) - *---------------------------------------------------------------------------*/ -void sys_arch_unprotect( sys_prot_t xValue ) -{ - (void) xValue; - if( xInsideISR == pdFALSE ) - { - taskEXIT_CRITICAL(); - } -} - -/* - * Prints an assertion messages and aborts execution. - */ -void sys_assert( const char *pcMessage ) -{ - (void) pcMessage; - - for (;;) - { - } -} -/*-------------------------------------------------------------------------* - * End of File: sys_arch.c - *-------------------------------------------------------------------------*/ - +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +//***************************************************************************** +// +// Include OS functionality. +// +//***************************************************************************** + +/* ------------------------ System architecture includes ----------------------------- */ +#include "arch/sys_arch.h" + +/* ------------------------ lwIP includes --------------------------------- */ +#include "lwip/opt.h" + +#include "lwip/err.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/stats.h" + +extern bool esp_in_isr; + +/* Based on the default xInsideISR mechanism to determine + if an ISR is running. + + Doesn't support the possibility that LWIP functions are called from the NMI + handler (none are called from NMI when using current/SDK implementation.) +*/ +static inline bool is_inside_isr() +{ + return esp_in_isr; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_mbox_new + *---------------------------------------------------------------------------* + * Description: + * Creates a new mailbox + * Inputs: + * int size -- Size of elements in the mailbox + * Outputs: + * sys_mbox_t -- Handle to new mailbox + *---------------------------------------------------------------------------*/ +err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize ) +{ + err_t xReturn = ERR_MEM; + + *pxMailBox = xQueueCreate( iSize, sizeof( void * ) ); + + if( *pxMailBox != NULL ) + { + xReturn = ERR_OK; + SYS_STATS_INC_USED( mbox ); + } + + return xReturn; +} + + +/*---------------------------------------------------------------------------* + * Routine: sys_mbox_free + *---------------------------------------------------------------------------* + * Description: + * Deallocates a mailbox. If there are messages still present in the + * mailbox when the mailbox is deallocated, it is an indication of a + * programming error in lwIP and the developer should be notified. + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * Outputs: + * sys_mbox_t -- Handle to new mailbox + *---------------------------------------------------------------------------*/ +void sys_mbox_free( sys_mbox_t *pxMailBox ) +{ +unsigned long ulMessagesWaiting; + + ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox ); + configASSERT( ( ulMessagesWaiting == 0 ) ); + + #if SYS_STATS + { + if( ulMessagesWaiting != 0UL ) + { + SYS_STATS_INC( mbox.err ); + } + + SYS_STATS_DEC( mbox.used ); + } + #endif /* SYS_STATS */ + + vQueueDelete( *pxMailBox ); +} + +/*---------------------------------------------------------------------------* + * Routine: sys_mbox_post + *---------------------------------------------------------------------------* + * Description: + * Post the "msg" to the mailbox. + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * void *data -- Pointer to data to post + *---------------------------------------------------------------------------*/ +void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost ) +{ + while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE ); +} + +/*---------------------------------------------------------------------------* + * Routine: sys_mbox_trypost + *---------------------------------------------------------------------------* + * Description: + * Try to post the "msg" to the mailbox. Returns immediately with + * error if cannot. + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * void *msg -- Pointer to data to post + * Outputs: + * err_t -- ERR_OK if message posted, else ERR_MEM + * if not. + *---------------------------------------------------------------------------*/ +err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost ) +{ +err_t xReturn; +portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + if( is_inside_isr() != pdFALSE ) + { + xReturn = xQueueSendFromISR( *pxMailBox, &pxMessageToPost, &xHigherPriorityTaskWoken ); + } + else + { + xReturn = xQueueSend( *pxMailBox, &pxMessageToPost, ( portTickType ) 0 ); + } + + if( xReturn == pdPASS ) + { + xReturn = ERR_OK; + } + else + { + /* The queue was already full. */ + xReturn = ERR_MEM; + SYS_STATS_INC( mbox.err ); + } + + return xReturn; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_arch_mbox_fetch + *---------------------------------------------------------------------------* + * Description: + * Blocks the thread until a message arrives in the mailbox, but does + * not block the thread longer than "timeout" milliseconds (similar to + * the sys_arch_sem_wait() function). The "msg" argument is a result + * parameter that is set by the function (i.e., by doing "*msg = + * ptr"). The "msg" parameter maybe NULL to indicate that the message + * should be dropped. + * + * The return values are the same as for the sys_arch_sem_wait() function: + * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a + * timeout. + * + * Note that a function with a similar name, sys_mbox_fetch(), is + * implemented by lwIP. + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * void **msg -- Pointer to pointer to msg received + * u32_t timeout -- Number of milliseconds until timeout + * Outputs: + * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number + * of milliseconds until received. + *---------------------------------------------------------------------------*/ +u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut ) +{ +void *pvDummy; +portTickType xStartTime, xEndTime, xElapsed; +unsigned long ulReturn; + + xStartTime = xTaskGetTickCount(); + + if( NULL == ppvBuffer ) + { + ppvBuffer = &pvDummy; + } + + if( ulTimeOut != 0UL ) + { + configASSERT( is_inside_isr() == ( portBASE_TYPE ) 0 ); + + if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_RATE_MS ) ) + { + xEndTime = xTaskGetTickCount(); + xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS; + + ulReturn = xElapsed; + } + else + { + /* Timed out. */ + *ppvBuffer = NULL; + ulReturn = SYS_ARCH_TIMEOUT; + } + } + else + { + while( pdTRUE != xQueueReceive( *pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) ); + xEndTime = xTaskGetTickCount(); + xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS; + + if( xElapsed == 0UL ) + { + xElapsed = 1UL; + } + + ulReturn = xElapsed; + } + + return ulReturn; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_arch_mbox_tryfetch + *---------------------------------------------------------------------------* + * Description: + * Similar to sys_arch_mbox_fetch, but if message is not ready + * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is + * returned. + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * void **msg -- Pointer to pointer to msg received + * Outputs: + * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise, + * return ERR_OK. + *---------------------------------------------------------------------------*/ +u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer ) +{ +void *pvDummy; +unsigned long ulReturn; +long lResult; +portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + if( ppvBuffer== NULL ) + { + ppvBuffer = &pvDummy; + } + + if( is_inside_isr() != pdFALSE ) + { + lResult = xQueueReceiveFromISR( *pxMailBox, &( *ppvBuffer ), &xHigherPriorityTaskWoken ); + } + else + { + lResult = xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL ); + } + + if( lResult == pdPASS ) + { + ulReturn = ERR_OK; + } + else + { + ulReturn = SYS_MBOX_EMPTY; + } + + return ulReturn; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_sem_new + *---------------------------------------------------------------------------* + * Description: + * Creates and returns a new semaphore. The "ucCount" argument specifies + * the initial state of the semaphore. + * NOTE: Currently this routine only creates counts of 1 or 0 + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * u8_t ucCount -- Initial ucCount of semaphore (1 or 0) + * Outputs: + * sys_sem_t -- Created semaphore or 0 if could not create. + *---------------------------------------------------------------------------*/ +err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount ) +{ +err_t xReturn = ERR_MEM; + + vSemaphoreCreateBinary( ( *pxSemaphore ) ); + + if( *pxSemaphore != NULL ) + { + if( ucCount == 0U ) + { + xSemaphoreTake( *pxSemaphore, 1UL ); + } + + xReturn = ERR_OK; + SYS_STATS_INC_USED( sem ); + } + else + { + SYS_STATS_INC( sem.err ); + } + + return xReturn; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_arch_sem_wait + *---------------------------------------------------------------------------* + * Description: + * Blocks the thread while waiting for the semaphore to be + * signaled. If the "timeout" argument is non-zero, the thread should + * only be blocked for the specified time (measured in + * milliseconds). + * + * If the timeout argument is non-zero, the return value is the number of + * milliseconds spent waiting for the semaphore to be signaled. If the + * semaphore wasn't signaled within the specified time, the return value is + * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore + * (i.e., it was already signaled), the function may return zero. + * + * Notice that lwIP implements a function with a similar name, + * sys_sem_wait(), that uses the sys_arch_sem_wait() function. + * Inputs: + * sys_sem_t sem -- Semaphore to wait on + * u32_t timeout -- Number of milliseconds until timeout + * Outputs: + * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT. + *---------------------------------------------------------------------------*/ +u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout ) +{ +portTickType xStartTime, xEndTime, xElapsed; +unsigned long ulReturn; + + xStartTime = xTaskGetTickCount(); + + if( ulTimeout != 0UL ) + { + if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_RATE_MS ) == pdTRUE ) + { + xEndTime = xTaskGetTickCount(); + xElapsed = (xEndTime - xStartTime) * portTICK_RATE_MS; + ulReturn = xElapsed; + } + else + { + ulReturn = SYS_ARCH_TIMEOUT; + } + } + else + { + while( xSemaphoreTake( *pxSemaphore, portMAX_DELAY ) != pdTRUE ); + xEndTime = xTaskGetTickCount(); + xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS; + + if( xElapsed == 0UL ) + { + xElapsed = 1UL; + } + + ulReturn = xElapsed; + } + + return ulReturn; +} + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t sys_mutex_new( sys_mutex_t *pxMutex ) +{ +err_t xReturn = ERR_MEM; + + *pxMutex = xSemaphoreCreateMutex(); + + if( *pxMutex != NULL ) + { + xReturn = ERR_OK; + SYS_STATS_INC_USED( mutex ); + } + else + { + SYS_STATS_INC( mutex.err ); + } + + return xReturn; +} + +/** Lock a mutex + * @param mutex the mutex to lock */ +void sys_mutex_lock( sys_mutex_t *pxMutex ) +{ + while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS ); +} + +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void sys_mutex_unlock(sys_mutex_t *pxMutex ) +{ + xSemaphoreGive( *pxMutex ); +} + + +/** Delete a semaphore + * @param mutex the mutex to delete */ +void sys_mutex_free( sys_mutex_t *pxMutex ) +{ + SYS_STATS_DEC( mutex.used ); + vQueueDelete( *pxMutex ); +} + + +/*---------------------------------------------------------------------------* + * Routine: sys_sem_signal + *---------------------------------------------------------------------------* + * Description: + * Signals (releases) a semaphore + * Inputs: + * sys_sem_t sem -- Semaphore to signal + *---------------------------------------------------------------------------*/ +void sys_sem_signal( sys_sem_t *pxSemaphore ) +{ +portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + if( is_inside_isr() != pdFALSE ) + { + xSemaphoreGiveFromISR( *pxSemaphore, &xHigherPriorityTaskWoken ); + } + else + { + xSemaphoreGive( *pxSemaphore ); + } +} + +/*---------------------------------------------------------------------------* + * Routine: sys_sem_free + *---------------------------------------------------------------------------* + * Description: + * Deallocates a semaphore + * Inputs: + * sys_sem_t sem -- Semaphore to free + *---------------------------------------------------------------------------*/ +void sys_sem_free( sys_sem_t *pxSemaphore ) +{ + SYS_STATS_DEC(sem.used); + vQueueDelete( *pxSemaphore ); +} + +/*---------------------------------------------------------------------------* + * Routine: sys_init + *---------------------------------------------------------------------------* + * Description: + * Initialize sys arch + *---------------------------------------------------------------------------*/ +void sys_init(void) +{ +} + +u32_t sys_now(void) +{ + return xTaskGetTickCount(); +} + +/*---------------------------------------------------------------------------* + * Routine: sys_thread_new + *---------------------------------------------------------------------------* + * Description: + * Starts a new thread with priority "prio" that will begin its + * execution in the function "thread()". The "arg" argument will be + * passed as an argument to the thread() function. The id of the new + * thread is returned. Both the id and the priority are system + * dependent. + * Inputs: + * char *name -- Name of thread + * void (* thread)(void *arg) -- Pointer to function to run. + * void *arg -- Argument passed into function + * int stacksize -- Required stack amount in bytes + * int prio -- Thread priority + * Outputs: + * sys_thread_t -- Pointer to per-thread timeouts. + *---------------------------------------------------------------------------*/ +sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority ) +{ +xTaskHandle xCreatedTask; +portBASE_TYPE xResult; +sys_thread_t xReturn; + + xResult = xTaskCreate( pxThread, ( signed char * ) pcName, iStackSize, pvArg, iPriority, &xCreatedTask ); + + if( xResult == pdPASS ) + { + xReturn = xCreatedTask; + } + else + { + xReturn = NULL; + } + + return xReturn; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_arch_protect + *---------------------------------------------------------------------------* + * Description: + * This optional function does a "fast" critical region protection and + * returns the previous protection level. This function is only called + * during very short critical regions. An embedded system which supports + * ISR-based drivers might want to implement this function by disabling + * interrupts. Task-based systems might want to implement this by using + * a mutex or disabling tasking. This function should support recursive + * calls from the same task or interrupt. In other words, + * sys_arch_protect() could be called while already protected. In + * that case the return value indicates that it is already protected. + * + * sys_arch_protect() is only required if your port is supporting an + * operating system. + * Outputs: + * sys_prot_t -- Previous protection level (not used here) + *---------------------------------------------------------------------------*/ +sys_prot_t sys_arch_protect( void ) +{ + if( is_inside_isr() == pdFALSE ) + { + taskENTER_CRITICAL(); + } + return ( sys_prot_t ) 1; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_arch_unprotect + *---------------------------------------------------------------------------* + * Description: + * This optional function does a "fast" set of critical region + * protection to the value specified by pval. See the documentation for + * sys_arch_protect() for more information. This function is only + * required if your port is supporting an operating system. + * Inputs: + * sys_prot_t -- Previous protection level (not used here) + *---------------------------------------------------------------------------*/ +void sys_arch_unprotect( sys_prot_t xValue ) +{ + (void) xValue; + if( is_inside_isr() == pdFALSE ) + { + taskEXIT_CRITICAL(); + } +} + +/* + * Prints an assertion messages and aborts execution. + */ +void sys_assert( const char *pcMessage ) +{ + (void) pcMessage; + + for (;;) + { + } +} +/*-------------------------------------------------------------------------* + * End of File: sys_arch.c + *-------------------------------------------------------------------------*/ diff --git a/utils/filteroutput.py b/utils/filteroutput.py new file mode 100755 index 0000000..5e9b1cf --- /dev/null +++ b/utils/filteroutput.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# +# A thin Python wrapper around addr2line, can monitor esp-open-rtos +# output and uses gdb to convert any suitable looking hex numbers +# found in the output into function and line numbers. +# +# Works with a serial port if the --port option is supplied. +# Otherwise waits for input on stdin. +# +import serial +import argparse +import re +import os +import os.path +import subprocess +import termios +import sys +import time + +# Try looking up anything in the executable address space +RE_EXECADDR = r"(0x)?40([0-9]|[a-z]){6}" + +def find_elf_file(): + out_files = [] + for top,_,files in os.walk('.', followlinks=False): + for f in files: + if f.endswith(".out"): + out_files.append(os.path.join(top,f)) + if len(out_files) == 1: + return out_files[0] + elif len(out_files) > 1: + print("Found multiple .out files: %s. Please specify one with the --elf option." % out_files) + else: + print("No .out file found under current directory. Please specify one with the --elf option.") + sys.exit(1) + +def main(): + parser = argparse.ArgumentParser(description='esp-open-rtos output filter tool', prog='filteroutput') + parser.add_argument( + '--elf', '-e', + help="ELF file (*.out file) to load symbols from (if not supplied, will search for one)"), + parser.add_argument( + '--port', '-p', + help='Serial port to monitor (will monitor stdin if None)', + default=None) + parser.add_argument( + '--baud', '-b', + help='Baud rate for serial port', + type=int, + default=74880) + parser.add_argument( + '--reset-on-connect', '-r', + help='Reset ESP8266 (via DTR) on serial connect. (Linux resets even if not set, except when using NodeMCU-style auto-reset circuit.)', + action='store_true') + + args = parser.parse_args() + + if args.elf is None: + args.elf = find_elf_file() + elif not os.path.exists(args.elf): + print("ELF file '%s' not found" % args.elf) + sys.exit(1) + + if args.port is not None: + print("Opening %s at %dbps..." % (args.port, args.baud)) + port = serial.Serial(args.port, baudrate=args.baud) + if args.reset_on_connect: + print("Resetting...") + port.setDTR(False) + time.sleep(0.1) + port.setDTR(True) + + else: + print("Reading from stdin...") + port = sys.stdin + # disable echo + try: + old_attr = termios.tcgetattr(sys.stdin.fileno()) + attr = termios.tcgetattr(sys.stdin.fileno()) + attr[3] = attr[3] & ~termios.ECHO + termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, attr) + except termios.error: + pass + + try: + while True: + line = port.readline() + if line == '': + break + print(line.strip()) + for match in re.finditer(RE_EXECADDR, line, re.IGNORECASE): + addr = match.group(0) + if not addr.startswith("0x"): + addr = "0x"+addr + # keeping addr2line and feeding it addresses on stdin didn't seem to work smoothly + addr2line = subprocess.check_output(["xtensa-lx106-elf-addr2line","-pfia","-e","%s" % args.elf, addr], cwd=".").strip() + if not addr2line.endswith(": ?? ??:0"): + print("\n%s\n" % addr2line.strip()) + finally: + if args.port is None: + # restore echo + termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_attr) + +if __name__ == "__main__": + main()