initial commit
This commit is contained in:
@@ -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)
|
||||
@@ -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(×tamp, NULL);
|
||||
struct tm* tm_info = localtime(×tamp.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(×tamp, 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(×tamp, 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__
|
||||
Reference in New Issue
Block a user