feat(gcc): Update cross toolchain GCC to v8.x

This commit is contained in:
donghengqaz
2020-02-12 10:22:49 +08:00
committed by Dong Heng
parent 1be2289fcd
commit 28f466d12e
159 changed files with 359 additions and 15440 deletions

View File

@@ -0,0 +1,54 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "FreeRTOS.h"
void *malloc(size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_malloc(n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *realloc(void *old_ptr, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_realloc(old_ptr, n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *zalloc(size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_zalloc(n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *calloc(size_t c, size_t s)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_calloc(c, s, MALLOC_CAP_32BIT, return_addr, 0);
}
void free(void *ptr)
{
void *return_addr = (void *)__builtin_return_address(0);
_heap_caps_free(ptr, return_addr, 0);
}

View File

@@ -0,0 +1,212 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sys/lock.h>
#include <stdlib.h>
#include <reent.h>
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
/* Initialize the given lock by allocating a new mutex semaphore
as the _lock_t value.
Called by _lock_init*, also called by _lock_acquire* to lazily initialize locks that might have
been initialised (to zero only) before the RTOS scheduler started.
*/
static void lock_init_generic(_lock_t *lock, uint8_t mutex_type) {
portENTER_CRITICAL();
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
/* nothing to do until the scheduler is running */
portEXIT_CRITICAL();
return;
}
if (*lock) {
/* Lock already initialised (either we didn't check earlier,
or it got initialised while we were waiting for the
spinlock.) */
}
else
{
/* Create a new semaphore
this is a bit of an API violation, as we're calling the
private function xQueueCreateMutex(x) directly instead of
the xSemaphoreCreateMutex / xSemaphoreCreateRecursiveMutex
wrapper functions...
The better alternative would be to pass pointers to one of
the two xSemaphoreCreate___Mutex functions, but as FreeRTOS
implements these as macros instead of inline functions
(*party like it's 1998!*) it's not possible to do this
without writing wrappers. Doing it this way seems much less
spaghetti-like.
*/
xSemaphoreHandle new_sem = xQueueCreateMutex(mutex_type);
if (!new_sem) {
abort(); /* No more semaphores available or OOM */
}
*lock = (_lock_t)new_sem;
}
portEXIT_CRITICAL();
}
void _lock_init(_lock_t *lock) {
*lock = 0; // In case lock's memory is uninitialized
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
}
void _lock_init_recursive(_lock_t *lock) {
*lock = 0; // In case lock's memory is uninitialized
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}
/* Free the mutex semaphore pointed to by *lock, and zero it out.
Note that FreeRTOS doesn't account for deleting mutexes while they
are held, and neither do we... so take care not to delete newlib
locks while they may be held by other tasks!
Also, deleting a lock in this way will cause it to be lazily
re-initialised if it is used again. Caller has to avoid doing
this!
*/
static void lock_close_generic(_lock_t *lock, uint8_t mutex_type) {
portENTER_CRITICAL();
if (*lock) {
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
#if (INCLUDE_xSemaphoreGetMutexHolder == 1)
configASSERT(xSemaphoreGetMutexHolder(h) == NULL); /* mutex should not be held */
#endif
vSemaphoreDelete(h);
*lock = 0;
}
portEXIT_CRITICAL();
}
void _lock_close(_lock_t *lock) {
lock_close_generic(lock, queueQUEUE_TYPE_MUTEX);
}
void _lock_close_recursive(_lock_t *lock) {
lock_close_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}
/* Acquire the mutex semaphore for lock. wait up to delay ticks.
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
*/
static int lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type) {
/* If application function has disabled interrupt, then it must not acquire the mutex */
if (interrupt_is_disable() == true && !xPortInIsrContext())
return 0;
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
if (!h) {
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
}
/* lazy initialise lock - might have had a static initializer in newlib (that we don't use),
or _lock_init might have been called before the scheduler was running... */
lock_init_generic(lock, mutex_type);
h = (xSemaphoreHandle)(*lock);
configASSERT(h != NULL);
}
BaseType_t success;
if (xPortInIsrContext()) {
/* In ISR Context */
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
abort(); /* recursive mutexes make no sense in ISR context */
}
BaseType_t higher_task_woken = false;
success = xSemaphoreTakeFromISR(h, &higher_task_woken);
if (!success && delay > 0) {
abort(); /* Tried to block on mutex from ISR, couldn't... rewrite your program to avoid libc interactions in ISRs! */
}
if (higher_task_woken) {
portYIELD_FROM_ISR();
}
}
else {
/* In task context */
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
success = xSemaphoreTakeRecursive(h, delay);
} else {
success = xSemaphoreTake(h, delay);
}
}
return (success == pdTRUE) ? 0 : -1;
}
void _lock_acquire(_lock_t *lock) {
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_MUTEX);
}
void _lock_acquire_recursive(_lock_t *lock) {
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}
int _lock_try_acquire(_lock_t *lock) {
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_MUTEX);
}
int _lock_try_acquire_recursive(_lock_t *lock) {
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}
/* Release the mutex semaphore for lock.
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
*/
static void lock_release_generic(_lock_t *lock, uint8_t mutex_type) {
/* If application function has disabled interrupt, then it must not release the mutex */
if (interrupt_is_disable() == true && !xPortInIsrContext())
return ;
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
if (h == NULL) {
/* This is probably because the scheduler isn't running yet,
or the scheduler just started running and some code was
"holding" a not-yet-initialised lock... */
return;
}
if (xPortInIsrContext()) {
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
abort(); /* indicates logic bug, it shouldn't be possible to lock recursively in ISR */
}
BaseType_t higher_task_woken = false;
xSemaphoreGiveFromISR(h, &higher_task_woken);
if (higher_task_woken) {
portYIELD_FROM_ISR();
}
} else {
if (mutex_type == queueQUEUE_TYPE_RECURSIVE_MUTEX) {
xSemaphoreGiveRecursive(h);
} else {
xSemaphoreGive(h);
}
}
}
void _lock_release(_lock_t *lock) {
lock_release_generic(lock, queueQUEUE_TYPE_MUTEX);
}
void _lock_release_recursive(_lock_t *lock) {
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}

View File

@@ -0,0 +1,43 @@
// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sys/random.h>
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"
static const char *TAG = "RANDOM";
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
{
// Flags are ignored because:
// - esp_random is non-blocking so it works for both blocking and non-blocking calls,
// - don't have opportunity so set som other source of entropy.
ESP_LOGD(TAG, "getrandom(buf=0x%x, buflen=%d, flags=%u)", (int) buf, buflen, flags);
if (buf == NULL) {
errno = EFAULT;
ESP_LOGD(TAG, "getrandom returns -1 (EFAULT)");
return -1;
}
esp_fill_random(buf, buflen);
ESP_LOGD(TAG, "getrandom returns %d", buflen);
return buflen;
}

View File

@@ -0,0 +1,153 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/reent.h>
#include "esp_attr.h"
#include "esp_vfs_dev.h"
#define _STR(_s) #_s
#define STR(_s) _STR(_s)
static struct _reent impure_data;
/* This function is not part on newlib API, it is defined in libc/stdio/local.h
* There is no nice way to get __cleanup member populated while avoiding __sinit,
* so extern declaration is used here.
*/
extern void _cleanup_r(struct _reent* r);
/**
* This is the replacement for newlib's _REENT_INIT_PTR and __sinit.
* The problem with __sinit is that it allocates three FILE structures
* (stdin, stdout, stderr). Having individual standard streams for each task
* is a bit too much on a small embedded system. So we point streams
* to the streams of the global struct _reent, which are initialized in
* startup code.
*/
void esp_reent_init(struct _reent* r)
{
memset(r, 0, sizeof(*r));
r->_stdout = _GLOBAL_REENT->_stdout;
r->_stderr = _GLOBAL_REENT->_stderr;
r->_stdin = _GLOBAL_REENT->_stdin;
r->__cleanup = &_cleanup_r;
r->__sdidinit = 1;
r->__sglue._next = NULL;
r->__sglue._niobs = 0;
r->__sglue._iobs = NULL;
}
/* only declared in private stdio header file, local.h */
extern void __sfp_lock_acquire(void);
extern void __sfp_lock_release(void);
void esp_reent_cleanup(void)
{
struct _reent* r = __getreent();
/* Clean up storage used by mprec functions */
if (r->_mp) {
if (_REENT_MP_FREELIST(r)) {
for (int i = 0; i < _Kmax; ++i) {
struct _Bigint *cur, *next;
next = _REENT_MP_FREELIST(r)[i];
while (next) {
cur = next;
next = next->_next;
free(cur);
}
}
}
free(_REENT_MP_FREELIST(r));
free(_REENT_MP_RESULT(r));
}
/* Clean up "glue" (lazily-allocated FILE objects) */
struct _glue* prev = &_GLOBAL_REENT->__sglue;
for (struct _glue* cur = _GLOBAL_REENT->__sglue._next; cur != NULL;) {
if (cur->_niobs == 0) {
cur = cur->_next;
continue;
}
bool has_open_files = false;
for (int i = 0; i < cur->_niobs; ++i) {
FILE* fp = &cur->_iobs[i];
if (fp->_flags != 0) {
has_open_files = true;
break;
}
}
if (has_open_files) {
prev = cur;
cur = cur->_next;
continue;
}
struct _glue* next = cur->_next;
prev->_next = next;
free(cur);
cur = next;
}
/* Clean up various other buffers */
free(r->_mp);
r->_mp = NULL;
free(r->_r48);
r->_r48 = NULL;
free(r->_localtime_buf);
r->_localtime_buf = NULL;
free(r->_asctime_buf);
r->_asctime_buf = NULL;
}
/*
* @brief Initialize newlib's platform object data
*/
int esp_newlib_init(void)
{
const char *default_uart_dev = "/dev/uart/" STR(CONFIG_CONSOLE_UART_NUM);
_global_impure_ptr = &impure_data;
esp_reent_init(_global_impure_ptr);
esp_vfs_dev_uart_register();
_GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w");
if (!_GLOBAL_REENT->_stdout)
goto err;
_GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w");
if (!_GLOBAL_REENT->_stderr)
goto err_fail;
_GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r");
if (!_GLOBAL_REENT->_stdin)
goto err_in;
return 0;
err_in:
fclose(_GLOBAL_REENT->_stderr);
err_fail:
fclose(_GLOBAL_REENT->_stdout);
err:
return -1;
}
struct _reent* __getreent()
{
return _global_impure_ptr;
}

View File

@@ -0,0 +1,65 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sys/select.h>
#include "sdkconfig.h"
#include "esp_vfs.h"
#ifdef CONFIG_USE_ONLY_LWIP_SELECT
#include "lwip/sockets.h"
#ifdef CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT
#define LOG_LOCAL_LEVEL ESP_LOG_NONE
#endif //CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT
#include "esp_log.h"
static const char *TAG = "newlib_select";
static void log_fd_set(const char *fds_name, const fd_set *fds)
{
if (fds_name && fds) {
ESP_LOGD(TAG, "FDs in %s =", fds_name);
for (int i = 0; i < MAX_FDS; ++i) {
if (FD_ISSET(i, fds)) {
ESP_LOGD(TAG, "%d", i);
}
}
}
}
#endif //CONFIG_USE_ONLY_LWIP_SELECT
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
{
#ifdef CONFIG_USE_ONLY_LWIP_SELECT
ESP_LOGD(TAG, "lwip_select starts with nfds = %d", nfds);
if (timeout) {
ESP_LOGD(TAG, "timeout is %lds + %ldus", timeout->tv_sec, timeout->tv_usec);
}
log_fd_set("readfds", readfds);
log_fd_set("writefds", writefds);
log_fd_set("errorfds", errorfds);
int ret = lwip_select(nfds, readfds, writefds, errorfds, timeout);
ESP_LOGD(TAG, "lwip_select returns %d", ret);
log_fd_set("readfds", readfds);
log_fd_set("writefds", writefds);
log_fd_set("errorfds", errorfds);
return ret;
#else
return esp_vfs_select(nfds, readfds, writefds, errorfds, timeout);
#endif
}

View File

@@ -0,0 +1,92 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include <stdio.h>
#include <string.h>
#include <reent.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include "FreeRTOS.h"
#include "task.h"
#include "esp_libc.h"
#include "esp_log.h"
#include "esp_vfs.h"
#define ERRNO_TLS_INDEX (configNUM_THREAD_LOCAL_STORAGE_POINTERS - 1)
void *_malloc_r(struct _reent *r, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_malloc(n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *_realloc_r(struct _reent *r, void *old_ptr, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_realloc(old_ptr, n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *_calloc_r(struct _reent *r, size_t c, size_t s)
{
void *return_addr = (void *)__builtin_return_address(0);
return _heap_caps_calloc(c, s, MALLOC_CAP_32BIT, return_addr, 0);
}
void _free_r(struct _reent *r, void *ptr)
{
void *return_addr = (void *)__builtin_return_address(0);
_heap_caps_free(ptr, return_addr, 0);
}
void abort(void)
{
#ifndef CONFIG_ESP_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC %p on core %d\r\n", __builtin_return_address(0) - 3, xPortGetCoreID());
#endif
/* cause a exception to jump into panic function */
while (1) {
*((int *)NULL) = 0;
}
}
void _exit(int status)
{
abort();
}
void *_sbrk_r(struct _reent *r, ptrdiff_t incr)
{
abort();
}
int _getpid_r(struct _reent *r)
{
__errno_r(r) = ENOSYS;
return -1;
}
int *__errno(void)
{
return (int *)pvTaskGetThreadLocalStorageBufferPointer(NULL, ERRNO_TLS_INDEX);
}

View File

@@ -0,0 +1,54 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#ifdef CONFIG_SUPPORT_TERMIOS
#include <sys/termios.h>
#include <sys/errno.h>
speed_t cfgetispeed(const struct termios *p)
{
return p ? p->c_ispeed : B0;
}
speed_t cfgetospeed(const struct termios *p)
{
return p ? p->c_ospeed : B0;
}
int cfsetispeed(struct termios *p, speed_t sp)
{
if (p) {
p->c_ispeed = sp;
return 0;
} else {
errno = EINVAL;
return -1;
}
}
int cfsetospeed(struct termios *p, speed_t sp)
{
if (p) {
p->c_ospeed = sp;
return 0;
} else {
errno = EINVAL;
return -1;
}
}
#endif // CONFIG_SUPPORT_TERMIOS

View File

@@ -0,0 +1,263 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <reent.h>
#include <time.h>
#include <sys/times.h>
#include <sys/time.h>
#include <sys/errno.h>
#include "esp_system.h"
#include "esp_timer.h"
#include "rom/ets_sys.h"
#include "FreeRTOS.h"
#include "task.h"
#include "driver/soc.h"
#include "limits.h"
#include "sdkconfig.h"
#ifdef CONFIG_ESP8266_TIME_SYSCALL_USE_FRC1
#define WITH_FRC 1
#endif
static uint64_t s_boot_time;
#if defined(WITH_RTC) || defined(WITH_FRC)
// stores the start time of the slew
static uint64_t adjtime_start = 0;
// is how many microseconds total to slew
static int64_t adjtime_total_correction = 0;
#define ADJTIME_CORRECTION_FACTOR 6
static uint64_t get_time_since_boot(void);
#endif
// Offset between FRC timer and the RTC.
// Initialized after reset or light sleep.
#if defined(WITH_RTC) && defined(WITH_FRC)
uint64_t s_microseconds_offset;
#endif
static inline void set_boot_time(uint64_t time_us)
{
esp_irqflag_t flag;
flag = soc_save_local_irq();
s_boot_time = time_us;
soc_restore_local_irq(flag);
}
static inline uint64_t get_boot_time()
{
uint64_t result;
esp_irqflag_t flag;
flag = soc_save_local_irq();
result = s_boot_time;
soc_restore_local_irq(flag);
return result;
}
// This function gradually changes boot_time to the correction value and immediately updates it.
static uint64_t adjust_boot_time(void)
{
uint64_t boot_time = get_boot_time();
if ((boot_time == 0) || (get_time_since_boot() < adjtime_start)) {
adjtime_start = 0;
}
if (adjtime_start > 0) {
uint64_t since_boot = get_time_since_boot();
// If to call this function once per second, then (since_boot - adjtime_start) will be 1_000_000 (1 second),
// and the correction will be equal to (1_000_000us >> 6) = 15_625 us.
// The minimum possible correction step can be (64us >> 6) = 1us.
// Example: if the time error is 1 second, then it will be compensate for 1 sec / 0,015625 = 64 seconds.
int64_t correction = (since_boot >> ADJTIME_CORRECTION_FACTOR) - (adjtime_start >> ADJTIME_CORRECTION_FACTOR);
if (correction > 0) {
adjtime_start = since_boot;
if (adjtime_total_correction < 0) {
if ((adjtime_total_correction + correction) >= 0) {
boot_time = boot_time + adjtime_total_correction;
adjtime_start = 0;
} else {
adjtime_total_correction += correction;
boot_time -= correction;
}
} else {
if ((adjtime_total_correction - correction) <= 0) {
boot_time = boot_time + adjtime_total_correction;
adjtime_start = 0;
} else {
adjtime_total_correction -= correction;
boot_time += correction;
}
}
set_boot_time(boot_time);
}
}
return boot_time;
}
#if defined( WITH_FRC ) || defined( WITH_RTC )
static uint64_t get_time_since_boot(void)
{
uint64_t microseconds = 0;
#ifdef WITH_FRC
#ifdef WITH_RTC
microseconds = s_microseconds_offset + esp_timer_get_time();
#else
microseconds = esp_timer_get_time();
#endif // WITH_RTC
#elif defined(WITH_RTC)
microseconds = get_rtc_time_us();
#endif // WITH_FRC
return microseconds;
}
#endif // defined( WITH_FRC ) || defined( WITH_RTC
int adjtime(const struct timeval *delta, struct timeval *outdelta)
{
#if defined( WITH_FRC ) || defined( WITH_RTC )
esp_irqflag_t flag;
if(delta != NULL){
int64_t sec = delta->tv_sec;
int64_t usec = delta->tv_usec;
if(llabs(sec) > ((INT_MAX / 1000000L) - 1L)) {
return -1;
}
/*
* If adjusting the system clock by adjtime () is already done during the second call adjtime (),
* and the delta of the second call is not NULL, the earlier tuning is stopped,
* but the already completed part of the adjustment is not canceled.
*/
flag = soc_save_local_irq();
// If correction is already in progress (adjtime_start != 0), then apply accumulated corrections.
adjust_boot_time();
adjtime_start = get_time_since_boot();
adjtime_total_correction = sec * 1000000L + usec;
soc_restore_local_irq(flag);
}
if(outdelta != NULL){
flag = soc_save_local_irq();
adjust_boot_time();
if (adjtime_start != 0) {
outdelta->tv_sec = adjtime_total_correction / 1000000L;
outdelta->tv_usec = adjtime_total_correction % 1000000L;
} else {
outdelta->tv_sec = 0;
outdelta->tv_usec = 0;
}
soc_restore_local_irq(flag);
}
return 0;
#else
return -1;
#endif
}
int _gettimeofday_r(struct _reent* r, struct timeval* tv, void* tz)
{
(void) tz;
if (tv) {
uint64_t microseconds = get_boot_time() + (uint64_t)esp_timer_get_time();
tv->tv_sec = microseconds / 1000000;
tv->tv_usec = microseconds % 1000000;
}
return 0;
}
int settimeofday(const struct timeval* tv, const struct timezone* tz)
{
(void) tz;
if (tv) {
uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec;
uint64_t since_boot = (uint64_t)esp_timer_get_time();
set_boot_time(now - since_boot);
}
return 0;
}
clock_t _times_r(struct _reent *r, struct tms *tms)
{
tms->tms_utime = xTaskGetTickCount();
tms->tms_stime = 0;
tms->tms_cutime = 0;
tms->tms_cstime = 0;
return 0;
}
int usleep(useconds_t us)
{
const int us_per_tick = portTICK_PERIOD_MS * 1000;
if (us < us_per_tick) {
ets_delay_us((uint32_t) us);
} else {
/* since vTaskDelay(1) blocks for anywhere between 0 and portTICK_PERIOD_MS,
* round up to compensate.
*/
vTaskDelay((us + us_per_tick - 1) / us_per_tick);
}
return 0;
}
unsigned int sleep(unsigned int seconds)
{
vTaskDelay(seconds * (1000 / portTICK_PERIOD_MS));
return 0;
}
int clock_gettime (clockid_t clock_id, struct timespec *tp)
{
#if defined( WITH_FRC ) || defined( WITH_RTC )
if (tp == NULL) {
errno = EINVAL;
return -1;
}
struct timeval tv;
uint64_t monotonic_time_us = 0;
switch (clock_id) {
case CLOCK_REALTIME:
_gettimeofday_r(NULL, &tv, NULL);
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = tv.tv_usec * 1000L;
break;
case CLOCK_MONOTONIC:
#if defined( WITH_FRC )
monotonic_time_us = (uint64_t) esp_timer_get_time();
#elif defined( WITH_RTC )
monotonic_time_us = get_rtc_time_us();
#endif // WITH_FRC
tp->tv_sec = monotonic_time_us / 1000000LL;
tp->tv_nsec = (monotonic_time_us % 1000000LL) * 1000L;
break;
default:
errno = EINVAL;
return -1;
}
return 0;
#else
errno = ENOSYS;
return -1;
#endif
}