initial commit

This commit is contained in:
2024-08-18 02:50:11 -06:00
commit c6f61bffb0
144 changed files with 19082 additions and 0 deletions
@@ -0,0 +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
@@ -0,0 +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)
+2
View File
@@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
@@ -0,0 +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)
@@ -0,0 +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();
}
@@ -0,0 +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);
}
@@ -0,0 +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"));
}
@@ -0,0 +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
@@ -0,0 +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");
}
@@ -0,0 +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);
}
@@ -0,0 +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
@@ -0,0 +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);
}
@@ -0,0 +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
@@ -0,0 +1,672 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "unity.h"
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "sdkconfig.h"
#include "soc/rtc.h"
#include "esp_system.h"
#include "test_utils.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "esp_private/system_internal.h"
#include "esp_private/esp_timer_private.h"
#include "../priv_include/esp_time_impl.h"
#include "esp_private/system_internal.h"
#include "esp_private/esp_clk.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C2
#include "esp32c2/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C61
#include "esp32c61/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32P4
#include "esp32p4/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C5
#include "esp32c5/rtc.h"
#endif
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#include "hal/cache_ll.h"
#endif
#if (CONFIG_FREERTOS_NUMBER_OF_CORES == 2) && CONFIG_IDF_TARGET_ARCH_XTENSA
// https://github.com/espressif/arduino-esp32/issues/120
/* Test for hardware bug, not needed for newer chips */
#include "soc/rtc_cntl_reg.h"
// This runs on APP CPU:
static void time_adc_test_task(void* arg)
{
for (int i = 0; i < 200000; ++i) {
// wait for 20us, reading one of RTC registers
uint32_t ccount = xthal_get_ccount();
while (xthal_get_ccount() - ccount < 20 * CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) {
volatile uint32_t val = REG_READ(RTC_CNTL_STATE0_REG);
(void) val;
}
}
SemaphoreHandle_t * p_done = (SemaphoreHandle_t *) arg;
xSemaphoreGive(*p_done);
vTaskDelay(1);
vTaskDelete(NULL);
}
TEST_CASE("Reading RTC registers on APP CPU doesn't affect clock", "[newlib]")
{
SemaphoreHandle_t done = xSemaphoreCreateBinary();
xTaskCreatePinnedToCore(&time_adc_test_task, "time_adc", 4096, &done, 5, NULL, 1);
// This runs on PRO CPU:
for (int i = 0; i < 4; ++i) {
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
vTaskDelay(1000 / portTICK_PERIOD_MS);
struct timeval tv_stop;
gettimeofday(&tv_stop, NULL);
float time_sec = tv_stop.tv_sec - tv_start.tv_sec + 1e-6f * (tv_stop.tv_usec - tv_start.tv_usec);
printf("(%d) time taken: %f sec\n", i, time_sec);
TEST_ASSERT_TRUE(fabs(time_sec - 1.0f) < 0.1);
}
TEST_ASSERT_TRUE(xSemaphoreTake(done, 5000 / portTICK_PERIOD_MS));
}
#endif // (CONFIG_FREERTOS_NUMBER_OF_CORES == 2) && CONFIG_IDF_TARGET_ARCH_XTENSA
TEST_CASE("test adjtime function", "[newlib]")
{
struct timeval tv_time;
struct timeval tv_delta;
struct timeval tv_outdelta;
TEST_ASSERT_EQUAL(adjtime(NULL, NULL), 0);
tv_time.tv_sec = 5000;
tv_time.tv_usec = 5000;
TEST_ASSERT_EQUAL(settimeofday(&tv_time, NULL), 0);
tv_outdelta.tv_sec = 5;
tv_outdelta.tv_usec = 5;
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_usec, 0);
tv_delta.tv_sec = INT_MAX / 1000000L;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, &tv_outdelta), -1);
tv_delta.tv_sec = INT_MIN / 1000000L;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, &tv_outdelta), -1);
tv_delta.tv_sec = 0;
tv_delta.tv_usec = -900000;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_usec, 0);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_LESS_THAN(-800000, tv_outdelta.tv_usec);
tv_delta.tv_sec = -4;
tv_delta.tv_usec = -900000;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, NULL), 0);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, -4);
TEST_ASSERT_LESS_THAN(-800000, tv_outdelta.tv_usec);
// after settimeofday() adjtime() is stopped
tv_delta.tv_sec = 15;
tv_delta.tv_usec = 900000;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, -4);
TEST_ASSERT_LESS_THAN(-800000, tv_outdelta.tv_usec);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 15);
TEST_ASSERT_GREATER_OR_EQUAL(800000, tv_outdelta.tv_usec);
TEST_ASSERT_EQUAL(gettimeofday(&tv_time, NULL), 0);
TEST_ASSERT_EQUAL(settimeofday(&tv_time, NULL), 0);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_usec, 0);
// after gettimeofday() adjtime() is not stopped
tv_delta.tv_sec = 15;
tv_delta.tv_usec = 900000;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_usec, 0);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 15);
TEST_ASSERT_GREATER_OR_EQUAL(800000, tv_outdelta.tv_usec);
TEST_ASSERT_EQUAL(gettimeofday(&tv_time, NULL), 0);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 15);
TEST_ASSERT_GREATER_OR_EQUAL(800000, tv_outdelta.tv_usec);
tv_delta.tv_sec = 1;
tv_delta.tv_usec = 0;
TEST_ASSERT_EQUAL(adjtime(&tv_delta, NULL), 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ASSERT_EQUAL(adjtime(NULL, &tv_outdelta), 0);
TEST_ASSERT_EQUAL(tv_outdelta.tv_sec, 0);
// the correction will be equal to (1_000_000us >> 6) = 15_625 us.
TEST_ASSERT_TRUE(1000000L - tv_outdelta.tv_usec >= 15600);
TEST_ASSERT_TRUE(1000000L - tv_outdelta.tv_usec <= 15650);
}
static volatile bool exit_flag;
static void adjtimeTask2(void *pvParameters)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) pvParameters;
struct timeval delta = {.tv_sec = 0, .tv_usec = 0};
struct timeval outdelta;
// although exit flag is set in another task, checking (exit_flag == false) is safe
while (exit_flag == false) {
delta.tv_sec += 1;
delta.tv_usec = 900000;
if (delta.tv_sec >= 2146) {
delta.tv_sec = 1;
}
adjtime(&delta, &outdelta);
}
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
static void timeTask(void *pvParameters)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) pvParameters;
struct timeval tv_time = { .tv_sec = 1520000000, .tv_usec = 900000 };
// although exit flag is set in another task, checking (exit_flag == false) is safe
while (exit_flag == false) {
tv_time.tv_sec += 1;
settimeofday(&tv_time, NULL);
gettimeofday(&tv_time, NULL);
}
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("test for no interlocking adjtime, gettimeofday and settimeofday functions", "[newlib]")
{
TaskHandle_t th[4];
exit_flag = false;
struct timeval tv_time = { .tv_sec = 1520000000, .tv_usec = 900000 };
TEST_ASSERT_EQUAL(settimeofday(&tv_time, NULL), 0);
const int max_tasks = 2;
SemaphoreHandle_t exit_sema[max_tasks];
for (int i = 0; i < max_tasks; ++i) {
exit_sema[i] = xSemaphoreCreateBinary();
}
#ifndef CONFIG_FREERTOS_UNICORE
printf("CPU0 and CPU1. Tasks run: 1 - adjtimeTask, 2 - gettimeofdayTask, 3 - settimeofdayTask \n");
xTaskCreatePinnedToCore(adjtimeTask2, "adjtimeTask2", 2048, &exit_sema[0], UNITY_FREERTOS_PRIORITY - 1, &th[0], 0);
xTaskCreatePinnedToCore(timeTask, "timeTask", 2048, &exit_sema[1], UNITY_FREERTOS_PRIORITY - 1, &th[1], 1);
#else
printf("Only one CPU. Tasks run: 1 - adjtimeTask, 2 - gettimeofdayTask, 3 - settimeofdayTask\n");
xTaskCreate(adjtimeTask2, "adjtimeTask2", 2048, &exit_sema[0], UNITY_FREERTOS_PRIORITY - 1, &th[0]);
xTaskCreate(timeTask, "timeTask", 2048, &exit_sema[1], UNITY_FREERTOS_PRIORITY - 1, &th[1]);
#endif
printf("start wait for 5 seconds\n");
vTaskDelay(5000 / portTICK_PERIOD_MS);
// set exit flag to let thread exit
exit_flag = true;
for (int i = 0; i < max_tasks; ++i) {
if (!xSemaphoreTake(exit_sema[i], 2000 / portTICK_PERIOD_MS)) {
TEST_FAIL_MESSAGE("exit_sema not released by test task");
}
vSemaphoreDelete(exit_sema[i]);
}
}
#ifndef CONFIG_FREERTOS_UNICORE
#define ADJTIME_CORRECTION_FACTOR 6
static int64_t result_adjtime_correction_us[2];
static void get_time_task(void *pvParameters)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) pvParameters;
struct timeval tv_time;
// although exit flag is set in another task, checking (exit_flag == false) is safe
while (exit_flag == false) {
gettimeofday(&tv_time, NULL);
vTaskDelay(1500 / portTICK_PERIOD_MS);
}
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
static void start_measure(int64_t* sys_time, int64_t* real_time)
{
struct timeval tv_time;
// there shouldn't be much time between gettimeofday and esp_timer_get_time
gettimeofday(&tv_time, NULL);
*real_time = esp_timer_get_time();
*sys_time = (int64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec;
}
static int64_t calc_correction(const char* tag, int64_t* sys_time, int64_t* real_time)
{
int64_t dt_real_time_us = real_time[1] - real_time[0];
int64_t dt_sys_time_us = sys_time[1] - sys_time[0];
int64_t calc_correction_us = dt_real_time_us >> ADJTIME_CORRECTION_FACTOR;
int64_t real_correction_us = dt_sys_time_us - dt_real_time_us;
int64_t error_us = calc_correction_us - real_correction_us;
printf("%s: dt_real_time = %lli us, dt_sys_time = %lli us, calc_correction = %lli us, error = %lli us\n",
tag, dt_real_time_us, dt_sys_time_us, calc_correction_us, error_us);
TEST_ASSERT_TRUE(dt_sys_time_us > 0 && dt_real_time_us > 0);
TEST_ASSERT_INT_WITHIN(100, 0, error_us);
return real_correction_us;
}
static void measure_time_task(void *pvParameters)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) pvParameters;
int64_t main_real_time_us[2];
int64_t main_sys_time_us[2];
struct timeval tv_time = {.tv_sec = 1550000000, .tv_usec = 0};
TEST_ASSERT_EQUAL(0, settimeofday(&tv_time, NULL));
struct timeval delta = {.tv_sec = 2000, .tv_usec = 900000};
adjtime(&delta, NULL);
gettimeofday(&tv_time, NULL);
start_measure(&main_sys_time_us[0], &main_real_time_us[0]);
{
int64_t real_time_us[2] = { main_real_time_us[0], 0};
int64_t sys_time_us[2] = { main_sys_time_us[0], 0};
// although exit flag is set in another task, checking (exit_flag == false) is safe
while (exit_flag == false) {
vTaskDelay(2000 / portTICK_PERIOD_MS);
start_measure(&sys_time_us[1], &real_time_us[1]);
result_adjtime_correction_us[1] += calc_correction("measure", sys_time_us, real_time_us);
sys_time_us[0] = sys_time_us[1];
real_time_us[0] = real_time_us[1];
}
main_sys_time_us[1] = sys_time_us[1];
main_real_time_us[1] = real_time_us[1];
}
result_adjtime_correction_us[0] = calc_correction("main", main_sys_time_us, main_real_time_us);
int64_t delta_us = result_adjtime_correction_us[0] - result_adjtime_correction_us[1];
printf("\nresult of adjtime correction: %lli us, %lli us. delta = %lli us\n", result_adjtime_correction_us[0], result_adjtime_correction_us[1], delta_us);
TEST_ASSERT_INT_WITHIN(100, 0, delta_us);
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("test time adjustment happens linearly", "[newlib][timeout=15]")
{
exit_flag = false;
SemaphoreHandle_t exit_sema[2];
for (int i = 0; i < 2; ++i) {
exit_sema[i] = xSemaphoreCreateBinary();
result_adjtime_correction_us[i] = 0;
}
xTaskCreatePinnedToCore(get_time_task, "get_time_task", 4096, &exit_sema[0], UNITY_FREERTOS_PRIORITY - 1, NULL, 0);
xTaskCreatePinnedToCore(measure_time_task, "measure_time_task", 4096, &exit_sema[1], UNITY_FREERTOS_PRIORITY - 1, NULL, 1);
printf("start waiting for 10 seconds\n");
vTaskDelay(10000 / portTICK_PERIOD_MS);
// set exit flag to let thread exit
exit_flag = true;
for (int i = 0; i < 2; ++i) {
if (!xSemaphoreTake(exit_sema[i], 2100 / portTICK_PERIOD_MS)) {
TEST_FAIL_MESSAGE("exit_sema not released by test task");
}
}
for (int i = 0; i < 2; ++i) {
vSemaphoreDelete(exit_sema[i]);
}
}
#endif
void test_posix_timers_clock(void)
{
#ifndef _POSIX_TIMERS
TEST_ASSERT_MESSAGE(false, "_POSIX_TIMERS - is not defined");
#endif
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER )
printf("CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ");
#endif
#if defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
printf("CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER ");
#endif
#ifdef CONFIG_RTC_CLK_SRC_EXT_CRYS
printf("External (crystal) Frequency = %d Hz\n", rtc_clk_slow_freq_get_hz());
#else
printf("Internal Frequency = %" PRIu32 " Hz\n", rtc_clk_slow_freq_get_hz());
#endif
TEST_ASSERT(clock_settime(CLOCK_REALTIME, NULL) == -1);
TEST_ASSERT(clock_gettime(CLOCK_REALTIME, NULL) == -1);
TEST_ASSERT(clock_getres(CLOCK_REALTIME, NULL) == -1);
TEST_ASSERT(clock_settime(CLOCK_MONOTONIC, NULL) == -1);
TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, NULL) == -1);
TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, NULL) == -1);
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
struct timeval now = {0};
now.tv_sec = 10L;
now.tv_usec = 100000L;
TEST_ASSERT(settimeofday(&now, NULL) == 0);
TEST_ASSERT(gettimeofday(&now, NULL) == 0);
struct timespec ts = {0};
TEST_ASSERT(clock_settime(0xFFFFFFFF, &ts) == -1);
TEST_ASSERT(clock_gettime(0xFFFFFFFF, &ts) == -1);
TEST_ASSERT(clock_getres(0xFFFFFFFF, &ts) == 0);
TEST_ASSERT(clock_gettime(CLOCK_REALTIME, &ts) == 0);
TEST_ASSERT(now.tv_sec == ts.tv_sec);
TEST_ASSERT_INT_WITHIN(5000000L, ts.tv_nsec, now.tv_usec * 1000L);
ts.tv_sec = 20;
ts.tv_nsec = 100000000L;
TEST_ASSERT(clock_settime(CLOCK_REALTIME, &ts) == 0);
TEST_ASSERT(gettimeofday(&now, NULL) == 0);
TEST_ASSERT_EQUAL(ts.tv_sec, now.tv_sec);
TEST_ASSERT_INT_WITHIN(5000L, ts.tv_nsec / 1000L, now.tv_usec);
TEST_ASSERT(clock_settime(CLOCK_MONOTONIC, &ts) == -1);
uint64_t delta_monotonic_us = 0;
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER )
TEST_ASSERT(clock_getres(CLOCK_REALTIME, &ts) == 0);
TEST_ASSERT_EQUAL_INT(1000, ts.tv_nsec);
TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, &ts) == 0);
TEST_ASSERT_EQUAL_INT(1000, ts.tv_nsec);
TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
delta_monotonic_us = esp_system_get_time() - (ts.tv_sec * 1000000L + ts.tv_nsec / 1000L);
TEST_ASSERT(delta_monotonic_us > 0 || delta_monotonic_us == 0);
TEST_ASSERT_INT_WITHIN(5000L, 0, delta_monotonic_us);
#elif defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
TEST_ASSERT(clock_getres(CLOCK_REALTIME, &ts) == 0);
TEST_ASSERT_EQUAL_INT(1000000000L / rtc_clk_slow_freq_get_hz(), ts.tv_nsec);
TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, &ts) == 0);
TEST_ASSERT_EQUAL_INT(1000000000L / rtc_clk_slow_freq_get_hz(), ts.tv_nsec);
TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
delta_monotonic_us = esp_clk_rtc_time() - (ts.tv_sec * 1000000L + ts.tv_nsec / 1000L);
TEST_ASSERT(delta_monotonic_us > 0 || delta_monotonic_us == 0);
TEST_ASSERT_INT_WITHIN(5000L, 0, delta_monotonic_us);
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
#else
struct timespec ts = {0};
TEST_ASSERT(clock_settime(CLOCK_REALTIME, &ts) == -1);
TEST_ASSERT(clock_gettime(CLOCK_REALTIME, &ts) == -1);
TEST_ASSERT(clock_getres(CLOCK_REALTIME, &ts) == -1);
TEST_ASSERT(clock_settime(CLOCK_MONOTONIC, &ts) == -1);
TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts) == -1);
TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, &ts) == -1);
#endif // defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
}
TEST_CASE("test posix_timers clock_... functions", "[newlib]")
{
test_posix_timers_clock();
}
#ifndef _USE_LONG_TIME_T
static struct timeval get_time(const char *desc, char *buffer)
{
struct timeval timestamp;
gettimeofday(&timestamp, NULL);
struct tm* tm_info = localtime(&timestamp.tv_sec);
strftime(buffer, 32, "%c", tm_info);
#if !CONFIG_NEWLIB_NANO_FORMAT
ESP_LOGI("TAG", "%s: %016llX (%s)", desc, timestamp.tv_sec, buffer);
#endif
return timestamp;
}
TEST_CASE("test time_t wide 64 bits", "[newlib]")
{
static char buffer[32];
ESP_LOGI("TAG", "sizeof(time_t): %d (%d-bit)", sizeof(time_t), sizeof(time_t) * 8);
TEST_ASSERT_EQUAL(8, sizeof(time_t));
// mktime takes current timezone into account, this test assumes it's UTC+0
setenv("TZ", "UTC+0", 1);
tzset();
struct tm tm = {4, 14, 3, 19, 0, 138, 0, 0, 0};
struct timeval timestamp = { mktime(&tm), 0 };
#if !CONFIG_NEWLIB_NANO_FORMAT
ESP_LOGI("TAG", "timestamp: %016llX", timestamp.tv_sec);
#endif
settimeofday(&timestamp, NULL);
get_time("Set time", buffer);
while (timestamp.tv_sec < 0x80000003LL) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
timestamp = get_time("Time now", buffer);
}
TEST_ASSERT_EQUAL_MEMORY("Tue Jan 19 03:14:11 2038", buffer, strlen(buffer));
}
TEST_CASE("test time functions wide 64 bits", "[newlib]")
{
static char origin_buffer[32];
char strftime_buf[64];
// mktime takes current timezone into account, this test assumes it's UTC+0
setenv("TZ", "UTC+0", 1);
tzset();
int year = 2018;
struct tm tm = {0, 14, 3, 19, 0, year - 1900, 0, 0, 0};
time_t t = mktime(&tm);
while (year < 2119) {
struct timeval timestamp = { t, 0 };
ESP_LOGI("TAG", "year: %d", year);
settimeofday(&timestamp, NULL);
get_time("Time now", origin_buffer);
vTaskDelay(10 / portTICK_PERIOD_MS);
t += 86400 * 366;
struct tm timeinfo = { 0 };
time_t now;
time(&now);
localtime_r(&now, &timeinfo);
time_t t = mktime(&timeinfo);
#if !CONFIG_NEWLIB_NANO_FORMAT
ESP_LOGI("TAG", "Test mktime(). Time: %016llX", t);
#endif
TEST_ASSERT_EQUAL(timestamp.tv_sec, t);
// mktime() has error in newlib-3.0.0. It fixed in newlib-3.0.0.20180720
TEST_ASSERT_EQUAL((timestamp.tv_sec >> 32), (t >> 32));
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI("TAG", "Test time() and localtime_r(). Time: %s", strftime_buf);
TEST_ASSERT_EQUAL(timeinfo.tm_year, year - 1900);
TEST_ASSERT_EQUAL_MEMORY(origin_buffer, strftime_buf, strlen(origin_buffer));
struct tm *tm2 = localtime(&now);
strftime(strftime_buf, sizeof(strftime_buf), "%c", tm2);
ESP_LOGI("TAG", "Test localtime(). Time: %s", strftime_buf);
TEST_ASSERT_EQUAL(tm2->tm_year, year - 1900);
TEST_ASSERT_EQUAL_MEMORY(origin_buffer, strftime_buf, strlen(origin_buffer));
struct tm *gm = gmtime(&now);
strftime(strftime_buf, sizeof(strftime_buf), "%c", gm);
ESP_LOGI("TAG", "Test gmtime(). Time: %s", strftime_buf);
TEST_ASSERT_EQUAL_MEMORY(origin_buffer, strftime_buf, strlen(origin_buffer));
const char* time_str1 = ctime(&now);
ESP_LOGI("TAG", "Test ctime(). Time: %s", time_str1);
TEST_ASSERT_EQUAL_MEMORY(origin_buffer, time_str1, strlen(origin_buffer));
const char* time_str2 = asctime(&timeinfo);
ESP_LOGI("TAG", "Test asctime(). Time: %s", time_str2);
TEST_ASSERT_EQUAL_MEMORY(origin_buffer, time_str2, strlen(origin_buffer));
printf("\n");
++year;
}
}
#endif // !_USE_LONG_TIME_T
#if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
extern int64_t s_microseconds_offset;
static const uint64_t s_start_timestamp = 1606838354;
static __NOINIT_ATTR uint64_t s_saved_time;
static __NOINIT_ATTR uint64_t s_time_in_reboot;
typedef enum {
TYPE_REBOOT_ABORT = 0,
TYPE_REBOOT_RESTART,
} type_reboot_t;
static void print_counters(void)
{
int64_t high_res_time = esp_system_get_time();
int64_t rtc = esp_rtc_get_time_us();
uint64_t boot_time = esp_time_impl_get_boot_time();
printf("\tHigh-res time %lld (us)\n", high_res_time);
printf("\tRTC %lld (us)\n", rtc);
printf("\tBOOT %lld (us)\n", boot_time);
printf("\ts_microseconds_offset %lld (us)\n", s_microseconds_offset);
printf("delta RTC - high-res time counters %lld (us)\n", rtc - high_res_time);
}
static void set_initial_condition(type_reboot_t type_reboot, int error_time)
{
s_saved_time = 0;
s_time_in_reboot = 0;
print_counters();
struct timeval tv = { .tv_sec = s_start_timestamp, .tv_usec = 0, };
settimeofday(&tv, NULL);
printf("set timestamp %lld (s)\n", s_start_timestamp);
print_counters();
int delay_s = abs(error_time) * 2;
printf("Waiting for %d (s) ...\n", delay_s);
vTaskDelay(delay_s * 1000 / portTICK_PERIOD_MS);
print_counters();
printf("High res counter increased to %d (s)\n", error_time);
esp_timer_private_advance(error_time * 1000000ULL);
print_counters();
gettimeofday(&tv, NULL);
s_saved_time = tv.tv_sec;
printf("s_saved_time %lld (s)\n", s_saved_time);
int dt = s_saved_time - s_start_timestamp;
printf("delta timestamp = %d (s)\n", dt);
TEST_ASSERT_GREATER_OR_EQUAL(error_time, dt);
s_time_in_reboot = esp_rtc_get_time_us();
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
/* If internal data is behind a cache it might not be written to the physical memory when we crash/reboot
force a full writeback here to ensure this */
cache_ll_writeback_all(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
#endif
if (type_reboot == TYPE_REBOOT_ABORT) {
printf("Update boot time based on diff\n");
esp_sync_timekeeping_timers();
print_counters();
printf("reboot as abort\n");
abort();
} else if (type_reboot == TYPE_REBOOT_RESTART) {
printf("reboot as restart\n");
esp_restart();
}
}
static void set_timestamp1(void)
{
set_initial_condition(TYPE_REBOOT_ABORT, 5);
}
static void set_timestamp2(void)
{
set_initial_condition(TYPE_REBOOT_RESTART, 5);
}
static void set_timestamp3(void)
{
set_initial_condition(TYPE_REBOOT_RESTART, -5);
}
static void check_time(void)
{
print_counters();
int latency_before_run_ut = 1 + (esp_rtc_get_time_us() - s_time_in_reboot) / 1000000;
struct timeval tv;
gettimeofday(&tv, NULL);
printf("timestamp %jd (s)\n", (intmax_t)tv.tv_sec);
int dt = tv.tv_sec - s_saved_time;
printf("delta timestamp = %d (s)\n", dt);
TEST_ASSERT_GREATER_OR_EQUAL(0, dt);
TEST_ASSERT_LESS_OR_EQUAL(latency_before_run_ut, dt);
}
TEST_CASE_MULTIPLE_STAGES("Timestamp after abort is correct in case RTC & High-res timer have + big error", "[newlib][reset=abort,SW_CPU_RESET]", set_timestamp1, check_time);
TEST_CASE_MULTIPLE_STAGES("Timestamp after restart is correct in case RTC & High-res timer have + big error", "[newlib][reset=SW_CPU_RESET]", set_timestamp2, check_time);
TEST_CASE_MULTIPLE_STAGES("Timestamp after restart is correct in case RTC & High-res timer have - big error", "[newlib][reset=SW_CPU_RESET]", set_timestamp3, check_time);
#endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER && CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
@@ -0,0 +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()
@@ -0,0 +1,2 @@
# Test all chips with nano off, nano on is tested in options config
CONFIG_NEWLIB_NANO_FORMAT=n
@@ -0,0 +1,2 @@
# Test with misc newlib config options turned on
CONFIG_NEWLIB_NANO_FORMAT=y
@@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_SPIRAM=y
@@ -0,0 +1,4 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
@@ -0,0 +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
@@ -0,0 +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
@@ -0,0 +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
@@ -0,0 +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__