migration
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
.build
|
||||
*.syms
|
||||
.build
|
||||
*.syms
|
||||
|
||||
+95
-95
@@ -1,95 +1,95 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
set(include_dirs "platform_include")
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
# Bootloader builds need the platform_include directory (for assert.h), but nothing else
|
||||
idf_component_register(INCLUDE_DIRS platform_include)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(srcs
|
||||
"abort.c"
|
||||
"assert.c"
|
||||
"heap.c"
|
||||
"flockfile.c"
|
||||
"locks.c"
|
||||
"poll.c"
|
||||
"pthread.c"
|
||||
"random.c"
|
||||
"getentropy.c"
|
||||
"reent_init.c"
|
||||
"newlib_init.c"
|
||||
"syscalls.c"
|
||||
"termios.c"
|
||||
"stdatomic.c"
|
||||
"time.c"
|
||||
"sysconf.c"
|
||||
"realpath.c"
|
||||
"scandir.c"
|
||||
)
|
||||
|
||||
if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
list(APPEND srcs "port/xtensa/stdatomic_s32c1i.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND)
|
||||
set(ldfragments "esp32-spiram-rom-functions-c.lf")
|
||||
endif()
|
||||
|
||||
list(APPEND ldfragments "newlib.lf" "system_libs.lf")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS priv_include
|
||||
PRIV_REQUIRES soc spi_flash
|
||||
LDFRAGMENTS "${ldfragments}")
|
||||
|
||||
# Toolchain libraries require code defined in this component
|
||||
idf_component_get_property(newlib newlib COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE c m ${CONFIG_COMPILER_RT_LIB_NAME} "$<TARGET_FILE:${newlib}>")
|
||||
|
||||
set_source_files_properties(heap.c PROPERTIES COMPILE_FLAGS -fno-builtin)
|
||||
|
||||
if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
set_source_files_properties("port/xtensa/stdatomic_s32c1i.c"
|
||||
PROPERTIES COMPILE_FLAGS "-mno-disable-hardware-atomics")
|
||||
endif()
|
||||
|
||||
# Forces the linker to include heap, syscall, pthread, assert, and retargetable locks from this component,
|
||||
# instead of the implementations provided by newlib.
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_heap_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_syscalls_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_pthread_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_assert_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_getentropy_impl")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "${EXTRA_LINK_FLAGS}")
|
||||
|
||||
# Forces the linker to include newlib_init.c
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u newlib_include_init_funcs")
|
||||
|
||||
if(CONFIG_NEWLIB_NANO_FORMAT)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
set(libc_dir_cmd ${CMAKE_C_COMPILER})
|
||||
string(REPLACE " " ";" cflags_list ${CMAKE_C_FLAGS})
|
||||
list(APPEND libc_dir_cmd ${cflags_list} "-print-file-name=libc.a")
|
||||
execute_process(
|
||||
COMMAND ${libc_dir_cmd}
|
||||
OUTPUT_VARIABLE libc_dir
|
||||
)
|
||||
get_filename_component(libc_dir ${libc_dir} DIRECTORY)
|
||||
target_link_directories(${COMPONENT_LIB} INTERFACE "${libc_dir}/nano")
|
||||
else()
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(port)
|
||||
|
||||
# if lwip is included in the build, add it as a public requirement so that
|
||||
# #include <sys/socket.h> works without any special provisions.
|
||||
idf_component_optional_requires(PUBLIC lwip)
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
set(include_dirs "platform_include")
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
# Bootloader builds need the platform_include directory (for assert.h), but nothing else
|
||||
idf_component_register(INCLUDE_DIRS platform_include)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(srcs
|
||||
"abort.c"
|
||||
"assert.c"
|
||||
"heap.c"
|
||||
"flockfile.c"
|
||||
"locks.c"
|
||||
"poll.c"
|
||||
"pthread.c"
|
||||
"random.c"
|
||||
"getentropy.c"
|
||||
"reent_init.c"
|
||||
"newlib_init.c"
|
||||
"syscalls.c"
|
||||
"termios.c"
|
||||
"stdatomic.c"
|
||||
"time.c"
|
||||
"sysconf.c"
|
||||
"realpath.c"
|
||||
"scandir.c"
|
||||
)
|
||||
|
||||
if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
list(APPEND srcs "port/xtensa/stdatomic_s32c1i.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND)
|
||||
set(ldfragments "esp32-spiram-rom-functions-c.lf")
|
||||
endif()
|
||||
|
||||
list(APPEND ldfragments "newlib.lf" "system_libs.lf")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS priv_include
|
||||
PRIV_REQUIRES soc spi_flash
|
||||
LDFRAGMENTS "${ldfragments}")
|
||||
|
||||
# Toolchain libraries require code defined in this component
|
||||
idf_component_get_property(newlib newlib COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE c m ${CONFIG_COMPILER_RT_LIB_NAME} "$<TARGET_FILE:${newlib}>")
|
||||
|
||||
set_source_files_properties(heap.c PROPERTIES COMPILE_FLAGS -fno-builtin)
|
||||
|
||||
if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
set_source_files_properties("port/xtensa/stdatomic_s32c1i.c"
|
||||
PROPERTIES COMPILE_FLAGS "-mno-disable-hardware-atomics")
|
||||
endif()
|
||||
|
||||
# Forces the linker to include heap, syscall, pthread, assert, and retargetable locks from this component,
|
||||
# instead of the implementations provided by newlib.
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_heap_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_syscalls_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_pthread_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_assert_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_getentropy_impl")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "${EXTRA_LINK_FLAGS}")
|
||||
|
||||
# Forces the linker to include newlib_init.c
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u newlib_include_init_funcs")
|
||||
|
||||
if(CONFIG_NEWLIB_NANO_FORMAT)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
set(libc_dir_cmd ${CMAKE_C_COMPILER})
|
||||
string(REPLACE " " ";" cflags_list ${CMAKE_C_FLAGS})
|
||||
list(APPEND libc_dir_cmd ${cflags_list} "-print-file-name=libc.a")
|
||||
execute_process(
|
||||
COMMAND ${libc_dir_cmd}
|
||||
OUTPUT_VARIABLE libc_dir
|
||||
)
|
||||
get_filename_component(libc_dir ${libc_dir} DIRECTORY)
|
||||
target_link_directories(${COMPONENT_LIB} INTERFACE "${libc_dir}/nano")
|
||||
else()
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(port)
|
||||
|
||||
# if lwip is included in the build, add it as a public requirement so that
|
||||
# #include <sys/socket.h> works without any special provisions.
|
||||
idf_component_optional_requires(PUBLIC lwip)
|
||||
|
||||
+952
-952
File diff suppressed because it is too large
Load Diff
+124
-124
@@ -1,124 +1,124 @@
|
||||
menu "Newlib"
|
||||
|
||||
choice NEWLIB_STDOUT_LINE_ENDING
|
||||
prompt "Line ending for UART output"
|
||||
default NEWLIB_STDOUT_LINE_ENDING_CRLF
|
||||
help
|
||||
This option allows configuring the desired line endings sent to UART
|
||||
when a newline ('\n', LF) appears on stdout.
|
||||
Three options are possible:
|
||||
|
||||
CRLF: whenever LF is encountered, prepend it with CR
|
||||
|
||||
LF: no modification is applied, stdout is sent as is
|
||||
|
||||
CR: each occurrence of LF is replaced with CR
|
||||
|
||||
This option doesn't affect behavior of the UART driver (drivers/uart.h).
|
||||
|
||||
config NEWLIB_STDOUT_LINE_ENDING_CRLF
|
||||
bool "CRLF"
|
||||
config NEWLIB_STDOUT_LINE_ENDING_LF
|
||||
bool "LF"
|
||||
config NEWLIB_STDOUT_LINE_ENDING_CR
|
||||
bool "CR"
|
||||
endchoice
|
||||
|
||||
choice NEWLIB_STDIN_LINE_ENDING
|
||||
prompt "Line ending for UART input"
|
||||
default NEWLIB_STDIN_LINE_ENDING_CR
|
||||
help
|
||||
This option allows configuring which input sequence on UART produces
|
||||
a newline ('\n', LF) on stdin.
|
||||
Three options are possible:
|
||||
|
||||
CRLF: CRLF is converted to LF
|
||||
|
||||
LF: no modification is applied, input is sent to stdin as is
|
||||
|
||||
CR: each occurrence of CR is replaced with LF
|
||||
|
||||
This option doesn't affect behavior of the UART driver (drivers/uart.h).
|
||||
|
||||
config NEWLIB_STDIN_LINE_ENDING_CRLF
|
||||
bool "CRLF"
|
||||
config NEWLIB_STDIN_LINE_ENDING_LF
|
||||
bool "LF"
|
||||
config NEWLIB_STDIN_LINE_ENDING_CR
|
||||
bool "CR"
|
||||
endchoice
|
||||
|
||||
config NEWLIB_NANO_FORMAT
|
||||
bool "Enable 'nano' formatting options for printf/scanf family"
|
||||
default y if IDF_TARGET_ESP32C2
|
||||
help
|
||||
In most chips the ROM contains parts of newlib C library, including printf/scanf family
|
||||
of functions. These functions have been compiled with so-called "nano"
|
||||
formatting option. This option doesn't support 64-bit integer formats and C99
|
||||
features, such as positional arguments.
|
||||
|
||||
For more details about "nano" formatting option, please see newlib readme file,
|
||||
search for '--enable-newlib-nano-formatted-io':
|
||||
https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/README;hb=HEAD
|
||||
|
||||
If this option is enabled and the ROM contains functions from newlib-nano, the build system
|
||||
will use functions available in ROM, reducing the application binary size.
|
||||
Functions available in ROM run faster than functions which run from flash. Functions available
|
||||
in ROM can also run when flash instruction cache is disabled.
|
||||
|
||||
Some chips (e.g. ESP32-C6) has the full formatting versions of printf/scanf in ROM instead of
|
||||
the nano versions and in this building with newlib nano might actually increase the size of
|
||||
the binary. Which functions are present in ROM can be seen from ROM caps:
|
||||
ESP_ROM_HAS_NEWLIB_NANO_FORMAT and ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT.
|
||||
|
||||
If you need 64-bit integer formatting support or C99 features, keep this
|
||||
option disabled.
|
||||
|
||||
choice NEWLIB_TIME_SYSCALL
|
||||
prompt "Timers used for gettimeofday function"
|
||||
default NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
help
|
||||
This setting defines which hardware timers are used to
|
||||
implement 'gettimeofday' and 'time' functions in C library.
|
||||
|
||||
- If both high-resolution (systimer for all targets except ESP32)
|
||||
and RTC timers are used, timekeeping will continue in deep sleep.
|
||||
Time will be reported at 1 microsecond resolution.
|
||||
This is the default, and the recommended option.
|
||||
- If only high-resolution timer (systimer) is used, gettimeofday will
|
||||
provide time at microsecond resolution.
|
||||
Time will not be preserved when going into deep sleep mode.
|
||||
- If only RTC timer is used, timekeeping will continue in
|
||||
deep sleep, but time will be measured at 6.(6) microsecond
|
||||
resolution. Also the gettimeofday function itself may take
|
||||
longer to run.
|
||||
- If no timers are used, gettimeofday and time functions
|
||||
return -1 and set errno to ENOSYS; they are defined as weak,
|
||||
so they could be overridden.
|
||||
If you want to customize gettimeofday() and other time functions,
|
||||
please choose this option and refer to the 'time.c' source file
|
||||
for the exact prototypes of these functions.
|
||||
|
||||
- When RTC is used for timekeeping, two RTC_STORE registers are
|
||||
used to keep time in deep sleep mode.
|
||||
|
||||
config NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
bool "RTC and high-resolution timer"
|
||||
select ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
select ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
config NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
bool "RTC"
|
||||
select ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
config NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
bool "High-resolution timer"
|
||||
select ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
config NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
bool "None"
|
||||
select ESP_TIME_FUNCS_USE_NONE
|
||||
endchoice
|
||||
|
||||
endmenu # Newlib
|
||||
|
||||
config STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
bool
|
||||
default SPIRAM && (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3) && !IDF_TOOLCHAIN_CLANG # TODO IDF-9032
|
||||
menu "Newlib"
|
||||
|
||||
choice NEWLIB_STDOUT_LINE_ENDING
|
||||
prompt "Line ending for UART output"
|
||||
default NEWLIB_STDOUT_LINE_ENDING_CRLF
|
||||
help
|
||||
This option allows configuring the desired line endings sent to UART
|
||||
when a newline ('\n', LF) appears on stdout.
|
||||
Three options are possible:
|
||||
|
||||
CRLF: whenever LF is encountered, prepend it with CR
|
||||
|
||||
LF: no modification is applied, stdout is sent as is
|
||||
|
||||
CR: each occurrence of LF is replaced with CR
|
||||
|
||||
This option doesn't affect behavior of the UART driver (drivers/uart.h).
|
||||
|
||||
config NEWLIB_STDOUT_LINE_ENDING_CRLF
|
||||
bool "CRLF"
|
||||
config NEWLIB_STDOUT_LINE_ENDING_LF
|
||||
bool "LF"
|
||||
config NEWLIB_STDOUT_LINE_ENDING_CR
|
||||
bool "CR"
|
||||
endchoice
|
||||
|
||||
choice NEWLIB_STDIN_LINE_ENDING
|
||||
prompt "Line ending for UART input"
|
||||
default NEWLIB_STDIN_LINE_ENDING_CR
|
||||
help
|
||||
This option allows configuring which input sequence on UART produces
|
||||
a newline ('\n', LF) on stdin.
|
||||
Three options are possible:
|
||||
|
||||
CRLF: CRLF is converted to LF
|
||||
|
||||
LF: no modification is applied, input is sent to stdin as is
|
||||
|
||||
CR: each occurrence of CR is replaced with LF
|
||||
|
||||
This option doesn't affect behavior of the UART driver (drivers/uart.h).
|
||||
|
||||
config NEWLIB_STDIN_LINE_ENDING_CRLF
|
||||
bool "CRLF"
|
||||
config NEWLIB_STDIN_LINE_ENDING_LF
|
||||
bool "LF"
|
||||
config NEWLIB_STDIN_LINE_ENDING_CR
|
||||
bool "CR"
|
||||
endchoice
|
||||
|
||||
config NEWLIB_NANO_FORMAT
|
||||
bool "Enable 'nano' formatting options for printf/scanf family"
|
||||
default y if IDF_TARGET_ESP32C2
|
||||
help
|
||||
In most chips the ROM contains parts of newlib C library, including printf/scanf family
|
||||
of functions. These functions have been compiled with so-called "nano"
|
||||
formatting option. This option doesn't support 64-bit integer formats and C99
|
||||
features, such as positional arguments.
|
||||
|
||||
For more details about "nano" formatting option, please see newlib readme file,
|
||||
search for '--enable-newlib-nano-formatted-io':
|
||||
https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/README;hb=HEAD
|
||||
|
||||
If this option is enabled and the ROM contains functions from newlib-nano, the build system
|
||||
will use functions available in ROM, reducing the application binary size.
|
||||
Functions available in ROM run faster than functions which run from flash. Functions available
|
||||
in ROM can also run when flash instruction cache is disabled.
|
||||
|
||||
Some chips (e.g. ESP32-C6) has the full formatting versions of printf/scanf in ROM instead of
|
||||
the nano versions and in this building with newlib nano might actually increase the size of
|
||||
the binary. Which functions are present in ROM can be seen from ROM caps:
|
||||
ESP_ROM_HAS_NEWLIB_NANO_FORMAT and ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT.
|
||||
|
||||
If you need 64-bit integer formatting support or C99 features, keep this
|
||||
option disabled.
|
||||
|
||||
choice NEWLIB_TIME_SYSCALL
|
||||
prompt "Timers used for gettimeofday function"
|
||||
default NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
help
|
||||
This setting defines which hardware timers are used to
|
||||
implement 'gettimeofday' and 'time' functions in C library.
|
||||
|
||||
- If both high-resolution (systimer for all targets except ESP32)
|
||||
and RTC timers are used, timekeeping will continue in deep sleep.
|
||||
Time will be reported at 1 microsecond resolution.
|
||||
This is the default, and the recommended option.
|
||||
- If only high-resolution timer (systimer) is used, gettimeofday will
|
||||
provide time at microsecond resolution.
|
||||
Time will not be preserved when going into deep sleep mode.
|
||||
- If only RTC timer is used, timekeeping will continue in
|
||||
deep sleep, but time will be measured at 6.(6) microsecond
|
||||
resolution. Also the gettimeofday function itself may take
|
||||
longer to run.
|
||||
- If no timers are used, gettimeofday and time functions
|
||||
return -1 and set errno to ENOSYS; they are defined as weak,
|
||||
so they could be overridden.
|
||||
If you want to customize gettimeofday() and other time functions,
|
||||
please choose this option and refer to the 'time.c' source file
|
||||
for the exact prototypes of these functions.
|
||||
|
||||
- When RTC is used for timekeeping, two RTC_STORE registers are
|
||||
used to keep time in deep sleep mode.
|
||||
|
||||
config NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
bool "RTC and high-resolution timer"
|
||||
select ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
select ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
config NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
bool "RTC"
|
||||
select ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
config NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
bool "High-resolution timer"
|
||||
select ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
config NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
bool "None"
|
||||
select ESP_TIME_FUNCS_USE_NONE
|
||||
endchoice
|
||||
|
||||
endmenu # Newlib
|
||||
|
||||
config STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
bool
|
||||
default SPIRAM && (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3) && !IDF_TOOLCHAIN_CLANG # TODO IDF-9032
|
||||
|
||||
+39
-39
@@ -1,39 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
void __attribute__((noreturn)) abort(void)
|
||||
{
|
||||
#define ERR_STR1 "abort() was called at PC 0x"
|
||||
#define ERR_STR2 " on core "
|
||||
|
||||
_Static_assert(UINTPTR_MAX == 0xffffffff, "abort() assumes 32-bit addresses");
|
||||
_Static_assert(SOC_CPU_CORES_NUM < 10, "abort() assumes number of cores is 1 to 9");
|
||||
|
||||
char addr_buf[9] = { 0 };
|
||||
char core_buf[2] = { 0 };
|
||||
|
||||
char buf[sizeof(ERR_STR1) + sizeof(addr_buf) + sizeof(core_buf) + sizeof(ERR_STR2) + 1 /* null char */] = { 0 };
|
||||
|
||||
itoa((uint32_t)(__builtin_return_address(0) - 3), addr_buf, 16);
|
||||
itoa(esp_cpu_get_core_id(), core_buf, 10);
|
||||
|
||||
const char *str[] = { ERR_STR1, addr_buf, ERR_STR2, core_buf };
|
||||
|
||||
char *dest = buf;
|
||||
|
||||
for (size_t i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
|
||||
strcat(dest, str[i]);
|
||||
}
|
||||
|
||||
esp_system_abort(buf);
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
void __attribute__((noreturn)) abort(void)
|
||||
{
|
||||
#define ERR_STR1 "abort() was called at PC 0x"
|
||||
#define ERR_STR2 " on core "
|
||||
|
||||
_Static_assert(UINTPTR_MAX == 0xffffffff, "abort() assumes 32-bit addresses");
|
||||
_Static_assert(SOC_CPU_CORES_NUM < 10, "abort() assumes number of cores is 1 to 9");
|
||||
|
||||
char addr_buf[9] = { 0 };
|
||||
char core_buf[2] = { 0 };
|
||||
|
||||
char buf[sizeof(ERR_STR1) + sizeof(addr_buf) + sizeof(core_buf) + sizeof(ERR_STR2) + 1 /* null char */] = { 0 };
|
||||
|
||||
itoa((uint32_t)(__builtin_return_address(0) - 3), addr_buf, 16);
|
||||
itoa(esp_cpu_get_core_id(), core_buf, 10);
|
||||
|
||||
const char *str[] = { ERR_STR1, addr_buf, ERR_STR2, core_buf };
|
||||
|
||||
char *dest = buf;
|
||||
|
||||
for (size_t i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
|
||||
strcat(dest, str[i]);
|
||||
}
|
||||
|
||||
esp_system_abort(buf);
|
||||
}
|
||||
|
||||
+92
-92
@@ -1,92 +1,92 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_system.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
|
||||
#define ASSERT_STR "assert failed: "
|
||||
#define CACHE_DISABLED_STR "<cached disabled>"
|
||||
|
||||
#if __XTENSA__
|
||||
#define INST_LEN 3
|
||||
#elif __riscv
|
||||
#define INST_LEN 4
|
||||
#endif
|
||||
|
||||
static inline void ra_to_str(char *addr)
|
||||
{
|
||||
addr[0] = '0';
|
||||
addr[1] = 'x';
|
||||
itoa((uint32_t)(__builtin_return_address(0) - INST_LEN), addr + 2, 16);
|
||||
}
|
||||
|
||||
/* Overriding assert function so that whenever assert is called from critical section,
|
||||
* it does not lead to a crash of its own.
|
||||
*/
|
||||
void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *expr)
|
||||
{
|
||||
#if CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
char buff[sizeof(ASSERT_STR) + 11 + 1] = ASSERT_STR;
|
||||
|
||||
ra_to_str(&buff[sizeof(ASSERT_STR) - 1]);
|
||||
|
||||
esp_system_abort(buff);
|
||||
#else
|
||||
char addr[11] = { 0 };
|
||||
char buff[200];
|
||||
char lbuf[5];
|
||||
uint32_t rem_len = sizeof(buff) - 1;
|
||||
uint32_t off = 0;
|
||||
|
||||
itoa(line, lbuf, 10);
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
if (!spi_flash_cache_enabled())
|
||||
#endif
|
||||
{
|
||||
if (esp_ptr_in_drom(file)) {
|
||||
file = CACHE_DISABLED_STR;
|
||||
}
|
||||
|
||||
if (esp_ptr_in_drom(func)) {
|
||||
ra_to_str(addr);
|
||||
func = addr;
|
||||
}
|
||||
|
||||
if (esp_ptr_in_drom(expr)) {
|
||||
expr = CACHE_DISABLED_STR;
|
||||
}
|
||||
}
|
||||
|
||||
const char *str[] = {ASSERT_STR, func ? func : "\b", " ", file, ":", lbuf, " (", expr, ")"};
|
||||
|
||||
for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
|
||||
uint32_t len = strlen(str[i]);
|
||||
uint32_t cpy_len = MIN(len, rem_len);
|
||||
memcpy(buff + off, str[i], cpy_len);
|
||||
rem_len -= cpy_len;
|
||||
off += cpy_len;
|
||||
if (rem_len == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buff[off] = '\0';
|
||||
esp_system_abort(buff);
|
||||
#endif /* CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT */
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) __assert(const char *file, int line, const char *failedexpr)
|
||||
{
|
||||
__assert_func(file, line, NULL, failedexpr);
|
||||
}
|
||||
|
||||
/* No-op function, used to force linker to include these changes */
|
||||
void newlib_include_assert_impl(void)
|
||||
{
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_system.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
|
||||
#define ASSERT_STR "assert failed: "
|
||||
#define CACHE_DISABLED_STR "<cached disabled>"
|
||||
|
||||
#if __XTENSA__
|
||||
#define INST_LEN 3
|
||||
#elif __riscv
|
||||
#define INST_LEN 4
|
||||
#endif
|
||||
|
||||
static inline void ra_to_str(char *addr)
|
||||
{
|
||||
addr[0] = '0';
|
||||
addr[1] = 'x';
|
||||
itoa((uint32_t)(__builtin_return_address(0) - INST_LEN), addr + 2, 16);
|
||||
}
|
||||
|
||||
/* Overriding assert function so that whenever assert is called from critical section,
|
||||
* it does not lead to a crash of its own.
|
||||
*/
|
||||
void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *expr)
|
||||
{
|
||||
#if CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
char buff[sizeof(ASSERT_STR) + 11 + 1] = ASSERT_STR;
|
||||
|
||||
ra_to_str(&buff[sizeof(ASSERT_STR) - 1]);
|
||||
|
||||
esp_system_abort(buff);
|
||||
#else
|
||||
char addr[11] = { 0 };
|
||||
char buff[200];
|
||||
char lbuf[5];
|
||||
uint32_t rem_len = sizeof(buff) - 1;
|
||||
uint32_t off = 0;
|
||||
|
||||
itoa(line, lbuf, 10);
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
if (!spi_flash_cache_enabled())
|
||||
#endif
|
||||
{
|
||||
if (esp_ptr_in_drom(file)) {
|
||||
file = CACHE_DISABLED_STR;
|
||||
}
|
||||
|
||||
if (esp_ptr_in_drom(func)) {
|
||||
ra_to_str(addr);
|
||||
func = addr;
|
||||
}
|
||||
|
||||
if (esp_ptr_in_drom(expr)) {
|
||||
expr = CACHE_DISABLED_STR;
|
||||
}
|
||||
}
|
||||
|
||||
const char *str[] = {ASSERT_STR, func ? func : "\b", " ", file, ":", lbuf, " (", expr, ")"};
|
||||
|
||||
for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
|
||||
uint32_t len = strlen(str[i]);
|
||||
uint32_t cpy_len = MIN(len, rem_len);
|
||||
memcpy(buff + off, str[i], cpy_len);
|
||||
rem_len -= cpy_len;
|
||||
off += cpy_len;
|
||||
if (rem_len == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buff[off] = '\0';
|
||||
esp_system_abort(buff);
|
||||
#endif /* CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT */
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) __assert(const char *file, int line, const char *failedexpr)
|
||||
{
|
||||
__assert_func(file, line, NULL, failedexpr);
|
||||
}
|
||||
|
||||
/* No-op function, used to force linker to include these changes */
|
||||
void newlib_include_assert_impl(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,171 +1,171 @@
|
||||
# If the Newlib functions in ROM aren't used (eg because the external SPI RAM workaround is active), these functions will
|
||||
# be linked into the application directly instead. Normally, they would end up in flash, which is undesirable because esp-idf
|
||||
# and/or applications may assume that because these functions normally are in ROM, they are accessible even when flash is
|
||||
# inaccessible. To work around this, this ld fragment places these functions in RAM instead. If the ROM functions are used,
|
||||
# these defines do nothing, so they can still be included in that situation.
|
||||
#
|
||||
#
|
||||
# Note: the only difference between esp32-spiram-rom-functions-c.lf
|
||||
# and esp32-spiram-rom-functions-psram-workaround.lf is the archive name.
|
||||
|
||||
[mapping:libc]
|
||||
archive:
|
||||
if NEWLIB_NANO_FORMAT = y:
|
||||
libc_nano.a
|
||||
else:
|
||||
libc.a
|
||||
entries:
|
||||
if SPIRAM_CACHE_WORKAROUND = y:
|
||||
# The following libs are either used in a lot of places or in critical
|
||||
# code. (such as panic or abort)
|
||||
# Thus, they shall always be placed in IRAM.
|
||||
libc_a-itoa (noflash)
|
||||
libc_a-memcmp (noflash)
|
||||
libc_a-memcpy (noflash)
|
||||
libc_a-memset (noflash)
|
||||
libc_a-strcat (noflash)
|
||||
libc_a-strcmp (noflash)
|
||||
libc_a-strlen (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBJMP_IN_IRAM = y:
|
||||
libc_a-longjmp (noflash)
|
||||
libc_a-setjmp (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBMATH_IN_IRAM = y:
|
||||
libc_a-abs (noflash)
|
||||
libc_a-div (noflash)
|
||||
libc_a-labs (noflash)
|
||||
libc_a-ldiv (noflash)
|
||||
libc_a-quorem (noflash)
|
||||
libc_a-s_fpclassify (noflash)
|
||||
libc_a-sf_nan (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM = y:
|
||||
libc_a-utoa (noflash)
|
||||
libc_a-atoi (noflash)
|
||||
libc_a-atol (noflash)
|
||||
libc_a-strtol (noflash)
|
||||
libc_a-strtoul (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBIO_IN_IRAM = y:
|
||||
libc_a-wcrtomb (noflash)
|
||||
libc_a-fvwrite (noflash)
|
||||
libc_a-wbuf (noflash)
|
||||
libc_a-wsetup (noflash)
|
||||
libc_a-fputwc (noflash)
|
||||
libc_a-wctomb_r (noflash)
|
||||
libc_a-ungetc (noflash)
|
||||
libc_a-makebuf (noflash)
|
||||
libc_a-fflush (noflash)
|
||||
libc_a-refill (noflash)
|
||||
libc_a-sccl (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBTIME_IN_IRAM = y:
|
||||
libc_a-asctime (noflash)
|
||||
libc_a-asctime_r (noflash)
|
||||
libc_a-ctime (noflash)
|
||||
libc_a-ctime_r (noflash)
|
||||
libc_a-lcltime (noflash)
|
||||
libc_a-lcltime_r (noflash)
|
||||
libc_a-gmtime (noflash)
|
||||
libc_a-gmtime_r (noflash)
|
||||
libc_a-strftime (noflash)
|
||||
libc_a-mktime (noflash)
|
||||
libc_a-tzset_r (noflash)
|
||||
libc_a-tzset (noflash)
|
||||
libc_a-time (noflash)
|
||||
libc_a-gettzinfo (noflash)
|
||||
libc_a-systimes (noflash)
|
||||
libc_a-month_lengths (noflash)
|
||||
libc_a-timelocal (noflash)
|
||||
libc_a-tzvars (noflash)
|
||||
libc_a-tzlock (noflash)
|
||||
libc_a-tzcalc_limits (noflash)
|
||||
libc_a-strptime (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBCHAR_IN_IRAM = y:
|
||||
libc_a-ctype_ (noflash)
|
||||
libc_a-toupper (noflash)
|
||||
libc_a-tolower (noflash)
|
||||
libc_a-toascii (noflash)
|
||||
libc_a-strupr (noflash)
|
||||
libc_a-bzero (noflash)
|
||||
libc_a-isalnum (noflash)
|
||||
libc_a-isalpha (noflash)
|
||||
libc_a-isascii (noflash)
|
||||
libc_a-isblank (noflash)
|
||||
libc_a-iscntrl (noflash)
|
||||
libc_a-isdigit (noflash)
|
||||
libc_a-isgraph (noflash)
|
||||
libc_a-islower (noflash)
|
||||
libc_a-isprint (noflash)
|
||||
libc_a-ispunct (noflash)
|
||||
libc_a-isspace (noflash)
|
||||
libc_a-isupper (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBMEM_IN_IRAM = y:
|
||||
libc_a-memccpy (noflash)
|
||||
libc_a-memchr (noflash)
|
||||
libc_a-memmove (noflash)
|
||||
libc_a-memrchr (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBSTR_IN_IRAM = y:
|
||||
libc_a-strcasecmp (noflash)
|
||||
libc_a-strcasestr (noflash)
|
||||
libc_a-strchr (noflash)
|
||||
libc_a-strcoll (noflash)
|
||||
libc_a-strcpy (noflash)
|
||||
libc_a-strcspn (noflash)
|
||||
libc_a-strdup (noflash)
|
||||
libc_a-strdup_r (noflash)
|
||||
libc_a-strlcat (noflash)
|
||||
libc_a-strlcpy (noflash)
|
||||
libc_a-strlwr (noflash)
|
||||
libc_a-strncasecmp (noflash)
|
||||
libc_a-strncat (noflash)
|
||||
libc_a-strncmp (noflash)
|
||||
libc_a-strncpy (noflash)
|
||||
libc_a-strndup (noflash)
|
||||
libc_a-strndup_r (noflash)
|
||||
libc_a-strnlen (noflash)
|
||||
libc_a-strrchr (noflash)
|
||||
libc_a-strsep (noflash)
|
||||
libc_a-strspn (noflash)
|
||||
libc_a-strstr (noflash)
|
||||
libc_a-strtok_r (noflash)
|
||||
libc_a-strupr (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBRAND_IN_IRAM = y:
|
||||
libc_a-srand (noflash)
|
||||
libc_a-rand (noflash)
|
||||
libc_a-rand_r (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBENV_IN_IRAM = y:
|
||||
libc_a-environ (noflash)
|
||||
libc_a-envlock (noflash)
|
||||
libc_a-getenv_r (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBFILE_IN_IRAM = y:
|
||||
lock (noflash)
|
||||
isatty (noflash)
|
||||
creat (noflash)
|
||||
libc_a-fclose (noflash)
|
||||
libc_a-open (noflash)
|
||||
libc_a-close (noflash)
|
||||
libc_a-creat (noflash)
|
||||
libc_a-read (noflash)
|
||||
libc_a-rshift (noflash)
|
||||
libc_a-sbrk (noflash)
|
||||
libc_a-stdio (noflash)
|
||||
libc_a-syssbrk (noflash)
|
||||
libc_a-sysclose (noflash)
|
||||
libc_a-sysopen (noflash)
|
||||
libc_a-sysread (noflash)
|
||||
libc_a-syswrite (noflash)
|
||||
libc_a-impure (noflash)
|
||||
libc_a-fwalk (noflash)
|
||||
libc_a-findfp (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBMISC_IN_IRAM = y:
|
||||
libc_a-raise (noflash)
|
||||
libc_a-system (noflash)
|
||||
# If the Newlib functions in ROM aren't used (eg because the external SPI RAM workaround is active), these functions will
|
||||
# be linked into the application directly instead. Normally, they would end up in flash, which is undesirable because esp-idf
|
||||
# and/or applications may assume that because these functions normally are in ROM, they are accessible even when flash is
|
||||
# inaccessible. To work around this, this ld fragment places these functions in RAM instead. If the ROM functions are used,
|
||||
# these defines do nothing, so they can still be included in that situation.
|
||||
#
|
||||
#
|
||||
# Note: the only difference between esp32-spiram-rom-functions-c.lf
|
||||
# and esp32-spiram-rom-functions-psram-workaround.lf is the archive name.
|
||||
|
||||
[mapping:libc]
|
||||
archive:
|
||||
if NEWLIB_NANO_FORMAT = y:
|
||||
libc_nano.a
|
||||
else:
|
||||
libc.a
|
||||
entries:
|
||||
if SPIRAM_CACHE_WORKAROUND = y:
|
||||
# The following libs are either used in a lot of places or in critical
|
||||
# code. (such as panic or abort)
|
||||
# Thus, they shall always be placed in IRAM.
|
||||
libc_a-itoa (noflash)
|
||||
libc_a-memcmp (noflash)
|
||||
libc_a-memcpy (noflash)
|
||||
libc_a-memset (noflash)
|
||||
libc_a-strcat (noflash)
|
||||
libc_a-strcmp (noflash)
|
||||
libc_a-strlen (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBJMP_IN_IRAM = y:
|
||||
libc_a-longjmp (noflash)
|
||||
libc_a-setjmp (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBMATH_IN_IRAM = y:
|
||||
libc_a-abs (noflash)
|
||||
libc_a-div (noflash)
|
||||
libc_a-labs (noflash)
|
||||
libc_a-ldiv (noflash)
|
||||
libc_a-quorem (noflash)
|
||||
libc_a-s_fpclassify (noflash)
|
||||
libc_a-sf_nan (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM = y:
|
||||
libc_a-utoa (noflash)
|
||||
libc_a-atoi (noflash)
|
||||
libc_a-atol (noflash)
|
||||
libc_a-strtol (noflash)
|
||||
libc_a-strtoul (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBIO_IN_IRAM = y:
|
||||
libc_a-wcrtomb (noflash)
|
||||
libc_a-fvwrite (noflash)
|
||||
libc_a-wbuf (noflash)
|
||||
libc_a-wsetup (noflash)
|
||||
libc_a-fputwc (noflash)
|
||||
libc_a-wctomb_r (noflash)
|
||||
libc_a-ungetc (noflash)
|
||||
libc_a-makebuf (noflash)
|
||||
libc_a-fflush (noflash)
|
||||
libc_a-refill (noflash)
|
||||
libc_a-sccl (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBTIME_IN_IRAM = y:
|
||||
libc_a-asctime (noflash)
|
||||
libc_a-asctime_r (noflash)
|
||||
libc_a-ctime (noflash)
|
||||
libc_a-ctime_r (noflash)
|
||||
libc_a-lcltime (noflash)
|
||||
libc_a-lcltime_r (noflash)
|
||||
libc_a-gmtime (noflash)
|
||||
libc_a-gmtime_r (noflash)
|
||||
libc_a-strftime (noflash)
|
||||
libc_a-mktime (noflash)
|
||||
libc_a-tzset_r (noflash)
|
||||
libc_a-tzset (noflash)
|
||||
libc_a-time (noflash)
|
||||
libc_a-gettzinfo (noflash)
|
||||
libc_a-systimes (noflash)
|
||||
libc_a-month_lengths (noflash)
|
||||
libc_a-timelocal (noflash)
|
||||
libc_a-tzvars (noflash)
|
||||
libc_a-tzlock (noflash)
|
||||
libc_a-tzcalc_limits (noflash)
|
||||
libc_a-strptime (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBCHAR_IN_IRAM = y:
|
||||
libc_a-ctype_ (noflash)
|
||||
libc_a-toupper (noflash)
|
||||
libc_a-tolower (noflash)
|
||||
libc_a-toascii (noflash)
|
||||
libc_a-strupr (noflash)
|
||||
libc_a-bzero (noflash)
|
||||
libc_a-isalnum (noflash)
|
||||
libc_a-isalpha (noflash)
|
||||
libc_a-isascii (noflash)
|
||||
libc_a-isblank (noflash)
|
||||
libc_a-iscntrl (noflash)
|
||||
libc_a-isdigit (noflash)
|
||||
libc_a-isgraph (noflash)
|
||||
libc_a-islower (noflash)
|
||||
libc_a-isprint (noflash)
|
||||
libc_a-ispunct (noflash)
|
||||
libc_a-isspace (noflash)
|
||||
libc_a-isupper (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBMEM_IN_IRAM = y:
|
||||
libc_a-memccpy (noflash)
|
||||
libc_a-memchr (noflash)
|
||||
libc_a-memmove (noflash)
|
||||
libc_a-memrchr (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBSTR_IN_IRAM = y:
|
||||
libc_a-strcasecmp (noflash)
|
||||
libc_a-strcasestr (noflash)
|
||||
libc_a-strchr (noflash)
|
||||
libc_a-strcoll (noflash)
|
||||
libc_a-strcpy (noflash)
|
||||
libc_a-strcspn (noflash)
|
||||
libc_a-strdup (noflash)
|
||||
libc_a-strdup_r (noflash)
|
||||
libc_a-strlcat (noflash)
|
||||
libc_a-strlcpy (noflash)
|
||||
libc_a-strlwr (noflash)
|
||||
libc_a-strncasecmp (noflash)
|
||||
libc_a-strncat (noflash)
|
||||
libc_a-strncmp (noflash)
|
||||
libc_a-strncpy (noflash)
|
||||
libc_a-strndup (noflash)
|
||||
libc_a-strndup_r (noflash)
|
||||
libc_a-strnlen (noflash)
|
||||
libc_a-strrchr (noflash)
|
||||
libc_a-strsep (noflash)
|
||||
libc_a-strspn (noflash)
|
||||
libc_a-strstr (noflash)
|
||||
libc_a-strtok_r (noflash)
|
||||
libc_a-strupr (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBRAND_IN_IRAM = y:
|
||||
libc_a-srand (noflash)
|
||||
libc_a-rand (noflash)
|
||||
libc_a-rand_r (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBENV_IN_IRAM = y:
|
||||
libc_a-environ (noflash)
|
||||
libc_a-envlock (noflash)
|
||||
libc_a-getenv_r (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBFILE_IN_IRAM = y:
|
||||
lock (noflash)
|
||||
isatty (noflash)
|
||||
creat (noflash)
|
||||
libc_a-fclose (noflash)
|
||||
libc_a-open (noflash)
|
||||
libc_a-close (noflash)
|
||||
libc_a-creat (noflash)
|
||||
libc_a-read (noflash)
|
||||
libc_a-rshift (noflash)
|
||||
libc_a-sbrk (noflash)
|
||||
libc_a-stdio (noflash)
|
||||
libc_a-syssbrk (noflash)
|
||||
libc_a-sysclose (noflash)
|
||||
libc_a-sysopen (noflash)
|
||||
libc_a-sysread (noflash)
|
||||
libc_a-syswrite (noflash)
|
||||
libc_a-impure (noflash)
|
||||
libc_a-fwalk (noflash)
|
||||
libc_a-findfp (noflash)
|
||||
|
||||
if SPIRAM_CACHE_LIBMISC_IN_IRAM = y:
|
||||
libc_a-raise (noflash)
|
||||
libc_a-system (noflash)
|
||||
|
||||
+32
-32
@@ -1,32 +1,32 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <sys/reent.h>
|
||||
|
||||
void flockfile(FILE *fp)
|
||||
{
|
||||
if (fp && !(fp->_flags & __SSTR)) {
|
||||
__lock_acquire_recursive(fp->_lock);
|
||||
}
|
||||
}
|
||||
|
||||
int ftrylockfile(FILE *fp)
|
||||
{
|
||||
if (fp && !(fp->_flags & __SSTR)) {
|
||||
return __lock_try_acquire_recursive(fp->_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void funlockfile(FILE *fp)
|
||||
{
|
||||
if (fp && !(fp->_flags & __SSTR)) {
|
||||
__lock_release_recursive(fp->_lock);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <sys/reent.h>
|
||||
|
||||
void flockfile(FILE *fp)
|
||||
{
|
||||
if (fp && !(fp->_flags & __SSTR)) {
|
||||
__lock_acquire_recursive(fp->_lock);
|
||||
}
|
||||
}
|
||||
|
||||
int ftrylockfile(FILE *fp)
|
||||
{
|
||||
if (fp && !(fp->_flags & __SSTR)) {
|
||||
return __lock_try_acquire_recursive(fp->_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void funlockfile(FILE *fp)
|
||||
{
|
||||
if (fp && !(fp->_flags & __SSTR)) {
|
||||
__lock_release_recursive(fp->_lock);
|
||||
}
|
||||
}
|
||||
|
||||
+35
-35
@@ -1,35 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/random.h>
|
||||
#include <errno.h>
|
||||
|
||||
int getentropy(void *buffer, size_t length)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
if (buffer == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length > 256) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = getrandom(buffer, length, 0);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void newlib_include_getentropy_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/random.h>
|
||||
#include <errno.h>
|
||||
|
||||
int getentropy(void *buffer, size_t length)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
if (buffer == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length > 256) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = getrandom(buffer, length, 0);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void newlib_include_getentropy_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
||||
|
||||
+139
-139
@@ -1,139 +1,139 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/reent.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
/*
|
||||
These contain the business logic for the malloc() and realloc() implementation. Because of heap tracing
|
||||
wrapping reasons, we do not want these to be a public api, however, so they're not defined publicly.
|
||||
*/
|
||||
extern void *heap_caps_malloc_default(size_t size);
|
||||
extern void *heap_caps_realloc_default(void *ptr, size_t size);
|
||||
extern void *heap_caps_aligned_alloc_default(size_t alignment, size_t size);
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
return heap_caps_malloc_default(size);
|
||||
}
|
||||
|
||||
void* calloc(size_t n, size_t size)
|
||||
{
|
||||
return _calloc_r(_REENT, n, size);
|
||||
}
|
||||
|
||||
void* realloc(void* ptr, size_t size)
|
||||
{
|
||||
return heap_caps_realloc_default(ptr, size);
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
void* _malloc_r(struct _reent *r, size_t size)
|
||||
{
|
||||
return heap_caps_malloc_default(size);
|
||||
}
|
||||
|
||||
void _free_r(struct _reent *r, void* ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
void* _realloc_r(struct _reent *r, void* ptr, size_t size)
|
||||
{
|
||||
return heap_caps_realloc_default(ptr, size);
|
||||
}
|
||||
|
||||
void* _calloc_r(struct _reent *r, size_t nmemb, size_t size)
|
||||
{
|
||||
void *result;
|
||||
size_t size_bytes;
|
||||
if (__builtin_mul_overflow(nmemb, size, &size_bytes)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = heap_caps_malloc_default(size_bytes);
|
||||
if (result != NULL) {
|
||||
bzero(result, size_bytes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void* memalign(size_t alignment, size_t n)
|
||||
{
|
||||
return heap_caps_aligned_alloc_default(alignment, n);
|
||||
}
|
||||
|
||||
void* aligned_alloc(size_t alignment, size_t n)
|
||||
{
|
||||
return heap_caps_aligned_alloc_default(alignment, n);
|
||||
}
|
||||
|
||||
int posix_memalign(void **out_ptr, size_t alignment, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
/* returning NULL for zero size is allowed, don't treat this as an error */
|
||||
*out_ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
void *result = heap_caps_aligned_alloc_default(alignment, size);
|
||||
if (result != NULL) {
|
||||
/* Modify output pointer only on success */
|
||||
*out_ptr = result;
|
||||
return 0;
|
||||
}
|
||||
/* Note: error returned, not set via errno! */
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* No-op function, used to force linking this file,
|
||||
instead of the heap implementation from newlib.
|
||||
*/
|
||||
void newlib_include_heap_impl(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* The following functions are implemented by newlib's heap allocator,
|
||||
but aren't available in the heap component.
|
||||
Define them as non-functional stubs here, so that the application
|
||||
can not cause the newlib heap implementation to be linked in
|
||||
*/
|
||||
|
||||
int malloc_trim(size_t pad)
|
||||
{
|
||||
return 0; // indicates failure
|
||||
}
|
||||
|
||||
size_t malloc_usable_size(void* p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void malloc_stats(void)
|
||||
{
|
||||
}
|
||||
|
||||
int mallopt(int parameter_number, int parameter_value)
|
||||
{
|
||||
return 0; // indicates failure
|
||||
}
|
||||
|
||||
struct mallinfo mallinfo(void)
|
||||
{
|
||||
struct mallinfo dummy = {0};
|
||||
return dummy;
|
||||
}
|
||||
|
||||
void* valloc(size_t n) __attribute__((alias("malloc")));
|
||||
void* pvalloc(size_t n) __attribute__((alias("malloc")));
|
||||
void cfree(void* p) __attribute__((alias("free")));
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/reent.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
/*
|
||||
These contain the business logic for the malloc() and realloc() implementation. Because of heap tracing
|
||||
wrapping reasons, we do not want these to be a public api, however, so they're not defined publicly.
|
||||
*/
|
||||
extern void *heap_caps_malloc_default(size_t size);
|
||||
extern void *heap_caps_realloc_default(void *ptr, size_t size);
|
||||
extern void *heap_caps_aligned_alloc_default(size_t alignment, size_t size);
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
return heap_caps_malloc_default(size);
|
||||
}
|
||||
|
||||
void* calloc(size_t n, size_t size)
|
||||
{
|
||||
return _calloc_r(_REENT, n, size);
|
||||
}
|
||||
|
||||
void* realloc(void* ptr, size_t size)
|
||||
{
|
||||
return heap_caps_realloc_default(ptr, size);
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
void* _malloc_r(struct _reent *r, size_t size)
|
||||
{
|
||||
return heap_caps_malloc_default(size);
|
||||
}
|
||||
|
||||
void _free_r(struct _reent *r, void* ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
void* _realloc_r(struct _reent *r, void* ptr, size_t size)
|
||||
{
|
||||
return heap_caps_realloc_default(ptr, size);
|
||||
}
|
||||
|
||||
void* _calloc_r(struct _reent *r, size_t nmemb, size_t size)
|
||||
{
|
||||
void *result;
|
||||
size_t size_bytes;
|
||||
if (__builtin_mul_overflow(nmemb, size, &size_bytes)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = heap_caps_malloc_default(size_bytes);
|
||||
if (result != NULL) {
|
||||
bzero(result, size_bytes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void* memalign(size_t alignment, size_t n)
|
||||
{
|
||||
return heap_caps_aligned_alloc_default(alignment, n);
|
||||
}
|
||||
|
||||
void* aligned_alloc(size_t alignment, size_t n)
|
||||
{
|
||||
return heap_caps_aligned_alloc_default(alignment, n);
|
||||
}
|
||||
|
||||
int posix_memalign(void **out_ptr, size_t alignment, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
/* returning NULL for zero size is allowed, don't treat this as an error */
|
||||
*out_ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
void *result = heap_caps_aligned_alloc_default(alignment, size);
|
||||
if (result != NULL) {
|
||||
/* Modify output pointer only on success */
|
||||
*out_ptr = result;
|
||||
return 0;
|
||||
}
|
||||
/* Note: error returned, not set via errno! */
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* No-op function, used to force linking this file,
|
||||
instead of the heap implementation from newlib.
|
||||
*/
|
||||
void newlib_include_heap_impl(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* The following functions are implemented by newlib's heap allocator,
|
||||
but aren't available in the heap component.
|
||||
Define them as non-functional stubs here, so that the application
|
||||
can not cause the newlib heap implementation to be linked in
|
||||
*/
|
||||
|
||||
int malloc_trim(size_t pad)
|
||||
{
|
||||
return 0; // indicates failure
|
||||
}
|
||||
|
||||
size_t malloc_usable_size(void* p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void malloc_stats(void)
|
||||
{
|
||||
}
|
||||
|
||||
int mallopt(int parameter_number, int parameter_value)
|
||||
{
|
||||
return 0; // indicates failure
|
||||
}
|
||||
|
||||
struct mallinfo mallinfo(void)
|
||||
{
|
||||
struct mallinfo dummy = {0};
|
||||
return dummy;
|
||||
}
|
||||
|
||||
void* valloc(size_t n) __attribute__((alias("malloc")));
|
||||
void* pvalloc(size_t n) __attribute__((alias("malloc")));
|
||||
void cfree(void* p) __attribute__((alias("free")));
|
||||
|
||||
+407
-407
@@ -1,407 +1,407 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/reent.h>
|
||||
#include "esp_attr.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/portable.h"
|
||||
#include "esp_rom_caps.h"
|
||||
|
||||
/* Notes on our newlib lock implementation:
|
||||
*
|
||||
* - Use FreeRTOS mutex semaphores as locks.
|
||||
* - lock_t is int, but we store an SemaphoreHandle_t there.
|
||||
* - Locks are no-ops until the FreeRTOS scheduler is running.
|
||||
* - Due to this, locks need to be lazily initialised the first time
|
||||
* they are acquired. Initialisation/deinitialisation of locks is
|
||||
* protected by lock_init_spinlock.
|
||||
* - Race conditions around lazy initialisation (via lock_acquire) are
|
||||
* protected against.
|
||||
* - Anyone calling lock_close is reponsible for ensuring noone else
|
||||
* is holding the lock at this time.
|
||||
* - Race conditions between lock_close & lock_init (for the same lock)
|
||||
* are the responsibility of the caller.
|
||||
*/
|
||||
|
||||
static portMUX_TYPE lock_init_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
/* Initialize the given lock by allocating a new mutex semaphore
|
||||
as the _lock_t value.
|
||||
|
||||
Called by _lock_init*, also called by _lock_acquire* to lazily initialize locks that might have
|
||||
been initialised (to zero only) before the RTOS scheduler started.
|
||||
*/
|
||||
static void IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
{
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
/* Lock already initialised (either we didn't check earlier,
|
||||
or it got initialised while we were waiting for the
|
||||
spinlock.) */
|
||||
} else {
|
||||
/* Create a new semaphore
|
||||
|
||||
this is a bit of an API violation, as we're calling the
|
||||
private function xQueueCreateMutex(x) directly instead of
|
||||
the xSemaphoreCreateMutex / xSemaphoreCreateRecursiveMutex
|
||||
wrapper functions...
|
||||
|
||||
The better alternative would be to pass pointers to one of
|
||||
the two xSemaphoreCreate___Mutex functions, but as FreeRTOS
|
||||
implements these as macros instead of inline functions
|
||||
(*party like it's 1998!*) it's not possible to do this
|
||||
without writing wrappers. Doing it this way seems much less
|
||||
spaghetti-like.
|
||||
*/
|
||||
SemaphoreHandle_t new_sem = xQueueCreateMutex(mutex_type);
|
||||
if (!new_sem) {
|
||||
abort(); /* No more semaphores available or OOM */
|
||||
}
|
||||
*lock = (_lock_t)new_sem;
|
||||
}
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_init(_lock_t *lock)
|
||||
{
|
||||
*lock = 0; // In case lock's memory is uninitialized
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_init_recursive(_lock_t *lock)
|
||||
{
|
||||
*lock = 0; // In case lock's memory is uninitialized
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* Free the mutex semaphore pointed to by *lock, and zero it out.
|
||||
|
||||
Note that FreeRTOS doesn't account for deleting mutexes while they
|
||||
are held, and neither do we... so take care not to delete newlib
|
||||
locks while they may be held by other tasks!
|
||||
|
||||
Also, deleting a lock in this way will cause it to be lazily
|
||||
re-initialised if it is used again. Caller has to avoid doing
|
||||
this!
|
||||
*/
|
||||
void IRAM_ATTR _lock_close(_lock_t *lock)
|
||||
{
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
#if (INCLUDE_xSemaphoreGetMutexHolder == 1)
|
||||
configASSERT(xSemaphoreGetMutexHolder(h) == NULL); /* mutex should not be held */
|
||||
#endif
|
||||
vSemaphoreDelete(h);
|
||||
*lock = 0;
|
||||
}
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void _lock_close_recursive(_lock_t *lock) __attribute__((alias("_lock_close")));
|
||||
|
||||
/* Acquire the mutex semaphore for lock. wait up to delay ticks.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static int IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type)
|
||||
{
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
if (!h) {
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
|
||||
}
|
||||
/* lazy initialise lock - might have had a static initializer (that we don't use) */
|
||||
lock_init_generic(lock, mutex_type);
|
||||
h = (SemaphoreHandle_t)(*lock);
|
||||
configASSERT(h != NULL);
|
||||
}
|
||||
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
|
||||
}
|
||||
BaseType_t success;
|
||||
if (!xPortCanYield()) {
|
||||
/* In ISR Context */
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
abort(); /* recursive mutexes make no sense in ISR context */
|
||||
}
|
||||
BaseType_t higher_task_woken = false;
|
||||
success = xSemaphoreTakeFromISR(h, &higher_task_woken);
|
||||
if (!success && delay > 0) {
|
||||
abort(); /* Tried to block on mutex from ISR, couldn't... rewrite your program to avoid libc interactions in ISRs! */
|
||||
}
|
||||
if (higher_task_woken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
/* In task context */
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
success = xSemaphoreTakeRecursive(h, delay);
|
||||
} else {
|
||||
success = xSemaphoreTake(h, delay);
|
||||
}
|
||||
}
|
||||
|
||||
return (success == pdTRUE) ? 0 : -1;
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_acquire(_lock_t *lock)
|
||||
{
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
int IRAM_ATTR _lock_try_acquire(_lock_t *lock)
|
||||
{
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
int IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* Release the mutex semaphore for lock.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static void IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
{
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return; /* locking is a no-op before scheduler is up */
|
||||
}
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
assert(h);
|
||||
|
||||
if (!xPortCanYield()) {
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
abort(); /* indicates logic bug, it shouldn't be possible to lock recursively in ISR */
|
||||
}
|
||||
BaseType_t higher_task_woken = false;
|
||||
xSemaphoreGiveFromISR(h, &higher_task_woken);
|
||||
if (higher_task_woken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
xSemaphoreGiveRecursive(h);
|
||||
} else {
|
||||
xSemaphoreGive(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_release(_lock_t *lock)
|
||||
{
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_release_recursive(_lock_t *lock)
|
||||
{
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* To ease the transition to newlib 3.3.0, this part is kept under an ifdef.
|
||||
* After the toolchain with newlib 3.3.0 is released and merged, the ifdefs
|
||||
* can be removed.
|
||||
*
|
||||
* Also the retargetable locking functions still rely on the previous
|
||||
* implementation. Once support for !_RETARGETABLE_LOCKING is removed,
|
||||
* the code can be simplified, removing support for lazy initialization of
|
||||
* locks. At the same time, IDF code which relies on _lock_acquire/_lock_release
|
||||
* will have to be updated to not depend on lazy initialization.
|
||||
*
|
||||
* Explanation of the different lock types:
|
||||
*
|
||||
* Newlib 2.2.0 and 3.0.0:
|
||||
* _lock_t is defined as int, stores SemaphoreHandle_t.
|
||||
*
|
||||
* Newlib 3.3.0:
|
||||
* struct __lock is (or contains) StaticSemaphore_t
|
||||
* _LOCK_T is a pointer to struct __lock, equivalent to SemaphoreHandle_t.
|
||||
* It has the same meaning as _lock_t in the previous implementation.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This ensures the platform-specific definition in lock.h is correct.
|
||||
* We use "greater or equal" since the size of StaticSemaphore_t may
|
||||
* vary by 2 words, depending on whether configUSE_TRACE_FACILITY is enabled.
|
||||
*/
|
||||
_Static_assert(sizeof(struct __lock) >= sizeof(StaticSemaphore_t),
|
||||
"Incorrect size of struct __lock");
|
||||
|
||||
/* FreeRTOS configuration check */
|
||||
_Static_assert(configSUPPORT_STATIC_ALLOCATION,
|
||||
"FreeRTOS should be configured with static allocation support");
|
||||
|
||||
/* These 2 locks are used instead of 9 distinct newlib static locks,
|
||||
* as most of the locks are required for lesser-used features, so
|
||||
* the chance of performance degradation due to lock contention is low.
|
||||
*/
|
||||
static StaticSemaphore_t s_common_mutex;
|
||||
static StaticSemaphore_t s_common_recursive_mutex;
|
||||
|
||||
#if ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
/* C3 and S3 ROMs are built without Newlib static lock symbols exported, and
|
||||
* with an extra level of _LOCK_T indirection in mind.
|
||||
* The following is a workaround for this:
|
||||
* - on startup, we call esp_rom_newlib_init_common_mutexes to set
|
||||
* the two mutex pointers to magic values.
|
||||
* - if in __retarget_lock_acquire*, we check if the argument dereferences
|
||||
* to the magic value. If yes, we lock the correct mutex defined in the app,
|
||||
* instead.
|
||||
* Casts from &StaticSemaphore_t to _LOCK_T are okay because _LOCK_T
|
||||
* (which is SemaphoreHandle_t) is a pointer to the corresponding
|
||||
* StaticSemaphore_t structure. This is ensured by asserts below.
|
||||
*/
|
||||
|
||||
#define ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#endif // ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
|
||||
#ifdef ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#define ROM_MUTEX_MAGIC 0xbb10c433
|
||||
/* This is a macro, since we are overwriting the argument */
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead) \
|
||||
if (*(int*)_lock == ROM_MUTEX_MAGIC) { \
|
||||
(_lock) = (_LOCK_T) (_lock_to_use_instead); \
|
||||
}
|
||||
#else // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead)
|
||||
#endif // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
|
||||
void IRAM_ATTR __retarget_lock_init(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_close(_LOCK_T lock)
|
||||
{
|
||||
_lock_close(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock)
|
||||
{
|
||||
_lock_close_recursive(&lock);
|
||||
}
|
||||
|
||||
/* Separate function, to prevent generating multiple assert strings */
|
||||
static void IRAM_ATTR check_lock_nonzero(_LOCK_T lock)
|
||||
{
|
||||
assert(lock != NULL && "Uninitialized lock used");
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
_lock_acquire(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
_lock_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
int IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
return _lock_try_acquire(&lock);
|
||||
}
|
||||
|
||||
int IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
return _lock_try_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_release(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release_recursive(&lock);
|
||||
}
|
||||
|
||||
/* When _RETARGETABLE_LOCKING is enabled, newlib expects the following locks to be provided: */
|
||||
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___sinit_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___malloc_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___env_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___sfp_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___atexit_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___at_quick_exit_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___tz_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___dd_hash_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___arc4random_mutex;
|
||||
|
||||
void esp_newlib_locks_init(void)
|
||||
{
|
||||
/* Initialize the two mutexes used for the locks above.
|
||||
* Asserts below check our assumption that SemaphoreHandle_t will always
|
||||
* point to the corresponding StaticSemaphore_t structure.
|
||||
*/
|
||||
SemaphoreHandle_t handle;
|
||||
handle = xSemaphoreCreateMutexStatic(&s_common_mutex);
|
||||
assert(handle == (SemaphoreHandle_t) &s_common_mutex);
|
||||
handle = xSemaphoreCreateRecursiveMutexStatic(&s_common_recursive_mutex);
|
||||
assert(handle == (SemaphoreHandle_t) &s_common_recursive_mutex);
|
||||
(void) handle;
|
||||
|
||||
/* Chip ROMs are built with older versions of newlib, and rely on different lock variables.
|
||||
* Initialize these locks to the same values.
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
/* Newlib 2.2.0 is used in ROM, the following lock symbols are defined: */
|
||||
extern _lock_t __sfp_lock;
|
||||
__sfp_lock = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __sinit_lock;
|
||||
__sinit_lock = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __env_lock_object;
|
||||
__env_lock_object = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __tz_lock_object;
|
||||
__tz_lock_object = (_lock_t) &s_common_mutex;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
/* Newlib 3.0.0 is used in ROM, the following lock symbols are defined: */
|
||||
extern _lock_t __sinit_recursive_mutex;
|
||||
__sinit_recursive_mutex = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __sfp_recursive_mutex;
|
||||
__sfp_recursive_mutex = (_lock_t) &s_common_recursive_mutex;
|
||||
#elif ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
/* Newlib 3.3.0 is used in ROM, built with _RETARGETABLE_LOCKING.
|
||||
* No access to lock variables for the purpose of ECO forward compatibility,
|
||||
* however we have an API to initialize lock variables used in the ROM.
|
||||
*/
|
||||
extern void esp_rom_newlib_init_common_mutexes(_LOCK_T, _LOCK_T);
|
||||
/* See notes about ROM_NEEDS_MUTEX_OVERRIDE above */
|
||||
int magic_val = ROM_MUTEX_MAGIC;
|
||||
_LOCK_T magic_mutex = (_LOCK_T) &magic_val;
|
||||
esp_rom_newlib_init_common_mutexes(magic_mutex, magic_mutex);
|
||||
#else // other target
|
||||
#error Unsupported target
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/reent.h>
|
||||
#include "esp_attr.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/portable.h"
|
||||
#include "esp_rom_caps.h"
|
||||
|
||||
/* Notes on our newlib lock implementation:
|
||||
*
|
||||
* - Use FreeRTOS mutex semaphores as locks.
|
||||
* - lock_t is int, but we store an SemaphoreHandle_t there.
|
||||
* - Locks are no-ops until the FreeRTOS scheduler is running.
|
||||
* - Due to this, locks need to be lazily initialised the first time
|
||||
* they are acquired. Initialisation/deinitialisation of locks is
|
||||
* protected by lock_init_spinlock.
|
||||
* - Race conditions around lazy initialisation (via lock_acquire) are
|
||||
* protected against.
|
||||
* - Anyone calling lock_close is reponsible for ensuring noone else
|
||||
* is holding the lock at this time.
|
||||
* - Race conditions between lock_close & lock_init (for the same lock)
|
||||
* are the responsibility of the caller.
|
||||
*/
|
||||
|
||||
static portMUX_TYPE lock_init_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
/* Initialize the given lock by allocating a new mutex semaphore
|
||||
as the _lock_t value.
|
||||
|
||||
Called by _lock_init*, also called by _lock_acquire* to lazily initialize locks that might have
|
||||
been initialised (to zero only) before the RTOS scheduler started.
|
||||
*/
|
||||
static void IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
{
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
/* Lock already initialised (either we didn't check earlier,
|
||||
or it got initialised while we were waiting for the
|
||||
spinlock.) */
|
||||
} else {
|
||||
/* Create a new semaphore
|
||||
|
||||
this is a bit of an API violation, as we're calling the
|
||||
private function xQueueCreateMutex(x) directly instead of
|
||||
the xSemaphoreCreateMutex / xSemaphoreCreateRecursiveMutex
|
||||
wrapper functions...
|
||||
|
||||
The better alternative would be to pass pointers to one of
|
||||
the two xSemaphoreCreate___Mutex functions, but as FreeRTOS
|
||||
implements these as macros instead of inline functions
|
||||
(*party like it's 1998!*) it's not possible to do this
|
||||
without writing wrappers. Doing it this way seems much less
|
||||
spaghetti-like.
|
||||
*/
|
||||
SemaphoreHandle_t new_sem = xQueueCreateMutex(mutex_type);
|
||||
if (!new_sem) {
|
||||
abort(); /* No more semaphores available or OOM */
|
||||
}
|
||||
*lock = (_lock_t)new_sem;
|
||||
}
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_init(_lock_t *lock)
|
||||
{
|
||||
*lock = 0; // In case lock's memory is uninitialized
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_init_recursive(_lock_t *lock)
|
||||
{
|
||||
*lock = 0; // In case lock's memory is uninitialized
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* Free the mutex semaphore pointed to by *lock, and zero it out.
|
||||
|
||||
Note that FreeRTOS doesn't account for deleting mutexes while they
|
||||
are held, and neither do we... so take care not to delete newlib
|
||||
locks while they may be held by other tasks!
|
||||
|
||||
Also, deleting a lock in this way will cause it to be lazily
|
||||
re-initialised if it is used again. Caller has to avoid doing
|
||||
this!
|
||||
*/
|
||||
void IRAM_ATTR _lock_close(_lock_t *lock)
|
||||
{
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
#if (INCLUDE_xSemaphoreGetMutexHolder == 1)
|
||||
configASSERT(xSemaphoreGetMutexHolder(h) == NULL); /* mutex should not be held */
|
||||
#endif
|
||||
vSemaphoreDelete(h);
|
||||
*lock = 0;
|
||||
}
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void _lock_close_recursive(_lock_t *lock) __attribute__((alias("_lock_close")));
|
||||
|
||||
/* Acquire the mutex semaphore for lock. wait up to delay ticks.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static int IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type)
|
||||
{
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
if (!h) {
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
|
||||
}
|
||||
/* lazy initialise lock - might have had a static initializer (that we don't use) */
|
||||
lock_init_generic(lock, mutex_type);
|
||||
h = (SemaphoreHandle_t)(*lock);
|
||||
configASSERT(h != NULL);
|
||||
}
|
||||
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
|
||||
}
|
||||
BaseType_t success;
|
||||
if (!xPortCanYield()) {
|
||||
/* In ISR Context */
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
abort(); /* recursive mutexes make no sense in ISR context */
|
||||
}
|
||||
BaseType_t higher_task_woken = false;
|
||||
success = xSemaphoreTakeFromISR(h, &higher_task_woken);
|
||||
if (!success && delay > 0) {
|
||||
abort(); /* Tried to block on mutex from ISR, couldn't... rewrite your program to avoid libc interactions in ISRs! */
|
||||
}
|
||||
if (higher_task_woken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
/* In task context */
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
success = xSemaphoreTakeRecursive(h, delay);
|
||||
} else {
|
||||
success = xSemaphoreTake(h, delay);
|
||||
}
|
||||
}
|
||||
|
||||
return (success == pdTRUE) ? 0 : -1;
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_acquire(_lock_t *lock)
|
||||
{
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
int IRAM_ATTR _lock_try_acquire(_lock_t *lock)
|
||||
{
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
int IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* Release the mutex semaphore for lock.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static void IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
{
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return; /* locking is a no-op before scheduler is up */
|
||||
}
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
assert(h);
|
||||
|
||||
if (!xPortCanYield()) {
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
abort(); /* indicates logic bug, it shouldn't be possible to lock recursively in ISR */
|
||||
}
|
||||
BaseType_t higher_task_woken = false;
|
||||
xSemaphoreGiveFromISR(h, &higher_task_woken);
|
||||
if (higher_task_woken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
|
||||
xSemaphoreGiveRecursive(h);
|
||||
} else {
|
||||
xSemaphoreGive(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_release(_lock_t *lock)
|
||||
{
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR _lock_release_recursive(_lock_t *lock)
|
||||
{
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* To ease the transition to newlib 3.3.0, this part is kept under an ifdef.
|
||||
* After the toolchain with newlib 3.3.0 is released and merged, the ifdefs
|
||||
* can be removed.
|
||||
*
|
||||
* Also the retargetable locking functions still rely on the previous
|
||||
* implementation. Once support for !_RETARGETABLE_LOCKING is removed,
|
||||
* the code can be simplified, removing support for lazy initialization of
|
||||
* locks. At the same time, IDF code which relies on _lock_acquire/_lock_release
|
||||
* will have to be updated to not depend on lazy initialization.
|
||||
*
|
||||
* Explanation of the different lock types:
|
||||
*
|
||||
* Newlib 2.2.0 and 3.0.0:
|
||||
* _lock_t is defined as int, stores SemaphoreHandle_t.
|
||||
*
|
||||
* Newlib 3.3.0:
|
||||
* struct __lock is (or contains) StaticSemaphore_t
|
||||
* _LOCK_T is a pointer to struct __lock, equivalent to SemaphoreHandle_t.
|
||||
* It has the same meaning as _lock_t in the previous implementation.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This ensures the platform-specific definition in lock.h is correct.
|
||||
* We use "greater or equal" since the size of StaticSemaphore_t may
|
||||
* vary by 2 words, depending on whether configUSE_TRACE_FACILITY is enabled.
|
||||
*/
|
||||
_Static_assert(sizeof(struct __lock) >= sizeof(StaticSemaphore_t),
|
||||
"Incorrect size of struct __lock");
|
||||
|
||||
/* FreeRTOS configuration check */
|
||||
_Static_assert(configSUPPORT_STATIC_ALLOCATION,
|
||||
"FreeRTOS should be configured with static allocation support");
|
||||
|
||||
/* These 2 locks are used instead of 9 distinct newlib static locks,
|
||||
* as most of the locks are required for lesser-used features, so
|
||||
* the chance of performance degradation due to lock contention is low.
|
||||
*/
|
||||
static StaticSemaphore_t s_common_mutex;
|
||||
static StaticSemaphore_t s_common_recursive_mutex;
|
||||
|
||||
#if ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
/* C3 and S3 ROMs are built without Newlib static lock symbols exported, and
|
||||
* with an extra level of _LOCK_T indirection in mind.
|
||||
* The following is a workaround for this:
|
||||
* - on startup, we call esp_rom_newlib_init_common_mutexes to set
|
||||
* the two mutex pointers to magic values.
|
||||
* - if in __retarget_lock_acquire*, we check if the argument dereferences
|
||||
* to the magic value. If yes, we lock the correct mutex defined in the app,
|
||||
* instead.
|
||||
* Casts from &StaticSemaphore_t to _LOCK_T are okay because _LOCK_T
|
||||
* (which is SemaphoreHandle_t) is a pointer to the corresponding
|
||||
* StaticSemaphore_t structure. This is ensured by asserts below.
|
||||
*/
|
||||
|
||||
#define ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#endif // ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
|
||||
#ifdef ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#define ROM_MUTEX_MAGIC 0xbb10c433
|
||||
/* This is a macro, since we are overwriting the argument */
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead) \
|
||||
if (*(int*)_lock == ROM_MUTEX_MAGIC) { \
|
||||
(_lock) = (_LOCK_T) (_lock_to_use_instead); \
|
||||
}
|
||||
#else // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead)
|
||||
#endif // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
|
||||
void IRAM_ATTR __retarget_lock_init(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_close(_LOCK_T lock)
|
||||
{
|
||||
_lock_close(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock)
|
||||
{
|
||||
_lock_close_recursive(&lock);
|
||||
}
|
||||
|
||||
/* Separate function, to prevent generating multiple assert strings */
|
||||
static void IRAM_ATTR check_lock_nonzero(_LOCK_T lock)
|
||||
{
|
||||
assert(lock != NULL && "Uninitialized lock used");
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
_lock_acquire(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
_lock_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
int IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
return _lock_try_acquire(&lock);
|
||||
}
|
||||
|
||||
int IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
return _lock_try_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_release(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release_recursive(&lock);
|
||||
}
|
||||
|
||||
/* When _RETARGETABLE_LOCKING is enabled, newlib expects the following locks to be provided: */
|
||||
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___sinit_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___malloc_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___env_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___sfp_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___atexit_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___at_quick_exit_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___tz_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___dd_hash_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___arc4random_mutex;
|
||||
|
||||
void esp_newlib_locks_init(void)
|
||||
{
|
||||
/* Initialize the two mutexes used for the locks above.
|
||||
* Asserts below check our assumption that SemaphoreHandle_t will always
|
||||
* point to the corresponding StaticSemaphore_t structure.
|
||||
*/
|
||||
SemaphoreHandle_t handle;
|
||||
handle = xSemaphoreCreateMutexStatic(&s_common_mutex);
|
||||
assert(handle == (SemaphoreHandle_t) &s_common_mutex);
|
||||
handle = xSemaphoreCreateRecursiveMutexStatic(&s_common_recursive_mutex);
|
||||
assert(handle == (SemaphoreHandle_t) &s_common_recursive_mutex);
|
||||
(void) handle;
|
||||
|
||||
/* Chip ROMs are built with older versions of newlib, and rely on different lock variables.
|
||||
* Initialize these locks to the same values.
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
/* Newlib 2.2.0 is used in ROM, the following lock symbols are defined: */
|
||||
extern _lock_t __sfp_lock;
|
||||
__sfp_lock = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __sinit_lock;
|
||||
__sinit_lock = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __env_lock_object;
|
||||
__env_lock_object = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __tz_lock_object;
|
||||
__tz_lock_object = (_lock_t) &s_common_mutex;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
/* Newlib 3.0.0 is used in ROM, the following lock symbols are defined: */
|
||||
extern _lock_t __sinit_recursive_mutex;
|
||||
__sinit_recursive_mutex = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __sfp_recursive_mutex;
|
||||
__sfp_recursive_mutex = (_lock_t) &s_common_recursive_mutex;
|
||||
#elif ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
/* Newlib 3.3.0 is used in ROM, built with _RETARGETABLE_LOCKING.
|
||||
* No access to lock variables for the purpose of ECO forward compatibility,
|
||||
* however we have an API to initialize lock variables used in the ROM.
|
||||
*/
|
||||
extern void esp_rom_newlib_init_common_mutexes(_LOCK_T, _LOCK_T);
|
||||
/* See notes about ROM_NEEDS_MUTEX_OVERRIDE above */
|
||||
int magic_val = ROM_MUTEX_MAGIC;
|
||||
_LOCK_T magic_mutex = (_LOCK_T) &magic_val;
|
||||
esp_rom_newlib_init_common_mutexes(magic_mutex, magic_mutex);
|
||||
#else // other target
|
||||
#error Unsupported target
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[mapping:newlib]
|
||||
archive: libnewlib.a
|
||||
entries:
|
||||
heap (noflash)
|
||||
abort (noflash)
|
||||
assert (noflash)
|
||||
stdatomic (noflash)
|
||||
if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y:
|
||||
stdatomic_s32c1i (noflash)
|
||||
[mapping:newlib]
|
||||
archive: libnewlib.a
|
||||
entries:
|
||||
heap (noflash)
|
||||
abort (noflash)
|
||||
assert (noflash)
|
||||
stdatomic (noflash)
|
||||
if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y:
|
||||
stdatomic_s32c1i (noflash)
|
||||
|
||||
+214
-214
@@ -1,214 +1,214 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/reent.h>
|
||||
#include <assert.h>
|
||||
#include "esp_newlib.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_rom_caps.h"
|
||||
#include "esp_rom_libc_stubs.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
|
||||
extern int _printf_float(struct _reent *rptr,
|
||||
void *pdata,
|
||||
FILE * fp,
|
||||
int (*pfunc)(struct _reent *, FILE *, const char *, size_t len),
|
||||
va_list * ap);
|
||||
|
||||
extern int _scanf_float(struct _reent *rptr,
|
||||
void *pdata,
|
||||
FILE *fp,
|
||||
va_list *ap);
|
||||
|
||||
static void raise_r_stub(struct _reent *rptr)
|
||||
{
|
||||
_raise_r(rptr, 0);
|
||||
}
|
||||
|
||||
static void esp_cleanup_r(struct _reent *rptr)
|
||||
{
|
||||
if (_REENT_STDIN(rptr) != _REENT_STDIN(_GLOBAL_REENT)) {
|
||||
_fclose_r(rptr, _REENT_STDIN(rptr));
|
||||
}
|
||||
|
||||
if (_REENT_STDOUT(rptr) != _REENT_STDOUT(_GLOBAL_REENT)) {
|
||||
_fclose_r(rptr, _REENT_STDOUT(rptr));
|
||||
}
|
||||
|
||||
if (_REENT_STDERR(rptr) != _REENT_STDERR(_GLOBAL_REENT)) {
|
||||
_fclose_r(rptr, _REENT_STDERR(rptr));
|
||||
}
|
||||
}
|
||||
|
||||
static struct syscall_stub_table s_stub_table = {
|
||||
.__getreent = &__getreent,
|
||||
._malloc_r = &_malloc_r,
|
||||
._free_r = &_free_r,
|
||||
._realloc_r = &_realloc_r,
|
||||
._calloc_r = &_calloc_r,
|
||||
._abort = &abort,
|
||||
._system_r = &_system_r,
|
||||
._rename_r = &_rename_r,
|
||||
._times_r = &_times_r,
|
||||
._gettimeofday_r = &_gettimeofday_r,
|
||||
._raise_r = &raise_r_stub,
|
||||
._unlink_r = &_unlink_r,
|
||||
._link_r = &_link_r,
|
||||
._stat_r = &_stat_r,
|
||||
._fstat_r = &_fstat_r,
|
||||
._sbrk_r = &_sbrk_r,
|
||||
._getpid_r = &_getpid_r,
|
||||
._kill_r = &_kill_r,
|
||||
._exit_r = NULL, // never called in ROM
|
||||
._close_r = &_close_r,
|
||||
._open_r = &_open_r,
|
||||
._write_r = (int (*)(struct _reent * r, int, const void *, int)) &_write_r,
|
||||
._lseek_r = (int (*)(struct _reent * r, int, int, int)) &_lseek_r,
|
||||
._read_r = (int (*)(struct _reent * r, int, void *, int)) &_read_r,
|
||||
#if ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
._retarget_lock_init = &__retarget_lock_init,
|
||||
._retarget_lock_init_recursive = &__retarget_lock_init_recursive,
|
||||
._retarget_lock_close = &__retarget_lock_close,
|
||||
._retarget_lock_close_recursive = &__retarget_lock_close_recursive,
|
||||
._retarget_lock_acquire = &__retarget_lock_acquire,
|
||||
._retarget_lock_acquire_recursive = &__retarget_lock_acquire_recursive,
|
||||
._retarget_lock_try_acquire = &__retarget_lock_try_acquire,
|
||||
._retarget_lock_try_acquire_recursive = &__retarget_lock_try_acquire_recursive,
|
||||
._retarget_lock_release = &__retarget_lock_release,
|
||||
._retarget_lock_release_recursive = &__retarget_lock_release_recursive,
|
||||
#else
|
||||
._lock_init = &_lock_init,
|
||||
._lock_init_recursive = &_lock_init_recursive,
|
||||
._lock_close = &_lock_close,
|
||||
._lock_close_recursive = &_lock_close_recursive,
|
||||
._lock_acquire = &_lock_acquire,
|
||||
._lock_acquire_recursive = &_lock_acquire_recursive,
|
||||
._lock_try_acquire = &_lock_try_acquire,
|
||||
._lock_try_acquire_recursive = &_lock_try_acquire_recursive,
|
||||
._lock_release = &_lock_release,
|
||||
._lock_release_recursive = &_lock_release_recursive,
|
||||
#endif
|
||||
#ifdef CONFIG_NEWLIB_NANO_FORMAT
|
||||
._printf_float = &_printf_float,
|
||||
._scanf_float = &_scanf_float,
|
||||
#else
|
||||
._printf_float = NULL,
|
||||
._scanf_float = NULL,
|
||||
#endif
|
||||
#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S2
|
||||
/* TODO IDF-2570 : mark that this assert failed in ROM, to avoid confusion between IDF & ROM
|
||||
assertion failures (as function names & source file names will be similar)
|
||||
*/
|
||||
.__assert_func = __assert_func,
|
||||
|
||||
/* We don't expect either ROM code to ever call __sinit, so it's implemented as abort() for now.
|
||||
|
||||
__sinit may be called in IDF side only if /dev/console used as input/output. It called only
|
||||
once for _GLOBAL_REENT. Then reuse std file pointers from _GLOBAL_REENT in another reents.
|
||||
See esp_newlib_init() and esp_reent_init() for details.
|
||||
*/
|
||||
.__sinit = (void *)abort,
|
||||
._cleanup_r = &esp_cleanup_r,
|
||||
#endif
|
||||
};
|
||||
|
||||
void esp_newlib_init(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
syscall_table_ptr_pro = syscall_table_ptr_app = &s_stub_table;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
syscall_table_ptr_pro = &s_stub_table;
|
||||
#else
|
||||
syscall_table_ptr = &s_stub_table;
|
||||
#endif
|
||||
|
||||
memset(&__sglue, 0, sizeof(__sglue));
|
||||
_global_impure_ptr = _GLOBAL_REENT;
|
||||
|
||||
/* Ensure that the initialization of sfp is prevented until esp_newlib_init_global_stdio() is explicitly invoked. */
|
||||
_GLOBAL_REENT->__cleanup = esp_cleanup_r;
|
||||
_REENT_SDIDINIT(_GLOBAL_REENT) = 1;
|
||||
|
||||
environ = malloc(sizeof(char*));
|
||||
if (environ == 0) {
|
||||
// if allocation fails this early in startup process, there's nothing else other than to panic.
|
||||
abort();
|
||||
}
|
||||
environ[0] = NULL;
|
||||
|
||||
esp_newlib_locks_init();
|
||||
}
|
||||
|
||||
ESP_SYSTEM_INIT_FN(init_newlib, CORE, BIT(0), 102)
|
||||
{
|
||||
esp_newlib_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_setup_newlib_syscalls(void) __attribute__((alias("esp_newlib_init")));
|
||||
|
||||
/**
|
||||
* Postponed _GLOBAL_REENT stdio FPs initialization.
|
||||
*
|
||||
* Can not be a part of esp_reent_init() because stdio device may not initialized yet.
|
||||
*
|
||||
* Called from startup code and FreeRTOS, not intended to be called from
|
||||
* application code.
|
||||
*/
|
||||
void esp_newlib_init_global_stdio(const char *stdio_dev)
|
||||
{
|
||||
if (stdio_dev == NULL) {
|
||||
_GLOBAL_REENT->__cleanup = NULL;
|
||||
_REENT_SDIDINIT(_GLOBAL_REENT) = 0;
|
||||
__sinit(_GLOBAL_REENT);
|
||||
_GLOBAL_REENT->__cleanup = esp_cleanup_r;
|
||||
_REENT_SDIDINIT(_GLOBAL_REENT) = 1;
|
||||
} else {
|
||||
_REENT_STDIN(_GLOBAL_REENT) = fopen(stdio_dev, "r");
|
||||
_REENT_STDOUT(_GLOBAL_REENT) = fopen(stdio_dev, "w");
|
||||
_REENT_STDERR(_GLOBAL_REENT) = fopen(stdio_dev, "w");
|
||||
#if ESP_ROM_NEEDS_SWSETUP_WORKAROUND
|
||||
/*
|
||||
- This workaround for printf functions using 32-bit time_t after the 64-bit time_t upgrade
|
||||
- The 32-bit time_t usage is triggered through ROM Newlib functions printf related functions calling __swsetup_r() on
|
||||
the first call to a particular file pointer (i.e., stdin, stdout, stderr)
|
||||
- Thus, we call the toolchain version of __swsetup_r() now (before any printf calls are made) to setup all of the
|
||||
file pointers. Thus, the ROM newlib code will never call the ROM version of __swsetup_r().
|
||||
- See IDFGH-7728 for more details
|
||||
*/
|
||||
extern int __swsetup_r(struct _reent *, FILE *);
|
||||
__swsetup_r(_GLOBAL_REENT, _REENT_STDIN(_GLOBAL_REENT));
|
||||
__swsetup_r(_GLOBAL_REENT, _REENT_STDOUT(_GLOBAL_REENT));
|
||||
__swsetup_r(_GLOBAL_REENT, _REENT_STDERR(_GLOBAL_REENT));
|
||||
#endif /* ESP_ROM_NEEDS_SWSETUP_WORKAROUND */
|
||||
}
|
||||
}
|
||||
|
||||
ESP_SYSTEM_INIT_FN(init_newlib_stdio, CORE, BIT(0), 115)
|
||||
{
|
||||
#if defined(CONFIG_VFS_SUPPORT_IO)
|
||||
esp_newlib_init_global_stdio("/dev/console");
|
||||
#else
|
||||
esp_newlib_init_global_stdio(NULL);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Hook to force the linker to include this file
|
||||
void newlib_include_init_funcs(void)
|
||||
{
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/reent.h>
|
||||
#include <assert.h>
|
||||
#include "esp_newlib.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_rom_caps.h"
|
||||
#include "esp_rom_libc_stubs.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
|
||||
extern int _printf_float(struct _reent *rptr,
|
||||
void *pdata,
|
||||
FILE * fp,
|
||||
int (*pfunc)(struct _reent *, FILE *, const char *, size_t len),
|
||||
va_list * ap);
|
||||
|
||||
extern int _scanf_float(struct _reent *rptr,
|
||||
void *pdata,
|
||||
FILE *fp,
|
||||
va_list *ap);
|
||||
|
||||
static void raise_r_stub(struct _reent *rptr)
|
||||
{
|
||||
_raise_r(rptr, 0);
|
||||
}
|
||||
|
||||
static void esp_cleanup_r(struct _reent *rptr)
|
||||
{
|
||||
if (_REENT_STDIN(rptr) != _REENT_STDIN(_GLOBAL_REENT)) {
|
||||
_fclose_r(rptr, _REENT_STDIN(rptr));
|
||||
}
|
||||
|
||||
if (_REENT_STDOUT(rptr) != _REENT_STDOUT(_GLOBAL_REENT)) {
|
||||
_fclose_r(rptr, _REENT_STDOUT(rptr));
|
||||
}
|
||||
|
||||
if (_REENT_STDERR(rptr) != _REENT_STDERR(_GLOBAL_REENT)) {
|
||||
_fclose_r(rptr, _REENT_STDERR(rptr));
|
||||
}
|
||||
}
|
||||
|
||||
static struct syscall_stub_table s_stub_table = {
|
||||
.__getreent = &__getreent,
|
||||
._malloc_r = &_malloc_r,
|
||||
._free_r = &_free_r,
|
||||
._realloc_r = &_realloc_r,
|
||||
._calloc_r = &_calloc_r,
|
||||
._abort = &abort,
|
||||
._system_r = &_system_r,
|
||||
._rename_r = &_rename_r,
|
||||
._times_r = &_times_r,
|
||||
._gettimeofday_r = &_gettimeofday_r,
|
||||
._raise_r = &raise_r_stub,
|
||||
._unlink_r = &_unlink_r,
|
||||
._link_r = &_link_r,
|
||||
._stat_r = &_stat_r,
|
||||
._fstat_r = &_fstat_r,
|
||||
._sbrk_r = &_sbrk_r,
|
||||
._getpid_r = &_getpid_r,
|
||||
._kill_r = &_kill_r,
|
||||
._exit_r = NULL, // never called in ROM
|
||||
._close_r = &_close_r,
|
||||
._open_r = &_open_r,
|
||||
._write_r = (int (*)(struct _reent * r, int, const void *, int)) &_write_r,
|
||||
._lseek_r = (int (*)(struct _reent * r, int, int, int)) &_lseek_r,
|
||||
._read_r = (int (*)(struct _reent * r, int, void *, int)) &_read_r,
|
||||
#if ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
._retarget_lock_init = &__retarget_lock_init,
|
||||
._retarget_lock_init_recursive = &__retarget_lock_init_recursive,
|
||||
._retarget_lock_close = &__retarget_lock_close,
|
||||
._retarget_lock_close_recursive = &__retarget_lock_close_recursive,
|
||||
._retarget_lock_acquire = &__retarget_lock_acquire,
|
||||
._retarget_lock_acquire_recursive = &__retarget_lock_acquire_recursive,
|
||||
._retarget_lock_try_acquire = &__retarget_lock_try_acquire,
|
||||
._retarget_lock_try_acquire_recursive = &__retarget_lock_try_acquire_recursive,
|
||||
._retarget_lock_release = &__retarget_lock_release,
|
||||
._retarget_lock_release_recursive = &__retarget_lock_release_recursive,
|
||||
#else
|
||||
._lock_init = &_lock_init,
|
||||
._lock_init_recursive = &_lock_init_recursive,
|
||||
._lock_close = &_lock_close,
|
||||
._lock_close_recursive = &_lock_close_recursive,
|
||||
._lock_acquire = &_lock_acquire,
|
||||
._lock_acquire_recursive = &_lock_acquire_recursive,
|
||||
._lock_try_acquire = &_lock_try_acquire,
|
||||
._lock_try_acquire_recursive = &_lock_try_acquire_recursive,
|
||||
._lock_release = &_lock_release,
|
||||
._lock_release_recursive = &_lock_release_recursive,
|
||||
#endif
|
||||
#ifdef CONFIG_NEWLIB_NANO_FORMAT
|
||||
._printf_float = &_printf_float,
|
||||
._scanf_float = &_scanf_float,
|
||||
#else
|
||||
._printf_float = NULL,
|
||||
._scanf_float = NULL,
|
||||
#endif
|
||||
#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S2
|
||||
/* TODO IDF-2570 : mark that this assert failed in ROM, to avoid confusion between IDF & ROM
|
||||
assertion failures (as function names & source file names will be similar)
|
||||
*/
|
||||
.__assert_func = __assert_func,
|
||||
|
||||
/* We don't expect either ROM code to ever call __sinit, so it's implemented as abort() for now.
|
||||
|
||||
__sinit may be called in IDF side only if /dev/console used as input/output. It called only
|
||||
once for _GLOBAL_REENT. Then reuse std file pointers from _GLOBAL_REENT in another reents.
|
||||
See esp_newlib_init() and esp_reent_init() for details.
|
||||
*/
|
||||
.__sinit = (void *)abort,
|
||||
._cleanup_r = &esp_cleanup_r,
|
||||
#endif
|
||||
};
|
||||
|
||||
void esp_newlib_init(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
syscall_table_ptr_pro = syscall_table_ptr_app = &s_stub_table;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
syscall_table_ptr_pro = &s_stub_table;
|
||||
#else
|
||||
syscall_table_ptr = &s_stub_table;
|
||||
#endif
|
||||
|
||||
memset(&__sglue, 0, sizeof(__sglue));
|
||||
_global_impure_ptr = _GLOBAL_REENT;
|
||||
|
||||
/* Ensure that the initialization of sfp is prevented until esp_newlib_init_global_stdio() is explicitly invoked. */
|
||||
_GLOBAL_REENT->__cleanup = esp_cleanup_r;
|
||||
_REENT_SDIDINIT(_GLOBAL_REENT) = 1;
|
||||
|
||||
environ = malloc(sizeof(char*));
|
||||
if (environ == 0) {
|
||||
// if allocation fails this early in startup process, there's nothing else other than to panic.
|
||||
abort();
|
||||
}
|
||||
environ[0] = NULL;
|
||||
|
||||
esp_newlib_locks_init();
|
||||
}
|
||||
|
||||
ESP_SYSTEM_INIT_FN(init_newlib, CORE, BIT(0), 102)
|
||||
{
|
||||
esp_newlib_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_setup_newlib_syscalls(void) __attribute__((alias("esp_newlib_init")));
|
||||
|
||||
/**
|
||||
* Postponed _GLOBAL_REENT stdio FPs initialization.
|
||||
*
|
||||
* Can not be a part of esp_reent_init() because stdio device may not initialized yet.
|
||||
*
|
||||
* Called from startup code and FreeRTOS, not intended to be called from
|
||||
* application code.
|
||||
*/
|
||||
void esp_newlib_init_global_stdio(const char *stdio_dev)
|
||||
{
|
||||
if (stdio_dev == NULL) {
|
||||
_GLOBAL_REENT->__cleanup = NULL;
|
||||
_REENT_SDIDINIT(_GLOBAL_REENT) = 0;
|
||||
__sinit(_GLOBAL_REENT);
|
||||
_GLOBAL_REENT->__cleanup = esp_cleanup_r;
|
||||
_REENT_SDIDINIT(_GLOBAL_REENT) = 1;
|
||||
} else {
|
||||
_REENT_STDIN(_GLOBAL_REENT) = fopen(stdio_dev, "r");
|
||||
_REENT_STDOUT(_GLOBAL_REENT) = fopen(stdio_dev, "w");
|
||||
_REENT_STDERR(_GLOBAL_REENT) = fopen(stdio_dev, "w");
|
||||
#if ESP_ROM_NEEDS_SWSETUP_WORKAROUND
|
||||
/*
|
||||
- This workaround for printf functions using 32-bit time_t after the 64-bit time_t upgrade
|
||||
- The 32-bit time_t usage is triggered through ROM Newlib functions printf related functions calling __swsetup_r() on
|
||||
the first call to a particular file pointer (i.e., stdin, stdout, stderr)
|
||||
- Thus, we call the toolchain version of __swsetup_r() now (before any printf calls are made) to setup all of the
|
||||
file pointers. Thus, the ROM newlib code will never call the ROM version of __swsetup_r().
|
||||
- See IDFGH-7728 for more details
|
||||
*/
|
||||
extern int __swsetup_r(struct _reent *, FILE *);
|
||||
__swsetup_r(_GLOBAL_REENT, _REENT_STDIN(_GLOBAL_REENT));
|
||||
__swsetup_r(_GLOBAL_REENT, _REENT_STDOUT(_GLOBAL_REENT));
|
||||
__swsetup_r(_GLOBAL_REENT, _REENT_STDERR(_GLOBAL_REENT));
|
||||
#endif /* ESP_ROM_NEEDS_SWSETUP_WORKAROUND */
|
||||
}
|
||||
}
|
||||
|
||||
ESP_SYSTEM_INIT_FN(init_newlib_stdio, CORE, BIT(0), 115)
|
||||
{
|
||||
#if defined(CONFIG_VFS_SUPPORT_IO)
|
||||
esp_newlib_init_global_stdio("/dev/console");
|
||||
#else
|
||||
esp_newlib_init_global_stdio(NULL);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Hook to force the linker to include this file
|
||||
void newlib_include_init_funcs(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* This header file wraps newlib's own unmodified assert.h and adds
|
||||
support for silent assertion failure.
|
||||
*/
|
||||
#pragma once
|
||||
#include <sdkconfig.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include_next <assert.h>
|
||||
|
||||
/* moved part of libc provided assert to here allows
|
||||
* tweaking the assert macro to use __builtin_expect()
|
||||
* and reduce jumps in the "asserts OK" code path
|
||||
*
|
||||
* Note: using __builtin_expect() not likely() to avoid defining the likely
|
||||
* macro in namespace of non-IDF code that may include this standard header.
|
||||
*/
|
||||
#undef assert
|
||||
|
||||
/* __FILENAME__ points to the file name instead of path + filename
|
||||
* e.g __FILE__ points to "/apps/test.c" where as __FILENAME__ points to "test.c"
|
||||
*/
|
||||
#define __FILENAME__ (__builtin_strrchr( "/" __FILE__, '/') + 1)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
|
||||
#define assert(__e) ((void)(__e))
|
||||
|
||||
#elif CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
|
||||
#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func(NULL, 0, NULL, NULL))
|
||||
|
||||
#else // !CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
|
||||
#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func (__FILENAME__, __LINE__, \
|
||||
__ASSERT_FUNC, #__e))
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* This header file wraps newlib's own unmodified assert.h and adds
|
||||
support for silent assertion failure.
|
||||
*/
|
||||
#pragma once
|
||||
#include <sdkconfig.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include_next <assert.h>
|
||||
|
||||
/* moved part of libc provided assert to here allows
|
||||
* tweaking the assert macro to use __builtin_expect()
|
||||
* and reduce jumps in the "asserts OK" code path
|
||||
*
|
||||
* Note: using __builtin_expect() not likely() to avoid defining the likely
|
||||
* macro in namespace of non-IDF code that may include this standard header.
|
||||
*/
|
||||
#undef assert
|
||||
|
||||
/* __FILENAME__ points to the file name instead of path + filename
|
||||
* e.g __FILE__ points to "/apps/test.c" where as __FILENAME__ points to "test.c"
|
||||
*/
|
||||
#define __FILENAME__ (__builtin_strrchr( "/" __FILE__, '/') + 1)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
|
||||
#define assert(__e) ((void)(__e))
|
||||
|
||||
#elif CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
|
||||
#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func(NULL, 0, NULL, NULL))
|
||||
|
||||
#else // !CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
|
||||
#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func (__FILENAME__, __LINE__, \
|
||||
__ASSERT_FUNC, #__e))
|
||||
#endif
|
||||
|
||||
@@ -1,208 +1,208 @@
|
||||
/*
|
||||
* All the code below is a rework of
|
||||
* https://github.com/freebsd/freebsd/blob/master/sys/sys/endian.h
|
||||
* to import symbols defining non-standard endian handling functions.
|
||||
* The aforementioned source code license terms are included here.
|
||||
* For further license info, please look at https://github.com/freebsd/freebsd
|
||||
*/
|
||||
|
||||
/*-
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020 Francesco Giancane <francesco.giancane@accenture.com>
|
||||
* SPDX-FileCopyrightText: 2002 Thomas Moestl <tmm@FreeBSD.org>
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* This is a compatibility header for <endian.h>.
|
||||
* In xtensa-newlib distribution it is located in <machine/endian.h>
|
||||
* but most program expect to be plain <endian.h>.
|
||||
*/
|
||||
#include <machine/endian.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* General byte order swapping functions.
|
||||
*/
|
||||
#define bswap16(x) __bswap16(x)
|
||||
#define bswap32(x) __bswap32(x)
|
||||
#define bswap64(x) __bswap64(x)
|
||||
|
||||
/*
|
||||
* Host to big endian, host to little endian, big endian to host, and little
|
||||
* endian to host byte order functions as detailed in byteorder(9).
|
||||
*/
|
||||
#if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
#define htobe16(x) bswap16((x))
|
||||
#define htobe32(x) bswap32((x))
|
||||
#define htobe64(x) bswap64((x))
|
||||
#define htole16(x) ((uint16_t)(x))
|
||||
#define htole32(x) ((uint32_t)(x))
|
||||
#define htole64(x) ((uint64_t)(x))
|
||||
|
||||
#define be16toh(x) bswap16((x))
|
||||
#define be32toh(x) bswap32((x))
|
||||
#define be64toh(x) bswap64((x))
|
||||
#define le16toh(x) ((uint16_t)(x))
|
||||
#define le32toh(x) ((uint32_t)(x))
|
||||
#define le64toh(x) ((uint64_t)(x))
|
||||
#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
|
||||
#define htobe16(x) ((uint16_t)(x))
|
||||
#define htobe32(x) ((uint32_t)(x))
|
||||
#define htobe64(x) ((uint64_t)(x))
|
||||
#define htole16(x) bswap16((x))
|
||||
#define htole32(x) bswap32((x))
|
||||
#define htole64(x) bswap64((x))
|
||||
|
||||
#define be16toh(x) ((uint16_t)(x))
|
||||
#define be32toh(x) ((uint32_t)(x))
|
||||
#define be64toh(x) ((uint64_t)(x))
|
||||
#define le16toh(x) bswap16((x))
|
||||
#define le32toh(x) bswap32((x))
|
||||
#define le64toh(x) bswap64((x))
|
||||
#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
|
||||
|
||||
/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
|
||||
|
||||
static __inline uint16_t
|
||||
be16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
be32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
be64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
le16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
le32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
le64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 8) & 0xff;
|
||||
p[1] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 24) & 0xff;
|
||||
p[1] = (u >> 16) & 0xff;
|
||||
p[2] = (u >> 8) & 0xff;
|
||||
p[3] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
be32enc(p, (uint32_t)(u >> 32));
|
||||
be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
p[2] = (u >> 16) & 0xff;
|
||||
p[3] = (u >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
le32enc(p, (uint32_t)(u & 0xffffffffU));
|
||||
le32enc(p + 4, (uint32_t)(u >> 32));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* All the code below is a rework of
|
||||
* https://github.com/freebsd/freebsd/blob/master/sys/sys/endian.h
|
||||
* to import symbols defining non-standard endian handling functions.
|
||||
* The aforementioned source code license terms are included here.
|
||||
* For further license info, please look at https://github.com/freebsd/freebsd
|
||||
*/
|
||||
|
||||
/*-
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020 Francesco Giancane <francesco.giancane@accenture.com>
|
||||
* SPDX-FileCopyrightText: 2002 Thomas Moestl <tmm@FreeBSD.org>
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* This is a compatibility header for <endian.h>.
|
||||
* In xtensa-newlib distribution it is located in <machine/endian.h>
|
||||
* but most program expect to be plain <endian.h>.
|
||||
*/
|
||||
#include <machine/endian.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* General byte order swapping functions.
|
||||
*/
|
||||
#define bswap16(x) __bswap16(x)
|
||||
#define bswap32(x) __bswap32(x)
|
||||
#define bswap64(x) __bswap64(x)
|
||||
|
||||
/*
|
||||
* Host to big endian, host to little endian, big endian to host, and little
|
||||
* endian to host byte order functions as detailed in byteorder(9).
|
||||
*/
|
||||
#if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
#define htobe16(x) bswap16((x))
|
||||
#define htobe32(x) bswap32((x))
|
||||
#define htobe64(x) bswap64((x))
|
||||
#define htole16(x) ((uint16_t)(x))
|
||||
#define htole32(x) ((uint32_t)(x))
|
||||
#define htole64(x) ((uint64_t)(x))
|
||||
|
||||
#define be16toh(x) bswap16((x))
|
||||
#define be32toh(x) bswap32((x))
|
||||
#define be64toh(x) bswap64((x))
|
||||
#define le16toh(x) ((uint16_t)(x))
|
||||
#define le32toh(x) ((uint32_t)(x))
|
||||
#define le64toh(x) ((uint64_t)(x))
|
||||
#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
|
||||
#define htobe16(x) ((uint16_t)(x))
|
||||
#define htobe32(x) ((uint32_t)(x))
|
||||
#define htobe64(x) ((uint64_t)(x))
|
||||
#define htole16(x) bswap16((x))
|
||||
#define htole32(x) bswap32((x))
|
||||
#define htole64(x) bswap64((x))
|
||||
|
||||
#define be16toh(x) ((uint16_t)(x))
|
||||
#define be32toh(x) ((uint32_t)(x))
|
||||
#define be64toh(x) ((uint64_t)(x))
|
||||
#define le16toh(x) bswap16((x))
|
||||
#define le32toh(x) bswap32((x))
|
||||
#define le64toh(x) bswap64((x))
|
||||
#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
|
||||
|
||||
/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
|
||||
|
||||
static __inline uint16_t
|
||||
be16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
be32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
be64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
le16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
le32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
le64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 8) & 0xff;
|
||||
p[1] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 24) & 0xff;
|
||||
p[1] = (u >> 16) & 0xff;
|
||||
p[2] = (u >> 8) & 0xff;
|
||||
p[3] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
be32enc(p, (uint32_t)(u >> 32));
|
||||
be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
p[2] = (u >> 16) & 0xff;
|
||||
p[3] = (u >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
le32enc(p, (uint32_t)(u & 0xffffffffU));
|
||||
le32enc(p + 4, (uint32_t)(u >> 32));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_PLATFORM_ERRNO_H_
|
||||
#define _ESP_PLATFORM_ERRNO_H_
|
||||
|
||||
#include_next "errno.h"
|
||||
|
||||
//
|
||||
// Possibly define some missing errors
|
||||
//
|
||||
#ifndef ESHUTDOWN
|
||||
#define ESHUTDOWN 110 /* Cannot send after transport endpoint shutdown */
|
||||
#endif
|
||||
|
||||
#ifndef EAI_SOCKTYPE
|
||||
#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
|
||||
#endif
|
||||
|
||||
#ifndef EAI_AGAIN
|
||||
#define EAI_AGAIN 2 /* temporary failure in name resolution */
|
||||
#endif
|
||||
|
||||
#ifndef EAI_BADFLAGS
|
||||
#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
|
||||
#endif
|
||||
|
||||
#endif // _ESP_PLATFORM_ERRNO_H_
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_PLATFORM_ERRNO_H_
|
||||
#define _ESP_PLATFORM_ERRNO_H_
|
||||
|
||||
#include_next "errno.h"
|
||||
|
||||
//
|
||||
// Possibly define some missing errors
|
||||
//
|
||||
#ifndef ESHUTDOWN
|
||||
#define ESHUTDOWN 110 /* Cannot send after transport endpoint shutdown */
|
||||
#endif
|
||||
|
||||
#ifndef EAI_SOCKTYPE
|
||||
#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
|
||||
#endif
|
||||
|
||||
#ifndef EAI_AGAIN
|
||||
#define EAI_AGAIN 2 /* temporary failure in name resolution */
|
||||
#endif
|
||||
|
||||
#ifndef EAI_BADFLAGS
|
||||
#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
|
||||
#endif
|
||||
|
||||
#endif // _ESP_PLATFORM_ERRNO_H_
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/reent.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize newlib time functions
|
||||
*/
|
||||
void esp_newlib_time_init(void);
|
||||
|
||||
/**
|
||||
* Replacement for newlib's _REENT_INIT_PTR and __sinit.
|
||||
*
|
||||
* Called from startup code and FreeRTOS, not intended to be called from
|
||||
* application code.
|
||||
*/
|
||||
void esp_reent_init(struct _reent* r);
|
||||
|
||||
/**
|
||||
* Postponed _GLOBAL_REENT stdio FPs initialization.
|
||||
*
|
||||
* Can not be a part of esp_reent_init() because stdio device may not initialized yet.
|
||||
*
|
||||
* Called from startup code and FreeRTOS, not intended to be called from
|
||||
* application code.
|
||||
*
|
||||
*/
|
||||
void esp_newlib_init_global_stdio(const char* stdio_dev);
|
||||
|
||||
/**
|
||||
* Clean up some of lazily allocated buffers in REENT structures.
|
||||
*/
|
||||
void esp_reent_cleanup(void);
|
||||
|
||||
/**
|
||||
* Function which sets up newlib in ROM for use with ESP-IDF
|
||||
*
|
||||
* Includes defining the syscall table, setting up any common locks, etc.
|
||||
*
|
||||
* Called from the startup code, not intended to be called from application
|
||||
* code.
|
||||
*/
|
||||
void esp_newlib_init(void);
|
||||
|
||||
void esp_setup_syscall_table(void) __attribute__((deprecated("Please call esp_newlib_init() in newer code")));
|
||||
|
||||
/**
|
||||
* Update current microsecond time from RTC
|
||||
*/
|
||||
void esp_set_time_from_rtc(void);
|
||||
|
||||
/*
|
||||
* Sync timekeeping timers, RTC and high-resolution timer. Update boot_time.
|
||||
*/
|
||||
void esp_sync_timekeeping_timers(void);
|
||||
|
||||
/* Kept for backward compatibility */
|
||||
#define esp_sync_counters_rtc_and_frc esp_sync_timekeeping_timers
|
||||
|
||||
/**
|
||||
* Initialize newlib static locks
|
||||
*/
|
||||
void esp_newlib_locks_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/reent.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize newlib time functions
|
||||
*/
|
||||
void esp_newlib_time_init(void);
|
||||
|
||||
/**
|
||||
* Replacement for newlib's _REENT_INIT_PTR and __sinit.
|
||||
*
|
||||
* Called from startup code and FreeRTOS, not intended to be called from
|
||||
* application code.
|
||||
*/
|
||||
void esp_reent_init(struct _reent* r);
|
||||
|
||||
/**
|
||||
* Postponed _GLOBAL_REENT stdio FPs initialization.
|
||||
*
|
||||
* Can not be a part of esp_reent_init() because stdio device may not initialized yet.
|
||||
*
|
||||
* Called from startup code and FreeRTOS, not intended to be called from
|
||||
* application code.
|
||||
*
|
||||
*/
|
||||
void esp_newlib_init_global_stdio(const char* stdio_dev);
|
||||
|
||||
/**
|
||||
* Clean up some of lazily allocated buffers in REENT structures.
|
||||
*/
|
||||
void esp_reent_cleanup(void);
|
||||
|
||||
/**
|
||||
* Function which sets up newlib in ROM for use with ESP-IDF
|
||||
*
|
||||
* Includes defining the syscall table, setting up any common locks, etc.
|
||||
*
|
||||
* Called from the startup code, not intended to be called from application
|
||||
* code.
|
||||
*/
|
||||
void esp_newlib_init(void);
|
||||
|
||||
void esp_setup_syscall_table(void) __attribute__((deprecated("Please call esp_newlib_init() in newer code")));
|
||||
|
||||
/**
|
||||
* Update current microsecond time from RTC
|
||||
*/
|
||||
void esp_set_time_from_rtc(void);
|
||||
|
||||
/*
|
||||
* Sync timekeeping timers, RTC and high-resolution timer. Update boot_time.
|
||||
*/
|
||||
void esp_sync_timekeeping_timers(void);
|
||||
|
||||
/* Kept for backward compatibility */
|
||||
#define esp_sync_counters_rtc_and_frc esp_sync_timekeeping_timers
|
||||
|
||||
/**
|
||||
* Initialize newlib static locks
|
||||
*/
|
||||
void esp_newlib_locks_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_PLATFORM_NET_IF_H_
|
||||
#define _ESP_PLATFORM_NET_IF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/if_api.h"
|
||||
|
||||
#define MSG_DONTROUTE 0x4 /* send without using routing tables */
|
||||
#define SOCK_SEQPACKET 5 /* sequenced packet stream */
|
||||
#define MSG_EOR 0x8 /* data completes record */
|
||||
#define SOCK_SEQPACKET 5 /* sequenced packet stream */
|
||||
#define SOMAXCONN 128
|
||||
|
||||
#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
|
||||
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
#define NI_NUMERICSERV 0x00000008
|
||||
#define NI_DGRAM 0x00000010
|
||||
|
||||
typedef u32_t socklen_t;
|
||||
|
||||
unsigned int if_nametoindex(const char *ifname);
|
||||
|
||||
char *if_indextoname(unsigned int ifindex, char *ifname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _ESP_PLATFORM_NET_IF_H_
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_PLATFORM_NET_IF_H_
|
||||
#define _ESP_PLATFORM_NET_IF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/if_api.h"
|
||||
|
||||
#define MSG_DONTROUTE 0x4 /* send without using routing tables */
|
||||
#define SOCK_SEQPACKET 5 /* sequenced packet stream */
|
||||
#define MSG_EOR 0x8 /* data completes record */
|
||||
#define SOCK_SEQPACKET 5 /* sequenced packet stream */
|
||||
#define SOMAXCONN 128
|
||||
|
||||
#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
|
||||
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
#define NI_NUMERICSERV 0x00000008
|
||||
#define NI_DGRAM 0x00000010
|
||||
|
||||
typedef u32_t socklen_t;
|
||||
|
||||
unsigned int if_nametoindex(const char *ifname);
|
||||
|
||||
char *if_indextoname(unsigned int ifindex, char *ifname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _ESP_PLATFORM_NET_IF_H_
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __ESP_PLATFORM_PTHREAD_H__
|
||||
#define __ESP_PLATFORM_PTHREAD_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/features.h>
|
||||
|
||||
#include_next <pthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int pthread_condattr_getclock(const pthread_condattr_t * attr, clockid_t * clock_id);
|
||||
|
||||
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ESP_PLATFORM_PTHREAD_H__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __ESP_PLATFORM_PTHREAD_H__
|
||||
#define __ESP_PLATFORM_PTHREAD_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/features.h>
|
||||
|
||||
#include_next <pthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int pthread_condattr_getclock(const pthread_condattr_t * attr, clockid_t * clock_id);
|
||||
|
||||
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ESP_PLATFORM_PTHREAD_H__
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned int sem_t;
|
||||
|
||||
/**
|
||||
* This is the maximum value to which any POSIX semaphore can count on ESP chips.
|
||||
*/
|
||||
#define SEM_VALUE_MAX 0x7FFF
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Must NOT be called if threads are still blocked on semaphore!
|
||||
*/
|
||||
int sem_destroy(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Note that on ESP chips, pshared is ignored. Semaphores can always be shared between FreeRTOS tasks.
|
||||
*/
|
||||
int sem_init(sem_t *sem, int pshared, unsigned value);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Note that, unlike specified in POSIX, this implementation returns -1 and sets errno to
|
||||
* EAGAIN if the semaphore can not be unlocked (posted) due to its value being SEM_VALUE_MAX.
|
||||
*/
|
||||
int sem_post(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Note the following three deviations/issues originating from the underlying FreeRTOS implementation:
|
||||
* * The time value passed by abstime will be rounded up to the next FreeRTOS tick.
|
||||
* * The actual timeout will happen after the tick the time was rounded to
|
||||
* and before the following tick.
|
||||
* * It is possible, though unlikely, that the task is preempted directly after the timeout calculation,
|
||||
* delaying timeout of the following blocking operating system call by the duration of the preemption.
|
||||
*/
|
||||
int sem_timedwait(sem_t *semaphore, const struct timespec *abstime);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*/
|
||||
int sem_trywait(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*/
|
||||
int sem_wait(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*/
|
||||
int sem_getvalue(sem_t *sem, int *sval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned int sem_t;
|
||||
|
||||
/**
|
||||
* This is the maximum value to which any POSIX semaphore can count on ESP chips.
|
||||
*/
|
||||
#define SEM_VALUE_MAX 0x7FFF
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Must NOT be called if threads are still blocked on semaphore!
|
||||
*/
|
||||
int sem_destroy(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Note that on ESP chips, pshared is ignored. Semaphores can always be shared between FreeRTOS tasks.
|
||||
*/
|
||||
int sem_init(sem_t *sem, int pshared, unsigned value);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Note that, unlike specified in POSIX, this implementation returns -1 and sets errno to
|
||||
* EAGAIN if the semaphore can not be unlocked (posted) due to its value being SEM_VALUE_MAX.
|
||||
*/
|
||||
int sem_post(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*
|
||||
* Note the following three deviations/issues originating from the underlying FreeRTOS implementation:
|
||||
* * The time value passed by abstime will be rounded up to the next FreeRTOS tick.
|
||||
* * The actual timeout will happen after the tick the time was rounded to
|
||||
* and before the following tick.
|
||||
* * It is possible, though unlikely, that the task is preempted directly after the timeout calculation,
|
||||
* delaying timeout of the following blocking operating system call by the duration of the preemption.
|
||||
*/
|
||||
int sem_timedwait(sem_t *semaphore, const struct timespec *abstime);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*/
|
||||
int sem_trywait(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*/
|
||||
int sem_wait(sem_t *sem);
|
||||
|
||||
/**
|
||||
* This is a POSIX function, please refer to the POSIX specification for a detailed description.
|
||||
*/
|
||||
int sem_getvalue(sem_t *sem, int *sval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifdef __clang__ // TODO LLVM-330
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* This header file provides POSIX-compatible definitions of directory
|
||||
* access data types. Starting with newlib 3.3, related functions are defined
|
||||
* in 'dirent.h' bundled with newlib.
|
||||
* See http://pubs.opengroup.org/onlinepubs/7908799/xsh/dirent.h.html
|
||||
* for reference.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Opaque directory structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t dd_vfs_idx; /*!< VFS index, not to be used by applications */
|
||||
uint16_t dd_rsv; /*!< field reserved for future extension */
|
||||
/* remaining fields are defined by VFS implementation */
|
||||
} DIR;
|
||||
|
||||
/**
|
||||
* @brief Directory entry structure
|
||||
*/
|
||||
struct dirent {
|
||||
ino_t d_ino; /*!< file number */
|
||||
uint8_t d_type; /*!< not defined in POSIX, but present in BSD and Linux */
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_REG 1
|
||||
#define DT_DIR 2
|
||||
#if __BSD_VISIBLE
|
||||
#define MAXNAMLEN 255
|
||||
char d_name[MAXNAMLEN + 1]; /*!< zero-terminated file name */
|
||||
#else
|
||||
char d_name[256];
|
||||
#endif
|
||||
};
|
||||
|
||||
DIR* opendir(const char* name);
|
||||
struct dirent* readdir(DIR* pdir);
|
||||
long telldir(DIR* pdir);
|
||||
void seekdir(DIR* pdir, long loc);
|
||||
void rewinddir(DIR* pdir);
|
||||
int closedir(DIR* pdir);
|
||||
int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
|
||||
int scandir(const char *dirname, struct dirent ***out_dirlist,
|
||||
int (*select_func)(const struct dirent *),
|
||||
int (*cmp_func)(const struct dirent **, const struct dirent **));
|
||||
int alphasort(const struct dirent **d1, const struct dirent **d2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // __clang__ TODO: IDF-10675
|
||||
#include_next <sys/dirent.h>
|
||||
#include <dirent.h>
|
||||
#endif // __clang__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifdef __clang__ // TODO LLVM-330
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* This header file provides POSIX-compatible definitions of directory
|
||||
* access data types. Starting with newlib 3.3, related functions are defined
|
||||
* in 'dirent.h' bundled with newlib.
|
||||
* See http://pubs.opengroup.org/onlinepubs/7908799/xsh/dirent.h.html
|
||||
* for reference.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Opaque directory structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t dd_vfs_idx; /*!< VFS index, not to be used by applications */
|
||||
uint16_t dd_rsv; /*!< field reserved for future extension */
|
||||
/* remaining fields are defined by VFS implementation */
|
||||
} DIR;
|
||||
|
||||
/**
|
||||
* @brief Directory entry structure
|
||||
*/
|
||||
struct dirent {
|
||||
ino_t d_ino; /*!< file number */
|
||||
uint8_t d_type; /*!< not defined in POSIX, but present in BSD and Linux */
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_REG 1
|
||||
#define DT_DIR 2
|
||||
#if __BSD_VISIBLE
|
||||
#define MAXNAMLEN 255
|
||||
char d_name[MAXNAMLEN + 1]; /*!< zero-terminated file name */
|
||||
#else
|
||||
char d_name[256];
|
||||
#endif
|
||||
};
|
||||
|
||||
DIR* opendir(const char* name);
|
||||
struct dirent* readdir(DIR* pdir);
|
||||
long telldir(DIR* pdir);
|
||||
void seekdir(DIR* pdir, long loc);
|
||||
void rewinddir(DIR* pdir);
|
||||
int closedir(DIR* pdir);
|
||||
int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
|
||||
int scandir(const char *dirname, struct dirent ***out_dirlist,
|
||||
int (*select_func)(const struct dirent *),
|
||||
int (*cmp_func)(const struct dirent **, const struct dirent **));
|
||||
int alphasort(const struct dirent **d1, const struct dirent **d2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // __clang__ TODO: IDF-10675
|
||||
#include_next <sys/dirent.h>
|
||||
#include <dirent.h>
|
||||
#endif // __clang__
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ioctl(int fd, int request, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ioctl(int fd, int request, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include_next <sys/lock.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef _RETARGETABLE_LOCKING
|
||||
|
||||
/* Actual platfrom-specific definition of struct __lock.
|
||||
* The size here should be sufficient for a FreeRTOS mutex.
|
||||
* This is checked by a static assertion in locks.c
|
||||
*
|
||||
* Note: this might need to be made dependent on whether FreeRTOS
|
||||
* is included in the build.
|
||||
*/
|
||||
struct __lock {
|
||||
#if (CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && CONFIG_FREERTOS_USE_TRACE_FACILITY)
|
||||
int reserved[29];
|
||||
#elif (CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && !CONFIG_FREERTOS_USE_TRACE_FACILITY)
|
||||
int reserved[27];
|
||||
#elif (!CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && CONFIG_FREERTOS_USE_TRACE_FACILITY)
|
||||
int reserved[23];
|
||||
#else
|
||||
int reserved[21];
|
||||
#endif /* #if (CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && CONFIG_FREERTOS_USE_TRACE_FACILITY) */
|
||||
};
|
||||
|
||||
/* Compatibility definitions for the legacy ESP-specific locking implementation.
|
||||
* These used to be provided by libc/sys/xtensa/sys/lock.h in newlib.
|
||||
* Newer versions of newlib don't have this ESP-specific lock.h header, and are
|
||||
* built with _RETARGETABLE_LOCKING enabled, instead.
|
||||
*/
|
||||
|
||||
typedef _LOCK_T _lock_t;
|
||||
|
||||
void _lock_init(_lock_t *plock);
|
||||
void _lock_init_recursive(_lock_t *plock);
|
||||
void _lock_close(_lock_t *plock);
|
||||
void _lock_close_recursive(_lock_t *plock);
|
||||
void _lock_acquire(_lock_t *plock);
|
||||
void _lock_acquire_recursive(_lock_t *plock);
|
||||
int _lock_try_acquire(_lock_t *plock);
|
||||
int _lock_try_acquire_recursive(_lock_t *plock);
|
||||
void _lock_release(_lock_t *plock);
|
||||
void _lock_release_recursive(_lock_t *plock);
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include_next <sys/lock.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef _RETARGETABLE_LOCKING
|
||||
|
||||
/* Actual platfrom-specific definition of struct __lock.
|
||||
* The size here should be sufficient for a FreeRTOS mutex.
|
||||
* This is checked by a static assertion in locks.c
|
||||
*
|
||||
* Note: this might need to be made dependent on whether FreeRTOS
|
||||
* is included in the build.
|
||||
*/
|
||||
struct __lock {
|
||||
#if (CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && CONFIG_FREERTOS_USE_TRACE_FACILITY)
|
||||
int reserved[29];
|
||||
#elif (CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && !CONFIG_FREERTOS_USE_TRACE_FACILITY)
|
||||
int reserved[27];
|
||||
#elif (!CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && CONFIG_FREERTOS_USE_TRACE_FACILITY)
|
||||
int reserved[23];
|
||||
#else
|
||||
int reserved[21];
|
||||
#endif /* #if (CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES && CONFIG_FREERTOS_USE_TRACE_FACILITY) */
|
||||
};
|
||||
|
||||
/* Compatibility definitions for the legacy ESP-specific locking implementation.
|
||||
* These used to be provided by libc/sys/xtensa/sys/lock.h in newlib.
|
||||
* Newer versions of newlib don't have this ESP-specific lock.h header, and are
|
||||
* built with _RETARGETABLE_LOCKING enabled, instead.
|
||||
*/
|
||||
|
||||
typedef _LOCK_T _lock_t;
|
||||
|
||||
void _lock_init(_lock_t *plock);
|
||||
void _lock_init_recursive(_lock_t *plock);
|
||||
void _lock_close(_lock_t *plock);
|
||||
void _lock_close_recursive(_lock_t *plock);
|
||||
void _lock_acquire(_lock_t *plock);
|
||||
void _lock_acquire_recursive(_lock_t *plock);
|
||||
int _lock_try_acquire(_lock_t *plock);
|
||||
int _lock_try_acquire_recursive(_lock_t *plock);
|
||||
void _lock_release(_lock_t *plock);
|
||||
void _lock_release_recursive(_lock_t *plock);
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _ESP_PLATFORM_SYS_POLL_H_
|
||||
#define _ESP_PLATFORM_SYS_POLL_H_
|
||||
|
||||
#define POLLIN (1u << 0) /* data other than high-priority may be read without blocking */
|
||||
#define POLLRDNORM (1u << 1) /* normal data may be read without blocking */
|
||||
#define POLLRDBAND (1u << 2) /* priority data may be read without blocking */
|
||||
#define POLLPRI (POLLRDBAND) /* high-priority data may be read without blocking */
|
||||
// Note: POLLPRI is made equivalent to POLLRDBAND in order to fit all these events into one byte
|
||||
#define POLLOUT (1u << 3) /* normal data may be written without blocking */
|
||||
#define POLLWRNORM (POLLOUT) /* equivalent to POLLOUT */
|
||||
#define POLLWRBAND (1u << 4) /* priority data my be written */
|
||||
#define POLLERR (1u << 5) /* some poll error occurred */
|
||||
#define POLLHUP (1u << 6) /* file descriptor was "hung up" */
|
||||
#define POLLNVAL (1u << 7) /* the specified file descriptor is invalid */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pollfd {
|
||||
int fd; /* The descriptor. */
|
||||
short events; /* The event(s) is/are specified here. */
|
||||
short revents; /* Events found are returned here. */
|
||||
};
|
||||
|
||||
typedef unsigned int nfds_t;
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _ESP_PLATFORM_SYS_POLL_H_
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _ESP_PLATFORM_SYS_POLL_H_
|
||||
#define _ESP_PLATFORM_SYS_POLL_H_
|
||||
|
||||
#define POLLIN (1u << 0) /* data other than high-priority may be read without blocking */
|
||||
#define POLLRDNORM (1u << 1) /* normal data may be read without blocking */
|
||||
#define POLLRDBAND (1u << 2) /* priority data may be read without blocking */
|
||||
#define POLLPRI (POLLRDBAND) /* high-priority data may be read without blocking */
|
||||
// Note: POLLPRI is made equivalent to POLLRDBAND in order to fit all these events into one byte
|
||||
#define POLLOUT (1u << 3) /* normal data may be written without blocking */
|
||||
#define POLLWRNORM (POLLOUT) /* equivalent to POLLOUT */
|
||||
#define POLLWRBAND (1u << 4) /* priority data my be written */
|
||||
#define POLLERR (1u << 5) /* some poll error occurred */
|
||||
#define POLLHUP (1u << 6) /* file descriptor was "hung up" */
|
||||
#define POLLNVAL (1u << 7) /* the specified file descriptor is invalid */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pollfd {
|
||||
int fd; /* The descriptor. */
|
||||
short events; /* The event(s) is/are specified here. */
|
||||
short revents; /* Events found are returned here. */
|
||||
};
|
||||
|
||||
typedef unsigned int nfds_t;
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _ESP_PLATFORM_SYS_POLL_H_
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SYS_RANDOM__
|
||||
#define __SYS_RANDOM__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif //__SYS_RANDOM__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SYS_RANDOM__
|
||||
#define __SYS_RANDOM__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif //__SYS_RANDOM__
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _REENT_BACKWARD_BINARY_COMPAT
|
||||
#define _REENT_SDIDINIT(_ptr) ((_ptr)->_reserved_0)
|
||||
#define _REENT_SGLUE(_ptr) (__sglue)
|
||||
|
||||
#include_next<sys/reent.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void __sinit(struct _reent *);
|
||||
|
||||
extern struct _glue __sglue;
|
||||
extern struct _reent * _global_impure_ptr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _REENT_BACKWARD_BINARY_COMPAT
|
||||
#define _REENT_SDIDINIT(_ptr) ((_ptr)->_reserved_0)
|
||||
#define _REENT_SGLUE(_ptr) (__sglue)
|
||||
|
||||
#include_next<sys/reent.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void __sinit(struct _reent *);
|
||||
|
||||
extern struct _glue __sglue;
|
||||
extern struct _reent * _global_impure_ptr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_SYS_SELECT_H__
|
||||
#define __ESP_SYS_SELECT_H__
|
||||
|
||||
/* Newlib 2.2.0 does not provide sys/select.h, and fd_set is defined in sys/types.h */
|
||||
#include <sys/types.h>
|
||||
#ifndef fd_set
|
||||
#include_next <sys/select.h>
|
||||
#else // fd_set
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // fd_set
|
||||
|
||||
#if defined(FD_ISSET) || defined(FD_SET) || defined(FD_CLR)
|
||||
#undef FD_SET
|
||||
#undef FD_CLR
|
||||
#undef FD_ISSET
|
||||
|
||||
#define __FD_SAFE_SET(n, code) do { if ((unsigned)(n) < FD_SETSIZE) { code; } } while(0)
|
||||
#define __FD_SAFE_GET(n, code) (((unsigned)(n) < FD_SETSIZE) ? (code) : 0)
|
||||
|
||||
#define FD_SET(n, p) __FD_SAFE_SET(n, ((p)->fds_bits[(n) / NFDBITS] |= (1L << ((n) % NFDBITS))))
|
||||
#define FD_CLR(n, p) __FD_SAFE_SET(n, ((p)->fds_bits[(n) / NFDBITS] &= ~(1L << ((n) % NFDBITS))))
|
||||
#define FD_ISSET(n, p) __FD_SAFE_GET(n, ((p)->fds_bits[(n) / NFDBITS] & (1L << ((n) % NFDBITS))))
|
||||
#endif // FD_ISSET || FD_SET || FD_CLR
|
||||
|
||||
#endif //__ESP_SYS_SELECT_H__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_SYS_SELECT_H__
|
||||
#define __ESP_SYS_SELECT_H__
|
||||
|
||||
/* Newlib 2.2.0 does not provide sys/select.h, and fd_set is defined in sys/types.h */
|
||||
#include <sys/types.h>
|
||||
#ifndef fd_set
|
||||
#include_next <sys/select.h>
|
||||
#else // fd_set
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // fd_set
|
||||
|
||||
#if defined(FD_ISSET) || defined(FD_SET) || defined(FD_CLR)
|
||||
#undef FD_SET
|
||||
#undef FD_CLR
|
||||
#undef FD_ISSET
|
||||
|
||||
#define __FD_SAFE_SET(n, code) do { if ((unsigned)(n) < FD_SETSIZE) { code; } } while(0)
|
||||
#define __FD_SAFE_GET(n, code) (((unsigned)(n) < FD_SETSIZE) ? (code) : 0)
|
||||
|
||||
#define FD_SET(n, p) __FD_SAFE_SET(n, ((p)->fds_bits[(n) / NFDBITS] |= (1L << ((n) % NFDBITS))))
|
||||
#define FD_CLR(n, p) __FD_SAFE_SET(n, ((p)->fds_bits[(n) / NFDBITS] &= ~(1L << ((n) % NFDBITS))))
|
||||
#define FD_ISSET(n, p) __FD_SAFE_GET(n, ((p)->fds_bits[(n) / NFDBITS] & (1L << ((n) % NFDBITS))))
|
||||
#endif // FD_ISSET || FD_SET || FD_CLR
|
||||
|
||||
#endif //__ESP_SYS_SELECT_H__
|
||||
|
||||
@@ -1,286 +1,286 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
//
|
||||
// This header file is based on the termios header of
|
||||
// "The Single UNIX (r) Specification, Version 2, Copyright (c) 1997 The Open Group".
|
||||
|
||||
#ifndef __ESP_SYS_TERMIOS_H__
|
||||
#define __ESP_SYS_TERMIOS_H__
|
||||
|
||||
// ESP-IDF NOTE: This header provides only a compatibility layer for macros and functions defined in sys/termios.h.
|
||||
// Not everything has a defined meaning for ESP-IDF (e.g. process leader IDs) and therefore are likely to be stubbed
|
||||
// in actual implementations.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
// subscripts for the array c_cc:
|
||||
#define VEOF 0 /** EOF character */
|
||||
#define VEOL 1 /** EOL character */
|
||||
#define VERASE 2 /** ERASE character */
|
||||
#define VINTR 3 /** INTR character */
|
||||
#define VKILL 4 /** KILL character */
|
||||
#define VMIN 5 /** MIN value */
|
||||
#define VQUIT 6 /** QUIT character */
|
||||
#define VSTART 7 /** START character */
|
||||
#define VSTOP 8 /** STOP character */
|
||||
#define VSUSP 9 /** SUSP character */
|
||||
#define VTIME 10 /** TIME value */
|
||||
#define NCCS (VTIME + 1) /** Size of the array c_cc for control characters */
|
||||
|
||||
// input modes for use as flags in the c_iflag field
|
||||
#define BRKINT (1u << 0) /** Signal interrupt on break. */
|
||||
#define ICRNL (1u << 1) /** Map CR to NL on input. */
|
||||
#define IGNBRK (1u << 2) /** Ignore break condition. */
|
||||
#define IGNCR (1u << 3) /** Ignore CR. */
|
||||
#define IGNPAR (1u << 4) /** Ignore characters with parity errors. */
|
||||
#define INLCR (1u << 5) /** Map NL to CR on input. */
|
||||
#define INPCK (1u << 6) /** Enable input parity check. */
|
||||
#define ISTRIP (1u << 7) /** Strip character. */
|
||||
#define IUCLC (1u << 8) /** Map upper-case to lower-case on input (LEGACY). */
|
||||
#define IXANY (1u << 9) /** Enable any character to restart output. */
|
||||
#define IXOFF (1u << 10) /** Enable start/stop input control. */
|
||||
#define IXON (1u << 11) /** Enable start/stop output control. */
|
||||
#define PARMRK (1u << 12) /** Mark parity errors. */
|
||||
|
||||
// output Modes for use as flags in the c_oflag field
|
||||
#define OPOST (1u << 0) /** Post-process output */
|
||||
#define OLCUC (1u << 1) /** Map lower-case to upper-case on output (LEGACY). */
|
||||
#define ONLCR (1u << 2) /** Map NL to CR-NL on output. */
|
||||
#define OCRNL (1u << 3) /** Map CR to NL on output. */
|
||||
#define ONOCR (1u << 4) /** No CR output at column 0. */
|
||||
#define ONLRET (1u << 5) /** NL performs CR function. */
|
||||
#define OFILL (1u << 6) /** Use fill characters for delay. */
|
||||
#define NLDLY (1u << 7) /** Select newline delays: */
|
||||
#define NL0 (0u << 7) /** Newline character type 0. */
|
||||
#define NL1 (1u << 7) /** Newline character type 1. */
|
||||
#define CRDLY (3u << 8) /** Select carriage-return delays: */
|
||||
#define CR0 (0u << 8) /** Carriage-return delay type 0. */
|
||||
#define CR1 (1u << 8) /** Carriage-return delay type 1. */
|
||||
#define CR2 (2u << 8) /** Carriage-return delay type 2. */
|
||||
#define CR3 (3u << 8) /** Carriage-return delay type 3. */
|
||||
#define TABDLY (3u << 10) /** Select horizontal-tab delays: */
|
||||
#define TAB0 (0u << 10) /** Horizontal-tab delay type 0. */
|
||||
#define TAB1 (1u << 10) /** Horizontal-tab delay type 1. */
|
||||
#define TAB2 (2u << 10) /** Horizontal-tab delay type 2. */
|
||||
#define TAB3 (3u << 10) /** Expand tabs to spaces. */
|
||||
#define BSDLY (1u << 12) /** Select backspace delays: */
|
||||
#define BS0 (0u << 12) /** Backspace-delay type 0. */
|
||||
#define BS1 (1u << 12) /** Backspace-delay type 1. */
|
||||
#define VTDLY (1u << 13) /** Select vertical-tab delays: */
|
||||
#define VT0 (0u << 13) /** Vertical-tab delay type 0. */
|
||||
#define VT1 (1u << 13) /** Vertical-tab delay type 1. */
|
||||
#define FFDLY (1u << 14) /** Select form-feed delays: */
|
||||
#define FF0 (0u << 14) /** Form-feed delay type 0. */
|
||||
#define FF1 (1u << 14) /** Form-feed delay type 1. */
|
||||
|
||||
// Baud Rate Selection. Valid values for objects of type speed_t:
|
||||
// CBAUD range B0 - B38400
|
||||
#define B0 0 /** Hang up */
|
||||
#define B50 1
|
||||
#define B75 2
|
||||
#define B110 3
|
||||
#define B134 4
|
||||
#define B150 5
|
||||
#define B200 6
|
||||
#define B300 7
|
||||
#define B600 8
|
||||
#define B1200 9
|
||||
#define B1800 10
|
||||
#define B2400 11
|
||||
#define B4800 12
|
||||
#define B9600 13
|
||||
#define B19200 14
|
||||
#define B38400 15
|
||||
// CBAUDEX range B57600 - B4000000
|
||||
#define B57600 16
|
||||
#define B115200 17
|
||||
#define B230400 18
|
||||
#define B460800 19
|
||||
#define B500000 20
|
||||
#define B576000 21
|
||||
#define B921600 22
|
||||
#define B1000000 23
|
||||
#define B1152000 24
|
||||
#define B1500000 25
|
||||
#define B2000000 26
|
||||
#define B2500000 27
|
||||
#define B3000000 28
|
||||
#define B3500000 29
|
||||
#define B4000000 30
|
||||
|
||||
// Control Modes for the c_cflag field:
|
||||
#define CSIZE (3u << 0) /* Character size: */
|
||||
#define CS5 (0u << 0) /** 5 bits. */
|
||||
#define CS6 (1u << 0) /** 6 bits. */
|
||||
#define CS7 (2u << 0) /** 7 bits. */
|
||||
#define CS8 (3u << 0) /** 8 bits. */
|
||||
#define CSTOPB (1u << 2) /** Send two stop bits, else one. */
|
||||
#define CREAD (1u << 3) /** Enable receiver. */
|
||||
#define PARENB (1u << 4) /** Parity enable. */
|
||||
#define PARODD (1u << 5) /** Odd parity, else even. */
|
||||
#define HUPCL (1u << 6) /** Hang up on last close. */
|
||||
#define CLOCAL (1u << 7) /** Ignore modem status lines. */
|
||||
#define CBAUD (1u << 8) /** Use baud rates defined by B0-B38400 macros. */
|
||||
#define CBAUDEX (1u << 9) /** Use baud rates defined by B57600-B4000000 macros. */
|
||||
#define BOTHER (1u << 10) /** Use custom baud rates */
|
||||
|
||||
// Local Modes for c_lflag field:
|
||||
#define ECHO (1u << 0) /** Enable echo. */
|
||||
#define ECHOE (1u << 1) /** Echo erase character as error-correcting backspace. */
|
||||
#define ECHOK (1u << 2) /** Echo KILL. */
|
||||
#define ECHONL (1u << 3) /** Echo NL. */
|
||||
#define ICANON (1u << 4) /** Canonical input (erase and kill processing). */
|
||||
#define IEXTEN (1u << 5) /** Enable extended input character processing. */
|
||||
#define ISIG (1u << 6) /** Enable signals. */
|
||||
#define NOFLSH (1u << 7) /** Disable flush after interrupt or quit. */
|
||||
#define TOSTOP (1u << 8) /** Send SIGTTOU for background output. */
|
||||
#define XCASE (1u << 9) /** Canonical upper/lower presentation (LEGACY). */
|
||||
|
||||
// Attribute Selection constants for use with tcsetattr():
|
||||
#define TCSANOW 0 /** Change attributes immediately. */
|
||||
#define TCSADRAIN 1 /** Change attributes when output has drained. */
|
||||
#define TCSAFLUSH 2 /** Change attributes when output has drained; also flush pending input. */
|
||||
|
||||
// Line Control constants for use with tcflush():
|
||||
#define TCIFLUSH 0 /** Flush pending input. Flush untransmitted output. */
|
||||
#define TCIOFLUSH 1 /** Flush both pending input and untransmitted output. */
|
||||
#define TCOFLUSH 2 /** Flush untransmitted output. */
|
||||
|
||||
// constants for use with tcflow():
|
||||
#define TCIOFF 0 /** Transmit a STOP character, intended to suspend input data. */
|
||||
#define TCION 1 /** Transmit a START character, intended to restart input data. */
|
||||
#define TCOOFF 2 /** Suspend output. */
|
||||
#define TCOON 3 /** Restart output. */
|
||||
|
||||
typedef uint8_t cc_t;
|
||||
typedef uint32_t speed_t;
|
||||
typedef uint16_t tcflag_t;
|
||||
|
||||
struct termios {
|
||||
tcflag_t c_iflag; /** Input modes */
|
||||
tcflag_t c_oflag; /** Output modes */
|
||||
tcflag_t c_cflag; /** Control modes */
|
||||
tcflag_t c_lflag; /** Local modes */
|
||||
cc_t c_cc[NCCS]; /** Control characters */
|
||||
speed_t c_ispeed; /** input baud rate */
|
||||
speed_t c_ospeed; /** output baud rate */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Extracts the input baud rate from the input structure exactly (without interpretation).
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @return input baud rate
|
||||
*/
|
||||
speed_t cfgetispeed(const struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Extracts the output baud rate from the input structure exactly (without interpretation).
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @return output baud rate
|
||||
*/
|
||||
speed_t cfgetospeed(const struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Set input baud rate in the termios structure
|
||||
*
|
||||
* There is no effect in hardware until a subsequent call of tcsetattr().
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @param sp input baud rate
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int cfsetispeed(struct termios *p, speed_t sp);
|
||||
|
||||
/**
|
||||
* @brief Set output baud rate in the termios structure
|
||||
*
|
||||
* There is no effect in hardware until a subsequent call of tcsetattr().
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @param sp output baud rate
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int cfsetospeed(struct termios *p, speed_t sp);
|
||||
|
||||
/**
|
||||
* @brief Wait for transmission of output
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcdrain(int fd);
|
||||
|
||||
/**
|
||||
* @brief Suspend or restart the transmission or reception of data
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param action selects actions to do
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcflow(int fd, int action);
|
||||
|
||||
/**
|
||||
* @brief Flush non-transmitted output data and non-read input data
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param select selects what should be flushed
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcflush(int fd, int select);
|
||||
|
||||
/**
|
||||
* @brief Gets the parameters of the terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param p output termios structure
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcgetattr(int fd, struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Get process group ID for session leader for controlling terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @return process group ID when successful, -1 otherwise with errno set
|
||||
*/
|
||||
pid_t tcgetsid(int fd);
|
||||
|
||||
/**
|
||||
* @brief Send a break for a specific duration
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param duration duration of break
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcsendbreak(int fd, int duration);
|
||||
|
||||
/**
|
||||
* @brief Sets the parameters of the terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param optional_actions optional actions
|
||||
* @param p input termios structure
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcsetattr(int fd, int optional_actions, const struct termios *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
#endif //__ESP_SYS_TERMIOS_H__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
//
|
||||
// This header file is based on the termios header of
|
||||
// "The Single UNIX (r) Specification, Version 2, Copyright (c) 1997 The Open Group".
|
||||
|
||||
#ifndef __ESP_SYS_TERMIOS_H__
|
||||
#define __ESP_SYS_TERMIOS_H__
|
||||
|
||||
// ESP-IDF NOTE: This header provides only a compatibility layer for macros and functions defined in sys/termios.h.
|
||||
// Not everything has a defined meaning for ESP-IDF (e.g. process leader IDs) and therefore are likely to be stubbed
|
||||
// in actual implementations.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
// subscripts for the array c_cc:
|
||||
#define VEOF 0 /** EOF character */
|
||||
#define VEOL 1 /** EOL character */
|
||||
#define VERASE 2 /** ERASE character */
|
||||
#define VINTR 3 /** INTR character */
|
||||
#define VKILL 4 /** KILL character */
|
||||
#define VMIN 5 /** MIN value */
|
||||
#define VQUIT 6 /** QUIT character */
|
||||
#define VSTART 7 /** START character */
|
||||
#define VSTOP 8 /** STOP character */
|
||||
#define VSUSP 9 /** SUSP character */
|
||||
#define VTIME 10 /** TIME value */
|
||||
#define NCCS (VTIME + 1) /** Size of the array c_cc for control characters */
|
||||
|
||||
// input modes for use as flags in the c_iflag field
|
||||
#define BRKINT (1u << 0) /** Signal interrupt on break. */
|
||||
#define ICRNL (1u << 1) /** Map CR to NL on input. */
|
||||
#define IGNBRK (1u << 2) /** Ignore break condition. */
|
||||
#define IGNCR (1u << 3) /** Ignore CR. */
|
||||
#define IGNPAR (1u << 4) /** Ignore characters with parity errors. */
|
||||
#define INLCR (1u << 5) /** Map NL to CR on input. */
|
||||
#define INPCK (1u << 6) /** Enable input parity check. */
|
||||
#define ISTRIP (1u << 7) /** Strip character. */
|
||||
#define IUCLC (1u << 8) /** Map upper-case to lower-case on input (LEGACY). */
|
||||
#define IXANY (1u << 9) /** Enable any character to restart output. */
|
||||
#define IXOFF (1u << 10) /** Enable start/stop input control. */
|
||||
#define IXON (1u << 11) /** Enable start/stop output control. */
|
||||
#define PARMRK (1u << 12) /** Mark parity errors. */
|
||||
|
||||
// output Modes for use as flags in the c_oflag field
|
||||
#define OPOST (1u << 0) /** Post-process output */
|
||||
#define OLCUC (1u << 1) /** Map lower-case to upper-case on output (LEGACY). */
|
||||
#define ONLCR (1u << 2) /** Map NL to CR-NL on output. */
|
||||
#define OCRNL (1u << 3) /** Map CR to NL on output. */
|
||||
#define ONOCR (1u << 4) /** No CR output at column 0. */
|
||||
#define ONLRET (1u << 5) /** NL performs CR function. */
|
||||
#define OFILL (1u << 6) /** Use fill characters for delay. */
|
||||
#define NLDLY (1u << 7) /** Select newline delays: */
|
||||
#define NL0 (0u << 7) /** Newline character type 0. */
|
||||
#define NL1 (1u << 7) /** Newline character type 1. */
|
||||
#define CRDLY (3u << 8) /** Select carriage-return delays: */
|
||||
#define CR0 (0u << 8) /** Carriage-return delay type 0. */
|
||||
#define CR1 (1u << 8) /** Carriage-return delay type 1. */
|
||||
#define CR2 (2u << 8) /** Carriage-return delay type 2. */
|
||||
#define CR3 (3u << 8) /** Carriage-return delay type 3. */
|
||||
#define TABDLY (3u << 10) /** Select horizontal-tab delays: */
|
||||
#define TAB0 (0u << 10) /** Horizontal-tab delay type 0. */
|
||||
#define TAB1 (1u << 10) /** Horizontal-tab delay type 1. */
|
||||
#define TAB2 (2u << 10) /** Horizontal-tab delay type 2. */
|
||||
#define TAB3 (3u << 10) /** Expand tabs to spaces. */
|
||||
#define BSDLY (1u << 12) /** Select backspace delays: */
|
||||
#define BS0 (0u << 12) /** Backspace-delay type 0. */
|
||||
#define BS1 (1u << 12) /** Backspace-delay type 1. */
|
||||
#define VTDLY (1u << 13) /** Select vertical-tab delays: */
|
||||
#define VT0 (0u << 13) /** Vertical-tab delay type 0. */
|
||||
#define VT1 (1u << 13) /** Vertical-tab delay type 1. */
|
||||
#define FFDLY (1u << 14) /** Select form-feed delays: */
|
||||
#define FF0 (0u << 14) /** Form-feed delay type 0. */
|
||||
#define FF1 (1u << 14) /** Form-feed delay type 1. */
|
||||
|
||||
// Baud Rate Selection. Valid values for objects of type speed_t:
|
||||
// CBAUD range B0 - B38400
|
||||
#define B0 0 /** Hang up */
|
||||
#define B50 1
|
||||
#define B75 2
|
||||
#define B110 3
|
||||
#define B134 4
|
||||
#define B150 5
|
||||
#define B200 6
|
||||
#define B300 7
|
||||
#define B600 8
|
||||
#define B1200 9
|
||||
#define B1800 10
|
||||
#define B2400 11
|
||||
#define B4800 12
|
||||
#define B9600 13
|
||||
#define B19200 14
|
||||
#define B38400 15
|
||||
// CBAUDEX range B57600 - B4000000
|
||||
#define B57600 16
|
||||
#define B115200 17
|
||||
#define B230400 18
|
||||
#define B460800 19
|
||||
#define B500000 20
|
||||
#define B576000 21
|
||||
#define B921600 22
|
||||
#define B1000000 23
|
||||
#define B1152000 24
|
||||
#define B1500000 25
|
||||
#define B2000000 26
|
||||
#define B2500000 27
|
||||
#define B3000000 28
|
||||
#define B3500000 29
|
||||
#define B4000000 30
|
||||
|
||||
// Control Modes for the c_cflag field:
|
||||
#define CSIZE (3u << 0) /* Character size: */
|
||||
#define CS5 (0u << 0) /** 5 bits. */
|
||||
#define CS6 (1u << 0) /** 6 bits. */
|
||||
#define CS7 (2u << 0) /** 7 bits. */
|
||||
#define CS8 (3u << 0) /** 8 bits. */
|
||||
#define CSTOPB (1u << 2) /** Send two stop bits, else one. */
|
||||
#define CREAD (1u << 3) /** Enable receiver. */
|
||||
#define PARENB (1u << 4) /** Parity enable. */
|
||||
#define PARODD (1u << 5) /** Odd parity, else even. */
|
||||
#define HUPCL (1u << 6) /** Hang up on last close. */
|
||||
#define CLOCAL (1u << 7) /** Ignore modem status lines. */
|
||||
#define CBAUD (1u << 8) /** Use baud rates defined by B0-B38400 macros. */
|
||||
#define CBAUDEX (1u << 9) /** Use baud rates defined by B57600-B4000000 macros. */
|
||||
#define BOTHER (1u << 10) /** Use custom baud rates */
|
||||
|
||||
// Local Modes for c_lflag field:
|
||||
#define ECHO (1u << 0) /** Enable echo. */
|
||||
#define ECHOE (1u << 1) /** Echo erase character as error-correcting backspace. */
|
||||
#define ECHOK (1u << 2) /** Echo KILL. */
|
||||
#define ECHONL (1u << 3) /** Echo NL. */
|
||||
#define ICANON (1u << 4) /** Canonical input (erase and kill processing). */
|
||||
#define IEXTEN (1u << 5) /** Enable extended input character processing. */
|
||||
#define ISIG (1u << 6) /** Enable signals. */
|
||||
#define NOFLSH (1u << 7) /** Disable flush after interrupt or quit. */
|
||||
#define TOSTOP (1u << 8) /** Send SIGTTOU for background output. */
|
||||
#define XCASE (1u << 9) /** Canonical upper/lower presentation (LEGACY). */
|
||||
|
||||
// Attribute Selection constants for use with tcsetattr():
|
||||
#define TCSANOW 0 /** Change attributes immediately. */
|
||||
#define TCSADRAIN 1 /** Change attributes when output has drained. */
|
||||
#define TCSAFLUSH 2 /** Change attributes when output has drained; also flush pending input. */
|
||||
|
||||
// Line Control constants for use with tcflush():
|
||||
#define TCIFLUSH 0 /** Flush pending input. Flush untransmitted output. */
|
||||
#define TCIOFLUSH 1 /** Flush both pending input and untransmitted output. */
|
||||
#define TCOFLUSH 2 /** Flush untransmitted output. */
|
||||
|
||||
// constants for use with tcflow():
|
||||
#define TCIOFF 0 /** Transmit a STOP character, intended to suspend input data. */
|
||||
#define TCION 1 /** Transmit a START character, intended to restart input data. */
|
||||
#define TCOOFF 2 /** Suspend output. */
|
||||
#define TCOON 3 /** Restart output. */
|
||||
|
||||
typedef uint8_t cc_t;
|
||||
typedef uint32_t speed_t;
|
||||
typedef uint16_t tcflag_t;
|
||||
|
||||
struct termios {
|
||||
tcflag_t c_iflag; /** Input modes */
|
||||
tcflag_t c_oflag; /** Output modes */
|
||||
tcflag_t c_cflag; /** Control modes */
|
||||
tcflag_t c_lflag; /** Local modes */
|
||||
cc_t c_cc[NCCS]; /** Control characters */
|
||||
speed_t c_ispeed; /** input baud rate */
|
||||
speed_t c_ospeed; /** output baud rate */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Extracts the input baud rate from the input structure exactly (without interpretation).
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @return input baud rate
|
||||
*/
|
||||
speed_t cfgetispeed(const struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Extracts the output baud rate from the input structure exactly (without interpretation).
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @return output baud rate
|
||||
*/
|
||||
speed_t cfgetospeed(const struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Set input baud rate in the termios structure
|
||||
*
|
||||
* There is no effect in hardware until a subsequent call of tcsetattr().
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @param sp input baud rate
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int cfsetispeed(struct termios *p, speed_t sp);
|
||||
|
||||
/**
|
||||
* @brief Set output baud rate in the termios structure
|
||||
*
|
||||
* There is no effect in hardware until a subsequent call of tcsetattr().
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @param sp output baud rate
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int cfsetospeed(struct termios *p, speed_t sp);
|
||||
|
||||
/**
|
||||
* @brief Wait for transmission of output
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcdrain(int fd);
|
||||
|
||||
/**
|
||||
* @brief Suspend or restart the transmission or reception of data
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param action selects actions to do
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcflow(int fd, int action);
|
||||
|
||||
/**
|
||||
* @brief Flush non-transmitted output data and non-read input data
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param select selects what should be flushed
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcflush(int fd, int select);
|
||||
|
||||
/**
|
||||
* @brief Gets the parameters of the terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param p output termios structure
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcgetattr(int fd, struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Get process group ID for session leader for controlling terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @return process group ID when successful, -1 otherwise with errno set
|
||||
*/
|
||||
pid_t tcgetsid(int fd);
|
||||
|
||||
/**
|
||||
* @brief Send a break for a specific duration
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param duration duration of break
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcsendbreak(int fd, int duration);
|
||||
|
||||
/**
|
||||
* @brief Sets the parameters of the terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param optional_actions optional actions
|
||||
* @param p input termios structure
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcsetattr(int fd, int optional_actions, const struct termios *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
#endif //__ESP_SYS_TERMIOS_H__
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
/* Newlib sys/time.h defines timerisset, timerclear, timercmp, timeradd, timersub macros
|
||||
for __CYGWIN__ and __rtems__. We want to define these macros in IDF as well.
|
||||
Since we wish to use un-modified newlib headers until a patched newlib version is
|
||||
available, temporarily define __rtems__ here before including sys/time.h.
|
||||
__rtems__ is chosen instead of __CYGWIN__ since there are no other checks in sys/time.h
|
||||
which depend on __rtems__.
|
||||
|
||||
Also, so that __rtems__ define does not affect other headers included from sys/time.h,
|
||||
we include them here in advance (_ansi.h and sys/types.h).
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include <sys/types.h>
|
||||
#define __rtems__
|
||||
#include_next <sys/time.h>
|
||||
#undef __rtems__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
/* Newlib sys/time.h defines timerisset, timerclear, timercmp, timeradd, timersub macros
|
||||
for __CYGWIN__ and __rtems__. We want to define these macros in IDF as well.
|
||||
Since we wish to use un-modified newlib headers until a patched newlib version is
|
||||
available, temporarily define __rtems__ here before including sys/time.h.
|
||||
__rtems__ is chosen instead of __CYGWIN__ since there are no other checks in sys/time.h
|
||||
which depend on __rtems__.
|
||||
|
||||
Also, so that __rtems__ define does not affect other headers included from sys/time.h,
|
||||
we include them here in advance (_ansi.h and sys/types.h).
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include <sys/types.h>
|
||||
#define __rtems__
|
||||
#include_next <sys/time.h>
|
||||
#undef __rtems__
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct iovec;
|
||||
|
||||
int writev(int s, const struct iovec *iov, int iovcnt);
|
||||
|
||||
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct iovec;
|
||||
|
||||
int writev(int s, const struct iovec *iov, int iovcnt);
|
||||
|
||||
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AF_UNIX 1 /* local to host (pipes) */
|
||||
|
||||
struct sockaddr_un {
|
||||
short sun_family; /*AF_UNIX*/
|
||||
char sun_path[108]; /*path name */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AF_UNIX 1 /* local to host (pipes) */
|
||||
|
||||
struct sockaddr_un {
|
||||
short sun_family; /*AF_UNIX*/
|
||||
char sun_path[108]; /*path name */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include_next <sys/unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int truncate(const char *, off_t __length);
|
||||
int gethostname(char *__name, size_t __len);
|
||||
int getentropy(void *buffer, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include_next <sys/unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int truncate(const char *, off_t __length);
|
||||
int gethostname(char *__name, size_t __len);
|
||||
int getentropy(void *buffer, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _UTIME_H_
|
||||
#define _UTIME_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct utimbuf {
|
||||
time_t actime; // access time
|
||||
time_t modtime; // modification time
|
||||
};
|
||||
|
||||
int utime(const char *path, const struct utimbuf *times);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _UTIME_H_ */
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _UTIME_H_
|
||||
#define _UTIME_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct utimbuf {
|
||||
time_t actime; // access time
|
||||
time_t modtime; // modification time
|
||||
};
|
||||
|
||||
int utime(const char *path, const struct utimbuf *times);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _UTIME_H_ */
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include_next <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _POSIX_TIMERS 1
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC (clockid_t)4
|
||||
#endif
|
||||
#ifndef CLOCK_BOOTTIME
|
||||
#define CLOCK_BOOTTIME (clockid_t)4
|
||||
#endif
|
||||
|
||||
int clock_settime(clockid_t clock_id, const struct timespec *tp);
|
||||
int clock_gettime(clockid_t clock_id, struct timespec *tp);
|
||||
int clock_getres(clockid_t clock_id, struct timespec *res);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include_next <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _POSIX_TIMERS 1
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC (clockid_t)4
|
||||
#endif
|
||||
#ifndef CLOCK_BOOTTIME
|
||||
#define CLOCK_BOOTTIME (clockid_t)4
|
||||
#endif
|
||||
|
||||
int clock_settime(clockid_t clock_id, const struct timespec *tp);
|
||||
int clock_gettime(clockid_t clock_id, struct timespec *tp);
|
||||
int clock_getres(clockid_t clock_id, struct timespec *res);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+87
-87
@@ -1,87 +1,87 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
struct timeval tv = {
|
||||
// timeout is in milliseconds
|
||||
.tv_sec = timeout / 1000,
|
||||
.tv_usec = (timeout % 1000) * 1000,
|
||||
};
|
||||
int max_fd = -1;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set errorfds;
|
||||
struct _reent* r = __getreent();
|
||||
int ret = 0;
|
||||
|
||||
if (fds == NULL) {
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&errorfds);
|
||||
|
||||
for (unsigned int i = 0; i < nfds; ++i) {
|
||||
fds[i].revents = 0;
|
||||
|
||||
if (fds[i].fd < 0) {
|
||||
// revents should remain 0 and events ignored (according to the documentation of poll()).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[i].fd >= FD_SETSIZE) {
|
||||
fds[i].revents |= POLLNVAL;
|
||||
++ret;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
|
||||
FD_SET(fds[i].fd, &readfds);
|
||||
FD_SET(fds[i].fd, &errorfds);
|
||||
max_fd = MAX(max_fd, fds[i].fd);
|
||||
}
|
||||
|
||||
if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
|
||||
FD_SET(fds[i].fd, &writefds);
|
||||
FD_SET(fds[i].fd, &errorfds);
|
||||
max_fd = MAX(max_fd, fds[i].fd);
|
||||
}
|
||||
}
|
||||
|
||||
const int select_ret = select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL : &tv);
|
||||
|
||||
if (select_ret > 0) {
|
||||
ret += select_ret;
|
||||
|
||||
for (unsigned int i = 0; i < nfds; ++i) {
|
||||
if (FD_ISSET(fds[i].fd, &readfds)) {
|
||||
fds[i].revents |= POLLIN;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fds[i].fd, &writefds)) {
|
||||
fds[i].revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fds[i].fd, &errorfds)) {
|
||||
fds[i].revents |= POLLERR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = select_ret;
|
||||
// keeping the errno from select()
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
struct timeval tv = {
|
||||
// timeout is in milliseconds
|
||||
.tv_sec = timeout / 1000,
|
||||
.tv_usec = (timeout % 1000) * 1000,
|
||||
};
|
||||
int max_fd = -1;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set errorfds;
|
||||
struct _reent* r = __getreent();
|
||||
int ret = 0;
|
||||
|
||||
if (fds == NULL) {
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&errorfds);
|
||||
|
||||
for (unsigned int i = 0; i < nfds; ++i) {
|
||||
fds[i].revents = 0;
|
||||
|
||||
if (fds[i].fd < 0) {
|
||||
// revents should remain 0 and events ignored (according to the documentation of poll()).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[i].fd >= FD_SETSIZE) {
|
||||
fds[i].revents |= POLLNVAL;
|
||||
++ret;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
|
||||
FD_SET(fds[i].fd, &readfds);
|
||||
FD_SET(fds[i].fd, &errorfds);
|
||||
max_fd = MAX(max_fd, fds[i].fd);
|
||||
}
|
||||
|
||||
if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
|
||||
FD_SET(fds[i].fd, &writefds);
|
||||
FD_SET(fds[i].fd, &errorfds);
|
||||
max_fd = MAX(max_fd, fds[i].fd);
|
||||
}
|
||||
}
|
||||
|
||||
const int select_ret = select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL : &tv);
|
||||
|
||||
if (select_ret > 0) {
|
||||
ret += select_ret;
|
||||
|
||||
for (unsigned int i = 0; i < nfds; ++i) {
|
||||
if (FD_ISSET(fds[i].fd, &readfds)) {
|
||||
fds[i].revents |= POLLIN;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fds[i].fd, &writefds)) {
|
||||
fds[i].revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fds[i].fd, &errorfds)) {
|
||||
fds[i].revents |= POLLERR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = select_ret;
|
||||
// keeping the errno from select()
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/esp_time_impl.c")
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/esp_time_impl.c")
|
||||
|
||||
+145
-145
@@ -1,145 +1,145 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#include "esp_private/system_internal.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
#include "esp_time_impl.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp32/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#include "esp32s2/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/rtc.h"
|
||||
#include "esp32s3/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#include "esp32c3/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
#include "esp32c2/rom/rtc.h"
|
||||
#include "esp32c2/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "esp32c6/rom/rtc.h"
|
||||
#include "esp32c6/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C61 //TODO: IDF-9526, refactor this
|
||||
#include "esp32c61/rom/rtc.h"
|
||||
#include "esp32c61/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C5
|
||||
#include "esp32c5/rom/rtc.h"
|
||||
#include "esp32c5/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#include "esp32h2/rom/rtc.h"
|
||||
#include "esp32h2/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#include "esp32p4/rom/rtc.h"
|
||||
#include "esp32p4/rtc.h"
|
||||
#endif
|
||||
|
||||
// Offset between High resolution timer and the RTC.
|
||||
// Initialized after reset or light sleep.
|
||||
#if defined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER) && defined(CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER)
|
||||
int64_t s_microseconds_offset = 0;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
static uint64_t s_boot_time; // when RTC is used to persist time, two RTC_STORE registers are used to store boot time instead
|
||||
#endif
|
||||
|
||||
static _lock_t s_boot_time_lock;
|
||||
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
uint64_t esp_time_impl_get_time_since_boot(void)
|
||||
{
|
||||
uint64_t microseconds = 0;
|
||||
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
microseconds = s_microseconds_offset + esp_system_get_time();
|
||||
#else
|
||||
microseconds = esp_system_get_time();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
#elif defined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER)
|
||||
microseconds = esp_rtc_get_time_us();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
return microseconds;
|
||||
}
|
||||
|
||||
uint64_t esp_time_impl_get_time(void)
|
||||
{
|
||||
uint64_t microseconds = 0;
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER )
|
||||
microseconds = esp_system_get_time();
|
||||
#elif defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
microseconds = esp_rtc_get_time_us();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
return microseconds;
|
||||
}
|
||||
|
||||
#endif // defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
|
||||
void esp_time_impl_set_boot_time(uint64_t time_us)
|
||||
{
|
||||
_lock_acquire(&s_boot_time_lock);
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
REG_WRITE(RTC_BOOT_TIME_LOW_REG, (uint32_t)(time_us & 0xffffffff));
|
||||
REG_WRITE(RTC_BOOT_TIME_HIGH_REG, (uint32_t)(time_us >> 32));
|
||||
#else
|
||||
s_boot_time = time_us;
|
||||
#endif
|
||||
_lock_release(&s_boot_time_lock);
|
||||
}
|
||||
|
||||
uint64_t esp_time_impl_get_boot_time(void)
|
||||
{
|
||||
uint64_t result;
|
||||
_lock_acquire(&s_boot_time_lock);
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
result = ((uint64_t) REG_READ(RTC_BOOT_TIME_LOW_REG)) + (((uint64_t) REG_READ(RTC_BOOT_TIME_HIGH_REG)) << 32);
|
||||
#else
|
||||
result = s_boot_time;
|
||||
#endif
|
||||
_lock_release(&s_boot_time_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void esp_set_time_from_rtc(void)
|
||||
{
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
// initialize time from RTC clock
|
||||
s_microseconds_offset = esp_rtc_get_time_us() - esp_system_get_time();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER && CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
}
|
||||
|
||||
void esp_sync_timekeeping_timers(void)
|
||||
{
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
settimeofday(&tv, NULL);
|
||||
int64_t s_microseconds_offset_cur = esp_rtc_get_time_us() - esp_system_get_time();
|
||||
esp_time_impl_set_boot_time(esp_time_impl_get_boot_time() + ((int64_t)s_microseconds_offset - s_microseconds_offset_cur));
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_time_impl_init(void)
|
||||
{
|
||||
esp_set_time_from_rtc();
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#include "esp_private/system_internal.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
#include "esp_time_impl.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp32/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#include "esp32s2/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/rtc.h"
|
||||
#include "esp32s3/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#include "esp32c3/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
#include "esp32c2/rom/rtc.h"
|
||||
#include "esp32c2/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "esp32c6/rom/rtc.h"
|
||||
#include "esp32c6/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C61 //TODO: IDF-9526, refactor this
|
||||
#include "esp32c61/rom/rtc.h"
|
||||
#include "esp32c61/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C5
|
||||
#include "esp32c5/rom/rtc.h"
|
||||
#include "esp32c5/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#include "esp32h2/rom/rtc.h"
|
||||
#include "esp32h2/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#include "esp32p4/rom/rtc.h"
|
||||
#include "esp32p4/rtc.h"
|
||||
#endif
|
||||
|
||||
// Offset between High resolution timer and the RTC.
|
||||
// Initialized after reset or light sleep.
|
||||
#if defined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER) && defined(CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER)
|
||||
int64_t s_microseconds_offset = 0;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
static uint64_t s_boot_time; // when RTC is used to persist time, two RTC_STORE registers are used to store boot time instead
|
||||
#endif
|
||||
|
||||
static _lock_t s_boot_time_lock;
|
||||
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
uint64_t esp_time_impl_get_time_since_boot(void)
|
||||
{
|
||||
uint64_t microseconds = 0;
|
||||
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
microseconds = s_microseconds_offset + esp_system_get_time();
|
||||
#else
|
||||
microseconds = esp_system_get_time();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
#elif defined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER)
|
||||
microseconds = esp_rtc_get_time_us();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
return microseconds;
|
||||
}
|
||||
|
||||
uint64_t esp_time_impl_get_time(void)
|
||||
{
|
||||
uint64_t microseconds = 0;
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER )
|
||||
microseconds = esp_system_get_time();
|
||||
#elif defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
microseconds = esp_rtc_get_time_us();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
|
||||
return microseconds;
|
||||
}
|
||||
|
||||
#endif // defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
|
||||
void esp_time_impl_set_boot_time(uint64_t time_us)
|
||||
{
|
||||
_lock_acquire(&s_boot_time_lock);
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
REG_WRITE(RTC_BOOT_TIME_LOW_REG, (uint32_t)(time_us & 0xffffffff));
|
||||
REG_WRITE(RTC_BOOT_TIME_HIGH_REG, (uint32_t)(time_us >> 32));
|
||||
#else
|
||||
s_boot_time = time_us;
|
||||
#endif
|
||||
_lock_release(&s_boot_time_lock);
|
||||
}
|
||||
|
||||
uint64_t esp_time_impl_get_boot_time(void)
|
||||
{
|
||||
uint64_t result;
|
||||
_lock_acquire(&s_boot_time_lock);
|
||||
#ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
result = ((uint64_t) REG_READ(RTC_BOOT_TIME_LOW_REG)) + (((uint64_t) REG_READ(RTC_BOOT_TIME_HIGH_REG)) << 32);
|
||||
#else
|
||||
result = s_boot_time;
|
||||
#endif
|
||||
_lock_release(&s_boot_time_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void esp_set_time_from_rtc(void)
|
||||
{
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
// initialize time from RTC clock
|
||||
s_microseconds_offset = esp_rtc_get_time_us() - esp_system_get_time();
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER && CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
}
|
||||
|
||||
void esp_sync_timekeeping_timers(void)
|
||||
{
|
||||
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
settimeofday(&tv, NULL);
|
||||
int64_t s_microseconds_offset_cur = esp_rtc_get_time_us() - esp_system_get_time();
|
||||
esp_time_impl_set_boot_time(esp_time_impl_get_boot_time() + ((int64_t)s_microseconds_offset - s_microseconds_offset_cur));
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_time_impl_init(void)
|
||||
{
|
||||
esp_set_time_from_rtc();
|
||||
}
|
||||
|
||||
@@ -1,79 +1,79 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_stdatomic.h"
|
||||
|
||||
#undef SYNC_OP_FUNCTIONS
|
||||
#undef _ATOMIC_OP_FUNCTION
|
||||
#undef ATOMIC_LOAD
|
||||
#undef ATOMIC_CMP_EXCHANGE
|
||||
#undef ATOMIC_STORE
|
||||
#undef ATOMIC_EXCHANGE
|
||||
#undef SYNC_BOOL_CMP_EXCHANGE
|
||||
#undef SYNC_VAL_CMP_EXCHANGE
|
||||
#undef SYNC_LOCK_TEST_AND_SET
|
||||
#undef SYNC_LOCK_RELEASE
|
||||
|
||||
#define SYNC_OP_FUNCTIONS(n, type, name)
|
||||
|
||||
#define _ATOMIC_OP_FUNCTION(n, type, name_1, name_2, ret_var, operation, inverse) \
|
||||
type __atomic_s32c1i_ ##name_1 ##_ ##name_2 ##_ ##n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
return __atomic_ ##name_1 ##_ ##name_2 ##_ ##n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define ATOMIC_LOAD(n, type) \
|
||||
type __atomic_s32c1i_load_ ## n (const volatile void* ptr, int memorder) \
|
||||
{ \
|
||||
return __atomic_load_ ## n (ptr, memorder); \
|
||||
}
|
||||
|
||||
#define ATOMIC_CMP_EXCHANGE(n, type) \
|
||||
bool __atomic_s32c1i_compare_exchange_ ## n (volatile void* ptr, void* expected, type desired, bool weak, int success, int failure) \
|
||||
{ \
|
||||
return __atomic_compare_exchange_ ## n (ptr, expected, desired, weak, success, failure); \
|
||||
}
|
||||
|
||||
#define ATOMIC_STORE(n, type) \
|
||||
void __atomic_s32c1i_store_ ## n (volatile void * ptr, type value, int memorder) \
|
||||
{ \
|
||||
__atomic_store_ ## n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define ATOMIC_EXCHANGE(n, type) \
|
||||
type __atomic_s32c1i_exchange_ ## n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
return __atomic_exchange_ ## n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
bool __sync_s32c1i_bool_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
return __sync_bool_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
type __sync_s32c1i_val_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
return __sync_val_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
type __sync_s32c1i_lock_test_and_set_ ## n (volatile void* ptr, type value) \
|
||||
{ \
|
||||
return __sync_lock_test_and_set_ ## n (ptr, value); \
|
||||
}
|
||||
|
||||
#define SYNC_LOCK_RELEASE(n, type) \
|
||||
void __sync_s32c1i_lock_release_ ## n (volatile void* ptr) \
|
||||
{ \
|
||||
__sync_lock_release_ ## n (ptr); \
|
||||
}
|
||||
|
||||
ATOMIC_FUNCTIONS(1, unsigned char)
|
||||
ATOMIC_FUNCTIONS(2, short unsigned int)
|
||||
ATOMIC_FUNCTIONS(4, unsigned int)
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_stdatomic.h"
|
||||
|
||||
#undef SYNC_OP_FUNCTIONS
|
||||
#undef _ATOMIC_OP_FUNCTION
|
||||
#undef ATOMIC_LOAD
|
||||
#undef ATOMIC_CMP_EXCHANGE
|
||||
#undef ATOMIC_STORE
|
||||
#undef ATOMIC_EXCHANGE
|
||||
#undef SYNC_BOOL_CMP_EXCHANGE
|
||||
#undef SYNC_VAL_CMP_EXCHANGE
|
||||
#undef SYNC_LOCK_TEST_AND_SET
|
||||
#undef SYNC_LOCK_RELEASE
|
||||
|
||||
#define SYNC_OP_FUNCTIONS(n, type, name)
|
||||
|
||||
#define _ATOMIC_OP_FUNCTION(n, type, name_1, name_2, ret_var, operation, inverse) \
|
||||
type __atomic_s32c1i_ ##name_1 ##_ ##name_2 ##_ ##n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
return __atomic_ ##name_1 ##_ ##name_2 ##_ ##n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define ATOMIC_LOAD(n, type) \
|
||||
type __atomic_s32c1i_load_ ## n (const volatile void* ptr, int memorder) \
|
||||
{ \
|
||||
return __atomic_load_ ## n (ptr, memorder); \
|
||||
}
|
||||
|
||||
#define ATOMIC_CMP_EXCHANGE(n, type) \
|
||||
bool __atomic_s32c1i_compare_exchange_ ## n (volatile void* ptr, void* expected, type desired, bool weak, int success, int failure) \
|
||||
{ \
|
||||
return __atomic_compare_exchange_ ## n (ptr, expected, desired, weak, success, failure); \
|
||||
}
|
||||
|
||||
#define ATOMIC_STORE(n, type) \
|
||||
void __atomic_s32c1i_store_ ## n (volatile void * ptr, type value, int memorder) \
|
||||
{ \
|
||||
__atomic_store_ ## n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define ATOMIC_EXCHANGE(n, type) \
|
||||
type __atomic_s32c1i_exchange_ ## n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
return __atomic_exchange_ ## n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
bool __sync_s32c1i_bool_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
return __sync_bool_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
type __sync_s32c1i_val_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
return __sync_val_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
type __sync_s32c1i_lock_test_and_set_ ## n (volatile void* ptr, type value) \
|
||||
{ \
|
||||
return __sync_lock_test_and_set_ ## n (ptr, value); \
|
||||
}
|
||||
|
||||
#define SYNC_LOCK_RELEASE(n, type) \
|
||||
void __sync_s32c1i_lock_release_ ## n (volatile void* ptr) \
|
||||
{ \
|
||||
__sync_lock_release_ ## n (ptr); \
|
||||
}
|
||||
|
||||
ATOMIC_FUNCTIONS(1, unsigned char)
|
||||
ATOMIC_FUNCTIONS(2, short unsigned int)
|
||||
ATOMIC_FUNCTIONS(4, unsigned int)
|
||||
|
||||
@@ -1,296 +1,296 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __XTENSA__
|
||||
#include "xtensa/config/core-isa.h"
|
||||
|
||||
#ifndef XCHAL_HAVE_S32C1I
|
||||
#error "XCHAL_HAVE_S32C1I not defined, include correct header!"
|
||||
#endif // XCHAL_HAVE_S32C1I
|
||||
|
||||
#ifndef CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
#define CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND 0
|
||||
#endif
|
||||
|
||||
#define HAS_ATOMICS_32 ((XCHAL_HAVE_S32C1I == 1) && !CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
|
||||
// no 64-bit atomics on Xtensa
|
||||
#define HAS_ATOMICS_64 0
|
||||
#else // RISCV
|
||||
// GCC toolchain will define this pre-processor if "A" extension is supported
|
||||
#ifndef __riscv_atomic
|
||||
#define __riscv_atomic 0
|
||||
#endif
|
||||
|
||||
#define HAS_ATOMICS_32 (__riscv_atomic == 1)
|
||||
#define HAS_ATOMICS_64 ((__riscv_atomic == 1) && (__riscv_xlen == 64))
|
||||
#endif // (__XTENSA__, __riscv)
|
||||
|
||||
#if SOC_CPU_CORES_NUM == 1
|
||||
// Single core SoC: atomics can be implemented using portSET_INTERRUPT_MASK_FROM_ISR
|
||||
// and portCLEAR_INTERRUPT_MASK_FROM_ISR, which disables and enables interrupts.
|
||||
#if CONFIG_FREERTOS_SMP
|
||||
#define _ATOMIC_ENTER_CRITICAL() unsigned int state = portDISABLE_INTERRUPTS();
|
||||
#define _ATOMIC_EXIT_CRITICAL() portRESTORE_INTERRUPTS(state)
|
||||
#else // CONFIG_FREERTOS_SMP
|
||||
#define _ATOMIC_ENTER_CRITICAL() unsigned int state = portSET_INTERRUPT_MASK_FROM_ISR()
|
||||
#define _ATOMIC_EXIT_CRITICAL() portCLEAR_INTERRUPT_MASK_FROM_ISR(state)
|
||||
#endif // CONFIG_FREERTOS_SMP
|
||||
#else // SOC_CPU_CORES_NUM
|
||||
|
||||
#define _ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL_SAFE(&s_atomic_lock);
|
||||
#define _ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL_SAFE(&s_atomic_lock);
|
||||
|
||||
#endif // SOC_CPU_CORES_NUM
|
||||
|
||||
#if CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
#define _ATOMIC_IF_NOT_EXT_RAM() \
|
||||
if (!((uintptr_t)ptr >= SOC_EXTRAM_DATA_LOW && (uintptr_t) ptr < SOC_EXTRAM_DATA_HIGH))
|
||||
|
||||
#define _ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __atomic_s32c1i_ ##name_1 ##_ ##name_2 ##_ ##n (volatile void* ptr, type value, int memorder); \
|
||||
return __atomic_s32c1i_ ##name_1 ##_ ##name_2 ##_ ##n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __atomic_s32c1i_exchange_ ## n (volatile void* ptr, type value, int memorder); \
|
||||
return __atomic_s32c1i_exchange_ ## n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_STORE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
void __atomic_s32c1i_store_ ## n (volatile void * ptr, type value, int memorder); \
|
||||
__atomic_s32c1i_store_ ## n (ptr, value, memorder); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_CMP_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
bool __atomic_s32c1i_compare_exchange_ ## n (volatile void* ptr, void* expected, type desired, bool weak, int success, int failure); \
|
||||
return __atomic_s32c1i_compare_exchange_ ## n (ptr, expected, desired, weak, success, failure); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_LOAD(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __atomic_s32c1i_load_ ## n (const volatile void* ptr, int memorder); \
|
||||
return __atomic_s32c1i_load_ ## n (ptr,memorder); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
bool __sync_s32c1i_bool_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired); \
|
||||
return __sync_s32c1i_bool_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __sync_s32c1i_val_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired); \
|
||||
return __sync_s32c1i_val_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __sync_s32c1i_lock_test_and_set_ ## n (volatile void* ptr, type value); \
|
||||
return __sync_s32c1i_lock_test_and_set_ ## n (ptr, value); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
void __sync_s32c1i_lock_release_ ## n (volatile void* ptr); \
|
||||
__sync_s32c1i_lock_release_ ## n (ptr); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#else // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
#define _ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2)
|
||||
#define _ATOMIC_HW_STUB_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_STORE(n, type)
|
||||
#define _ATOMIC_HW_STUB_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_LOAD(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type)
|
||||
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
#ifdef __clang__
|
||||
// Clang doesn't allow to define "__sync_*" atomics. The workaround is to define function with name "__sync_*_builtin",
|
||||
// which implements "__sync_*" atomic functionality and use asm directive to set the value of symbol "__sync_*" to the name
|
||||
// of defined function.
|
||||
|
||||
#define CLANG_ATOMIC_SUFFIX(name_) name_ ## _builtin
|
||||
#define CLANG_DECLARE_ALIAS(name_) \
|
||||
__asm__(".type " # name_ ", @function\n" \
|
||||
".global " #name_ "\n" \
|
||||
".equ " #name_ ", " #name_ "_builtin");
|
||||
|
||||
#else // __clang__
|
||||
|
||||
#define CLANG_ATOMIC_SUFFIX(name_) name_
|
||||
#define CLANG_DECLARE_ALIAS(name_)
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
#define ATOMIC_OP_FUNCTIONS(n, type, name, operation, inverse) \
|
||||
_ATOMIC_OP_FUNCTION(n, type, fetch, name, old, operation, inverse) \
|
||||
_ATOMIC_OP_FUNCTION(n, type, name, fetch, new, operation, inverse)
|
||||
|
||||
#define _ATOMIC_OP_FUNCTION(n, type, name_1, name_2, ret_var, operation, inverse) \
|
||||
type __atomic_ ##name_1 ##_ ##name_2 ##_ ##n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
type old, new; \
|
||||
_ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = (*(volatile type*)ptr); \
|
||||
new = inverse(old operation value); \
|
||||
*(volatile type*)ptr = new; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return ret_var; \
|
||||
}
|
||||
|
||||
#define ATOMIC_LOAD(n, type) \
|
||||
type __atomic_load_ ## n (const volatile void* ptr, int memorder) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_LOAD(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(const volatile type*)ptr; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
}
|
||||
|
||||
#define ATOMIC_CMP_EXCHANGE(n, type) \
|
||||
bool __atomic_compare_exchange_ ## n (volatile void* ptr, void* expected, type desired, bool weak, int success, int failure) \
|
||||
{ \
|
||||
bool ret = false; \
|
||||
_ATOMIC_HW_STUB_CMP_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
if (*(volatile type*)ptr == *(type*)expected) { \
|
||||
ret = true; \
|
||||
*(volatile type*)ptr = desired; \
|
||||
} else { \
|
||||
*(type*)expected = *(volatile type*)ptr; \
|
||||
} \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define ATOMIC_STORE(n, type) \
|
||||
void __atomic_store_ ## n (volatile void * ptr, type value, int memorder) \
|
||||
{ \
|
||||
_ATOMIC_HW_STUB_STORE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
*(volatile type*)ptr = value; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
}
|
||||
|
||||
#define ATOMIC_EXCHANGE(n, type) \
|
||||
type __atomic_exchange_ ## n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(volatile type*)ptr; \
|
||||
*(volatile type*)ptr = value; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
}
|
||||
|
||||
#define SYNC_OP_FUNCTIONS(n, type, name) \
|
||||
_SYNC_OP_FUNCTION(n, type, fetch, name) \
|
||||
_SYNC_OP_FUNCTION(n, type, name, fetch)
|
||||
|
||||
#define _SYNC_OP_FUNCTION(n, type, name_1, name_2) \
|
||||
type CLANG_ATOMIC_SUFFIX(__sync_ ##name_1 ##_and_ ##name_2 ##_ ##n) (volatile void* ptr, type value) \
|
||||
{ \
|
||||
return __atomic_ ##name_1 ##_ ##name_2 ##_ ##n (ptr, value, __ATOMIC_SEQ_CST); \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_##name_1 ##_and_ ##name_2 ##_ ##n )
|
||||
|
||||
#define SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
bool CLANG_ATOMIC_SUFFIX(__sync_bool_compare_and_swap_ ## n) (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
bool ret = false; \
|
||||
_ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
if (*(volatile type*)ptr == expected) { \
|
||||
*(volatile type*)ptr = desired; \
|
||||
ret = true; \
|
||||
} \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return ret; \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_bool_compare_and_swap_ ## n )
|
||||
|
||||
#define SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
type CLANG_ATOMIC_SUFFIX(__sync_val_compare_and_swap_ ## n) (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(volatile type*)ptr; \
|
||||
if (old == expected) { \
|
||||
*(volatile type*)ptr = desired; \
|
||||
} \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_val_compare_and_swap_ ## n )
|
||||
|
||||
#define SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
type CLANG_ATOMIC_SUFFIX(__sync_lock_test_and_set_ ## n) (volatile void* ptr, type value) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(volatile type*)ptr; \
|
||||
*(volatile type*)ptr = value; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_lock_test_and_set_ ## n )
|
||||
|
||||
#define SYNC_LOCK_RELEASE(n, type) \
|
||||
void CLANG_ATOMIC_SUFFIX(__sync_lock_release_ ## n) (volatile void* ptr) \
|
||||
{ \
|
||||
_ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
*(volatile type*)ptr = 0; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_lock_release_ ## n )
|
||||
|
||||
#define ATOMIC_FUNCTIONS(n, type) \
|
||||
ATOMIC_EXCHANGE(n, type) \
|
||||
ATOMIC_CMP_EXCHANGE(n, type) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, add, +, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, sub, -, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, and, &, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, or, |, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, xor, ^, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, nand, &, ~) \
|
||||
/* LLVM has not implemented native atomic load/stores for riscv targets without the Atomic extension. LLVM thread: https://reviews.llvm.org/D47553. \
|
||||
* Even though GCC does transform them, these libcalls need to be available for the case where a LLVM based project links against IDF. */ \
|
||||
ATOMIC_LOAD(n, type) \
|
||||
ATOMIC_STORE(n, type) \
|
||||
SYNC_OP_FUNCTIONS(n, type, add) \
|
||||
SYNC_OP_FUNCTIONS(n, type, sub) \
|
||||
SYNC_OP_FUNCTIONS(n, type, and) \
|
||||
SYNC_OP_FUNCTIONS(n, type, or) \
|
||||
SYNC_OP_FUNCTIONS(n, type, xor) \
|
||||
SYNC_OP_FUNCTIONS(n, type, nand) \
|
||||
SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
SYNC_LOCK_RELEASE(n, type)
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __XTENSA__
|
||||
#include "xtensa/config/core-isa.h"
|
||||
|
||||
#ifndef XCHAL_HAVE_S32C1I
|
||||
#error "XCHAL_HAVE_S32C1I not defined, include correct header!"
|
||||
#endif // XCHAL_HAVE_S32C1I
|
||||
|
||||
#ifndef CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
#define CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND 0
|
||||
#endif
|
||||
|
||||
#define HAS_ATOMICS_32 ((XCHAL_HAVE_S32C1I == 1) && !CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
|
||||
// no 64-bit atomics on Xtensa
|
||||
#define HAS_ATOMICS_64 0
|
||||
#else // RISCV
|
||||
// GCC toolchain will define this pre-processor if "A" extension is supported
|
||||
#ifndef __riscv_atomic
|
||||
#define __riscv_atomic 0
|
||||
#endif
|
||||
|
||||
#define HAS_ATOMICS_32 (__riscv_atomic == 1)
|
||||
#define HAS_ATOMICS_64 ((__riscv_atomic == 1) && (__riscv_xlen == 64))
|
||||
#endif // (__XTENSA__, __riscv)
|
||||
|
||||
#if SOC_CPU_CORES_NUM == 1
|
||||
// Single core SoC: atomics can be implemented using portSET_INTERRUPT_MASK_FROM_ISR
|
||||
// and portCLEAR_INTERRUPT_MASK_FROM_ISR, which disables and enables interrupts.
|
||||
#if CONFIG_FREERTOS_SMP
|
||||
#define _ATOMIC_ENTER_CRITICAL() unsigned int state = portDISABLE_INTERRUPTS();
|
||||
#define _ATOMIC_EXIT_CRITICAL() portRESTORE_INTERRUPTS(state)
|
||||
#else // CONFIG_FREERTOS_SMP
|
||||
#define _ATOMIC_ENTER_CRITICAL() unsigned int state = portSET_INTERRUPT_MASK_FROM_ISR()
|
||||
#define _ATOMIC_EXIT_CRITICAL() portCLEAR_INTERRUPT_MASK_FROM_ISR(state)
|
||||
#endif // CONFIG_FREERTOS_SMP
|
||||
#else // SOC_CPU_CORES_NUM
|
||||
|
||||
#define _ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL_SAFE(&s_atomic_lock);
|
||||
#define _ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL_SAFE(&s_atomic_lock);
|
||||
|
||||
#endif // SOC_CPU_CORES_NUM
|
||||
|
||||
#if CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
#define _ATOMIC_IF_NOT_EXT_RAM() \
|
||||
if (!((uintptr_t)ptr >= SOC_EXTRAM_DATA_LOW && (uintptr_t) ptr < SOC_EXTRAM_DATA_HIGH))
|
||||
|
||||
#define _ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __atomic_s32c1i_ ##name_1 ##_ ##name_2 ##_ ##n (volatile void* ptr, type value, int memorder); \
|
||||
return __atomic_s32c1i_ ##name_1 ##_ ##name_2 ##_ ##n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __atomic_s32c1i_exchange_ ## n (volatile void* ptr, type value, int memorder); \
|
||||
return __atomic_s32c1i_exchange_ ## n (ptr, value, memorder); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_STORE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
void __atomic_s32c1i_store_ ## n (volatile void * ptr, type value, int memorder); \
|
||||
__atomic_s32c1i_store_ ## n (ptr, value, memorder); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_CMP_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
bool __atomic_s32c1i_compare_exchange_ ## n (volatile void* ptr, void* expected, type desired, bool weak, int success, int failure); \
|
||||
return __atomic_s32c1i_compare_exchange_ ## n (ptr, expected, desired, weak, success, failure); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_LOAD(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __atomic_s32c1i_load_ ## n (const volatile void* ptr, int memorder); \
|
||||
return __atomic_s32c1i_load_ ## n (ptr,memorder); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
bool __sync_s32c1i_bool_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired); \
|
||||
return __sync_s32c1i_bool_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __sync_s32c1i_val_compare_and_swap_ ## n (volatile void* ptr, type expected, type desired); \
|
||||
return __sync_s32c1i_val_compare_and_swap_ ## n (ptr, expected, desired); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
type __sync_s32c1i_lock_test_and_set_ ## n (volatile void* ptr, type value); \
|
||||
return __sync_s32c1i_lock_test_and_set_ ## n (ptr, value); \
|
||||
}
|
||||
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type) \
|
||||
_ATOMIC_IF_NOT_EXT_RAM() { \
|
||||
void __sync_s32c1i_lock_release_ ## n (volatile void* ptr); \
|
||||
__sync_s32c1i_lock_release_ ## n (ptr); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#else // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
#define _ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2)
|
||||
#define _ATOMIC_HW_STUB_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_STORE(n, type)
|
||||
#define _ATOMIC_HW_STUB_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_LOAD(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type)
|
||||
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
#ifdef __clang__
|
||||
// Clang doesn't allow to define "__sync_*" atomics. The workaround is to define function with name "__sync_*_builtin",
|
||||
// which implements "__sync_*" atomic functionality and use asm directive to set the value of symbol "__sync_*" to the name
|
||||
// of defined function.
|
||||
|
||||
#define CLANG_ATOMIC_SUFFIX(name_) name_ ## _builtin
|
||||
#define CLANG_DECLARE_ALIAS(name_) \
|
||||
__asm__(".type " # name_ ", @function\n" \
|
||||
".global " #name_ "\n" \
|
||||
".equ " #name_ ", " #name_ "_builtin");
|
||||
|
||||
#else // __clang__
|
||||
|
||||
#define CLANG_ATOMIC_SUFFIX(name_) name_
|
||||
#define CLANG_DECLARE_ALIAS(name_)
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
#define ATOMIC_OP_FUNCTIONS(n, type, name, operation, inverse) \
|
||||
_ATOMIC_OP_FUNCTION(n, type, fetch, name, old, operation, inverse) \
|
||||
_ATOMIC_OP_FUNCTION(n, type, name, fetch, new, operation, inverse)
|
||||
|
||||
#define _ATOMIC_OP_FUNCTION(n, type, name_1, name_2, ret_var, operation, inverse) \
|
||||
type __atomic_ ##name_1 ##_ ##name_2 ##_ ##n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
type old, new; \
|
||||
_ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = (*(volatile type*)ptr); \
|
||||
new = inverse(old operation value); \
|
||||
*(volatile type*)ptr = new; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return ret_var; \
|
||||
}
|
||||
|
||||
#define ATOMIC_LOAD(n, type) \
|
||||
type __atomic_load_ ## n (const volatile void* ptr, int memorder) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_LOAD(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(const volatile type*)ptr; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
}
|
||||
|
||||
#define ATOMIC_CMP_EXCHANGE(n, type) \
|
||||
bool __atomic_compare_exchange_ ## n (volatile void* ptr, void* expected, type desired, bool weak, int success, int failure) \
|
||||
{ \
|
||||
bool ret = false; \
|
||||
_ATOMIC_HW_STUB_CMP_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
if (*(volatile type*)ptr == *(type*)expected) { \
|
||||
ret = true; \
|
||||
*(volatile type*)ptr = desired; \
|
||||
} else { \
|
||||
*(type*)expected = *(volatile type*)ptr; \
|
||||
} \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define ATOMIC_STORE(n, type) \
|
||||
void __atomic_store_ ## n (volatile void * ptr, type value, int memorder) \
|
||||
{ \
|
||||
_ATOMIC_HW_STUB_STORE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
*(volatile type*)ptr = value; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
}
|
||||
|
||||
#define ATOMIC_EXCHANGE(n, type) \
|
||||
type __atomic_exchange_ ## n (volatile void* ptr, type value, int memorder) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(volatile type*)ptr; \
|
||||
*(volatile type*)ptr = value; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
}
|
||||
|
||||
#define SYNC_OP_FUNCTIONS(n, type, name) \
|
||||
_SYNC_OP_FUNCTION(n, type, fetch, name) \
|
||||
_SYNC_OP_FUNCTION(n, type, name, fetch)
|
||||
|
||||
#define _SYNC_OP_FUNCTION(n, type, name_1, name_2) \
|
||||
type CLANG_ATOMIC_SUFFIX(__sync_ ##name_1 ##_and_ ##name_2 ##_ ##n) (volatile void* ptr, type value) \
|
||||
{ \
|
||||
return __atomic_ ##name_1 ##_ ##name_2 ##_ ##n (ptr, value, __ATOMIC_SEQ_CST); \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_##name_1 ##_and_ ##name_2 ##_ ##n )
|
||||
|
||||
#define SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
bool CLANG_ATOMIC_SUFFIX(__sync_bool_compare_and_swap_ ## n) (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
bool ret = false; \
|
||||
_ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
if (*(volatile type*)ptr == expected) { \
|
||||
*(volatile type*)ptr = desired; \
|
||||
ret = true; \
|
||||
} \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return ret; \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_bool_compare_and_swap_ ## n )
|
||||
|
||||
#define SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
type CLANG_ATOMIC_SUFFIX(__sync_val_compare_and_swap_ ## n) (volatile void* ptr, type expected, type desired) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(volatile type*)ptr; \
|
||||
if (old == expected) { \
|
||||
*(volatile type*)ptr = desired; \
|
||||
} \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_val_compare_and_swap_ ## n )
|
||||
|
||||
#define SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
type CLANG_ATOMIC_SUFFIX(__sync_lock_test_and_set_ ## n) (volatile void* ptr, type value) \
|
||||
{ \
|
||||
type old; \
|
||||
_ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
old = *(volatile type*)ptr; \
|
||||
*(volatile type*)ptr = value; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
return old; \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_lock_test_and_set_ ## n )
|
||||
|
||||
#define SYNC_LOCK_RELEASE(n, type) \
|
||||
void CLANG_ATOMIC_SUFFIX(__sync_lock_release_ ## n) (volatile void* ptr) \
|
||||
{ \
|
||||
_ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type); \
|
||||
_ATOMIC_ENTER_CRITICAL(); \
|
||||
*(volatile type*)ptr = 0; \
|
||||
_ATOMIC_EXIT_CRITICAL(); \
|
||||
} \
|
||||
CLANG_DECLARE_ALIAS( __sync_lock_release_ ## n )
|
||||
|
||||
#define ATOMIC_FUNCTIONS(n, type) \
|
||||
ATOMIC_EXCHANGE(n, type) \
|
||||
ATOMIC_CMP_EXCHANGE(n, type) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, add, +, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, sub, -, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, and, &, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, or, |, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, xor, ^, ) \
|
||||
ATOMIC_OP_FUNCTIONS(n, type, nand, &, ~) \
|
||||
/* LLVM has not implemented native atomic load/stores for riscv targets without the Atomic extension. LLVM thread: https://reviews.llvm.org/D47553. \
|
||||
* Even though GCC does transform them, these libcalls need to be available for the case where a LLVM based project links against IDF. */ \
|
||||
ATOMIC_LOAD(n, type) \
|
||||
ATOMIC_STORE(n, type) \
|
||||
SYNC_OP_FUNCTIONS(n, type, add) \
|
||||
SYNC_OP_FUNCTIONS(n, type, sub) \
|
||||
SYNC_OP_FUNCTIONS(n, type, and) \
|
||||
SYNC_OP_FUNCTIONS(n, type, or) \
|
||||
SYNC_OP_FUNCTIONS(n, type, xor) \
|
||||
SYNC_OP_FUNCTIONS(n, type, nand) \
|
||||
SYNC_BOOL_CMP_EXCHANGE(n, type) \
|
||||
SYNC_VAL_CMP_EXCHANGE(n, type) \
|
||||
SYNC_LOCK_TEST_AND_SET(n, type) \
|
||||
SYNC_LOCK_RELEASE(n, type)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
void esp_time_impl_init(void);
|
||||
|
||||
uint64_t esp_time_impl_get_time(void);
|
||||
|
||||
uint64_t esp_time_impl_get_time_since_boot(void);
|
||||
|
||||
uint32_t esp_time_impl_get_time_resolution(void);
|
||||
|
||||
void esp_time_impl_set_boot_time(uint64_t t);
|
||||
|
||||
uint64_t esp_time_impl_get_boot_time(void);
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
void esp_time_impl_init(void);
|
||||
|
||||
uint64_t esp_time_impl_get_time(void);
|
||||
|
||||
uint64_t esp_time_impl_get_time_since_boot(void);
|
||||
|
||||
uint32_t esp_time_impl_get_time_resolution(void);
|
||||
|
||||
void esp_time_impl_set_boot_time(uint64_t t);
|
||||
|
||||
uint64_t esp_time_impl_get_boot_time(void);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND)
|
||||
endif()
|
||||
if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND)
|
||||
idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND)
|
||||
endif()
|
||||
|
||||
+37
-37
@@ -1,37 +1,37 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <pthread.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
const static char *TAG = "esp32_asio_pthread";
|
||||
|
||||
int pthread_setcancelstate(int state, int *oldstate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This functions (pthread_sigmask(), sigfillset) are called from ASIO::signal_blocker to temporarily silence signals
|
||||
// Since signals are not yet supported in ESP pthread these functions serve as no-ops
|
||||
//
|
||||
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s: Signals not supported in ESP pthread", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigfillset(sigset_t *what)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s: Signals not supported in ESP pthread", __func__);
|
||||
if (what != NULL) {
|
||||
*what = ~0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void newlib_include_pthread_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <pthread.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
const static char *TAG = "esp32_asio_pthread";
|
||||
|
||||
int pthread_setcancelstate(int state, int *oldstate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This functions (pthread_sigmask(), sigfillset) are called from ASIO::signal_blocker to temporarily silence signals
|
||||
// Since signals are not yet supported in ESP pthread these functions serve as no-ops
|
||||
//
|
||||
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s: Signals not supported in ESP pthread", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigfillset(sigset_t *what)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s: Signals not supported in ESP pthread", __func__);
|
||||
if (what != NULL) {
|
||||
*what = ~0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void newlib_include_pthread_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
||||
|
||||
+35
-35
@@ -1,35 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/random.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "esp_random.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "RANDOM";
|
||||
|
||||
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
// Flags are ignored because:
|
||||
// - esp_random is non-blocking so it works for both blocking and non-blocking calls,
|
||||
// - don't have opportunity so set som other source of entropy.
|
||||
|
||||
ESP_LOGD(TAG, "getrandom(buf=0x%x, buflen=%d, flags=%u)", (int) buf, buflen, flags);
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = EFAULT;
|
||||
ESP_LOGD(TAG, "getrandom returns -1 (EFAULT)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
esp_fill_random(buf, buflen);
|
||||
|
||||
ESP_LOGD(TAG, "getrandom returns %d", buflen);
|
||||
return buflen;
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/random.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "esp_random.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "RANDOM";
|
||||
|
||||
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
// Flags are ignored because:
|
||||
// - esp_random is non-blocking so it works for both blocking and non-blocking calls,
|
||||
// - don't have opportunity so set som other source of entropy.
|
||||
|
||||
ESP_LOGD(TAG, "getrandom(buf=0x%x, buflen=%d, flags=%u)", (int) buf, buflen, flags);
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = EFAULT;
|
||||
ESP_LOGD(TAG, "getrandom returns -1 (EFAULT)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
esp_fill_random(buf, buflen);
|
||||
|
||||
ESP_LOGD(TAG, "getrandom returns %d", buflen);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
+124
-124
@@ -1,124 +1,124 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* realpath logic:
|
||||
* 1. prepend CWD (/)
|
||||
* 2. iterate over components (search until next '/' or end of line)
|
||||
* - empty, skip the component
|
||||
* - if it is '.', skip the component
|
||||
* - if it is '..'
|
||||
* - and out_level == 0, ??? ('/..')
|
||||
* - otherwise, reverse-search for '/', set out_pos to that - 1, decrement out_level
|
||||
* - otherwise, add the component to output, increment out_level
|
||||
*/
|
||||
|
||||
char * realpath(const char *file_name, char *resolved_name)
|
||||
{
|
||||
char * out_path = resolved_name;
|
||||
if (out_path == NULL) {
|
||||
/* allowed as an extension, allocate memory for the output path */
|
||||
out_path = malloc(PATH_MAX);
|
||||
if (out_path == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* canonical path starts with / */
|
||||
strlcpy(out_path, "/", PATH_MAX);
|
||||
|
||||
/* pointers moving over the input and output path buffers */
|
||||
const char* in_ptr = file_name;
|
||||
char* out_ptr = out_path + 1;
|
||||
/* number of path components in the output buffer */
|
||||
size_t out_depth = 0;
|
||||
|
||||
while (*in_ptr) {
|
||||
/* "path component" is the part between two '/' path separators.
|
||||
* locate the next path component in the input path:
|
||||
*/
|
||||
const char* end_of_path_component = strchrnul(in_ptr, '/');
|
||||
size_t path_component_len = end_of_path_component - in_ptr;
|
||||
|
||||
if (path_component_len == 0 ||
|
||||
(path_component_len == 1 && in_ptr[0] == '.')) {
|
||||
/* empty path component or '.' - nothing to do */
|
||||
} else if (path_component_len == 2 && in_ptr[0] == '.' && in_ptr[1] == '.') {
|
||||
/* '..' - remove one path component from the output */
|
||||
if (out_depth == 0) {
|
||||
/* nothing to remove */
|
||||
} else if (out_depth == 1) {
|
||||
/* there is only one path component in output;
|
||||
* remove it, but keep the leading separator
|
||||
*/
|
||||
out_ptr = out_path + 1;
|
||||
*out_ptr = '\0';
|
||||
out_depth = 0;
|
||||
} else {
|
||||
/* remove last path component and the separator preceding it */
|
||||
char * prev_sep = strrchr(out_path, '/');
|
||||
assert(prev_sep > out_path); /* this shouldn't be the leading separator */
|
||||
out_ptr = prev_sep;
|
||||
*out_ptr = '\0';
|
||||
--out_depth;
|
||||
}
|
||||
} else {
|
||||
/* copy path component to output; +1 is for the separator */
|
||||
if (out_ptr - out_path + 1 + path_component_len > PATH_MAX - 1) {
|
||||
/* output buffer insufficient */
|
||||
errno = E2BIG;
|
||||
goto fail;
|
||||
} else {
|
||||
/* add separator if necessary */
|
||||
if (out_depth > 0) {
|
||||
*out_ptr = '/';
|
||||
++out_ptr;
|
||||
}
|
||||
memcpy(out_ptr, in_ptr, path_component_len);
|
||||
out_ptr += path_component_len;
|
||||
*out_ptr = '\0';
|
||||
++out_depth;
|
||||
}
|
||||
}
|
||||
/* move input pointer to separator right after this path component */
|
||||
in_ptr += path_component_len;
|
||||
if (*in_ptr != '\0') {
|
||||
/* move past it unless already at the end of the input string */
|
||||
++in_ptr;
|
||||
}
|
||||
}
|
||||
return out_path;
|
||||
|
||||
fail:
|
||||
if (resolved_name == NULL) {
|
||||
/* out_path was allocated, free it */
|
||||
free(out_path);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * getcwd(char *buf, size_t size)
|
||||
{
|
||||
if (buf == NULL) {
|
||||
return strdup("/");
|
||||
}
|
||||
strlcpy(buf, "/", size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int chdir(const char *path)
|
||||
{
|
||||
(void) path;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* realpath logic:
|
||||
* 1. prepend CWD (/)
|
||||
* 2. iterate over components (search until next '/' or end of line)
|
||||
* - empty, skip the component
|
||||
* - if it is '.', skip the component
|
||||
* - if it is '..'
|
||||
* - and out_level == 0, ??? ('/..')
|
||||
* - otherwise, reverse-search for '/', set out_pos to that - 1, decrement out_level
|
||||
* - otherwise, add the component to output, increment out_level
|
||||
*/
|
||||
|
||||
char * realpath(const char *file_name, char *resolved_name)
|
||||
{
|
||||
char * out_path = resolved_name;
|
||||
if (out_path == NULL) {
|
||||
/* allowed as an extension, allocate memory for the output path */
|
||||
out_path = malloc(PATH_MAX);
|
||||
if (out_path == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* canonical path starts with / */
|
||||
strlcpy(out_path, "/", PATH_MAX);
|
||||
|
||||
/* pointers moving over the input and output path buffers */
|
||||
const char* in_ptr = file_name;
|
||||
char* out_ptr = out_path + 1;
|
||||
/* number of path components in the output buffer */
|
||||
size_t out_depth = 0;
|
||||
|
||||
while (*in_ptr) {
|
||||
/* "path component" is the part between two '/' path separators.
|
||||
* locate the next path component in the input path:
|
||||
*/
|
||||
const char* end_of_path_component = strchrnul(in_ptr, '/');
|
||||
size_t path_component_len = end_of_path_component - in_ptr;
|
||||
|
||||
if (path_component_len == 0 ||
|
||||
(path_component_len == 1 && in_ptr[0] == '.')) {
|
||||
/* empty path component or '.' - nothing to do */
|
||||
} else if (path_component_len == 2 && in_ptr[0] == '.' && in_ptr[1] == '.') {
|
||||
/* '..' - remove one path component from the output */
|
||||
if (out_depth == 0) {
|
||||
/* nothing to remove */
|
||||
} else if (out_depth == 1) {
|
||||
/* there is only one path component in output;
|
||||
* remove it, but keep the leading separator
|
||||
*/
|
||||
out_ptr = out_path + 1;
|
||||
*out_ptr = '\0';
|
||||
out_depth = 0;
|
||||
} else {
|
||||
/* remove last path component and the separator preceding it */
|
||||
char * prev_sep = strrchr(out_path, '/');
|
||||
assert(prev_sep > out_path); /* this shouldn't be the leading separator */
|
||||
out_ptr = prev_sep;
|
||||
*out_ptr = '\0';
|
||||
--out_depth;
|
||||
}
|
||||
} else {
|
||||
/* copy path component to output; +1 is for the separator */
|
||||
if (out_ptr - out_path + 1 + path_component_len > PATH_MAX - 1) {
|
||||
/* output buffer insufficient */
|
||||
errno = E2BIG;
|
||||
goto fail;
|
||||
} else {
|
||||
/* add separator if necessary */
|
||||
if (out_depth > 0) {
|
||||
*out_ptr = '/';
|
||||
++out_ptr;
|
||||
}
|
||||
memcpy(out_ptr, in_ptr, path_component_len);
|
||||
out_ptr += path_component_len;
|
||||
*out_ptr = '\0';
|
||||
++out_depth;
|
||||
}
|
||||
}
|
||||
/* move input pointer to separator right after this path component */
|
||||
in_ptr += path_component_len;
|
||||
if (*in_ptr != '\0') {
|
||||
/* move past it unless already at the end of the input string */
|
||||
++in_ptr;
|
||||
}
|
||||
}
|
||||
return out_path;
|
||||
|
||||
fail:
|
||||
if (resolved_name == NULL) {
|
||||
/* out_path was allocated, free it */
|
||||
free(out_path);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * getcwd(char *buf, size_t size)
|
||||
{
|
||||
if (buf == NULL) {
|
||||
return strdup("/");
|
||||
}
|
||||
strlcpy(buf, "/", size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int chdir(const char *path)
|
||||
{
|
||||
(void) path;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
+75
-75
@@ -1,75 +1,75 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/reent.h>
|
||||
#include "esp_attr.h"
|
||||
|
||||
/**
|
||||
* This is the replacement for newlib's _REENT_INIT_PTR and __sinit.
|
||||
* The problem with __sinit is that it allocates three FILE structures
|
||||
* (stdin, stdout, stderr). Having individual standard streams for each task
|
||||
* is a bit too much on a small embedded system. So we point streams
|
||||
* to the streams of the global struct _reent, which are initialized in
|
||||
* startup code.
|
||||
*/
|
||||
void IRAM_ATTR esp_reent_init(struct _reent* r)
|
||||
{
|
||||
memset(r, 0, sizeof(*r));
|
||||
_REENT_STDIN(r) = _REENT_STDIN(_GLOBAL_REENT);
|
||||
_REENT_STDOUT(r) = _REENT_STDOUT(_GLOBAL_REENT);
|
||||
_REENT_STDERR(r) = _REENT_STDERR(_GLOBAL_REENT);
|
||||
_REENT_CLEANUP(r) = _REENT_CLEANUP(_GLOBAL_REENT);
|
||||
_REENT_SDIDINIT(r) = _REENT_SDIDINIT(_GLOBAL_REENT);
|
||||
}
|
||||
|
||||
/* only declared in private stdio header file, local.h */
|
||||
extern void __sfp_lock_acquire(void);
|
||||
extern void __sfp_lock_release(void);
|
||||
|
||||
void esp_reent_cleanup(void)
|
||||
{
|
||||
struct _reent* r = __getreent();
|
||||
_reclaim_reent(r);
|
||||
|
||||
r->_emergency = NULL;
|
||||
r->_mp = NULL;
|
||||
r->_r48 = NULL;
|
||||
r->_localtime_buf = NULL;
|
||||
r->_asctime_buf = NULL;
|
||||
r->_signal_buf = NULL;
|
||||
r->_misc = NULL;
|
||||
r->_cvtbuf = NULL;
|
||||
|
||||
/* Clean up "glue" (lazily-allocated FILE objects) */
|
||||
struct _glue* prev = &_REENT_SGLUE(_GLOBAL_REENT);
|
||||
for (struct _glue * cur = _REENT_SGLUE(_GLOBAL_REENT)._next; cur != NULL;) {
|
||||
if (cur->_niobs == 0) {
|
||||
cur = cur->_next;
|
||||
continue;
|
||||
}
|
||||
bool has_open_files = false;
|
||||
for (int i = 0; i < cur->_niobs; ++i) {
|
||||
FILE* fp = &cur->_iobs[i];
|
||||
if (fp->_flags != 0) {
|
||||
has_open_files = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_open_files) {
|
||||
prev = cur;
|
||||
cur = cur->_next;
|
||||
continue;
|
||||
}
|
||||
struct _glue * next = cur->_next;
|
||||
prev->_next = next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/reent.h>
|
||||
#include "esp_attr.h"
|
||||
|
||||
/**
|
||||
* This is the replacement for newlib's _REENT_INIT_PTR and __sinit.
|
||||
* The problem with __sinit is that it allocates three FILE structures
|
||||
* (stdin, stdout, stderr). Having individual standard streams for each task
|
||||
* is a bit too much on a small embedded system. So we point streams
|
||||
* to the streams of the global struct _reent, which are initialized in
|
||||
* startup code.
|
||||
*/
|
||||
void IRAM_ATTR esp_reent_init(struct _reent* r)
|
||||
{
|
||||
memset(r, 0, sizeof(*r));
|
||||
_REENT_STDIN(r) = _REENT_STDIN(_GLOBAL_REENT);
|
||||
_REENT_STDOUT(r) = _REENT_STDOUT(_GLOBAL_REENT);
|
||||
_REENT_STDERR(r) = _REENT_STDERR(_GLOBAL_REENT);
|
||||
_REENT_CLEANUP(r) = _REENT_CLEANUP(_GLOBAL_REENT);
|
||||
_REENT_SDIDINIT(r) = _REENT_SDIDINIT(_GLOBAL_REENT);
|
||||
}
|
||||
|
||||
/* only declared in private stdio header file, local.h */
|
||||
extern void __sfp_lock_acquire(void);
|
||||
extern void __sfp_lock_release(void);
|
||||
|
||||
void esp_reent_cleanup(void)
|
||||
{
|
||||
struct _reent* r = __getreent();
|
||||
_reclaim_reent(r);
|
||||
|
||||
r->_emergency = NULL;
|
||||
r->_mp = NULL;
|
||||
r->_r48 = NULL;
|
||||
r->_localtime_buf = NULL;
|
||||
r->_asctime_buf = NULL;
|
||||
r->_signal_buf = NULL;
|
||||
r->_misc = NULL;
|
||||
r->_cvtbuf = NULL;
|
||||
|
||||
/* Clean up "glue" (lazily-allocated FILE objects) */
|
||||
struct _glue* prev = &_REENT_SGLUE(_GLOBAL_REENT);
|
||||
for (struct _glue * cur = _REENT_SGLUE(_GLOBAL_REENT)._next; cur != NULL;) {
|
||||
if (cur->_niobs == 0) {
|
||||
cur = cur->_next;
|
||||
continue;
|
||||
}
|
||||
bool has_open_files = false;
|
||||
for (int i = 0; i < cur->_niobs; ++i) {
|
||||
FILE* fp = &cur->_iobs[i];
|
||||
if (fp->_flags != 0) {
|
||||
has_open_files = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_open_files) {
|
||||
prev = cur;
|
||||
cur = cur->_next;
|
||||
continue;
|
||||
}
|
||||
struct _glue * next = cur->_next;
|
||||
prev->_next = next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: 'newlib'
|
||||
version: '4.3.0'
|
||||
cpe: cpe:2.3:a:newlib_project:newlib:{}:*:*:*:*:*:*:*
|
||||
supplier: 'Organization: Espressif Systems (Shanghai) CO LTD'
|
||||
originator: 'Organization: Red Hat Incorporated'
|
||||
description: An open-source C standard library implementation with additional features and patches from Espressif.
|
||||
name: 'newlib'
|
||||
version: '4.3.0'
|
||||
cpe: cpe:2.3:a:newlib_project:newlib:{}:*:*:*:*:*:*:*
|
||||
supplier: 'Organization: Espressif Systems (Shanghai) CO LTD'
|
||||
originator: 'Organization: Red Hat Incorporated'
|
||||
description: An open-source C standard library implementation with additional features and patches from Espressif.
|
||||
|
||||
+81
-81
@@ -1,81 +1,81 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "scandir";
|
||||
|
||||
int alphasort(const struct dirent **lhs, const struct dirent **rhs)
|
||||
{
|
||||
return strcoll((*lhs)->d_name, (*rhs)->d_name);
|
||||
}
|
||||
|
||||
int scandir(const char *dirname, struct dirent ***out_dirlist,
|
||||
int (*select_func)(const struct dirent *),
|
||||
int (*cmp_func)(const struct dirent **, const struct dirent **))
|
||||
{
|
||||
DIR *dir_ptr = NULL;
|
||||
struct dirent *entry;
|
||||
size_t num_entries = 0;
|
||||
size_t array_size = 8; /* initial estimate */
|
||||
struct dirent **entries = NULL;
|
||||
int ret = -1;
|
||||
|
||||
entries = malloc(array_size * sizeof(struct dirent *));
|
||||
ESP_RETURN_ON_FALSE(entries, -1, TAG, "Malloc failed for entries");
|
||||
|
||||
dir_ptr = opendir(dirname);
|
||||
ESP_GOTO_ON_FALSE(dir_ptr, -1, out, TAG, "Failed to open directory: %s", dirname);
|
||||
|
||||
while ((entry = readdir(dir_ptr)) != NULL) {
|
||||
/* skip entries that don't match the filter function */
|
||||
if (select_func != NULL && !select_func(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dirent *entry_copy = malloc(sizeof(struct dirent));
|
||||
ESP_GOTO_ON_FALSE(entry_copy, -1, out, TAG, "Malloc failed for entry_copy");
|
||||
|
||||
*entry_copy = *entry;
|
||||
entries[num_entries++] = entry_copy;
|
||||
|
||||
/* grow the array size if it's full */
|
||||
if (num_entries >= array_size) {
|
||||
array_size *= 2;
|
||||
struct dirent **new_entries = realloc(entries, array_size * sizeof(struct dirent *));
|
||||
ESP_GOTO_ON_FALSE(new_entries, -1, out, TAG, "Realloc failed for entries");
|
||||
entries = new_entries;
|
||||
}
|
||||
}
|
||||
|
||||
/* sort the entries if a comparison function is provided */
|
||||
if (num_entries && cmp_func) {
|
||||
qsort(entries, num_entries, sizeof(struct dirent *),
|
||||
(int (*)(const void *, const void *))cmp_func);
|
||||
}
|
||||
|
||||
*out_dirlist = entries;
|
||||
ret = num_entries;
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
while (num_entries > 0) {
|
||||
free(entries[--num_entries]);
|
||||
}
|
||||
free(entries);
|
||||
}
|
||||
|
||||
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak") // Ignore intended return of allocated *out_dirlist
|
||||
if (dir_ptr) {
|
||||
closedir(dir_ptr);
|
||||
}
|
||||
return ret;
|
||||
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "scandir";
|
||||
|
||||
int alphasort(const struct dirent **lhs, const struct dirent **rhs)
|
||||
{
|
||||
return strcoll((*lhs)->d_name, (*rhs)->d_name);
|
||||
}
|
||||
|
||||
int scandir(const char *dirname, struct dirent ***out_dirlist,
|
||||
int (*select_func)(const struct dirent *),
|
||||
int (*cmp_func)(const struct dirent **, const struct dirent **))
|
||||
{
|
||||
DIR *dir_ptr = NULL;
|
||||
struct dirent *entry;
|
||||
size_t num_entries = 0;
|
||||
size_t array_size = 8; /* initial estimate */
|
||||
struct dirent **entries = NULL;
|
||||
int ret = -1;
|
||||
|
||||
entries = malloc(array_size * sizeof(struct dirent *));
|
||||
ESP_RETURN_ON_FALSE(entries, -1, TAG, "Malloc failed for entries");
|
||||
|
||||
dir_ptr = opendir(dirname);
|
||||
ESP_GOTO_ON_FALSE(dir_ptr, -1, out, TAG, "Failed to open directory: %s", dirname);
|
||||
|
||||
while ((entry = readdir(dir_ptr)) != NULL) {
|
||||
/* skip entries that don't match the filter function */
|
||||
if (select_func != NULL && !select_func(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dirent *entry_copy = malloc(sizeof(struct dirent));
|
||||
ESP_GOTO_ON_FALSE(entry_copy, -1, out, TAG, "Malloc failed for entry_copy");
|
||||
|
||||
*entry_copy = *entry;
|
||||
entries[num_entries++] = entry_copy;
|
||||
|
||||
/* grow the array size if it's full */
|
||||
if (num_entries >= array_size) {
|
||||
array_size *= 2;
|
||||
struct dirent **new_entries = realloc(entries, array_size * sizeof(struct dirent *));
|
||||
ESP_GOTO_ON_FALSE(new_entries, -1, out, TAG, "Realloc failed for entries");
|
||||
entries = new_entries;
|
||||
}
|
||||
}
|
||||
|
||||
/* sort the entries if a comparison function is provided */
|
||||
if (num_entries && cmp_func) {
|
||||
qsort(entries, num_entries, sizeof(struct dirent *),
|
||||
(int (*)(const void *, const void *))cmp_func);
|
||||
}
|
||||
|
||||
*out_dirlist = entries;
|
||||
ret = num_entries;
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
while (num_entries > 0) {
|
||||
free(entries[--num_entries]);
|
||||
}
|
||||
free(entries);
|
||||
}
|
||||
|
||||
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak") // Ignore intended return of allocated *out_dirlist
|
||||
if (dir_ptr) {
|
||||
closedir(dir_ptr);
|
||||
}
|
||||
return ret;
|
||||
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_HRT CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_HRT CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32C3_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S2_TIME_SYSCALL_USE_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_SYSTIMER CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT
|
||||
CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT
|
||||
|
||||
+111
-111
@@ -1,111 +1,111 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
//replacement for gcc built-in functions
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "esp_stdatomic.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if SOC_CPU_CORES_NUM > 1
|
||||
#if !CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
_Static_assert(HAS_ATOMICS_32, "32-bit atomics should be supported if SOC_CPU_CORES_NUM > 1");
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
// Only need to implement 64-bit atomics here. Use a single global portMUX_TYPE spinlock
|
||||
// to emulate the atomics.
|
||||
static portMUX_TYPE s_atomic_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#endif
|
||||
|
||||
#if !HAS_ATOMICS_32
|
||||
|
||||
_Static_assert(sizeof(unsigned char) == 1, "atomics require a 1-byte type");
|
||||
_Static_assert(sizeof(short unsigned int) == 2, "atomics require a 2-bytes type");
|
||||
_Static_assert(sizeof(unsigned int) == 4, "atomics require a 4-bytes type");
|
||||
|
||||
ATOMIC_FUNCTIONS(1, unsigned char)
|
||||
ATOMIC_FUNCTIONS(2, short unsigned int)
|
||||
ATOMIC_FUNCTIONS(4, unsigned int)
|
||||
|
||||
#elif __riscv_atomic == 1
|
||||
|
||||
bool CLANG_ATOMIC_SUFFIX(__atomic_always_lock_free)(unsigned int size, const volatile void *)
|
||||
{
|
||||
return size <= sizeof(int);
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_always_lock_free)
|
||||
|
||||
bool CLANG_ATOMIC_SUFFIX(__atomic_is_lock_free)(unsigned int size, const volatile void *)
|
||||
{
|
||||
return size <= sizeof(int);
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_is_lock_free)
|
||||
|
||||
#endif // !HAS_ATOMICS_32
|
||||
|
||||
#if !HAS_ATOMICS_64
|
||||
|
||||
#if CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
#undef _ATOMIC_HW_STUB_OP_FUNCTION
|
||||
#undef _ATOMIC_HW_STUB_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_STORE
|
||||
#undef _ATOMIC_HW_STUB_CMP_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_LOAD
|
||||
#undef _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET
|
||||
#undef _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE
|
||||
|
||||
#define _ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2)
|
||||
#define _ATOMIC_HW_STUB_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_STORE(n, type)
|
||||
#define _ATOMIC_HW_STUB_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_LOAD(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type)
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
_Static_assert(sizeof(long long unsigned int) == 8, "atomics require a 8-bytes type");
|
||||
|
||||
ATOMIC_FUNCTIONS(8, long long unsigned int)
|
||||
|
||||
#endif // !HAS_ATOMICS_64
|
||||
|
||||
// Clang generates calls to the __atomic_load/__atomic_store functions for object size more then 4 bytes
|
||||
void CLANG_ATOMIC_SUFFIX(__atomic_load)(size_t size, const volatile void *src, void *dest, int model)
|
||||
{
|
||||
_ATOMIC_ENTER_CRITICAL();
|
||||
memcpy(dest, (const void *)src, size);
|
||||
_ATOMIC_EXIT_CRITICAL();
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_load)
|
||||
|
||||
void CLANG_ATOMIC_SUFFIX(__atomic_store)(size_t size, volatile void *dest, void *src, int model)
|
||||
{
|
||||
_ATOMIC_ENTER_CRITICAL();
|
||||
memcpy((void *)dest, (const void *)src, size);
|
||||
_ATOMIC_EXIT_CRITICAL();
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_store)
|
||||
|
||||
bool CLANG_ATOMIC_SUFFIX(__atomic_compare_exchange)(size_t size, volatile void *ptr, void *expected, void *desired, int success_memorder, int failure_memorder)
|
||||
{
|
||||
bool ret = false;
|
||||
_ATOMIC_ENTER_CRITICAL();
|
||||
if (!memcmp((void *)ptr, expected, size)) {
|
||||
memcpy((void *)ptr, (const void *)desired, size);
|
||||
ret = true;
|
||||
} else {
|
||||
memcpy((void *)expected, (const void *)ptr, size);
|
||||
}
|
||||
_ATOMIC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_compare_exchange)
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
//replacement for gcc built-in functions
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "esp_stdatomic.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if SOC_CPU_CORES_NUM > 1
|
||||
#if !CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
_Static_assert(HAS_ATOMICS_32, "32-bit atomics should be supported if SOC_CPU_CORES_NUM > 1");
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
// Only need to implement 64-bit atomics here. Use a single global portMUX_TYPE spinlock
|
||||
// to emulate the atomics.
|
||||
static portMUX_TYPE s_atomic_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#endif
|
||||
|
||||
#if !HAS_ATOMICS_32
|
||||
|
||||
_Static_assert(sizeof(unsigned char) == 1, "atomics require a 1-byte type");
|
||||
_Static_assert(sizeof(short unsigned int) == 2, "atomics require a 2-bytes type");
|
||||
_Static_assert(sizeof(unsigned int) == 4, "atomics require a 4-bytes type");
|
||||
|
||||
ATOMIC_FUNCTIONS(1, unsigned char)
|
||||
ATOMIC_FUNCTIONS(2, short unsigned int)
|
||||
ATOMIC_FUNCTIONS(4, unsigned int)
|
||||
|
||||
#elif __riscv_atomic == 1
|
||||
|
||||
bool CLANG_ATOMIC_SUFFIX(__atomic_always_lock_free)(unsigned int size, const volatile void *)
|
||||
{
|
||||
return size <= sizeof(int);
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_always_lock_free)
|
||||
|
||||
bool CLANG_ATOMIC_SUFFIX(__atomic_is_lock_free)(unsigned int size, const volatile void *)
|
||||
{
|
||||
return size <= sizeof(int);
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_is_lock_free)
|
||||
|
||||
#endif // !HAS_ATOMICS_32
|
||||
|
||||
#if !HAS_ATOMICS_64
|
||||
|
||||
#if CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
#undef _ATOMIC_HW_STUB_OP_FUNCTION
|
||||
#undef _ATOMIC_HW_STUB_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_STORE
|
||||
#undef _ATOMIC_HW_STUB_CMP_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_LOAD
|
||||
#undef _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE
|
||||
#undef _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET
|
||||
#undef _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE
|
||||
|
||||
#define _ATOMIC_HW_STUB_OP_FUNCTION(n, type, name_1, name_2)
|
||||
#define _ATOMIC_HW_STUB_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_STORE(n, type)
|
||||
#define _ATOMIC_HW_STUB_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_LOAD(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_BOOL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_VAL_CMP_EXCHANGE(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_TEST_AND_SET(n, type)
|
||||
#define _ATOMIC_HW_STUB_SYNC_LOCK_RELEASE(n, type)
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
_Static_assert(sizeof(long long unsigned int) == 8, "atomics require a 8-bytes type");
|
||||
|
||||
ATOMIC_FUNCTIONS(8, long long unsigned int)
|
||||
|
||||
#endif // !HAS_ATOMICS_64
|
||||
|
||||
// Clang generates calls to the __atomic_load/__atomic_store functions for object size more then 4 bytes
|
||||
void CLANG_ATOMIC_SUFFIX(__atomic_load)(size_t size, const volatile void *src, void *dest, int model)
|
||||
{
|
||||
_ATOMIC_ENTER_CRITICAL();
|
||||
memcpy(dest, (const void *)src, size);
|
||||
_ATOMIC_EXIT_CRITICAL();
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_load)
|
||||
|
||||
void CLANG_ATOMIC_SUFFIX(__atomic_store)(size_t size, volatile void *dest, void *src, int model)
|
||||
{
|
||||
_ATOMIC_ENTER_CRITICAL();
|
||||
memcpy((void *)dest, (const void *)src, size);
|
||||
_ATOMIC_EXIT_CRITICAL();
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_store)
|
||||
|
||||
bool CLANG_ATOMIC_SUFFIX(__atomic_compare_exchange)(size_t size, volatile void *ptr, void *expected, void *desired, int success_memorder, int failure_memorder)
|
||||
{
|
||||
bool ret = false;
|
||||
_ATOMIC_ENTER_CRITICAL();
|
||||
if (!memcmp((void *)ptr, expected, size)) {
|
||||
memcpy((void *)ptr, (const void *)desired, size);
|
||||
ret = true;
|
||||
} else {
|
||||
memcpy((void *)expected, (const void *)ptr, size);
|
||||
}
|
||||
_ATOMIC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
CLANG_DECLARE_ALIAS(__atomic_compare_exchange)
|
||||
|
||||
+174
-174
@@ -1,174 +1,174 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <reent.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_uart.h"
|
||||
|
||||
static int syscall_not_implemented(struct _reent *r, ...)
|
||||
{
|
||||
__errno_r(r) = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int syscall_not_implemented_aborts(void)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
ssize_t _write_r_console(struct _reent *r, int fd, const void * data, size_t size)
|
||||
{
|
||||
#if !CONFIG_ESP_CONSOLE_NONE
|
||||
const char* cdata = (const char*) data;
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
esp_rom_output_tx_one_char(cdata[i]);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
#endif //!CONFIG_ESP_CONSOLE_NONE
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t _read_r_console(struct _reent *r, int fd, void * data, size_t size)
|
||||
{
|
||||
#if !CONFIG_ESP_CONSOLE_NONE
|
||||
char* cdata = (char*) data;
|
||||
if (fd == STDIN_FILENO) {
|
||||
size_t received;
|
||||
for (received = 0; received < size; ++received) {
|
||||
int status = esp_rom_output_rx_one_char((uint8_t*) &cdata[received]);
|
||||
if (status != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (received == 0) {
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
return received;
|
||||
}
|
||||
#endif //!CONFIG_ESP_CONSOLE_NONE
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t _fstat_r_console(struct _reent *r, int fd, struct stat * st)
|
||||
{
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
memset(st, 0, sizeof(*st));
|
||||
/* This needs to be set so that stdout and stderr are line buffered. */
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _fsync_console(int fd)
|
||||
{
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
esp_rom_output_flush_tx(CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM);
|
||||
return 0;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The following weak definitions of syscalls will be used unless
|
||||
* another definition is provided. That definition may come from
|
||||
* VFS, LWIP, or the application.
|
||||
*/
|
||||
ssize_t _read_r(struct _reent *r, int fd, void * dst, size_t size)
|
||||
__attribute__((weak, alias("_read_r_console")));
|
||||
ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size)
|
||||
__attribute__((weak, alias("_write_r_console")));
|
||||
int _fstat_r(struct _reent *r, int fd, struct stat *st)
|
||||
__attribute__((weak, alias("_fstat_r_console")));
|
||||
int fsync(int fd)
|
||||
__attribute__((weak, alias("_fsync_console")));
|
||||
|
||||
/* The aliases below are to "syscall_not_implemented", which
|
||||
* doesn't have the same signature as the original function.
|
||||
* Disable type mismatch warnings for this reason.
|
||||
*/
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wattribute-alias"
|
||||
#endif
|
||||
|
||||
int _open_r(struct _reent *r, const char * path, int flags, int mode)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _close_r(struct _reent *r, int fd)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
off_t _lseek_r(struct _reent *r, int fd, off_t size, int mode)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _fcntl_r(struct _reent *r, int fd, int cmd, int arg)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _stat_r(struct _reent *r, const char * path, struct stat * st)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _link_r(struct _reent *r, const char* n1, const char* n2)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _unlink_r(struct _reent *r, const char *path)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _rename_r(struct _reent *r, const char *src, const char *dst)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _isatty_r(struct _reent *r, int fd)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
|
||||
/* These functions are not expected to be overridden */
|
||||
int _system_r(struct _reent *r, const char *str)
|
||||
__attribute__((alias("syscall_not_implemented")));
|
||||
int raise(int sig)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
int _raise_r(struct _reent *r, int sig)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
void* _sbrk_r(struct _reent *r, ptrdiff_t sz)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
int _getpid_r(struct _reent *r)
|
||||
__attribute__((alias("syscall_not_implemented")));
|
||||
int _kill_r(struct _reent *r, int pid, int sig)
|
||||
__attribute__((alias("syscall_not_implemented")));
|
||||
void _exit(int __status)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/* Similar to syscall_not_implemented, but not taking struct _reent argument */
|
||||
int system(const char* str)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Replaces newlib fcntl, which has been compiled without HAVE_FCNTL */
|
||||
int fcntl(int fd, int cmd, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, cmd);
|
||||
int arg = va_arg(args, int);
|
||||
va_end(args);
|
||||
struct _reent* r = __getreent();
|
||||
return _fcntl_r(r, fd, cmd, arg);
|
||||
}
|
||||
|
||||
/* No-op function, used to force linking this file,
|
||||
instead of the syscalls implementation from libgloss.
|
||||
*/
|
||||
void newlib_include_syscalls_impl(void)
|
||||
{
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <reent.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_uart.h"
|
||||
|
||||
static int syscall_not_implemented(struct _reent *r, ...)
|
||||
{
|
||||
__errno_r(r) = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int syscall_not_implemented_aborts(void)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
ssize_t _write_r_console(struct _reent *r, int fd, const void * data, size_t size)
|
||||
{
|
||||
#if !CONFIG_ESP_CONSOLE_NONE
|
||||
const char* cdata = (const char*) data;
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
esp_rom_output_tx_one_char(cdata[i]);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
#endif //!CONFIG_ESP_CONSOLE_NONE
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t _read_r_console(struct _reent *r, int fd, void * data, size_t size)
|
||||
{
|
||||
#if !CONFIG_ESP_CONSOLE_NONE
|
||||
char* cdata = (char*) data;
|
||||
if (fd == STDIN_FILENO) {
|
||||
size_t received;
|
||||
for (received = 0; received < size; ++received) {
|
||||
int status = esp_rom_output_rx_one_char((uint8_t*) &cdata[received]);
|
||||
if (status != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (received == 0) {
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
return received;
|
||||
}
|
||||
#endif //!CONFIG_ESP_CONSOLE_NONE
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t _fstat_r_console(struct _reent *r, int fd, struct stat * st)
|
||||
{
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
memset(st, 0, sizeof(*st));
|
||||
/* This needs to be set so that stdout and stderr are line buffered. */
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _fsync_console(int fd)
|
||||
{
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
esp_rom_output_flush_tx(CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM);
|
||||
return 0;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The following weak definitions of syscalls will be used unless
|
||||
* another definition is provided. That definition may come from
|
||||
* VFS, LWIP, or the application.
|
||||
*/
|
||||
ssize_t _read_r(struct _reent *r, int fd, void * dst, size_t size)
|
||||
__attribute__((weak, alias("_read_r_console")));
|
||||
ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size)
|
||||
__attribute__((weak, alias("_write_r_console")));
|
||||
int _fstat_r(struct _reent *r, int fd, struct stat *st)
|
||||
__attribute__((weak, alias("_fstat_r_console")));
|
||||
int fsync(int fd)
|
||||
__attribute__((weak, alias("_fsync_console")));
|
||||
|
||||
/* The aliases below are to "syscall_not_implemented", which
|
||||
* doesn't have the same signature as the original function.
|
||||
* Disable type mismatch warnings for this reason.
|
||||
*/
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wattribute-alias"
|
||||
#endif
|
||||
|
||||
int _open_r(struct _reent *r, const char * path, int flags, int mode)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _close_r(struct _reent *r, int fd)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
off_t _lseek_r(struct _reent *r, int fd, off_t size, int mode)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _fcntl_r(struct _reent *r, int fd, int cmd, int arg)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _stat_r(struct _reent *r, const char * path, struct stat * st)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _link_r(struct _reent *r, const char* n1, const char* n2)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _unlink_r(struct _reent *r, const char *path)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _rename_r(struct _reent *r, const char *src, const char *dst)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
int _isatty_r(struct _reent *r, int fd)
|
||||
__attribute__((weak, alias("syscall_not_implemented")));
|
||||
|
||||
/* These functions are not expected to be overridden */
|
||||
int _system_r(struct _reent *r, const char *str)
|
||||
__attribute__((alias("syscall_not_implemented")));
|
||||
int raise(int sig)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
int _raise_r(struct _reent *r, int sig)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
void* _sbrk_r(struct _reent *r, ptrdiff_t sz)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
int _getpid_r(struct _reent *r)
|
||||
__attribute__((alias("syscall_not_implemented")));
|
||||
int _kill_r(struct _reent *r, int pid, int sig)
|
||||
__attribute__((alias("syscall_not_implemented")));
|
||||
void _exit(int __status)
|
||||
__attribute__((alias("syscall_not_implemented_aborts")));
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/* Similar to syscall_not_implemented, but not taking struct _reent argument */
|
||||
int system(const char* str)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Replaces newlib fcntl, which has been compiled without HAVE_FCNTL */
|
||||
int fcntl(int fd, int cmd, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, cmd);
|
||||
int arg = va_arg(args, int);
|
||||
va_end(args);
|
||||
struct _reent* r = __getreent();
|
||||
return _fcntl_r(r, fd, cmd, arg);
|
||||
}
|
||||
|
||||
/* No-op function, used to force linking this file,
|
||||
instead of the syscalls implementation from libgloss.
|
||||
*/
|
||||
void newlib_include_syscalls_impl(void)
|
||||
{
|
||||
}
|
||||
|
||||
+27
-27
@@ -1,27 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_FREERTOS_UNICORE
|
||||
#define CPU_NUM 1
|
||||
#else
|
||||
#define CPU_NUM CONFIG_SOC_CPU_CORES_NUM
|
||||
#endif
|
||||
|
||||
long sysconf(int arg)
|
||||
{
|
||||
switch (arg) {
|
||||
case _SC_NPROCESSORS_CONF:
|
||||
case _SC_NPROCESSORS_ONLN:
|
||||
return CPU_NUM;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_FREERTOS_UNICORE
|
||||
#define CPU_NUM 1
|
||||
#else
|
||||
#define CPU_NUM CONFIG_SOC_CPU_CORES_NUM
|
||||
#endif
|
||||
|
||||
long sysconf(int arg)
|
||||
{
|
||||
switch (arg) {
|
||||
case _SC_NPROCESSORS_CONF:
|
||||
case _SC_NPROCESSORS_ONLN:
|
||||
return CPU_NUM;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-22
@@ -1,22 +1,22 @@
|
||||
[mapping:gcc]
|
||||
archive: libgcc.a
|
||||
entries:
|
||||
lib2funcs (noflash_text)
|
||||
if IDF_TARGET_ESP32 = n:
|
||||
_divsf3 (noflash)
|
||||
if IDF_TARGET_ARCH_RISCV:
|
||||
save-restore (noflash)
|
||||
|
||||
[mapping:clang_rt_builtins]
|
||||
archive: libclang_rt.builtins.a
|
||||
entries:
|
||||
if IDF_TARGET_ESP32 = n:
|
||||
_divsf3 (noflash)
|
||||
if IDF_TARGET_ARCH_RISCV:
|
||||
save (noflash)
|
||||
restore (noflash)
|
||||
|
||||
[mapping:gcov]
|
||||
archive: libgcov.a
|
||||
entries:
|
||||
* (noflash)
|
||||
[mapping:gcc]
|
||||
archive: libgcc.a
|
||||
entries:
|
||||
lib2funcs (noflash_text)
|
||||
if IDF_TARGET_ESP32 = n:
|
||||
_divsf3 (noflash)
|
||||
if IDF_TARGET_ARCH_RISCV:
|
||||
save-restore (noflash)
|
||||
|
||||
[mapping:clang_rt_builtins]
|
||||
archive: libclang_rt.builtins.a
|
||||
entries:
|
||||
if IDF_TARGET_ESP32 = n:
|
||||
_divsf3 (noflash)
|
||||
if IDF_TARGET_ARCH_RISCV:
|
||||
save (noflash)
|
||||
restore (noflash)
|
||||
|
||||
[mapping:gcov]
|
||||
archive: libgcov.a
|
||||
entries:
|
||||
* (noflash)
|
||||
|
||||
+46
-46
@@ -1,46 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
#include <sys/termios.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
speed_t cfgetispeed(const struct termios *p)
|
||||
{
|
||||
return p ? p->c_ispeed : B0;
|
||||
}
|
||||
|
||||
speed_t cfgetospeed(const struct termios *p)
|
||||
{
|
||||
return p ? p->c_ospeed : B0;
|
||||
}
|
||||
|
||||
int cfsetispeed(struct termios *p, speed_t sp)
|
||||
{
|
||||
if (p) {
|
||||
p->c_ispeed = sp;
|
||||
return 0;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int cfsetospeed(struct termios *p, speed_t sp)
|
||||
{
|
||||
if (p) {
|
||||
p->c_ospeed = sp;
|
||||
return 0;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_TERMIOS
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
#include <sys/termios.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
speed_t cfgetispeed(const struct termios *p)
|
||||
{
|
||||
return p ? p->c_ispeed : B0;
|
||||
}
|
||||
|
||||
speed_t cfgetospeed(const struct termios *p)
|
||||
{
|
||||
return p ? p->c_ospeed : B0;
|
||||
}
|
||||
|
||||
int cfsetispeed(struct termios *p, speed_t sp)
|
||||
{
|
||||
if (p) {
|
||||
p->c_ispeed = sp;
|
||||
return 0;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int cfsetospeed(struct termios *p, speed_t sp)
|
||||
{
|
||||
if (p) {
|
||||
p->c_ospeed = sp;
|
||||
return 0;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/newlib/test_apps/newlib:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32c61"]
|
||||
temporary: true
|
||||
reason: not supported yet # TODO: [esp32c61] IDF-9284
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/newlib/test_apps/newlib:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32c61"]
|
||||
temporary: true
|
||||
reason: not supported yet # TODO: [esp32c61] IDF-9284
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(newlib_test)
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(newlib_test)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
idf_component_register(SRCS
|
||||
"test_app_main.c"
|
||||
"test_atomic.c"
|
||||
"test_file.c"
|
||||
"test_locks.c"
|
||||
"test_misc.c"
|
||||
"test_newlib.c"
|
||||
"test_printf.c"
|
||||
"test_setjmp.c"
|
||||
"test_stdatomic.c"
|
||||
"test_time.c"
|
||||
PRIV_REQUIRES unity vfs cmock esp_timer spi_flash test_utils pthread esp_psram
|
||||
WHOLE_ARCHIVE)
|
||||
idf_component_register(SRCS
|
||||
"test_app_main.c"
|
||||
"test_atomic.c"
|
||||
"test_file.c"
|
||||
"test_locks.c"
|
||||
"test_misc.c"
|
||||
"test_newlib.c"
|
||||
"test_printf.c"
|
||||
"test_setjmp.c"
|
||||
"test_stdatomic.c"
|
||||
"test_time.c"
|
||||
PRIV_REQUIRES unity vfs cmock esp_timer spi_flash test_utils pthread esp_psram
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-350)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
// Add a short delay of 10ms to allow the idle task to free an remaining memory
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// Raise priority to main task as some tests depend on the test task being at priority UNITY_FREERTOS_PRIORITY
|
||||
vTaskPrioritySet(NULL, UNITY_FREERTOS_PRIORITY);
|
||||
unity_run_menu();
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-350)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
// Add a short delay of 10ms to allow the idle task to free an remaining memory
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// Raise priority to main task as some tests depend on the test task being at priority UNITY_FREERTOS_PRIORITY
|
||||
vTaskPrioritySet(NULL, UNITY_FREERTOS_PRIORITY);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
@@ -1,140 +1,140 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include <stdatomic.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
|
||||
#define RECORD_TIME_PREPARE() uint32_t __t1, __t2
|
||||
#define RECORD_TIME_START() do {__t1 = esp_cpu_get_cycle_count();}while(0)
|
||||
#define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_cycle_count(); *p_time = (__t2-__t1);}while(0)
|
||||
|
||||
#define TEST_TIMES 11
|
||||
|
||||
//Test twice, and only get the result of second time, to avoid influence of cache miss
|
||||
#define TEST_WRAP_START() \
|
||||
RECORD_TIME_PREPARE(); \
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu(); \
|
||||
for (int i = 0; i < 2; i++) { \
|
||||
RECORD_TIME_START();
|
||||
|
||||
#define TEST_WRAP_END(output) \
|
||||
RECORD_TIME_END(output); \
|
||||
} \
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
typedef void (*test_f)(uint32_t* t_op);
|
||||
|
||||
static const char TAG[] = "test_atomic";
|
||||
static uint32_t s_t_ref;
|
||||
|
||||
static void sorted_array_insert(uint32_t* array, int* size, uint32_t item)
|
||||
{
|
||||
int pos;
|
||||
for (pos = *size; pos > 0; pos--) {
|
||||
if (array[pos - 1] < item) {
|
||||
break;
|
||||
}
|
||||
array[pos] = array[pos - 1];
|
||||
}
|
||||
array[pos] = item;
|
||||
(*size)++;
|
||||
}
|
||||
|
||||
static void test_flow(const char* name, test_f func)
|
||||
{
|
||||
int t_flight_num = 0;
|
||||
uint32_t t_flight_sorted[TEST_TIMES];
|
||||
|
||||
for (int i = 0; i < TEST_TIMES; i++) {
|
||||
uint32_t t_op;
|
||||
func(&t_op);
|
||||
sorted_array_insert(t_flight_sorted, &t_flight_num, t_op);
|
||||
}
|
||||
for (int i = 0; i < TEST_TIMES; i++) {
|
||||
ESP_LOGI(TAG, "%s: %" PRIu32 " ops", name, t_flight_sorted[i] - s_t_ref);
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_ref(uint32_t* t_op)
|
||||
{
|
||||
TEST_WRAP_START()
|
||||
TEST_WRAP_END(t_op)
|
||||
s_t_ref = *t_op;
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_load(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t target = rand();
|
||||
TEST_WRAP_START()
|
||||
target = atomic_load(&var);
|
||||
TEST_WRAP_END(t_op)
|
||||
(void) target;
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_store(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
atomic_store(&var, src);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_store_load(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
atomic_store(&var, src);
|
||||
src = atomic_load(&var);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_fetch_and(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
src = atomic_fetch_and(&var, src);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_fetch_or(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
src = atomic_fetch_or(&var, src);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_compare_exchange(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
uint32_t cmp = rand();
|
||||
bool res;
|
||||
TEST_WRAP_START()
|
||||
res = atomic_compare_exchange_weak(&var, &src, cmp);
|
||||
TEST_WRAP_END(t_op)
|
||||
(void) res;
|
||||
}
|
||||
|
||||
TEST_CASE("test atomic", "[atomic]")
|
||||
{
|
||||
test_flow("ref", test_ref);
|
||||
|
||||
test_flow("atomic_load", test_atomic_load);
|
||||
test_flow("atomic_store", test_atomic_store);
|
||||
test_flow("atomic_compare_exchange", test_atomic_compare_exchange);
|
||||
test_flow("atomic_store + atomic_load", test_atomic_store_load);
|
||||
test_flow("atomic_and", test_atomic_fetch_and);
|
||||
test_flow("atomic_or", test_atomic_fetch_or);
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include <stdatomic.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
|
||||
#define RECORD_TIME_PREPARE() uint32_t __t1, __t2
|
||||
#define RECORD_TIME_START() do {__t1 = esp_cpu_get_cycle_count();}while(0)
|
||||
#define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_cycle_count(); *p_time = (__t2-__t1);}while(0)
|
||||
|
||||
#define TEST_TIMES 11
|
||||
|
||||
//Test twice, and only get the result of second time, to avoid influence of cache miss
|
||||
#define TEST_WRAP_START() \
|
||||
RECORD_TIME_PREPARE(); \
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu(); \
|
||||
for (int i = 0; i < 2; i++) { \
|
||||
RECORD_TIME_START();
|
||||
|
||||
#define TEST_WRAP_END(output) \
|
||||
RECORD_TIME_END(output); \
|
||||
} \
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
typedef void (*test_f)(uint32_t* t_op);
|
||||
|
||||
static const char TAG[] = "test_atomic";
|
||||
static uint32_t s_t_ref;
|
||||
|
||||
static void sorted_array_insert(uint32_t* array, int* size, uint32_t item)
|
||||
{
|
||||
int pos;
|
||||
for (pos = *size; pos > 0; pos--) {
|
||||
if (array[pos - 1] < item) {
|
||||
break;
|
||||
}
|
||||
array[pos] = array[pos - 1];
|
||||
}
|
||||
array[pos] = item;
|
||||
(*size)++;
|
||||
}
|
||||
|
||||
static void test_flow(const char* name, test_f func)
|
||||
{
|
||||
int t_flight_num = 0;
|
||||
uint32_t t_flight_sorted[TEST_TIMES];
|
||||
|
||||
for (int i = 0; i < TEST_TIMES; i++) {
|
||||
uint32_t t_op;
|
||||
func(&t_op);
|
||||
sorted_array_insert(t_flight_sorted, &t_flight_num, t_op);
|
||||
}
|
||||
for (int i = 0; i < TEST_TIMES; i++) {
|
||||
ESP_LOGI(TAG, "%s: %" PRIu32 " ops", name, t_flight_sorted[i] - s_t_ref);
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_ref(uint32_t* t_op)
|
||||
{
|
||||
TEST_WRAP_START()
|
||||
TEST_WRAP_END(t_op)
|
||||
s_t_ref = *t_op;
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_load(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t target = rand();
|
||||
TEST_WRAP_START()
|
||||
target = atomic_load(&var);
|
||||
TEST_WRAP_END(t_op)
|
||||
(void) target;
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_store(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
atomic_store(&var, src);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_store_load(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
atomic_store(&var, src);
|
||||
src = atomic_load(&var);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_fetch_and(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
src = atomic_fetch_and(&var, src);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_fetch_or(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
TEST_WRAP_START()
|
||||
src = atomic_fetch_or(&var, src);
|
||||
TEST_WRAP_END(t_op)
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_atomic_compare_exchange(uint32_t* t_op)
|
||||
{
|
||||
atomic_uint_fast32_t var;
|
||||
uint32_t src = rand();
|
||||
uint32_t cmp = rand();
|
||||
bool res;
|
||||
TEST_WRAP_START()
|
||||
res = atomic_compare_exchange_weak(&var, &src, cmp);
|
||||
TEST_WRAP_END(t_op)
|
||||
(void) res;
|
||||
}
|
||||
|
||||
TEST_CASE("test atomic", "[atomic]")
|
||||
{
|
||||
test_flow("ref", test_ref);
|
||||
|
||||
test_flow("atomic_load", test_atomic_load);
|
||||
test_flow("atomic_store", test_atomic_store);
|
||||
test_flow("atomic_compare_exchange", test_atomic_compare_exchange);
|
||||
test_flow("atomic_store + atomic_load", test_atomic_store_load);
|
||||
test_flow("atomic_and", test_atomic_fetch_and);
|
||||
test_flow("atomic_or", test_atomic_fetch_or);
|
||||
}
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "esp_vfs.h"
|
||||
#include "unity.h"
|
||||
|
||||
/* This test checks that st_blksize value set in struct stat correctly affects the
|
||||
* FILE structure:
|
||||
* - _blksize field should be equal to st_blksize
|
||||
* - buffer size should be equal to st_blksize if it is nonzero, and __BUFSIZ__ otherwise.
|
||||
* This is more of an integration test since some of the functions responsible for this are
|
||||
* in ROM, and have been built without HAVE_BLKSIZE feature for the ESP32 chip.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned blksize;
|
||||
} blksize_test_ctx_t;
|
||||
|
||||
static int blksize_test_open(void* ctx, const char * path, int flags, int mode)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int blksize_test_fstat(void* ctx, int fd, struct stat * st)
|
||||
{
|
||||
blksize_test_ctx_t* test_ctx = (blksize_test_ctx_t*) ctx;
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = S_IFREG;
|
||||
st->st_blksize = test_ctx->blksize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t blksize_test_write(void* ctx, int fd, const void * data, size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
TEST_CASE("file - blksize", "[newlib_file]")
|
||||
{
|
||||
FILE* f;
|
||||
blksize_test_ctx_t ctx = {};
|
||||
const char c = 42;
|
||||
const esp_vfs_t desc = {
|
||||
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
|
||||
.open_p = blksize_test_open,
|
||||
.fstat_p = blksize_test_fstat,
|
||||
.write_p = blksize_test_write,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_vfs_register("/test", &desc, &ctx));
|
||||
|
||||
/* test with zero st_blksize (=not set) */
|
||||
ctx.blksize = 0;
|
||||
f = fopen("/test/path", "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
fwrite(&c, 1, 1, f);
|
||||
TEST_ASSERT_EQUAL(0, f->_blksize);
|
||||
TEST_ASSERT_EQUAL(__BUFSIZ__, __fbufsize(f));
|
||||
fclose(f);
|
||||
|
||||
/* test with non-zero st_blksize */
|
||||
ctx.blksize = 4096;
|
||||
f = fopen("/test/path", "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
fwrite(&c, 1, 1, f);
|
||||
TEST_ASSERT_EQUAL(ctx.blksize, f->_blksize);
|
||||
TEST_ASSERT_EQUAL(ctx.blksize, __fbufsize(f));
|
||||
fclose(f);
|
||||
|
||||
TEST_ESP_OK(esp_vfs_unregister("/test"));
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "esp_vfs.h"
|
||||
#include "unity.h"
|
||||
|
||||
/* This test checks that st_blksize value set in struct stat correctly affects the
|
||||
* FILE structure:
|
||||
* - _blksize field should be equal to st_blksize
|
||||
* - buffer size should be equal to st_blksize if it is nonzero, and __BUFSIZ__ otherwise.
|
||||
* This is more of an integration test since some of the functions responsible for this are
|
||||
* in ROM, and have been built without HAVE_BLKSIZE feature for the ESP32 chip.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned blksize;
|
||||
} blksize_test_ctx_t;
|
||||
|
||||
static int blksize_test_open(void* ctx, const char * path, int flags, int mode)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int blksize_test_fstat(void* ctx, int fd, struct stat * st)
|
||||
{
|
||||
blksize_test_ctx_t* test_ctx = (blksize_test_ctx_t*) ctx;
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = S_IFREG;
|
||||
st->st_blksize = test_ctx->blksize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t blksize_test_write(void* ctx, int fd, const void * data, size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
TEST_CASE("file - blksize", "[newlib_file]")
|
||||
{
|
||||
FILE* f;
|
||||
blksize_test_ctx_t ctx = {};
|
||||
const char c = 42;
|
||||
const esp_vfs_t desc = {
|
||||
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
|
||||
.open_p = blksize_test_open,
|
||||
.fstat_p = blksize_test_fstat,
|
||||
.write_p = blksize_test_write,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_vfs_register("/test", &desc, &ctx));
|
||||
|
||||
/* test with zero st_blksize (=not set) */
|
||||
ctx.blksize = 0;
|
||||
f = fopen("/test/path", "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
fwrite(&c, 1, 1, f);
|
||||
TEST_ASSERT_EQUAL(0, f->_blksize);
|
||||
TEST_ASSERT_EQUAL(__BUFSIZ__, __fbufsize(f));
|
||||
fclose(f);
|
||||
|
||||
/* test with non-zero st_blksize */
|
||||
ctx.blksize = 4096;
|
||||
f = fopen("/test/path", "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
fwrite(&c, 1, 1, f);
|
||||
TEST_ASSERT_EQUAL(ctx.blksize, f->_blksize);
|
||||
TEST_ASSERT_EQUAL(ctx.blksize, __fbufsize(f));
|
||||
fclose(f);
|
||||
|
||||
TEST_ESP_OK(esp_vfs_unregister("/test"));
|
||||
}
|
||||
|
||||
@@ -1,114 +1,114 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/lock.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#if defined(_RETARGETABLE_LOCKING)
|
||||
|
||||
static void locking_task(void* arg)
|
||||
{
|
||||
_LOCK_T lock = (_LOCK_T) arg;
|
||||
__lock_acquire(lock);
|
||||
__lock_release(lock);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
static void recursive_locking_task(void* arg)
|
||||
{
|
||||
_LOCK_T lock = (_LOCK_T) arg;
|
||||
__lock_acquire_recursive(lock);
|
||||
__lock_release_recursive(lock);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
static void test_inner_normal(_LOCK_T lock)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
__lock_acquire(lock);
|
||||
|
||||
/* Create another task to try acquire same lock */
|
||||
TaskHandle_t task_hdl;
|
||||
TEST_ASSERT(xTaskCreate(&locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
|
||||
vTaskDelay(2);
|
||||
/* It should get blocked */
|
||||
TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
|
||||
|
||||
/* Once we release the lock, the task should succeed and suspend itself */
|
||||
__lock_release(lock);
|
||||
vTaskDelay(2);
|
||||
TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
|
||||
vTaskDelete(task_hdl);
|
||||
|
||||
/* Can not recursively acquire the lock from same task */
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire(lock));
|
||||
TEST_ASSERT_EQUAL(-1, __lock_try_acquire(lock));
|
||||
__lock_release(lock);
|
||||
}
|
||||
|
||||
static void test_inner_recursive(_LOCK_T lock)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
__lock_acquire_recursive(lock);
|
||||
|
||||
/* Create another task to try acquire same lock */
|
||||
TaskHandle_t task_hdl;
|
||||
TEST_ASSERT(xTaskCreate(&recursive_locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
|
||||
vTaskDelay(2);
|
||||
/* It should get blocked */
|
||||
TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
|
||||
|
||||
/* Once we release the lock, the task should succeed and suspend itself */
|
||||
__lock_release_recursive(lock);
|
||||
vTaskDelay(2);
|
||||
TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
|
||||
vTaskDelete(task_hdl);
|
||||
|
||||
/* Try recursively acquiring the lock */
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
|
||||
__lock_release_recursive(lock);
|
||||
__lock_release_recursive(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable static locks", "[newlib_locks]")
|
||||
{
|
||||
StaticSemaphore_t semaphore;
|
||||
_LOCK_T lock = (_LOCK_T) xSemaphoreCreateMutexStatic(&semaphore);
|
||||
test_inner_normal(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable static recursive locks", "[newlib_locks]")
|
||||
{
|
||||
StaticSemaphore_t semaphore;
|
||||
_LOCK_T lock = (_LOCK_T) xSemaphoreCreateRecursiveMutexStatic(&semaphore);
|
||||
test_inner_recursive(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable dynamic locks", "[newlib_locks]")
|
||||
{
|
||||
_LOCK_T lock;
|
||||
__lock_init(lock);
|
||||
test_inner_normal(lock);
|
||||
__lock_close(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable dynamic recursive locks", "[newlib_locks]")
|
||||
{
|
||||
_LOCK_T lock;
|
||||
__lock_init_recursive(lock);
|
||||
test_inner_recursive(lock);
|
||||
__lock_close_recursive(lock);
|
||||
}
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/lock.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#if defined(_RETARGETABLE_LOCKING)
|
||||
|
||||
static void locking_task(void* arg)
|
||||
{
|
||||
_LOCK_T lock = (_LOCK_T) arg;
|
||||
__lock_acquire(lock);
|
||||
__lock_release(lock);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
static void recursive_locking_task(void* arg)
|
||||
{
|
||||
_LOCK_T lock = (_LOCK_T) arg;
|
||||
__lock_acquire_recursive(lock);
|
||||
__lock_release_recursive(lock);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
static void test_inner_normal(_LOCK_T lock)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
__lock_acquire(lock);
|
||||
|
||||
/* Create another task to try acquire same lock */
|
||||
TaskHandle_t task_hdl;
|
||||
TEST_ASSERT(xTaskCreate(&locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
|
||||
vTaskDelay(2);
|
||||
/* It should get blocked */
|
||||
TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
|
||||
|
||||
/* Once we release the lock, the task should succeed and suspend itself */
|
||||
__lock_release(lock);
|
||||
vTaskDelay(2);
|
||||
TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
|
||||
vTaskDelete(task_hdl);
|
||||
|
||||
/* Can not recursively acquire the lock from same task */
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire(lock));
|
||||
TEST_ASSERT_EQUAL(-1, __lock_try_acquire(lock));
|
||||
__lock_release(lock);
|
||||
}
|
||||
|
||||
static void test_inner_recursive(_LOCK_T lock)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
__lock_acquire_recursive(lock);
|
||||
|
||||
/* Create another task to try acquire same lock */
|
||||
TaskHandle_t task_hdl;
|
||||
TEST_ASSERT(xTaskCreate(&recursive_locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
|
||||
vTaskDelay(2);
|
||||
/* It should get blocked */
|
||||
TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
|
||||
|
||||
/* Once we release the lock, the task should succeed and suspend itself */
|
||||
__lock_release_recursive(lock);
|
||||
vTaskDelay(2);
|
||||
TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
|
||||
vTaskDelete(task_hdl);
|
||||
|
||||
/* Try recursively acquiring the lock */
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
|
||||
__lock_release_recursive(lock);
|
||||
__lock_release_recursive(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable static locks", "[newlib_locks]")
|
||||
{
|
||||
StaticSemaphore_t semaphore;
|
||||
_LOCK_T lock = (_LOCK_T) xSemaphoreCreateMutexStatic(&semaphore);
|
||||
test_inner_normal(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable static recursive locks", "[newlib_locks]")
|
||||
{
|
||||
StaticSemaphore_t semaphore;
|
||||
_LOCK_T lock = (_LOCK_T) xSemaphoreCreateRecursiveMutexStatic(&semaphore);
|
||||
test_inner_recursive(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable dynamic locks", "[newlib_locks]")
|
||||
{
|
||||
_LOCK_T lock;
|
||||
__lock_init(lock);
|
||||
test_inner_normal(lock);
|
||||
__lock_close(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable dynamic recursive locks", "[newlib_locks]")
|
||||
{
|
||||
_LOCK_T lock;
|
||||
__lock_init_recursive(lock);
|
||||
test_inner_recursive(lock);
|
||||
__lock_close_recursive(lock);
|
||||
}
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
||||
|
||||
@@ -1,185 +1,185 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __clang__ // TODO LLVM-330
|
||||
#include <sys/dirent.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#include "unity.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_vfs.h"
|
||||
|
||||
TEST_CASE("misc - posix_memalign", "[newlib_misc]")
|
||||
{
|
||||
void* outptr = NULL;
|
||||
int ret;
|
||||
|
||||
ret = posix_memalign(&outptr, 4, 0);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
|
||||
void* magic = (void*) 0xEFEFEFEF;
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 0x10000000, 64); // too big alignment - should fail on all targets
|
||||
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
|
||||
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
|
||||
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 16, 0x10000000); // too big size - should fail on all targets
|
||||
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
|
||||
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
|
||||
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 16, 64);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
|
||||
outptr = magic;
|
||||
heap_caps_malloc_extmem_enable(128);
|
||||
ret = posix_memalign(&outptr, 16, 64);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
|
||||
outptr = magic;
|
||||
heap_caps_malloc_extmem_enable(64);
|
||||
ret = posix_memalign(&outptr, 16, 128);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("misc - sysconf", "[newlib_misc]")
|
||||
{
|
||||
TEST_ASSERT_NOT_EQUAL(-1, sysconf(_SC_NPROCESSORS_ONLN));
|
||||
}
|
||||
|
||||
TEST_CASE("misc - realpath", "[newlib_misc]")
|
||||
{
|
||||
char out[PATH_MAX];
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("//", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath(".", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("./", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/.", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("./.", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("../..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/a", realpath("/a/", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/../..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/c", realpath("/a/../b/../c", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/abc/def", realpath("/abc/./def/ghi/..", out));
|
||||
char* out_new = realpath("/abc/./def/ghi/..", NULL);
|
||||
TEST_ASSERT_NOT_NULL(out_new);
|
||||
TEST_ASSERT_EQUAL_STRING("/abc/def", out_new);
|
||||
free(out_new);
|
||||
}
|
||||
|
||||
static int s_select_calls = 0;
|
||||
|
||||
typedef struct {
|
||||
const char **filenames;
|
||||
size_t num_files;
|
||||
size_t current_index;
|
||||
} scandir_test_dir_context_t;
|
||||
|
||||
static DIR *scandir_test_opendir(void* ctx, const char* name)
|
||||
{
|
||||
scandir_test_dir_context_t *dir_ctx = (scandir_test_dir_context_t *)ctx;
|
||||
dir_ctx->current_index = 0;
|
||||
static DIR dir = {};
|
||||
return &dir;
|
||||
}
|
||||
|
||||
static struct dirent *scandir_test_readdir(void* ctx, DIR* pdir)
|
||||
{
|
||||
scandir_test_dir_context_t *dir_ctx = (scandir_test_dir_context_t *)ctx;
|
||||
if (dir_ctx->current_index >= dir_ctx->num_files) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dirent entry;
|
||||
snprintf(entry.d_name, sizeof(entry.d_name), "%s", dir_ctx->filenames[dir_ctx->current_index]);
|
||||
dir_ctx->current_index++;
|
||||
return &entry;
|
||||
}
|
||||
|
||||
static int scandir_test_closedir(void* ctx, DIR* pdir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scandir_test_select(const struct dirent *entry)
|
||||
{
|
||||
s_select_calls++;
|
||||
return strstr(entry->d_name, "test") != NULL;
|
||||
}
|
||||
|
||||
TEST_CASE("file - scandir", "[newlib_misc]")
|
||||
{
|
||||
const char *test_filenames[] = {
|
||||
".",
|
||||
"..",
|
||||
"test_file1.txt",
|
||||
"file2.txt",
|
||||
"test_file3.txt",
|
||||
"test_file4.txt",
|
||||
"test_file5.txt",
|
||||
"test_file6.txt",
|
||||
"test_file7.txt",
|
||||
"test_file8.txt",
|
||||
"test_file9.txt",
|
||||
"test_file10.txt",
|
||||
};
|
||||
size_t num_test_files = sizeof(test_filenames) / sizeof(test_filenames[0]);
|
||||
|
||||
scandir_test_dir_context_t scandir_test_dir_ctx = { .filenames = test_filenames, .num_files = num_test_files };
|
||||
|
||||
const esp_vfs_t scandir_test_vfs = {
|
||||
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
|
||||
.opendir_p = scandir_test_opendir,
|
||||
.readdir_p = scandir_test_readdir,
|
||||
.closedir_p = scandir_test_closedir
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_vfs_register("/data", &scandir_test_vfs, &scandir_test_dir_ctx));
|
||||
|
||||
struct dirent **namelist;
|
||||
s_select_calls = 0;
|
||||
int n = scandir("/data", &namelist, scandir_test_select, alphasort);
|
||||
TEST_ASSERT_NOT_NULL(namelist);
|
||||
TEST_ASSERT_GREATER_THAN(0, n);
|
||||
|
||||
TEST_ASSERT_EQUAL(num_test_files, s_select_calls);
|
||||
TEST_ASSERT_EQUAL(9, n);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
TEST_ASSERT_NOT_NULL(strstr(namelist[i]->d_name, "test"));
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
|
||||
esp_vfs_unregister("/data");
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __clang__ // TODO LLVM-330
|
||||
#include <sys/dirent.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#include "unity.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_vfs.h"
|
||||
|
||||
TEST_CASE("misc - posix_memalign", "[newlib_misc]")
|
||||
{
|
||||
void* outptr = NULL;
|
||||
int ret;
|
||||
|
||||
ret = posix_memalign(&outptr, 4, 0);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
|
||||
void* magic = (void*) 0xEFEFEFEF;
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 0x10000000, 64); // too big alignment - should fail on all targets
|
||||
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
|
||||
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
|
||||
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 16, 0x10000000); // too big size - should fail on all targets
|
||||
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
|
||||
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
|
||||
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 16, 64);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
|
||||
outptr = magic;
|
||||
heap_caps_malloc_extmem_enable(128);
|
||||
ret = posix_memalign(&outptr, 16, 64);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
|
||||
outptr = magic;
|
||||
heap_caps_malloc_extmem_enable(64);
|
||||
ret = posix_memalign(&outptr, 16, 128);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("misc - sysconf", "[newlib_misc]")
|
||||
{
|
||||
TEST_ASSERT_NOT_EQUAL(-1, sysconf(_SC_NPROCESSORS_ONLN));
|
||||
}
|
||||
|
||||
TEST_CASE("misc - realpath", "[newlib_misc]")
|
||||
{
|
||||
char out[PATH_MAX];
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("//", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath(".", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("./", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/.", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("./.", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("../..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/a", realpath("/a/", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/../..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/c", realpath("/a/../b/../c", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/abc/def", realpath("/abc/./def/ghi/..", out));
|
||||
char* out_new = realpath("/abc/./def/ghi/..", NULL);
|
||||
TEST_ASSERT_NOT_NULL(out_new);
|
||||
TEST_ASSERT_EQUAL_STRING("/abc/def", out_new);
|
||||
free(out_new);
|
||||
}
|
||||
|
||||
static int s_select_calls = 0;
|
||||
|
||||
typedef struct {
|
||||
const char **filenames;
|
||||
size_t num_files;
|
||||
size_t current_index;
|
||||
} scandir_test_dir_context_t;
|
||||
|
||||
static DIR *scandir_test_opendir(void* ctx, const char* name)
|
||||
{
|
||||
scandir_test_dir_context_t *dir_ctx = (scandir_test_dir_context_t *)ctx;
|
||||
dir_ctx->current_index = 0;
|
||||
static DIR dir = {};
|
||||
return &dir;
|
||||
}
|
||||
|
||||
static struct dirent *scandir_test_readdir(void* ctx, DIR* pdir)
|
||||
{
|
||||
scandir_test_dir_context_t *dir_ctx = (scandir_test_dir_context_t *)ctx;
|
||||
if (dir_ctx->current_index >= dir_ctx->num_files) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dirent entry;
|
||||
snprintf(entry.d_name, sizeof(entry.d_name), "%s", dir_ctx->filenames[dir_ctx->current_index]);
|
||||
dir_ctx->current_index++;
|
||||
return &entry;
|
||||
}
|
||||
|
||||
static int scandir_test_closedir(void* ctx, DIR* pdir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scandir_test_select(const struct dirent *entry)
|
||||
{
|
||||
s_select_calls++;
|
||||
return strstr(entry->d_name, "test") != NULL;
|
||||
}
|
||||
|
||||
TEST_CASE("file - scandir", "[newlib_misc]")
|
||||
{
|
||||
const char *test_filenames[] = {
|
||||
".",
|
||||
"..",
|
||||
"test_file1.txt",
|
||||
"file2.txt",
|
||||
"test_file3.txt",
|
||||
"test_file4.txt",
|
||||
"test_file5.txt",
|
||||
"test_file6.txt",
|
||||
"test_file7.txt",
|
||||
"test_file8.txt",
|
||||
"test_file9.txt",
|
||||
"test_file10.txt",
|
||||
};
|
||||
size_t num_test_files = sizeof(test_filenames) / sizeof(test_filenames[0]);
|
||||
|
||||
scandir_test_dir_context_t scandir_test_dir_ctx = { .filenames = test_filenames, .num_files = num_test_files };
|
||||
|
||||
const esp_vfs_t scandir_test_vfs = {
|
||||
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
|
||||
.opendir_p = scandir_test_opendir,
|
||||
.readdir_p = scandir_test_readdir,
|
||||
.closedir_p = scandir_test_closedir
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_vfs_register("/data", &scandir_test_vfs, &scandir_test_dir_ctx));
|
||||
|
||||
struct dirent **namelist;
|
||||
s_select_calls = 0;
|
||||
int n = scandir("/data", &namelist, scandir_test_select, alphasort);
|
||||
TEST_ASSERT_NOT_NULL(namelist);
|
||||
TEST_ASSERT_GREATER_THAN(0, n);
|
||||
|
||||
TEST_ASSERT_EQUAL(num_test_files, s_select_calls);
|
||||
TEST_ASSERT_EQUAL(9, n);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
TEST_ASSERT_NOT_NULL(strstr(namelist[i]->d_name, "test"));
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
|
||||
esp_vfs_unregister("/data");
|
||||
}
|
||||
|
||||
@@ -1,239 +1,239 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
#include "esp_rom_caps.h"
|
||||
|
||||
TEST_CASE("test ctype functions", "[newlib]")
|
||||
{
|
||||
TEST_ASSERT_TRUE(isalnum('a') && isalnum('A') && isalnum('z') && isalnum('Z') && isalnum('0') && isalnum('9'));
|
||||
TEST_ASSERT_FALSE(isalnum('(') || isalnum('-') || isalnum(' ') || isalnum('\x81') || isalnum('.') || isalnum('\\'));
|
||||
TEST_ASSERT_TRUE(isalpha('a') && isalpha('A') && isalpha('z') && isalpha('Z'));
|
||||
TEST_ASSERT_FALSE(isalpha('0') || isalpha('9') || isalpha(')') || isalpha('\t') || isalpha(' ') || isalpha('\x81'));
|
||||
TEST_ASSERT_TRUE(isspace(' ') && isspace('\t') && isspace('\n') && isspace('\r'));
|
||||
TEST_ASSERT_FALSE(isspace('0') || isspace('9') || isspace(')') || isspace('A') || isspace('*') || isspace('\x81') || isspace('a'));
|
||||
}
|
||||
|
||||
TEST_CASE("test atoX functions", "[newlib]")
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(-2147483648, atoi("-2147483648"));
|
||||
TEST_ASSERT_EQUAL_INT(2147483647, atoi("2147483647"));
|
||||
TEST_ASSERT_EQUAL_INT(42, atoi("000000042"));
|
||||
TEST_ASSERT_EQUAL_INT(0, strtol("foo", NULL, 10));
|
||||
TEST_ASSERT_EQUAL_DOUBLE(0.123443, atof("0.123443"));
|
||||
TEST_ASSERT_EQUAL_FLOAT(0.123443f, atoff("0.123443"));
|
||||
TEST_ASSERT_EQUAL_DOUBLE(31.41238, strtod("0.3141238e2", NULL));
|
||||
TEST_ASSERT_EQUAL_FLOAT(0.025f, strtof("0.025", NULL));
|
||||
}
|
||||
|
||||
TEST_CASE("test sprintf function", "[newlib]")
|
||||
{
|
||||
char *res = NULL;
|
||||
asprintf(&res, "%d %011i %lu %p %x %c %.4f\n", 42, 2147483647, 2147483648UL, (void *) 0x40010000, 0x40020000, 'Q', 1.0f / 137.0f);
|
||||
TEST_ASSERT_NOT_NULL(res);
|
||||
TEST_ASSERT_EQUAL_STRING("42 02147483647 2147483648 0x40010000 40020000 Q 0.0073\n", res);
|
||||
free(res);
|
||||
}
|
||||
|
||||
TEST_CASE("test sscanf function", "[newlib]")
|
||||
{
|
||||
const char *src = "42 02147483647 2147483648 0x40010000 40020000 Q 0.0073\n";
|
||||
int fourty_two;
|
||||
int int_max;
|
||||
unsigned long int_max_plus_one;
|
||||
void *iram_ptr;
|
||||
int irom_ptr;
|
||||
char department;
|
||||
float inv_fine_structure_constant;
|
||||
int res = sscanf(src, "%d %d %lu %p %x %c %f", &fourty_two, &int_max, &int_max_plus_one, &iram_ptr, &irom_ptr, &department, &inv_fine_structure_constant);
|
||||
TEST_ASSERT_EQUAL(7, res);
|
||||
TEST_ASSERT_EQUAL(42, fourty_two);
|
||||
TEST_ASSERT_EQUAL(2147483647, int_max);
|
||||
TEST_ASSERT_EQUAL_UINT32(2147483648UL, int_max_plus_one);
|
||||
TEST_ASSERT_EQUAL(0x40010000, (UNITY_UINT32)iram_ptr);
|
||||
TEST_ASSERT_EQUAL(0x40020000, irom_ptr);
|
||||
TEST_ASSERT_EQUAL('Q', department);
|
||||
TEST_ASSERT_TRUE(1.0f / inv_fine_structure_constant > 136 && 1.0f / inv_fine_structure_constant < 138);
|
||||
}
|
||||
|
||||
TEST_CASE("test time functions", "[newlib]")
|
||||
{
|
||||
time_t now = 1464248488;
|
||||
setenv("TZ", "UTC-8", 1);
|
||||
tzset();
|
||||
struct tm *tm_utc = gmtime(&now);
|
||||
TEST_ASSERT_EQUAL(28, tm_utc->tm_sec);
|
||||
TEST_ASSERT_EQUAL(41, tm_utc->tm_min);
|
||||
TEST_ASSERT_EQUAL(7, tm_utc->tm_hour);
|
||||
TEST_ASSERT_EQUAL(26, tm_utc->tm_mday);
|
||||
TEST_ASSERT_EQUAL(4, tm_utc->tm_mon);
|
||||
TEST_ASSERT_EQUAL(116, tm_utc->tm_year);
|
||||
TEST_ASSERT_EQUAL(4, tm_utc->tm_wday);
|
||||
TEST_ASSERT_EQUAL(146, tm_utc->tm_yday);
|
||||
|
||||
struct tm *tm_local = localtime(&now);
|
||||
TEST_ASSERT_EQUAL(28, tm_local->tm_sec);
|
||||
TEST_ASSERT_EQUAL(41, tm_local->tm_min);
|
||||
TEST_ASSERT_EQUAL(15, tm_local->tm_hour);
|
||||
TEST_ASSERT_EQUAL(26, tm_local->tm_mday);
|
||||
TEST_ASSERT_EQUAL(4, tm_local->tm_mon);
|
||||
TEST_ASSERT_EQUAL(116, tm_local->tm_year);
|
||||
TEST_ASSERT_EQUAL(4, tm_local->tm_wday);
|
||||
TEST_ASSERT_EQUAL(146, tm_local->tm_yday);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("test asctime", "[newlib]")
|
||||
{
|
||||
char buf[64];
|
||||
struct tm tm = { 0 };
|
||||
tm.tm_year = 2016 - 1900;
|
||||
tm.tm_mon = 0;
|
||||
tm.tm_mday = 10;
|
||||
tm.tm_hour = 16;
|
||||
tm.tm_min = 30;
|
||||
tm.tm_sec = 0;
|
||||
time_t t = mktime(&tm);
|
||||
const char* time_str = asctime(&tm);
|
||||
strlcpy(buf, time_str, sizeof(buf));
|
||||
printf("Setting time: %s", time_str);
|
||||
struct timeval now = { .tv_sec = t };
|
||||
settimeofday(&now, NULL);
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
time_t mtime = tv.tv_sec;
|
||||
struct tm mtm;
|
||||
localtime_r(&mtime, &mtm);
|
||||
time_str = asctime(&mtm);
|
||||
printf("Got time: %s", time_str);
|
||||
TEST_ASSERT_EQUAL_STRING(buf, time_str);
|
||||
}
|
||||
|
||||
static bool fn_in_rom(void *fn)
|
||||
{
|
||||
const int fnaddr = (int)fn;
|
||||
return (fnaddr >= SOC_IROM_MASK_LOW && fnaddr < SOC_IROM_MASK_HIGH);
|
||||
}
|
||||
|
||||
/* Older chips have newlib nano in rom as well, but this is not linked in due to us now using 64 bit time_t
|
||||
and the ROM code was compiled for 32 bit.
|
||||
*/
|
||||
#define PRINTF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && CONFIG_IDF_TARGET_ESP32C2)
|
||||
#define SSCANF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && CONFIG_IDF_TARGET_ESP32C2)
|
||||
|
||||
TEST_CASE("check if ROM or Flash is used for functions", "[newlib]")
|
||||
{
|
||||
#if PRINTF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
TEST_ASSERT(fn_in_rom(vfprintf));
|
||||
#else
|
||||
TEST_ASSERT_FALSE(fn_in_rom(vfprintf));
|
||||
#endif // PRINTF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
|
||||
#if SSCANF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
TEST_ASSERT(fn_in_rom(sscanf));
|
||||
#else
|
||||
TEST_ASSERT_FALSE(fn_in_rom(sscanf));
|
||||
#endif // SSCANF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
|
||||
#if defined(CONFIG_SPIRAM_CACHE_WORKAROUND)
|
||||
TEST_ASSERT_FALSE(fn_in_rom(atoi));
|
||||
TEST_ASSERT_FALSE(fn_in_rom(strtol));
|
||||
#else
|
||||
TEST_ASSERT(fn_in_rom(atoi));
|
||||
TEST_ASSERT(fn_in_rom(strtol));
|
||||
#endif //CONFIG_SPIRAM_CACHE_WORKAROUND
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
/* S2 do not have these in ROM */
|
||||
TEST_ASSERT_FALSE(fn_in_rom(atoi));
|
||||
TEST_ASSERT_FALSE(fn_in_rom(strtol));
|
||||
#else
|
||||
TEST_ASSERT(fn_in_rom(atoi));
|
||||
TEST_ASSERT(fn_in_rom(strtol));
|
||||
#endif // defined(CONFIG_IDF_TARGET_ESP32)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NEWLIB_NANO_FORMAT
|
||||
TEST_CASE("test 64bit int formats", "[newlib]")
|
||||
{
|
||||
char* res = NULL;
|
||||
const uint64_t val = 123456789012LL;
|
||||
|
||||
asprintf(&res, "%llu", val);
|
||||
TEST_ASSERT_NOT_NULL(res);
|
||||
TEST_ASSERT_EQUAL_STRING("123456789012", res);
|
||||
|
||||
uint64_t sval;
|
||||
int ret = sscanf(res, "%llu", &sval);
|
||||
free(res);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, ret);
|
||||
TEST_ASSERT_EQUAL(val, sval);
|
||||
}
|
||||
#else // CONFIG_NEWLIB_NANO_FORMAT
|
||||
TEST_CASE("test 64bit int formats", "[newlib]")
|
||||
{
|
||||
char* res = NULL;
|
||||
const uint64_t val = 123456789012LL;
|
||||
|
||||
asprintf(&res, "%llu", val);
|
||||
TEST_ASSERT_NOT_NULL(res);
|
||||
TEST_ASSERT_EQUAL_STRING("lu", res);
|
||||
|
||||
uint64_t sval;
|
||||
int ret = sscanf(res, "%llu", &sval);
|
||||
free(res);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
}
|
||||
#endif // CONFIG_NEWLIB_NANO_FORMAT
|
||||
|
||||
TEST_CASE("fmod and fmodf work as expected", "[newlib]")
|
||||
{
|
||||
TEST_ASSERT_EQUAL(0.1, fmod(10.1, 2.0));
|
||||
TEST_ASSERT_EQUAL(0.1f, fmodf(10.1f, 2.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("newlib: can link 'system', 'raise'", "[newlib]")
|
||||
{
|
||||
printf("system: %p, raise: %p\n", &system, &raise);
|
||||
}
|
||||
|
||||
TEST_CASE("newlib: rom and toolchain localtime func gives the same result", "[newlib]")
|
||||
{
|
||||
// This UNIX time represents 2020-03-12 15:00:00 EDT (19:00 GMT)
|
||||
// as can be verified with 'date --date @1584039600'
|
||||
const time_t seconds = 1584039600;
|
||||
setenv("TZ", "EST5EDT,M3.2.0,M11.1.0", 1); // America/New_York
|
||||
tzset();
|
||||
struct tm *tm = localtime(&seconds);
|
||||
tm->tm_isdst = 1;
|
||||
static char buf[32];
|
||||
strftime(buf, sizeof(buf), "%F %T %Z", tm);
|
||||
static char test_result[64];
|
||||
sprintf(test_result, "%s (tm_isdst = %d)", buf, tm->tm_isdst);
|
||||
printf("%s\n", test_result);
|
||||
TEST_ASSERT_EQUAL_STRING("2020-03-12 15:00:00 EDT (tm_isdst = 1)", test_result);
|
||||
}
|
||||
|
||||
TEST_CASE("newlib: printf float as expected", "[newlib]")
|
||||
{
|
||||
const float val = 1.23;
|
||||
int len = printf("test printf float val is %1.2f\n", val);
|
||||
TEST_ASSERT_EQUAL_INT(30, len);
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
#include "esp_rom_caps.h"
|
||||
|
||||
TEST_CASE("test ctype functions", "[newlib]")
|
||||
{
|
||||
TEST_ASSERT_TRUE(isalnum('a') && isalnum('A') && isalnum('z') && isalnum('Z') && isalnum('0') && isalnum('9'));
|
||||
TEST_ASSERT_FALSE(isalnum('(') || isalnum('-') || isalnum(' ') || isalnum('\x81') || isalnum('.') || isalnum('\\'));
|
||||
TEST_ASSERT_TRUE(isalpha('a') && isalpha('A') && isalpha('z') && isalpha('Z'));
|
||||
TEST_ASSERT_FALSE(isalpha('0') || isalpha('9') || isalpha(')') || isalpha('\t') || isalpha(' ') || isalpha('\x81'));
|
||||
TEST_ASSERT_TRUE(isspace(' ') && isspace('\t') && isspace('\n') && isspace('\r'));
|
||||
TEST_ASSERT_FALSE(isspace('0') || isspace('9') || isspace(')') || isspace('A') || isspace('*') || isspace('\x81') || isspace('a'));
|
||||
}
|
||||
|
||||
TEST_CASE("test atoX functions", "[newlib]")
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(-2147483648, atoi("-2147483648"));
|
||||
TEST_ASSERT_EQUAL_INT(2147483647, atoi("2147483647"));
|
||||
TEST_ASSERT_EQUAL_INT(42, atoi("000000042"));
|
||||
TEST_ASSERT_EQUAL_INT(0, strtol("foo", NULL, 10));
|
||||
TEST_ASSERT_EQUAL_DOUBLE(0.123443, atof("0.123443"));
|
||||
TEST_ASSERT_EQUAL_FLOAT(0.123443f, atoff("0.123443"));
|
||||
TEST_ASSERT_EQUAL_DOUBLE(31.41238, strtod("0.3141238e2", NULL));
|
||||
TEST_ASSERT_EQUAL_FLOAT(0.025f, strtof("0.025", NULL));
|
||||
}
|
||||
|
||||
TEST_CASE("test sprintf function", "[newlib]")
|
||||
{
|
||||
char *res = NULL;
|
||||
asprintf(&res, "%d %011i %lu %p %x %c %.4f\n", 42, 2147483647, 2147483648UL, (void *) 0x40010000, 0x40020000, 'Q', 1.0f / 137.0f);
|
||||
TEST_ASSERT_NOT_NULL(res);
|
||||
TEST_ASSERT_EQUAL_STRING("42 02147483647 2147483648 0x40010000 40020000 Q 0.0073\n", res);
|
||||
free(res);
|
||||
}
|
||||
|
||||
TEST_CASE("test sscanf function", "[newlib]")
|
||||
{
|
||||
const char *src = "42 02147483647 2147483648 0x40010000 40020000 Q 0.0073\n";
|
||||
int fourty_two;
|
||||
int int_max;
|
||||
unsigned long int_max_plus_one;
|
||||
void *iram_ptr;
|
||||
int irom_ptr;
|
||||
char department;
|
||||
float inv_fine_structure_constant;
|
||||
int res = sscanf(src, "%d %d %lu %p %x %c %f", &fourty_two, &int_max, &int_max_plus_one, &iram_ptr, &irom_ptr, &department, &inv_fine_structure_constant);
|
||||
TEST_ASSERT_EQUAL(7, res);
|
||||
TEST_ASSERT_EQUAL(42, fourty_two);
|
||||
TEST_ASSERT_EQUAL(2147483647, int_max);
|
||||
TEST_ASSERT_EQUAL_UINT32(2147483648UL, int_max_plus_one);
|
||||
TEST_ASSERT_EQUAL(0x40010000, (UNITY_UINT32)iram_ptr);
|
||||
TEST_ASSERT_EQUAL(0x40020000, irom_ptr);
|
||||
TEST_ASSERT_EQUAL('Q', department);
|
||||
TEST_ASSERT_TRUE(1.0f / inv_fine_structure_constant > 136 && 1.0f / inv_fine_structure_constant < 138);
|
||||
}
|
||||
|
||||
TEST_CASE("test time functions", "[newlib]")
|
||||
{
|
||||
time_t now = 1464248488;
|
||||
setenv("TZ", "UTC-8", 1);
|
||||
tzset();
|
||||
struct tm *tm_utc = gmtime(&now);
|
||||
TEST_ASSERT_EQUAL(28, tm_utc->tm_sec);
|
||||
TEST_ASSERT_EQUAL(41, tm_utc->tm_min);
|
||||
TEST_ASSERT_EQUAL(7, tm_utc->tm_hour);
|
||||
TEST_ASSERT_EQUAL(26, tm_utc->tm_mday);
|
||||
TEST_ASSERT_EQUAL(4, tm_utc->tm_mon);
|
||||
TEST_ASSERT_EQUAL(116, tm_utc->tm_year);
|
||||
TEST_ASSERT_EQUAL(4, tm_utc->tm_wday);
|
||||
TEST_ASSERT_EQUAL(146, tm_utc->tm_yday);
|
||||
|
||||
struct tm *tm_local = localtime(&now);
|
||||
TEST_ASSERT_EQUAL(28, tm_local->tm_sec);
|
||||
TEST_ASSERT_EQUAL(41, tm_local->tm_min);
|
||||
TEST_ASSERT_EQUAL(15, tm_local->tm_hour);
|
||||
TEST_ASSERT_EQUAL(26, tm_local->tm_mday);
|
||||
TEST_ASSERT_EQUAL(4, tm_local->tm_mon);
|
||||
TEST_ASSERT_EQUAL(116, tm_local->tm_year);
|
||||
TEST_ASSERT_EQUAL(4, tm_local->tm_wday);
|
||||
TEST_ASSERT_EQUAL(146, tm_local->tm_yday);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("test asctime", "[newlib]")
|
||||
{
|
||||
char buf[64];
|
||||
struct tm tm = { 0 };
|
||||
tm.tm_year = 2016 - 1900;
|
||||
tm.tm_mon = 0;
|
||||
tm.tm_mday = 10;
|
||||
tm.tm_hour = 16;
|
||||
tm.tm_min = 30;
|
||||
tm.tm_sec = 0;
|
||||
time_t t = mktime(&tm);
|
||||
const char* time_str = asctime(&tm);
|
||||
strlcpy(buf, time_str, sizeof(buf));
|
||||
printf("Setting time: %s", time_str);
|
||||
struct timeval now = { .tv_sec = t };
|
||||
settimeofday(&now, NULL);
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
time_t mtime = tv.tv_sec;
|
||||
struct tm mtm;
|
||||
localtime_r(&mtime, &mtm);
|
||||
time_str = asctime(&mtm);
|
||||
printf("Got time: %s", time_str);
|
||||
TEST_ASSERT_EQUAL_STRING(buf, time_str);
|
||||
}
|
||||
|
||||
static bool fn_in_rom(void *fn)
|
||||
{
|
||||
const int fnaddr = (int)fn;
|
||||
return (fnaddr >= SOC_IROM_MASK_LOW && fnaddr < SOC_IROM_MASK_HIGH);
|
||||
}
|
||||
|
||||
/* Older chips have newlib nano in rom as well, but this is not linked in due to us now using 64 bit time_t
|
||||
and the ROM code was compiled for 32 bit.
|
||||
*/
|
||||
#define PRINTF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && CONFIG_IDF_TARGET_ESP32C2)
|
||||
#define SSCANF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && CONFIG_IDF_TARGET_ESP32C2)
|
||||
|
||||
TEST_CASE("check if ROM or Flash is used for functions", "[newlib]")
|
||||
{
|
||||
#if PRINTF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
TEST_ASSERT(fn_in_rom(vfprintf));
|
||||
#else
|
||||
TEST_ASSERT_FALSE(fn_in_rom(vfprintf));
|
||||
#endif // PRINTF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
|
||||
#if SSCANF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
TEST_ASSERT(fn_in_rom(sscanf));
|
||||
#else
|
||||
TEST_ASSERT_FALSE(fn_in_rom(sscanf));
|
||||
#endif // SSCANF_NANO_IN_ROM || (ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT && !CONFIG_NEWLIB_NANO_FORMAT)
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
|
||||
#if defined(CONFIG_SPIRAM_CACHE_WORKAROUND)
|
||||
TEST_ASSERT_FALSE(fn_in_rom(atoi));
|
||||
TEST_ASSERT_FALSE(fn_in_rom(strtol));
|
||||
#else
|
||||
TEST_ASSERT(fn_in_rom(atoi));
|
||||
TEST_ASSERT(fn_in_rom(strtol));
|
||||
#endif //CONFIG_SPIRAM_CACHE_WORKAROUND
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
/* S2 do not have these in ROM */
|
||||
TEST_ASSERT_FALSE(fn_in_rom(atoi));
|
||||
TEST_ASSERT_FALSE(fn_in_rom(strtol));
|
||||
#else
|
||||
TEST_ASSERT(fn_in_rom(atoi));
|
||||
TEST_ASSERT(fn_in_rom(strtol));
|
||||
#endif // defined(CONFIG_IDF_TARGET_ESP32)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NEWLIB_NANO_FORMAT
|
||||
TEST_CASE("test 64bit int formats", "[newlib]")
|
||||
{
|
||||
char* res = NULL;
|
||||
const uint64_t val = 123456789012LL;
|
||||
|
||||
asprintf(&res, "%llu", val);
|
||||
TEST_ASSERT_NOT_NULL(res);
|
||||
TEST_ASSERT_EQUAL_STRING("123456789012", res);
|
||||
|
||||
uint64_t sval;
|
||||
int ret = sscanf(res, "%llu", &sval);
|
||||
free(res);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, ret);
|
||||
TEST_ASSERT_EQUAL(val, sval);
|
||||
}
|
||||
#else // CONFIG_NEWLIB_NANO_FORMAT
|
||||
TEST_CASE("test 64bit int formats", "[newlib]")
|
||||
{
|
||||
char* res = NULL;
|
||||
const uint64_t val = 123456789012LL;
|
||||
|
||||
asprintf(&res, "%llu", val);
|
||||
TEST_ASSERT_NOT_NULL(res);
|
||||
TEST_ASSERT_EQUAL_STRING("lu", res);
|
||||
|
||||
uint64_t sval;
|
||||
int ret = sscanf(res, "%llu", &sval);
|
||||
free(res);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
}
|
||||
#endif // CONFIG_NEWLIB_NANO_FORMAT
|
||||
|
||||
TEST_CASE("fmod and fmodf work as expected", "[newlib]")
|
||||
{
|
||||
TEST_ASSERT_EQUAL(0.1, fmod(10.1, 2.0));
|
||||
TEST_ASSERT_EQUAL(0.1f, fmodf(10.1f, 2.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("newlib: can link 'system', 'raise'", "[newlib]")
|
||||
{
|
||||
printf("system: %p, raise: %p\n", &system, &raise);
|
||||
}
|
||||
|
||||
TEST_CASE("newlib: rom and toolchain localtime func gives the same result", "[newlib]")
|
||||
{
|
||||
// This UNIX time represents 2020-03-12 15:00:00 EDT (19:00 GMT)
|
||||
// as can be verified with 'date --date @1584039600'
|
||||
const time_t seconds = 1584039600;
|
||||
setenv("TZ", "EST5EDT,M3.2.0,M11.1.0", 1); // America/New_York
|
||||
tzset();
|
||||
struct tm *tm = localtime(&seconds);
|
||||
tm->tm_isdst = 1;
|
||||
static char buf[32];
|
||||
strftime(buf, sizeof(buf), "%F %T %Z", tm);
|
||||
static char test_result[64];
|
||||
sprintf(test_result, "%s (tm_isdst = %d)", buf, tm->tm_isdst);
|
||||
printf("%s\n", test_result);
|
||||
TEST_ASSERT_EQUAL_STRING("2020-03-12 15:00:00 EDT (tm_isdst = 1)", test_result);
|
||||
}
|
||||
|
||||
TEST_CASE("newlib: printf float as expected", "[newlib]")
|
||||
{
|
||||
const float val = 1.23;
|
||||
int len = printf("test printf float val is %1.2f\n", val);
|
||||
TEST_ASSERT_EQUAL_INT(30, len);
|
||||
}
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
static int my_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
int result = vprintf(fmt, list);
|
||||
va_end(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void test_task(void* arg)
|
||||
{
|
||||
for (unsigned i = 0; i < 5; i++) {
|
||||
printf("00000000%d\n", i);
|
||||
}
|
||||
SemaphoreHandle_t * p_done = (SemaphoreHandle_t *) arg;
|
||||
xSemaphoreGive(*p_done);
|
||||
vTaskDelay(1);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test flockfile/funlockfile", "[newlib]")
|
||||
{
|
||||
SemaphoreHandle_t done = xSemaphoreCreateBinary();
|
||||
flockfile(stdout);
|
||||
{
|
||||
xTaskCreatePinnedToCore(&test_task, "test_task", 4096, &done, 5, NULL, 1);
|
||||
// make sure test_task is already running and is actually blocked by flockfile
|
||||
TEST_ASSERT_FALSE(xSemaphoreTake(done, 100 / portTICK_PERIOD_MS));
|
||||
for (unsigned i = 0; i < 5; i++) {
|
||||
my_printf(LOG_ANSI_COLOR_BOLD_BACKGROUND(LOG_ANSI_COLOR_BLACK, LOG_ANSI_COLOR_BG_RED) "I ");
|
||||
my_printf("(%d) ", 737);
|
||||
my_printf("[%s]: ", "TAG");
|
||||
my_printf("%s %d ", "message ", i);
|
||||
my_printf("%s\n", LOG_ANSI_COLOR_RESET);
|
||||
}
|
||||
// test_task is still blocked by flockfile
|
||||
TEST_ASSERT_FALSE(xSemaphoreTake(done, 100 / portTICK_PERIOD_MS));
|
||||
}
|
||||
funlockfile(stdout);
|
||||
// after funlockfile, test_task can print a msg and complete test_task
|
||||
TEST_ASSERT_TRUE(xSemaphoreTake(done, portMAX_DELAY));
|
||||
vSemaphoreDelete(done);
|
||||
}
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
static int my_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
int result = vprintf(fmt, list);
|
||||
va_end(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void test_task(void* arg)
|
||||
{
|
||||
for (unsigned i = 0; i < 5; i++) {
|
||||
printf("00000000%d\n", i);
|
||||
}
|
||||
SemaphoreHandle_t * p_done = (SemaphoreHandle_t *) arg;
|
||||
xSemaphoreGive(*p_done);
|
||||
vTaskDelay(1);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test flockfile/funlockfile", "[newlib]")
|
||||
{
|
||||
SemaphoreHandle_t done = xSemaphoreCreateBinary();
|
||||
flockfile(stdout);
|
||||
{
|
||||
xTaskCreatePinnedToCore(&test_task, "test_task", 4096, &done, 5, NULL, 1);
|
||||
// make sure test_task is already running and is actually blocked by flockfile
|
||||
TEST_ASSERT_FALSE(xSemaphoreTake(done, 100 / portTICK_PERIOD_MS));
|
||||
for (unsigned i = 0; i < 5; i++) {
|
||||
my_printf(LOG_ANSI_COLOR_BOLD_BACKGROUND(LOG_ANSI_COLOR_BLACK, LOG_ANSI_COLOR_BG_RED) "I ");
|
||||
my_printf("(%d) ", 737);
|
||||
my_printf("[%s]: ", "TAG");
|
||||
my_printf("%s %d ", "message ", i);
|
||||
my_printf("%s\n", LOG_ANSI_COLOR_RESET);
|
||||
}
|
||||
// test_task is still blocked by flockfile
|
||||
TEST_ASSERT_FALSE(xSemaphoreTake(done, 100 / portTICK_PERIOD_MS));
|
||||
}
|
||||
funlockfile(stdout);
|
||||
// after funlockfile, test_task can print a msg and complete test_task
|
||||
TEST_ASSERT_TRUE(xSemaphoreTake(done, portMAX_DELAY));
|
||||
vSemaphoreDelete(done);
|
||||
}
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "unity.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
typedef struct {
|
||||
jmp_buf jmp_env;
|
||||
uint32_t retval;
|
||||
volatile bool inner_called;
|
||||
} setjmp_test_ctx_t;
|
||||
|
||||
static __attribute__((noreturn)) void inner(setjmp_test_ctx_t *ctx)
|
||||
{
|
||||
printf("inner, retval=0x%" PRIx32 "\n", ctx->retval);
|
||||
ctx->inner_called = true;
|
||||
longjmp(ctx->jmp_env, ctx->retval);
|
||||
TEST_FAIL_MESSAGE("Should not reach here");
|
||||
}
|
||||
|
||||
TEST_CASE("setjmp and longjmp", "[newlib]")
|
||||
{
|
||||
const uint32_t expected = 0x12345678;
|
||||
setjmp_test_ctx_t ctx = {
|
||||
.retval = expected
|
||||
};
|
||||
uint32_t ret = setjmp(ctx.jmp_env);
|
||||
if (!ctx.inner_called) {
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
inner(&ctx);
|
||||
} else {
|
||||
TEST_ASSERT_EQUAL(expected, ret);
|
||||
}
|
||||
TEST_ASSERT(ctx.inner_called);
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "unity.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
typedef struct {
|
||||
jmp_buf jmp_env;
|
||||
uint32_t retval;
|
||||
volatile bool inner_called;
|
||||
} setjmp_test_ctx_t;
|
||||
|
||||
static __attribute__((noreturn)) void inner(setjmp_test_ctx_t *ctx)
|
||||
{
|
||||
printf("inner, retval=0x%" PRIx32 "\n", ctx->retval);
|
||||
ctx->inner_called = true;
|
||||
longjmp(ctx->jmp_env, ctx->retval);
|
||||
TEST_FAIL_MESSAGE("Should not reach here");
|
||||
}
|
||||
|
||||
TEST_CASE("setjmp and longjmp", "[newlib]")
|
||||
{
|
||||
const uint32_t expected = 0x12345678;
|
||||
setjmp_test_ctx_t ctx = {
|
||||
.retval = expected
|
||||
};
|
||||
uint32_t ret = setjmp(ctx.jmp_env);
|
||||
if (!ctx.inner_called) {
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
inner(&ctx);
|
||||
} else {
|
||||
TEST_ASSERT_EQUAL(expected, ret);
|
||||
}
|
||||
TEST_ASSERT(ctx.inner_called);
|
||||
}
|
||||
|
||||
@@ -1,462 +1,462 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include "esp_pthread.h"
|
||||
#include "esp_attr.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "unity.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define MALLOC_CAP_ATOMIC MALLOC_CAP_DEFAULT
|
||||
|
||||
/* non-static to prevent optimization */
|
||||
atomic_ullong *g_atomic64;
|
||||
atomic_uint *g_atomic32;
|
||||
atomic_ushort *g_atomic16;
|
||||
atomic_uchar *g_atomic8;
|
||||
|
||||
TEST_CASE("stdatomic - test_64bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned long long x64 = 0;
|
||||
g_atomic64 = heap_caps_calloc(sizeof(*g_atomic64), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x64 += atomic_fetch_or(g_atomic64, 0x1111111111111111ULL);
|
||||
x64 += atomic_fetch_xor(g_atomic64, 0x3333333333333333ULL);
|
||||
x64 += atomic_fetch_and(g_atomic64, 0xf0f0f0f0f0f0f0f0ULL);
|
||||
x64 += atomic_fetch_sub(g_atomic64, 0x0f0f0f0f0f0f0f0fULL);
|
||||
x64 += atomic_fetch_add(g_atomic64, 0x2222222222222222ULL);
|
||||
#ifndef __clang__
|
||||
x64 += __atomic_fetch_nand_8(g_atomic64, 0xAAAAAAAAAAAAAAAAULL, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX64(0x9797979797979797ULL, x64);
|
||||
TEST_ASSERT_EQUAL_HEX64(0xDDDDDDDDDDDDDDDDULL, *g_atomic64); // calls atomic_load
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX64(0x6464646464646464ULL, x64);
|
||||
TEST_ASSERT_EQUAL_HEX64(0x3333333333333333ULL, *g_atomic64); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic64);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_32bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x32 = 0;
|
||||
g_atomic32 = heap_caps_calloc(sizeof(*g_atomic32), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x32 += atomic_fetch_or(g_atomic32, 0x11111111U);
|
||||
x32 += atomic_fetch_xor(g_atomic32, 0x33333333U);
|
||||
x32 += atomic_fetch_and(g_atomic32, 0xf0f0f0f0U);
|
||||
x32 += atomic_fetch_sub(g_atomic32, 0x0f0f0f0fU);
|
||||
x32 += atomic_fetch_add(g_atomic32, 0x22222222U);
|
||||
#ifndef __clang__
|
||||
x32 += __atomic_fetch_nand_4(g_atomic32, 0xAAAAAAAAU, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX32(0x97979797U, x32);
|
||||
TEST_ASSERT_EQUAL_HEX32(0xDDDDDDDDU, *g_atomic32);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX32(0x64646464U, x32);
|
||||
TEST_ASSERT_EQUAL_HEX32(0x33333333U, *g_atomic32); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic32);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_16bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x16 = 0;
|
||||
g_atomic16 = heap_caps_calloc(sizeof(*g_atomic16), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x16 += atomic_fetch_or(g_atomic16, 0x1111);
|
||||
x16 += atomic_fetch_xor(g_atomic16, 0x3333);
|
||||
x16 += atomic_fetch_and(g_atomic16, 0xf0f0);
|
||||
x16 += atomic_fetch_sub(g_atomic16, 0x0f0f);
|
||||
x16 += atomic_fetch_add(g_atomic16, 0x2222);
|
||||
#ifndef __clang__
|
||||
x16 += __atomic_fetch_nand_2(g_atomic16, 0xAAAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(0x9797, x16);
|
||||
TEST_ASSERT_EQUAL_HEX16(0xDDDD, *g_atomic16);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX16(0x6464, x16);
|
||||
TEST_ASSERT_EQUAL_HEX16(0x3333, *g_atomic16); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic16);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_8bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x8 = 0;
|
||||
g_atomic8 = heap_caps_calloc(sizeof(*g_atomic8), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x8 += atomic_fetch_or(g_atomic8, 0x11);
|
||||
x8 += atomic_fetch_xor(g_atomic8, 0x33);
|
||||
x8 += atomic_fetch_and(g_atomic8, 0xf0);
|
||||
x8 += atomic_fetch_sub(g_atomic8, 0x0f);
|
||||
x8 += atomic_fetch_add(g_atomic8, 0x22);
|
||||
#ifndef __clang__
|
||||
x8 += __atomic_fetch_nand_1(g_atomic8, 0xAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8(0x97, x8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0xDD, *g_atomic8);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX8(0x64, x8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0x33, *g_atomic8); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic8);
|
||||
}
|
||||
|
||||
#ifndef __clang__
|
||||
TEST_CASE("stdatomic - test_64bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned long long x64 = 0;
|
||||
g_atomic64 = heap_caps_calloc(sizeof(*g_atomic64), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x64 += __atomic_or_fetch_8(g_atomic64, 0x1111111111111111ULL, 0);
|
||||
x64 += __atomic_xor_fetch_8(g_atomic64, 0x3333333333333333ULL, 0);
|
||||
x64 += __atomic_and_fetch_8(g_atomic64, 0xf0f0f0f0f0f0f0f0ULL, 0);
|
||||
x64 += __atomic_sub_fetch_8(g_atomic64, 0x0f0f0f0f0f0f0f0fULL, 0);
|
||||
x64 += __atomic_add_fetch_8(g_atomic64, 0x2222222222222222ULL, 0);
|
||||
x64 += __atomic_nand_fetch_8(g_atomic64, 0xAAAAAAAAAAAAAAAAULL, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX64(0x7575757575757574ULL, x64);
|
||||
TEST_ASSERT_EQUAL_HEX64(0xDDDDDDDDDDDDDDDDULL, *g_atomic64); // calls atomic_load
|
||||
free(g_atomic64);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_32bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x32 = 0;
|
||||
g_atomic32 = heap_caps_calloc(sizeof(*g_atomic32), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x32 += __atomic_or_fetch_4(g_atomic32, 0x11111111U, 0);
|
||||
x32 += __atomic_xor_fetch_4(g_atomic32, 0x33333333U, 0);
|
||||
x32 += __atomic_and_fetch_4(g_atomic32, 0xf0f0f0f0U, 0);
|
||||
x32 += __atomic_sub_fetch_4(g_atomic32, 0x0f0f0f0fU, 0);
|
||||
x32 += __atomic_add_fetch_4(g_atomic32, 0x22222222U, 0);
|
||||
x32 += __atomic_nand_fetch_4(g_atomic32, 0xAAAAAAAAU, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX32(0x75757574U, x32);
|
||||
TEST_ASSERT_EQUAL_HEX32(0xDDDDDDDDU, *g_atomic32);
|
||||
free(g_atomic32);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_16bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x16 = 0;
|
||||
g_atomic16 = heap_caps_calloc(sizeof(*g_atomic16), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x16 += __atomic_or_fetch_2(g_atomic16, 0x1111, 0);
|
||||
x16 += __atomic_xor_fetch_2(g_atomic16, 0x3333, 0);
|
||||
x16 += __atomic_and_fetch_2(g_atomic16, 0xf0f0, 0);
|
||||
x16 += __atomic_sub_fetch_2(g_atomic16, 0x0f0f, 0);
|
||||
x16 += __atomic_add_fetch_2(g_atomic16, 0x2222, 0);
|
||||
x16 += __atomic_nand_fetch_2(g_atomic16, 0xAAAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(0x7574, x16);
|
||||
TEST_ASSERT_EQUAL_HEX16(0xDDDD, *g_atomic16);
|
||||
free(g_atomic16);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_8bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x8 = 0;
|
||||
g_atomic8 = heap_caps_calloc(sizeof(*g_atomic8), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x8 += __atomic_or_fetch_1(g_atomic8, 0x11, 0);
|
||||
x8 += __atomic_xor_fetch_1(g_atomic8, 0x33, 0);
|
||||
x8 += __atomic_and_fetch_1(g_atomic8, 0xf0, 0);
|
||||
x8 += __atomic_sub_fetch_1(g_atomic8, 0x0f, 0);
|
||||
x8 += __atomic_add_fetch_1(g_atomic8, 0x22, 0);
|
||||
x8 += __atomic_nand_fetch_1(g_atomic8, 0xAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8(0x74, x8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0xDD, *g_atomic8);
|
||||
free(g_atomic8);
|
||||
}
|
||||
|
||||
#endif // #ifndef __clang__
|
||||
|
||||
#define TEST_EXCLUSION(n, POSTFIX) TEST_CASE("stdatomic - test_" #n #POSTFIX "bit_exclusion", "[newlib_stdatomic]") \
|
||||
{ \
|
||||
g_atomic ## n = heap_caps_calloc(sizeof(*g_atomic ## n), 1, MALLOC_CAP_ATOMIC); \
|
||||
pthread_t thread1; \
|
||||
pthread_t thread2; \
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); \
|
||||
cfg.pin_to_core = (xPortGetCoreID() + 1) % portNUM_PROCESSORS; \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create(&thread1, NULL, exclusion_task_ ##n ##POSTFIX, (void*) 1); \
|
||||
cfg.pin_to_core = xPortGetCoreID(); \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create(&thread2, NULL, exclusion_task_ ##n ##POSTFIX, (void*) 0); \
|
||||
pthread_join(thread1, NULL); \
|
||||
pthread_join(thread2, NULL); \
|
||||
TEST_ASSERT_EQUAL(0, (*g_atomic ## n)); \
|
||||
free(g_atomic ## n); \
|
||||
}
|
||||
|
||||
#define TEST_EXCLUSION_TASK(n, POSTFIX) static void* exclusion_task_ ##n ##POSTFIX(void *varg) \
|
||||
{ \
|
||||
int arg = (int) varg; \
|
||||
for (int i = 0; i < 1000000; ++i) { \
|
||||
if (arg == 0) { \
|
||||
atomic_fetch_add(g_atomic ## n, 1ULL); \
|
||||
} else { \
|
||||
atomic_fetch_sub(g_atomic ## n, 1ULL); \
|
||||
} \
|
||||
} \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
TEST_EXCLUSION_TASK(64, _default_mem)
|
||||
TEST_EXCLUSION(64, _default_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(32, _default_mem)
|
||||
TEST_EXCLUSION(32, _default_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(16, _default_mem)
|
||||
TEST_EXCLUSION(16, _default_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(8, _default_mem)
|
||||
TEST_EXCLUSION(8, _default_mem)
|
||||
|
||||
#define ITER_COUNT 20000
|
||||
|
||||
#define TEST_RACE_OPERATION(ASSERT_SUFFIX, NAME, LHSTYPE, PRE, POST, INIT, FINAL) \
|
||||
\
|
||||
static _Atomic LHSTYPE *var_##NAME; \
|
||||
\
|
||||
static void *test_thread_##NAME (void *arg) \
|
||||
{ \
|
||||
for (int i = 0; i < ITER_COUNT; i++) \
|
||||
{ \
|
||||
PRE (*var_##NAME) POST; \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
TEST_CASE("stdatomic - test_" #NAME, "[newlib_stdatomic]") \
|
||||
{ \
|
||||
pthread_t thread_id1; \
|
||||
pthread_t thread_id2; \
|
||||
var_##NAME = heap_caps_calloc(sizeof(*var_##NAME), 1, MALLOC_CAP_ATOMIC); \
|
||||
*var_##NAME = (INIT); \
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); \
|
||||
cfg.pin_to_core = (xPortGetCoreID() + 1) % CONFIG_FREERTOS_NUMBER_OF_CORES; \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id1, NULL, test_thread_##NAME, NULL); \
|
||||
cfg.pin_to_core = xPortGetCoreID(); \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id2, NULL, test_thread_##NAME, NULL); \
|
||||
pthread_join (thread_id1, NULL); \
|
||||
pthread_join (thread_id2, NULL); \
|
||||
TEST_ASSERT_EQUAL##ASSERT_SUFFIX((FINAL), (*var_##NAME)); \
|
||||
free(var_##NAME); \
|
||||
}
|
||||
|
||||
// Note that the assert at the end is doing an excat bitwise comparison.
|
||||
// This easily can fail due to rounding errors. However, there is currently
|
||||
// no corresponding Unity assert macro for long double. USE THIS WITH CARE!
|
||||
#define TEST_RACE_OPERATION_LONG_DOUBLE(NAME, LHSTYPE, PRE, POST, INIT, FINAL) \
|
||||
\
|
||||
static _Atomic LHSTYPE *var_##NAME; \
|
||||
\
|
||||
static void *test_thread_##NAME (void *arg) \
|
||||
{ \
|
||||
for (int i = 0; i < ITER_COUNT; i++) \
|
||||
{ \
|
||||
PRE (*var_##NAME) POST; \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
TEST_CASE("stdatomic - test_" #NAME, "[newlib_stdatomic]") \
|
||||
{ \
|
||||
pthread_t thread_id1; \
|
||||
pthread_t thread_id2; \
|
||||
var_##NAME = heap_caps_calloc(sizeof(*var_##NAME), 1, MALLOC_CAP_ATOMIC); \
|
||||
*var_##NAME = (INIT); \
|
||||
const LHSTYPE EXPECTED = (FINAL); \
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); \
|
||||
cfg.pin_to_core = (xPortGetCoreID() + 1) % CONFIG_FREERTOS_NUMBER_OF_CORES; \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id1, NULL, test_thread_##NAME, NULL); \
|
||||
cfg.pin_to_core = xPortGetCoreID(); \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id2, NULL, test_thread_##NAME, NULL); \
|
||||
pthread_join (thread_id1, NULL); \
|
||||
pthread_join (thread_id2, NULL); \
|
||||
TEST_ASSERT(EXPECTED == (*var_##NAME)); \
|
||||
free(var_##NAME); \
|
||||
}
|
||||
|
||||
TEST_RACE_OPERATION(, uint8_add, uint8_t,, += 1, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_add_3, uint8_t,, += 3, 0, (uint8_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postinc, uint8_t,, ++, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_preinc, uint8_t, ++,, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub, uint8_t,, -= 1, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub_3, uint8_t,, -= 3, 0, (uint8_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postdec, uint8_t,, --, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_predec, uint8_t, --,, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_mul, uint8_t,, *= 3, 1, (uint8_t) 0x1)
|
||||
|
||||
TEST_RACE_OPERATION(, uint16_add, uint16_t,, += 1, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_add_3, uint16_t,, += 3, 0, (uint16_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postinc, uint16_t,, ++, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_preinc, uint16_t, ++,, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub, uint16_t,, -= 1, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub_3, uint16_t,, -= 3, 0, (uint16_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postdec, uint16_t,, --, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_predec, uint16_t, --,, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_mul, uint16_t,, *= 3, 1, (uint16_t) 0x6D01)
|
||||
|
||||
TEST_RACE_OPERATION(, uint32_add, uint32_t,, += 1, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_add_3, uint32_t,, += 3, 0, (uint32_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postinc, uint32_t,, ++, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_preinc, uint32_t, ++,, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub, uint32_t,, -= 1, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub_3, uint32_t,, -= 3, 0, (uint32_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postdec, uint32_t,, --, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_predec, uint32_t, --,, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_mul, uint32_t,, *= 3, 1, (uint32_t) 0xC1E36D01U)
|
||||
|
||||
TEST_RACE_OPERATION(, uint64_add, uint64_t,, += 1, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_3, uint64_t,, += 3, 0, (uint64_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_neg, uint64_t,, += 1, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postinc, uint64_t,, ++, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postinc_neg, uint64_t,, ++, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_preinc, uint64_t, ++,, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_preinc_neg, uint64_t, ++,, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_sub, uint64_t,, -= 1, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_3, uint64_t,, -= 3, 0, (uint64_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_neg, uint64_t,, -= 1, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postdec, uint64_t,, --, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postdec_neg, uint64_t,, --, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_predec, uint64_t, --,, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_predec_neg, uint64_t, --,, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_mul, uint64_t,, *= 3, 1, (uint64_t) 0x988EE974C1E36D01ULL)
|
||||
|
||||
TEST_RACE_OPERATION(_FLOAT, float_add, float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_add, _Complex float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postinc, float,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_preinc, float, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_sub, float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_sub, _Complex float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postdec, float,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_predec, float, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_add, double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_add, _Complex double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postinc, double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_preinc, double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_sub, double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_sub, _Complex double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postdec, double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_predec, double, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_add, long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_add, _Complex long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postinc, long double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_sub, long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_preinc, long double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_sub, _Complex long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postdec, long double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_predec, long double, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
#if CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
#undef MALLOC_CAP_ATOMIC
|
||||
#define MALLOC_CAP_ATOMIC MALLOC_CAP_SPIRAM
|
||||
|
||||
TEST_EXCLUSION_TASK(64, _ext_mem)
|
||||
TEST_EXCLUSION(64, _ext_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(32, _ext_mem)
|
||||
TEST_EXCLUSION(32, _ext_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(16, _ext_mem)
|
||||
TEST_EXCLUSION(16, _ext_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(8, _ext_mem)
|
||||
TEST_EXCLUSION(8, _ext_mem)
|
||||
|
||||
TEST_RACE_OPERATION(, uint8_add_ext, uint8_t,, += 1, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_add_3_ext, uint8_t,, += 3, 0, (uint8_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postinc_ext, uint8_t,, ++, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_preinc_ext, uint8_t, ++,, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub_ext, uint8_t,, -= 1, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub_3_ext, uint8_t,, -= 3, 0, (uint8_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postdec_ext, uint8_t,, --, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_predec_ext, uint8_t, --,, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_mul_ext, uint8_t,, *= 3, 1, (uint8_t) 0x1)
|
||||
|
||||
TEST_RACE_OPERATION(, uint16_add_ext, uint16_t,, += 1, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_add_3_ext, uint16_t,, += 3, 0, (uint16_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postinc_ext, uint16_t,, ++, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_preinc_ext, uint16_t, ++,, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub_ext, uint16_t,, -= 1, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub_3_ext, uint16_t,, -= 3, 0, (uint16_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postdec_ext, uint16_t,, --, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_predec_ext, uint16_t, --,, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_mul_ext, uint16_t,, *= 3, 1, (uint16_t) 0x6D01)
|
||||
|
||||
TEST_RACE_OPERATION(, uint32_add_ext, uint32_t,, += 1, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_add_3_ext, uint32_t,, += 3, 0, (uint32_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postinc_ext, uint32_t,, ++, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_preinc_ext, uint32_t, ++,, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub_ext, uint32_t,, -= 1, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub_3_ext, uint32_t,, -= 3, 0, (uint32_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postdec_ext, uint32_t,, --, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_predec_ext, uint32_t, --,, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_mul_ext, uint32_t,, *= 3, 1, (uint32_t) 0xC1E36D01U)
|
||||
|
||||
TEST_RACE_OPERATION(, uint64_add_ext, uint64_t,, += 1, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_3_ext, uint64_t,, += 3, 0, (uint64_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_neg_ext, uint64_t,, += 1, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postinc_ext, uint64_t,, ++, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postinc_neg_ext, uint64_t,, ++, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_preinc_ext, uint64_t, ++,, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_preinc_neg_ext, uint64_t, ++,, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_sub_ext, uint64_t,, -= 1, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_3_ext, uint64_t,, -= 3, 0, (uint64_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_neg_ext, uint64_t,, -= 1, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postdec_ext, uint64_t,, --, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postdec_neg_ext, uint64_t,, --, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_predec_ext, uint64_t, --,, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_predec_neg_ext, uint64_t, --,, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_mul_ext, uint64_t,, *= 3, 1, (uint64_t) 0x988EE974C1E36D01ULL)
|
||||
|
||||
TEST_RACE_OPERATION(_FLOAT, float_add_ext, float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_add_ext, _Complex float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postinc_ext, float,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_preinc_ext, float, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_sub_ext, float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_sub_ext, _Complex float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postdec_ext, float,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_predec_ext, float, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_add_ext, double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_add_ext, _Complex double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postinc_ext, double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_preinc_ext, double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_sub_ext, double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_sub_ext, _Complex double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postdec_ext, double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_predec_ext, double, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_add_ext, long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_add_ext, _Complex long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postinc_ext, long double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_sub_ext, long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_preinc_ext, long double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_sub_ext, _Complex long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postdec_ext, long double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_predec_ext, long double, --,, 0, -(2 * ITER_COUNT))
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include "esp_pthread.h"
|
||||
#include "esp_attr.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "unity.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define MALLOC_CAP_ATOMIC MALLOC_CAP_DEFAULT
|
||||
|
||||
/* non-static to prevent optimization */
|
||||
atomic_ullong *g_atomic64;
|
||||
atomic_uint *g_atomic32;
|
||||
atomic_ushort *g_atomic16;
|
||||
atomic_uchar *g_atomic8;
|
||||
|
||||
TEST_CASE("stdatomic - test_64bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned long long x64 = 0;
|
||||
g_atomic64 = heap_caps_calloc(sizeof(*g_atomic64), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x64 += atomic_fetch_or(g_atomic64, 0x1111111111111111ULL);
|
||||
x64 += atomic_fetch_xor(g_atomic64, 0x3333333333333333ULL);
|
||||
x64 += atomic_fetch_and(g_atomic64, 0xf0f0f0f0f0f0f0f0ULL);
|
||||
x64 += atomic_fetch_sub(g_atomic64, 0x0f0f0f0f0f0f0f0fULL);
|
||||
x64 += atomic_fetch_add(g_atomic64, 0x2222222222222222ULL);
|
||||
#ifndef __clang__
|
||||
x64 += __atomic_fetch_nand_8(g_atomic64, 0xAAAAAAAAAAAAAAAAULL, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX64(0x9797979797979797ULL, x64);
|
||||
TEST_ASSERT_EQUAL_HEX64(0xDDDDDDDDDDDDDDDDULL, *g_atomic64); // calls atomic_load
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX64(0x6464646464646464ULL, x64);
|
||||
TEST_ASSERT_EQUAL_HEX64(0x3333333333333333ULL, *g_atomic64); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic64);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_32bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x32 = 0;
|
||||
g_atomic32 = heap_caps_calloc(sizeof(*g_atomic32), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x32 += atomic_fetch_or(g_atomic32, 0x11111111U);
|
||||
x32 += atomic_fetch_xor(g_atomic32, 0x33333333U);
|
||||
x32 += atomic_fetch_and(g_atomic32, 0xf0f0f0f0U);
|
||||
x32 += atomic_fetch_sub(g_atomic32, 0x0f0f0f0fU);
|
||||
x32 += atomic_fetch_add(g_atomic32, 0x22222222U);
|
||||
#ifndef __clang__
|
||||
x32 += __atomic_fetch_nand_4(g_atomic32, 0xAAAAAAAAU, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX32(0x97979797U, x32);
|
||||
TEST_ASSERT_EQUAL_HEX32(0xDDDDDDDDU, *g_atomic32);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX32(0x64646464U, x32);
|
||||
TEST_ASSERT_EQUAL_HEX32(0x33333333U, *g_atomic32); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic32);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_16bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x16 = 0;
|
||||
g_atomic16 = heap_caps_calloc(sizeof(*g_atomic16), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x16 += atomic_fetch_or(g_atomic16, 0x1111);
|
||||
x16 += atomic_fetch_xor(g_atomic16, 0x3333);
|
||||
x16 += atomic_fetch_and(g_atomic16, 0xf0f0);
|
||||
x16 += atomic_fetch_sub(g_atomic16, 0x0f0f);
|
||||
x16 += atomic_fetch_add(g_atomic16, 0x2222);
|
||||
#ifndef __clang__
|
||||
x16 += __atomic_fetch_nand_2(g_atomic16, 0xAAAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(0x9797, x16);
|
||||
TEST_ASSERT_EQUAL_HEX16(0xDDDD, *g_atomic16);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX16(0x6464, x16);
|
||||
TEST_ASSERT_EQUAL_HEX16(0x3333, *g_atomic16); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic16);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_8bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x8 = 0;
|
||||
g_atomic8 = heap_caps_calloc(sizeof(*g_atomic8), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x8 += atomic_fetch_or(g_atomic8, 0x11);
|
||||
x8 += atomic_fetch_xor(g_atomic8, 0x33);
|
||||
x8 += atomic_fetch_and(g_atomic8, 0xf0);
|
||||
x8 += atomic_fetch_sub(g_atomic8, 0x0f);
|
||||
x8 += atomic_fetch_add(g_atomic8, 0x22);
|
||||
#ifndef __clang__
|
||||
x8 += __atomic_fetch_nand_1(g_atomic8, 0xAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8(0x97, x8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0xDD, *g_atomic8);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_HEX8(0x64, x8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0x33, *g_atomic8); // calls atomic_load
|
||||
#endif
|
||||
free(g_atomic8);
|
||||
}
|
||||
|
||||
#ifndef __clang__
|
||||
TEST_CASE("stdatomic - test_64bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned long long x64 = 0;
|
||||
g_atomic64 = heap_caps_calloc(sizeof(*g_atomic64), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x64 += __atomic_or_fetch_8(g_atomic64, 0x1111111111111111ULL, 0);
|
||||
x64 += __atomic_xor_fetch_8(g_atomic64, 0x3333333333333333ULL, 0);
|
||||
x64 += __atomic_and_fetch_8(g_atomic64, 0xf0f0f0f0f0f0f0f0ULL, 0);
|
||||
x64 += __atomic_sub_fetch_8(g_atomic64, 0x0f0f0f0f0f0f0f0fULL, 0);
|
||||
x64 += __atomic_add_fetch_8(g_atomic64, 0x2222222222222222ULL, 0);
|
||||
x64 += __atomic_nand_fetch_8(g_atomic64, 0xAAAAAAAAAAAAAAAAULL, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX64(0x7575757575757574ULL, x64);
|
||||
TEST_ASSERT_EQUAL_HEX64(0xDDDDDDDDDDDDDDDDULL, *g_atomic64); // calls atomic_load
|
||||
free(g_atomic64);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_32bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x32 = 0;
|
||||
g_atomic32 = heap_caps_calloc(sizeof(*g_atomic32), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x32 += __atomic_or_fetch_4(g_atomic32, 0x11111111U, 0);
|
||||
x32 += __atomic_xor_fetch_4(g_atomic32, 0x33333333U, 0);
|
||||
x32 += __atomic_and_fetch_4(g_atomic32, 0xf0f0f0f0U, 0);
|
||||
x32 += __atomic_sub_fetch_4(g_atomic32, 0x0f0f0f0fU, 0);
|
||||
x32 += __atomic_add_fetch_4(g_atomic32, 0x22222222U, 0);
|
||||
x32 += __atomic_nand_fetch_4(g_atomic32, 0xAAAAAAAAU, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX32(0x75757574U, x32);
|
||||
TEST_ASSERT_EQUAL_HEX32(0xDDDDDDDDU, *g_atomic32);
|
||||
free(g_atomic32);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_16bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x16 = 0;
|
||||
g_atomic16 = heap_caps_calloc(sizeof(*g_atomic16), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x16 += __atomic_or_fetch_2(g_atomic16, 0x1111, 0);
|
||||
x16 += __atomic_xor_fetch_2(g_atomic16, 0x3333, 0);
|
||||
x16 += __atomic_and_fetch_2(g_atomic16, 0xf0f0, 0);
|
||||
x16 += __atomic_sub_fetch_2(g_atomic16, 0x0f0f, 0);
|
||||
x16 += __atomic_add_fetch_2(g_atomic16, 0x2222, 0);
|
||||
x16 += __atomic_nand_fetch_2(g_atomic16, 0xAAAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX16(0x7574, x16);
|
||||
TEST_ASSERT_EQUAL_HEX16(0xDDDD, *g_atomic16);
|
||||
free(g_atomic16);
|
||||
}
|
||||
|
||||
TEST_CASE("stdatomic - test_8bit_atomics", "[newlib_stdatomic]")
|
||||
{
|
||||
unsigned int x8 = 0;
|
||||
g_atomic8 = heap_caps_calloc(sizeof(*g_atomic8), 1, MALLOC_CAP_DEFAULT);
|
||||
|
||||
x8 += __atomic_or_fetch_1(g_atomic8, 0x11, 0);
|
||||
x8 += __atomic_xor_fetch_1(g_atomic8, 0x33, 0);
|
||||
x8 += __atomic_and_fetch_1(g_atomic8, 0xf0, 0);
|
||||
x8 += __atomic_sub_fetch_1(g_atomic8, 0x0f, 0);
|
||||
x8 += __atomic_add_fetch_1(g_atomic8, 0x22, 0);
|
||||
x8 += __atomic_nand_fetch_1(g_atomic8, 0xAA, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8(0x74, x8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0xDD, *g_atomic8);
|
||||
free(g_atomic8);
|
||||
}
|
||||
|
||||
#endif // #ifndef __clang__
|
||||
|
||||
#define TEST_EXCLUSION(n, POSTFIX) TEST_CASE("stdatomic - test_" #n #POSTFIX "bit_exclusion", "[newlib_stdatomic]") \
|
||||
{ \
|
||||
g_atomic ## n = heap_caps_calloc(sizeof(*g_atomic ## n), 1, MALLOC_CAP_ATOMIC); \
|
||||
pthread_t thread1; \
|
||||
pthread_t thread2; \
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); \
|
||||
cfg.pin_to_core = (xPortGetCoreID() + 1) % portNUM_PROCESSORS; \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create(&thread1, NULL, exclusion_task_ ##n ##POSTFIX, (void*) 1); \
|
||||
cfg.pin_to_core = xPortGetCoreID(); \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create(&thread2, NULL, exclusion_task_ ##n ##POSTFIX, (void*) 0); \
|
||||
pthread_join(thread1, NULL); \
|
||||
pthread_join(thread2, NULL); \
|
||||
TEST_ASSERT_EQUAL(0, (*g_atomic ## n)); \
|
||||
free(g_atomic ## n); \
|
||||
}
|
||||
|
||||
#define TEST_EXCLUSION_TASK(n, POSTFIX) static void* exclusion_task_ ##n ##POSTFIX(void *varg) \
|
||||
{ \
|
||||
int arg = (int) varg; \
|
||||
for (int i = 0; i < 1000000; ++i) { \
|
||||
if (arg == 0) { \
|
||||
atomic_fetch_add(g_atomic ## n, 1ULL); \
|
||||
} else { \
|
||||
atomic_fetch_sub(g_atomic ## n, 1ULL); \
|
||||
} \
|
||||
} \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
TEST_EXCLUSION_TASK(64, _default_mem)
|
||||
TEST_EXCLUSION(64, _default_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(32, _default_mem)
|
||||
TEST_EXCLUSION(32, _default_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(16, _default_mem)
|
||||
TEST_EXCLUSION(16, _default_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(8, _default_mem)
|
||||
TEST_EXCLUSION(8, _default_mem)
|
||||
|
||||
#define ITER_COUNT 20000
|
||||
|
||||
#define TEST_RACE_OPERATION(ASSERT_SUFFIX, NAME, LHSTYPE, PRE, POST, INIT, FINAL) \
|
||||
\
|
||||
static _Atomic LHSTYPE *var_##NAME; \
|
||||
\
|
||||
static void *test_thread_##NAME (void *arg) \
|
||||
{ \
|
||||
for (int i = 0; i < ITER_COUNT; i++) \
|
||||
{ \
|
||||
PRE (*var_##NAME) POST; \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
TEST_CASE("stdatomic - test_" #NAME, "[newlib_stdatomic]") \
|
||||
{ \
|
||||
pthread_t thread_id1; \
|
||||
pthread_t thread_id2; \
|
||||
var_##NAME = heap_caps_calloc(sizeof(*var_##NAME), 1, MALLOC_CAP_ATOMIC); \
|
||||
*var_##NAME = (INIT); \
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); \
|
||||
cfg.pin_to_core = (xPortGetCoreID() + 1) % CONFIG_FREERTOS_NUMBER_OF_CORES; \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id1, NULL, test_thread_##NAME, NULL); \
|
||||
cfg.pin_to_core = xPortGetCoreID(); \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id2, NULL, test_thread_##NAME, NULL); \
|
||||
pthread_join (thread_id1, NULL); \
|
||||
pthread_join (thread_id2, NULL); \
|
||||
TEST_ASSERT_EQUAL##ASSERT_SUFFIX((FINAL), (*var_##NAME)); \
|
||||
free(var_##NAME); \
|
||||
}
|
||||
|
||||
// Note that the assert at the end is doing an excat bitwise comparison.
|
||||
// This easily can fail due to rounding errors. However, there is currently
|
||||
// no corresponding Unity assert macro for long double. USE THIS WITH CARE!
|
||||
#define TEST_RACE_OPERATION_LONG_DOUBLE(NAME, LHSTYPE, PRE, POST, INIT, FINAL) \
|
||||
\
|
||||
static _Atomic LHSTYPE *var_##NAME; \
|
||||
\
|
||||
static void *test_thread_##NAME (void *arg) \
|
||||
{ \
|
||||
for (int i = 0; i < ITER_COUNT; i++) \
|
||||
{ \
|
||||
PRE (*var_##NAME) POST; \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
TEST_CASE("stdatomic - test_" #NAME, "[newlib_stdatomic]") \
|
||||
{ \
|
||||
pthread_t thread_id1; \
|
||||
pthread_t thread_id2; \
|
||||
var_##NAME = heap_caps_calloc(sizeof(*var_##NAME), 1, MALLOC_CAP_ATOMIC); \
|
||||
*var_##NAME = (INIT); \
|
||||
const LHSTYPE EXPECTED = (FINAL); \
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); \
|
||||
cfg.pin_to_core = (xPortGetCoreID() + 1) % CONFIG_FREERTOS_NUMBER_OF_CORES; \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id1, NULL, test_thread_##NAME, NULL); \
|
||||
cfg.pin_to_core = xPortGetCoreID(); \
|
||||
esp_pthread_set_cfg(&cfg); \
|
||||
pthread_create (&thread_id2, NULL, test_thread_##NAME, NULL); \
|
||||
pthread_join (thread_id1, NULL); \
|
||||
pthread_join (thread_id2, NULL); \
|
||||
TEST_ASSERT(EXPECTED == (*var_##NAME)); \
|
||||
free(var_##NAME); \
|
||||
}
|
||||
|
||||
TEST_RACE_OPERATION(, uint8_add, uint8_t,, += 1, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_add_3, uint8_t,, += 3, 0, (uint8_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postinc, uint8_t,, ++, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_preinc, uint8_t, ++,, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub, uint8_t,, -= 1, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub_3, uint8_t,, -= 3, 0, (uint8_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postdec, uint8_t,, --, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_predec, uint8_t, --,, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_mul, uint8_t,, *= 3, 1, (uint8_t) 0x1)
|
||||
|
||||
TEST_RACE_OPERATION(, uint16_add, uint16_t,, += 1, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_add_3, uint16_t,, += 3, 0, (uint16_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postinc, uint16_t,, ++, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_preinc, uint16_t, ++,, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub, uint16_t,, -= 1, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub_3, uint16_t,, -= 3, 0, (uint16_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postdec, uint16_t,, --, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_predec, uint16_t, --,, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_mul, uint16_t,, *= 3, 1, (uint16_t) 0x6D01)
|
||||
|
||||
TEST_RACE_OPERATION(, uint32_add, uint32_t,, += 1, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_add_3, uint32_t,, += 3, 0, (uint32_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postinc, uint32_t,, ++, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_preinc, uint32_t, ++,, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub, uint32_t,, -= 1, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub_3, uint32_t,, -= 3, 0, (uint32_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postdec, uint32_t,, --, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_predec, uint32_t, --,, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_mul, uint32_t,, *= 3, 1, (uint32_t) 0xC1E36D01U)
|
||||
|
||||
TEST_RACE_OPERATION(, uint64_add, uint64_t,, += 1, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_3, uint64_t,, += 3, 0, (uint64_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_neg, uint64_t,, += 1, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postinc, uint64_t,, ++, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postinc_neg, uint64_t,, ++, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_preinc, uint64_t, ++,, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_preinc_neg, uint64_t, ++,, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_sub, uint64_t,, -= 1, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_3, uint64_t,, -= 3, 0, (uint64_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_neg, uint64_t,, -= 1, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postdec, uint64_t,, --, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postdec_neg, uint64_t,, --, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_predec, uint64_t, --,, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_predec_neg, uint64_t, --,, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_mul, uint64_t,, *= 3, 1, (uint64_t) 0x988EE974C1E36D01ULL)
|
||||
|
||||
TEST_RACE_OPERATION(_FLOAT, float_add, float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_add, _Complex float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postinc, float,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_preinc, float, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_sub, float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_sub, _Complex float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postdec, float,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_predec, float, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_add, double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_add, _Complex double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postinc, double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_preinc, double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_sub, double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_sub, _Complex double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postdec, double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_predec, double, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_add, long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_add, _Complex long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postinc, long double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_sub, long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_preinc, long double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_sub, _Complex long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postdec, long double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_predec, long double, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
#if CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
#undef MALLOC_CAP_ATOMIC
|
||||
#define MALLOC_CAP_ATOMIC MALLOC_CAP_SPIRAM
|
||||
|
||||
TEST_EXCLUSION_TASK(64, _ext_mem)
|
||||
TEST_EXCLUSION(64, _ext_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(32, _ext_mem)
|
||||
TEST_EXCLUSION(32, _ext_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(16, _ext_mem)
|
||||
TEST_EXCLUSION(16, _ext_mem)
|
||||
|
||||
TEST_EXCLUSION_TASK(8, _ext_mem)
|
||||
TEST_EXCLUSION(8, _ext_mem)
|
||||
|
||||
TEST_RACE_OPERATION(, uint8_add_ext, uint8_t,, += 1, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_add_3_ext, uint8_t,, += 3, 0, (uint8_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postinc_ext, uint8_t,, ++, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_preinc_ext, uint8_t, ++,, 0, (uint8_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub_ext, uint8_t,, -= 1, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_sub_3_ext, uint8_t,, -= 3, 0, (uint8_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_postdec_ext, uint8_t,, --, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_predec_ext, uint8_t, --,, 0, (uint8_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint8_mul_ext, uint8_t,, *= 3, 1, (uint8_t) 0x1)
|
||||
|
||||
TEST_RACE_OPERATION(, uint16_add_ext, uint16_t,, += 1, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_add_3_ext, uint16_t,, += 3, 0, (uint16_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postinc_ext, uint16_t,, ++, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_preinc_ext, uint16_t, ++,, 0, (uint16_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub_ext, uint16_t,, -= 1, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_sub_3_ext, uint16_t,, -= 3, 0, (uint16_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_postdec_ext, uint16_t,, --, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_predec_ext, uint16_t, --,, 0, (uint16_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint16_mul_ext, uint16_t,, *= 3, 1, (uint16_t) 0x6D01)
|
||||
|
||||
TEST_RACE_OPERATION(, uint32_add_ext, uint32_t,, += 1, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_add_3_ext, uint32_t,, += 3, 0, (uint32_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postinc_ext, uint32_t,, ++, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_preinc_ext, uint32_t, ++,, 0, (uint32_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub_ext, uint32_t,, -= 1, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_sub_3_ext, uint32_t,, -= 3, 0, (uint32_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_postdec_ext, uint32_t,, --, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_predec_ext, uint32_t, --,, 0, (uint32_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint32_mul_ext, uint32_t,, *= 3, 1, (uint32_t) 0xC1E36D01U)
|
||||
|
||||
TEST_RACE_OPERATION(, uint64_add_ext, uint64_t,, += 1, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_3_ext, uint64_t,, += 3, 0, (uint64_t)(6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_add_neg_ext, uint64_t,, += 1, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postinc_ext, uint64_t,, ++, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postinc_neg_ext, uint64_t,, ++, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_preinc_ext, uint64_t, ++,, 0, (uint64_t)(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_preinc_neg_ext, uint64_t, ++,, -10000, (uint64_t)(2 * ITER_COUNT - 10000))
|
||||
TEST_RACE_OPERATION(, uint64_sub_ext, uint64_t,, -= 1, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_3_ext, uint64_t,, -= 3, 0, (uint64_t) - (6 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_sub_neg_ext, uint64_t,, -= 1, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_postdec_ext, uint64_t,, --, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_postdec_neg_ext, uint64_t,, --, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_predec_ext, uint64_t, --,, 0, (uint64_t) - (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(, uint64_predec_neg_ext, uint64_t, --,, 10000, (uint64_t)((-2 * ITER_COUNT) + 10000))
|
||||
TEST_RACE_OPERATION(, uint64_mul_ext, uint64_t,, *= 3, 1, (uint64_t) 0x988EE974C1E36D01ULL)
|
||||
|
||||
TEST_RACE_OPERATION(_FLOAT, float_add_ext, float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_add_ext, _Complex float,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postinc_ext, float,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_preinc_ext, float, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_sub_ext, float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, complex_float_sub_ext, _Complex float,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_postdec_ext, float,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_FLOAT, float_predec_ext, float, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_add_ext, double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_add_ext, _Complex double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postinc_ext, double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_preinc_ext, double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_sub_ext, double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, complex_double_sub_ext, _Complex double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_postdec_ext, double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION(_DOUBLE, double_predec_ext, double, --,, 0, -(2 * ITER_COUNT))
|
||||
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_add_ext, long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_add_ext, _Complex long double,, += 1, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postinc_ext, long double,, ++, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_sub_ext, long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_preinc_ext, long double, ++,, 0, (2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(complex_long_double_sub_ext, _Complex long double,, -= 1, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_postdec_ext, long double,, --, 0, -(2 * ITER_COUNT))
|
||||
TEST_RACE_OPERATION_LONG_DOUBLE(long_double_predec_ext, long double, --,, 0, -(2 * ITER_COUNT))
|
||||
#endif // CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,48 +1,48 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import subprocess
|
||||
from os import path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def validate_sbom(dut: Dut) -> None:
|
||||
dirname = path.dirname(path.abspath(__file__))
|
||||
sbom_file = path.join(path.dirname(path.dirname(dirname)), 'sbom.yml')
|
||||
gcc_input_file = path.join(dirname, 'test_sbom', 'newlib_version.c')
|
||||
gcc = 'riscv32-esp-elf-gcc'
|
||||
if dut.target in dut.XTENSA_TARGETS:
|
||||
gcc = f'xtensa-{dut.target}-elf-gcc'
|
||||
gcc_process = subprocess.run(f'{gcc} -E {gcc_input_file}',
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True)
|
||||
output_lines = gcc_process.stdout.splitlines()
|
||||
assert output_lines, 'Can not get newlib version'
|
||||
toolchain_newlib_version = output_lines[-1].replace(' ', '.')
|
||||
with open(sbom_file, 'r', encoding='utf-8') as yaml_file:
|
||||
sbom_newlib_version = yaml.safe_load(yaml_file).get('version')
|
||||
assert sbom_newlib_version, 'Can not get newlib version from sbom.yml'
|
||||
assert toolchain_newlib_version == sbom_newlib_version, 'toolchain_newlib_version != sbom_newlib_version'
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
pytest.param('default', marks=[pytest.mark.supported_targets]),
|
||||
pytest.param('options', marks=[pytest.mark.supported_targets]),
|
||||
pytest.param('single_core_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('psram_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('release_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('release_esp32c2', marks=[pytest.mark.esp32c2]),
|
||||
],
|
||||
indirect=True
|
||||
)
|
||||
def test_newlib(dut: Dut) -> None:
|
||||
validate_sbom(dut)
|
||||
dut.run_all_single_board_cases()
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import subprocess
|
||||
from os import path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def validate_sbom(dut: Dut) -> None:
|
||||
dirname = path.dirname(path.abspath(__file__))
|
||||
sbom_file = path.join(path.dirname(path.dirname(dirname)), 'sbom.yml')
|
||||
gcc_input_file = path.join(dirname, 'test_sbom', 'newlib_version.c')
|
||||
gcc = 'riscv32-esp-elf-gcc'
|
||||
if dut.target in dut.XTENSA_TARGETS:
|
||||
gcc = f'xtensa-{dut.target}-elf-gcc'
|
||||
gcc_process = subprocess.run(f'{gcc} -E {gcc_input_file}',
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True)
|
||||
output_lines = gcc_process.stdout.splitlines()
|
||||
assert output_lines, 'Can not get newlib version'
|
||||
toolchain_newlib_version = output_lines[-1].replace(' ', '.')
|
||||
with open(sbom_file, 'r', encoding='utf-8') as yaml_file:
|
||||
sbom_newlib_version = yaml.safe_load(yaml_file).get('version')
|
||||
assert sbom_newlib_version, 'Can not get newlib version from sbom.yml'
|
||||
assert toolchain_newlib_version == sbom_newlib_version, 'toolchain_newlib_version != sbom_newlib_version'
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
pytest.param('default', marks=[pytest.mark.supported_targets]),
|
||||
pytest.param('options', marks=[pytest.mark.supported_targets]),
|
||||
pytest.param('single_core_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('psram_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('release_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('release_esp32c2', marks=[pytest.mark.esp32c2]),
|
||||
],
|
||||
indirect=True
|
||||
)
|
||||
def test_newlib(dut: Dut) -> None:
|
||||
validate_sbom(dut)
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Test all chips with nano off, nano on is tested in options config
|
||||
CONFIG_NEWLIB_NANO_FORMAT=n
|
||||
# Test all chips with nano off, nano on is tested in options config
|
||||
CONFIG_NEWLIB_NANO_FORMAT=n
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Test with misc newlib config options turned on
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
# Test with misc newlib config options turned on
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_SPIRAM=y
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
||||
# C2 specific moved from old C2 default config
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE=n
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT=y
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC=n
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=n
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
||||
# C2 specific moved from old C2 default config
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE=n
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT=y
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC=n
|
||||
CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=n
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
# IDF-6964 test nano format in this configuration (current tests are not passing, so keep disabled for now)
|
||||
CONFIG_NEWLIB_NANO_FORMAT=n
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
# IDF-6964 test nano format in this configuration (current tests are not passing, so keep disabled for now)
|
||||
CONFIG_NEWLIB_NANO_FORMAT=n
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# certain 64-bit related asserts need this option to be enabled in unity in order to work correctly
|
||||
CONFIG_UNITY_ENABLE_64BIT=y
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
|
||||
CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
|
||||
# certain 64-bit related asserts need this option to be enabled in unity in order to work correctly
|
||||
CONFIG_UNITY_ENABLE_64BIT=y
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
|
||||
CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <_newlib_version.h>
|
||||
__NEWLIB__ __NEWLIB_MINOR__ __NEWLIB_PATCHLEVEL__
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <_newlib_version.h>
|
||||
__NEWLIB__ __NEWLIB_MINOR__ __NEWLIB_PATCHLEVEL__
|
||||
|
||||
+298
-298
@@ -1,298 +1,298 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <reent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/reent.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_private/system_internal.h"
|
||||
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#include "esp_time_impl.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !CONFIG_ESP_TIME_FUNCS_USE_NONE
|
||||
#define IMPL_NEWLIB_TIME_FUNCS 1
|
||||
#endif
|
||||
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
// time functions are implemented -- they should not be weak
|
||||
#define WEAK_UNLESS_TIMEFUNC_IMPL
|
||||
|
||||
// stores the start time of the slew
|
||||
static uint64_t s_adjtime_start_us;
|
||||
// is how many microseconds total to slew
|
||||
static int64_t s_adjtime_total_correction_us;
|
||||
|
||||
static _lock_t s_time_lock;
|
||||
|
||||
// This function gradually changes boot_time to the correction value and immediately updates it.
|
||||
static uint64_t adjust_boot_time(void)
|
||||
{
|
||||
#define ADJTIME_CORRECTION_FACTOR 6
|
||||
|
||||
uint64_t boot_time = esp_time_impl_get_boot_time();
|
||||
if ((boot_time == 0) || (esp_time_impl_get_time_since_boot() < s_adjtime_start_us)) {
|
||||
s_adjtime_start_us = 0;
|
||||
}
|
||||
if (s_adjtime_start_us > 0) {
|
||||
uint64_t since_boot = esp_time_impl_get_time_since_boot();
|
||||
// If to call this function once per second, then (since_boot - s_adjtime_start_us) will be 1_000_000 (1 second),
|
||||
// and the correction will be equal to (1_000_000us >> 6) = 15_625 us.
|
||||
// The minimum possible correction step can be (64us >> 6) = 1us.
|
||||
// Example: if the time error is 1 second, then it will be compensate for 1 sec / 0,015625 = 64 seconds.
|
||||
int64_t correction = (since_boot >> ADJTIME_CORRECTION_FACTOR) - (s_adjtime_start_us >> ADJTIME_CORRECTION_FACTOR);
|
||||
if (correction > 0) {
|
||||
s_adjtime_start_us = since_boot;
|
||||
if (s_adjtime_total_correction_us < 0) {
|
||||
if ((s_adjtime_total_correction_us + correction) >= 0) {
|
||||
boot_time = boot_time + s_adjtime_total_correction_us;
|
||||
s_adjtime_start_us = 0;
|
||||
} else {
|
||||
s_adjtime_total_correction_us += correction;
|
||||
boot_time -= correction;
|
||||
}
|
||||
} else {
|
||||
if ((s_adjtime_total_correction_us - correction) <= 0) {
|
||||
boot_time = boot_time + s_adjtime_total_correction_us;
|
||||
s_adjtime_start_us = 0;
|
||||
} else {
|
||||
s_adjtime_total_correction_us -= correction;
|
||||
boot_time += correction;
|
||||
}
|
||||
}
|
||||
esp_time_impl_set_boot_time(boot_time);
|
||||
}
|
||||
}
|
||||
return boot_time;
|
||||
}
|
||||
|
||||
// Get the adjusted boot time.
|
||||
static uint64_t get_adjusted_boot_time(void)
|
||||
{
|
||||
_lock_acquire(&s_time_lock);
|
||||
uint64_t adjust_time = adjust_boot_time();
|
||||
_lock_release(&s_time_lock);
|
||||
return adjust_time;
|
||||
}
|
||||
|
||||
// Applying the accumulated correction to base_time and stopping the smooth time adjustment.
|
||||
static void adjtime_corr_stop(void)
|
||||
{
|
||||
_lock_acquire(&s_time_lock);
|
||||
if (s_adjtime_start_us != 0) {
|
||||
adjust_boot_time();
|
||||
s_adjtime_start_us = 0;
|
||||
}
|
||||
_lock_release(&s_time_lock);
|
||||
}
|
||||
#else
|
||||
|
||||
// no time functions are actually implemented -- allow users to override them
|
||||
#define WEAK_UNLESS_TIMEFUNC_IMPL __attribute__((weak))
|
||||
#endif
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int adjtime(const struct timeval *delta, struct timeval *outdelta)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (outdelta != NULL) {
|
||||
_lock_acquire(&s_time_lock);
|
||||
adjust_boot_time();
|
||||
if (s_adjtime_start_us != 0) {
|
||||
outdelta->tv_sec = s_adjtime_total_correction_us / 1000000L;
|
||||
outdelta->tv_usec = s_adjtime_total_correction_us % 1000000L;
|
||||
} else {
|
||||
outdelta->tv_sec = 0;
|
||||
outdelta->tv_usec = 0;
|
||||
}
|
||||
_lock_release(&s_time_lock);
|
||||
}
|
||||
if (delta != NULL) {
|
||||
int64_t sec = delta->tv_sec;
|
||||
int64_t usec = delta->tv_usec;
|
||||
if (llabs(sec) > ((INT_MAX / 1000000L) - 1L)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* If adjusting the system clock by adjtime () is already done during the second call adjtime (),
|
||||
* and the delta of the second call is not NULL, the earlier tuning is stopped,
|
||||
* but the already completed part of the adjustment is not canceled.
|
||||
*/
|
||||
_lock_acquire(&s_time_lock);
|
||||
// If correction is already in progress (s_adjtime_start_time_us != 0), then apply accumulated corrections.
|
||||
adjust_boot_time();
|
||||
s_adjtime_start_us = esp_time_impl_get_time_since_boot();
|
||||
s_adjtime_total_correction_us = sec * 1000000L + usec;
|
||||
_lock_release(&s_time_lock);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms)
|
||||
{
|
||||
clock_t t = xTaskGetTickCount() * (portTICK_PERIOD_MS * CLK_TCK / 1000);
|
||||
ptms->tms_cstime = 0;
|
||||
ptms->tms_cutime = 0;
|
||||
ptms->tms_stime = t;
|
||||
ptms->tms_utime = 0;
|
||||
struct timeval tv = {0, 0};
|
||||
_gettimeofday_r(r, &tv, NULL);
|
||||
return (clock_t) tv.tv_sec;
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
|
||||
{
|
||||
(void) tz;
|
||||
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tv) {
|
||||
uint64_t microseconds = get_adjusted_boot_time() + esp_time_impl_get_time_since_boot();
|
||||
tv->tv_sec = microseconds / 1000000;
|
||||
tv->tv_usec = microseconds % 1000000;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
__errno_r(r) = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int settimeofday(const struct timeval *tv, const struct timezone *tz)
|
||||
{
|
||||
(void) tz;
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tv) {
|
||||
adjtime_corr_stop();
|
||||
uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec;
|
||||
uint64_t since_boot = esp_time_impl_get_time_since_boot();
|
||||
esp_time_impl_set_boot_time(now - since_boot);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int usleep(useconds_t us)
|
||||
{
|
||||
const int us_per_tick = portTICK_PERIOD_MS * 1000;
|
||||
if (us < us_per_tick) {
|
||||
esp_rom_delay_us((uint32_t) us);
|
||||
} else {
|
||||
/* since vTaskDelay(1) blocks for anywhere between 0 and portTICK_PERIOD_MS,
|
||||
* round up to compensate.
|
||||
*/
|
||||
vTaskDelay((us + us_per_tick - 1) / us_per_tick);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
usleep(seconds * 1000000UL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int clock_settime(clockid_t clock_id, const struct timespec *tp)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tp == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
struct timeval tv;
|
||||
switch (clock_id) {
|
||||
case CLOCK_REALTIME:
|
||||
tv.tv_sec = tp->tv_sec;
|
||||
tv.tv_usec = tp->tv_nsec / 1000L;
|
||||
settimeofday(&tv, NULL);
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int clock_gettime(clockid_t clock_id, struct timespec *tp)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tp == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
struct timeval tv;
|
||||
uint64_t monotonic_time_us = 0;
|
||||
switch (clock_id) {
|
||||
case CLOCK_REALTIME:
|
||||
_gettimeofday_r(NULL, &tv, NULL);
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_nsec = tv.tv_usec * 1000L;
|
||||
break;
|
||||
case CLOCK_MONOTONIC:
|
||||
monotonic_time_us = esp_time_impl_get_time();
|
||||
tp->tv_sec = monotonic_time_us / 1000000LL;
|
||||
tp->tv_nsec = (monotonic_time_us % 1000000LL) * 1000L;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int clock_getres(clockid_t clock_id, struct timespec *res)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (res == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res->tv_sec = 0;
|
||||
res->tv_nsec = esp_system_get_time_resolution();
|
||||
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_newlib_time_init(void)
|
||||
{
|
||||
esp_time_impl_init();
|
||||
}
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <reent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/reent.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_private/system_internal.h"
|
||||
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#include "esp_time_impl.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !CONFIG_ESP_TIME_FUNCS_USE_NONE
|
||||
#define IMPL_NEWLIB_TIME_FUNCS 1
|
||||
#endif
|
||||
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
// time functions are implemented -- they should not be weak
|
||||
#define WEAK_UNLESS_TIMEFUNC_IMPL
|
||||
|
||||
// stores the start time of the slew
|
||||
static uint64_t s_adjtime_start_us;
|
||||
// is how many microseconds total to slew
|
||||
static int64_t s_adjtime_total_correction_us;
|
||||
|
||||
static _lock_t s_time_lock;
|
||||
|
||||
// This function gradually changes boot_time to the correction value and immediately updates it.
|
||||
static uint64_t adjust_boot_time(void)
|
||||
{
|
||||
#define ADJTIME_CORRECTION_FACTOR 6
|
||||
|
||||
uint64_t boot_time = esp_time_impl_get_boot_time();
|
||||
if ((boot_time == 0) || (esp_time_impl_get_time_since_boot() < s_adjtime_start_us)) {
|
||||
s_adjtime_start_us = 0;
|
||||
}
|
||||
if (s_adjtime_start_us > 0) {
|
||||
uint64_t since_boot = esp_time_impl_get_time_since_boot();
|
||||
// If to call this function once per second, then (since_boot - s_adjtime_start_us) will be 1_000_000 (1 second),
|
||||
// and the correction will be equal to (1_000_000us >> 6) = 15_625 us.
|
||||
// The minimum possible correction step can be (64us >> 6) = 1us.
|
||||
// Example: if the time error is 1 second, then it will be compensate for 1 sec / 0,015625 = 64 seconds.
|
||||
int64_t correction = (since_boot >> ADJTIME_CORRECTION_FACTOR) - (s_adjtime_start_us >> ADJTIME_CORRECTION_FACTOR);
|
||||
if (correction > 0) {
|
||||
s_adjtime_start_us = since_boot;
|
||||
if (s_adjtime_total_correction_us < 0) {
|
||||
if ((s_adjtime_total_correction_us + correction) >= 0) {
|
||||
boot_time = boot_time + s_adjtime_total_correction_us;
|
||||
s_adjtime_start_us = 0;
|
||||
} else {
|
||||
s_adjtime_total_correction_us += correction;
|
||||
boot_time -= correction;
|
||||
}
|
||||
} else {
|
||||
if ((s_adjtime_total_correction_us - correction) <= 0) {
|
||||
boot_time = boot_time + s_adjtime_total_correction_us;
|
||||
s_adjtime_start_us = 0;
|
||||
} else {
|
||||
s_adjtime_total_correction_us -= correction;
|
||||
boot_time += correction;
|
||||
}
|
||||
}
|
||||
esp_time_impl_set_boot_time(boot_time);
|
||||
}
|
||||
}
|
||||
return boot_time;
|
||||
}
|
||||
|
||||
// Get the adjusted boot time.
|
||||
static uint64_t get_adjusted_boot_time(void)
|
||||
{
|
||||
_lock_acquire(&s_time_lock);
|
||||
uint64_t adjust_time = adjust_boot_time();
|
||||
_lock_release(&s_time_lock);
|
||||
return adjust_time;
|
||||
}
|
||||
|
||||
// Applying the accumulated correction to base_time and stopping the smooth time adjustment.
|
||||
static void adjtime_corr_stop(void)
|
||||
{
|
||||
_lock_acquire(&s_time_lock);
|
||||
if (s_adjtime_start_us != 0) {
|
||||
adjust_boot_time();
|
||||
s_adjtime_start_us = 0;
|
||||
}
|
||||
_lock_release(&s_time_lock);
|
||||
}
|
||||
#else
|
||||
|
||||
// no time functions are actually implemented -- allow users to override them
|
||||
#define WEAK_UNLESS_TIMEFUNC_IMPL __attribute__((weak))
|
||||
#endif
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int adjtime(const struct timeval *delta, struct timeval *outdelta)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (outdelta != NULL) {
|
||||
_lock_acquire(&s_time_lock);
|
||||
adjust_boot_time();
|
||||
if (s_adjtime_start_us != 0) {
|
||||
outdelta->tv_sec = s_adjtime_total_correction_us / 1000000L;
|
||||
outdelta->tv_usec = s_adjtime_total_correction_us % 1000000L;
|
||||
} else {
|
||||
outdelta->tv_sec = 0;
|
||||
outdelta->tv_usec = 0;
|
||||
}
|
||||
_lock_release(&s_time_lock);
|
||||
}
|
||||
if (delta != NULL) {
|
||||
int64_t sec = delta->tv_sec;
|
||||
int64_t usec = delta->tv_usec;
|
||||
if (llabs(sec) > ((INT_MAX / 1000000L) - 1L)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* If adjusting the system clock by adjtime () is already done during the second call adjtime (),
|
||||
* and the delta of the second call is not NULL, the earlier tuning is stopped,
|
||||
* but the already completed part of the adjustment is not canceled.
|
||||
*/
|
||||
_lock_acquire(&s_time_lock);
|
||||
// If correction is already in progress (s_adjtime_start_time_us != 0), then apply accumulated corrections.
|
||||
adjust_boot_time();
|
||||
s_adjtime_start_us = esp_time_impl_get_time_since_boot();
|
||||
s_adjtime_total_correction_us = sec * 1000000L + usec;
|
||||
_lock_release(&s_time_lock);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms)
|
||||
{
|
||||
clock_t t = xTaskGetTickCount() * (portTICK_PERIOD_MS * CLK_TCK / 1000);
|
||||
ptms->tms_cstime = 0;
|
||||
ptms->tms_cutime = 0;
|
||||
ptms->tms_stime = t;
|
||||
ptms->tms_utime = 0;
|
||||
struct timeval tv = {0, 0};
|
||||
_gettimeofday_r(r, &tv, NULL);
|
||||
return (clock_t) tv.tv_sec;
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
|
||||
{
|
||||
(void) tz;
|
||||
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tv) {
|
||||
uint64_t microseconds = get_adjusted_boot_time() + esp_time_impl_get_time_since_boot();
|
||||
tv->tv_sec = microseconds / 1000000;
|
||||
tv->tv_usec = microseconds % 1000000;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
__errno_r(r) = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int settimeofday(const struct timeval *tv, const struct timezone *tz)
|
||||
{
|
||||
(void) tz;
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tv) {
|
||||
adjtime_corr_stop();
|
||||
uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec;
|
||||
uint64_t since_boot = esp_time_impl_get_time_since_boot();
|
||||
esp_time_impl_set_boot_time(now - since_boot);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int usleep(useconds_t us)
|
||||
{
|
||||
const int us_per_tick = portTICK_PERIOD_MS * 1000;
|
||||
if (us < us_per_tick) {
|
||||
esp_rom_delay_us((uint32_t) us);
|
||||
} else {
|
||||
/* since vTaskDelay(1) blocks for anywhere between 0 and portTICK_PERIOD_MS,
|
||||
* round up to compensate.
|
||||
*/
|
||||
vTaskDelay((us + us_per_tick - 1) / us_per_tick);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
usleep(seconds * 1000000UL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int clock_settime(clockid_t clock_id, const struct timespec *tp)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tp == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
struct timeval tv;
|
||||
switch (clock_id) {
|
||||
case CLOCK_REALTIME:
|
||||
tv.tv_sec = tp->tv_sec;
|
||||
tv.tv_usec = tp->tv_nsec / 1000L;
|
||||
settimeofday(&tv, NULL);
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int clock_gettime(clockid_t clock_id, struct timespec *tp)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (tp == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
struct timeval tv;
|
||||
uint64_t monotonic_time_us = 0;
|
||||
switch (clock_id) {
|
||||
case CLOCK_REALTIME:
|
||||
_gettimeofday_r(NULL, &tv, NULL);
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_nsec = tv.tv_usec * 1000L;
|
||||
break;
|
||||
case CLOCK_MONOTONIC:
|
||||
monotonic_time_us = esp_time_impl_get_time();
|
||||
tp->tv_sec = monotonic_time_us / 1000000LL;
|
||||
tp->tv_nsec = (monotonic_time_us % 1000000LL) * 1000L;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
WEAK_UNLESS_TIMEFUNC_IMPL int clock_getres(clockid_t clock_id, struct timespec *res)
|
||||
{
|
||||
#if IMPL_NEWLIB_TIME_FUNCS
|
||||
if (res == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res->tv_sec = 0;
|
||||
res->tv_nsec = esp_system_get_time_resolution();
|
||||
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_newlib_time_init(void)
|
||||
{
|
||||
esp_time_impl_init();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user