| /* | |
| * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. | |
| * | |
| * SPDX-License-Identifier: BSD-3-Clause | |
| */ | |
| #include "hardware/timer.h" | |
| #if defined(__unix__) || defined(__APPLE__) | |
| #include <unistd.h> | |
| #include <sys/time.h> | |
| #include <time.h> | |
| #endif | |
| // in our case not a busy wait | |
| PICO_WEAK_FUNCTION_DEF(busy_wait_us_32) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_us_32)(uint32_t delay_us) { | |
| #if defined(__unix__) || defined(__APPLE__) | |
| usleep(delay_us); | |
| #else | |
| assert(false); | |
| #endif | |
| } | |
| PICO_WEAK_FUNCTION_DEF(busy_wait_us) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_us)(uint64_t delay_us) { | |
| absolute_time_t t; | |
| update_us_since_boot(&t, time_us_64() + delay_us); | |
| busy_wait_until(t); | |
| } | |
| PICO_WEAK_FUNCTION_DEF(busy_wait_ms) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_ms)(uint32_t delay_ms) { | |
| #if defined(__unix__) || defined(__APPLE__) | |
| usleep(delay_ms * 1000); | |
| #else | |
| assert(false); | |
| #endif | |
| } | |
| // this may or may not wrap | |
| PICO_WEAK_FUNCTION_DEF(time_us_64) | |
| uint64_t PICO_WEAK_FUNCTION_IMPL_NAME(time_us_64)() { | |
| #if defined(__unix__) || defined(__APPLE__) | |
| // struct timeval tv; | |
| // gettimeofday(&tv, NULL); | |
| // return tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec; | |
| struct timespec ts; | |
| clock_gettime(CLOCK_MONOTONIC, &ts); | |
| return ts.tv_sec * (uint64_t) 1000000 + ts.tv_nsec / 1000; | |
| #else | |
| panic_unsupported(); | |
| #endif | |
| } | |
| PICO_WEAK_FUNCTION_DEF(timer_us_32) | |
| uint32_t PICO_WEAK_FUNCTION_IMPL_NAME(timer_us_32)() { | |
| return (uint32_t) time_us_64(); | |
| } | |
| PICO_WEAK_FUNCTION_DEF(time_reached) | |
| bool PICO_WEAK_FUNCTION_IMPL_NAME(time_reached)(absolute_time_t t) { | |
| uint64_t target = to_us_since_boot(t); | |
| return time_us_64() >= target; | |
| } | |
| PICO_WEAK_FUNCTION_DEF(busy_wait_until) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(busy_wait_until)(absolute_time_t target) { | |
| #if defined(__unix__) | |
| struct timespec tspec; | |
| tspec.tv_sec = to_us_since_boot(target) / 1000000; | |
| tspec.tv_nsec = (to_us_since_boot(target) % 1000000) * 1000; | |
| clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tspec, NULL); | |
| #else | |
| const int chunk = 1u<<30u; | |
| uint64_t target_us = to_us_since_boot(target); | |
| uint64_t time_us = time_us_64(); | |
| while ((int64_t)(target_us - time_us) >= chunk) { | |
| busy_wait_us_32(chunk); | |
| time_us = time_us_64(); | |
| } | |
| if (target_us > time_us) { | |
| busy_wait_us_32(target_us - time_us); | |
| } | |
| #endif | |
| } | |
| static uint8_t claimed_alarms; | |
| void hardware_alarm_claim(uint alarm_num) { | |
| assert(!(claimed_alarms & (1u << alarm_num))); | |
| claimed_alarms |= 1u <<alarm_num; | |
| } | |
| void hardware_alarm_unclaim(uint alarm_num) { | |
| assert(claimed_alarms & (1u << alarm_num)); | |
| claimed_alarms &= ~(1u <<alarm_num); | |
| } | |
| int hardware_alarm_claim_unused(bool required) { | |
| int alarm_id = claimed_alarms ? __builtin_clz(~claimed_alarms) : 1; | |
| if (alarm_id >= NUM_ALARMS) return -1; | |
| claimed_alarms |= 1u << alarm_id; | |
| return alarm_id; | |
| } | |
| PICO_WEAK_FUNCTION_DEF(hardware_alarm_set_callback) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_set_callback)(uint alarm_num, hardware_alarm_callback_t callback) { | |
| panic_unsupported(); | |
| } | |
| PICO_WEAK_FUNCTION_DEF(hardware_alarm_set_target) | |
| bool PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_set_target)(uint alarm_num, absolute_time_t target) { | |
| panic_unsupported(); | |
| } | |
| PICO_WEAK_FUNCTION_DEF(hardware_alarm_cancel) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_cancel)(uint alarm_num) { | |
| panic_unsupported(); | |
| } | |
| PICO_WEAK_FUNCTION_DEF(hardware_alarm_force_irq) | |
| void PICO_WEAK_FUNCTION_IMPL_NAME(hardware_alarm_force_irq)(uint alarm_num) { | |
| panic_unsupported(); | |
| } |