Add Chrono support to Ticker et al

pull/12425/head
Kevin Bracey 2020-02-13 11:21:20 +02:00
parent b9aa69a376
commit 34428f9d4c
14 changed files with 551 additions and 137 deletions

View File

@ -19,7 +19,6 @@
#include "platform/platform.h"
#include "drivers/Ticker.h"
#include "platform/NonCopyable.h"
#if defined (DEVICE_LPTICKER) || defined(DOXYGEN_ONLY)
@ -40,14 +39,10 @@ namespace mbed {
*
* @note Synchronization level: Interrupt safe
*/
class LowPowerTicker : public Ticker, private NonCopyable<LowPowerTicker> {
class LowPowerTicker : public TickerBase {
public:
LowPowerTicker() : Ticker(get_lp_ticker_data())
{
}
virtual ~LowPowerTicker()
LowPowerTicker() : TickerBase(get_lp_ticker_data())
{
}
};

View File

@ -21,9 +21,8 @@
#if DEVICE_LPTICKER || defined(DOXYGEN_ONLY)
#include "hal/lp_ticker_api.h"
#include "drivers/LowPowerTicker.h"
#include "platform/NonCopyable.h"
#include "drivers/LowPowerClock.h"
#include "drivers/Timeout.h"
namespace mbed {
/**
@ -36,14 +35,37 @@ namespace mbed {
*
* @note Synchronization level: Interrupt safe
*/
class LowPowerTimeout : public LowPowerTicker, private NonCopyable<LowPowerTimeout> {
#if !defined(DOXYGEN_ONLY)
private:
virtual void handler(void)
class LowPowerTimeout : public TimeoutBase {
public:
LowPowerTimeout();
/** Clock to use with attach_absolute, guaranteeing running only while attached or manually locked */
using clock = LowPowerClock;
/** Clock to use with attach_absolute, running always */
using steady_clock = LowPowerClock;
/** @copydoc TimeoutBase::scheduled_time() */
LowPowerClock::time_point scheduled_time() const
{
_function.call();
/* Massage from virtual TickerDataClock::time_point used internally to true LowPowerClock::time_point */
return LowPowerClock::time_point{TimeoutBase::scheduled_time().time_since_epoch()};
}
/** Attach a function to be called by the Timeout, specifying the absolute time
*
* @param func pointer to the function to be called
* @param abs_time the absolute time for the call, referenced to LowPowerClock
*
* @note setting @a abs_time to a time in the past means the event will be scheduled immediately
* resulting in an instant call to the function.
*/
template <class F>
void attach_absolute(F &&func, LowPowerClock::time_point abs_time)
{
/* Massage from true LowPowerClock::time_point to virtual TickerDataClock::time_point used internally */
TimeoutBase::attach_absolute(std::forward<F>(func), TickerDataClock::time_point{abs_time.time_since_epoch()});
}
#endif
};
/** @}*/

View File

@ -36,10 +36,10 @@ namespace mbed {
*
* @note Synchronization level: Interrupt safe
*/
class LowPowerTimer : public Timer, private NonCopyable<LowPowerTimer> {
class LowPowerTimer : public TimerBase {
public:
LowPowerTimer() : Timer(get_lp_ticker_data())
LowPowerTimer() : TimerBase(get_lp_ticker_data())
{
}

View File

@ -17,7 +17,9 @@
#ifndef MBED_TICKER_H
#define MBED_TICKER_H
#include <chrono>
#include <mstd_utility>
#include "drivers/TickerDataClock.h"
#include "drivers/TimerEvent.h"
#include "platform/Callback.h"
#include "platform/mbed_toolchain.h"
@ -25,6 +27,7 @@
#include "hal/lp_ticker_api.h"
namespace mbed {
/**
* \defgroup drivers_Ticker Ticker class
* \ingroup drivers-public-api-ticker
@ -42,6 +45,7 @@ namespace mbed {
* // Toggle the blinking LED after 5 seconds
*
* #include "mbed.h"
* using namespace std::chrono;
*
* Ticker timer;
* DigitalOut led1(LED1);
@ -54,26 +58,20 @@ namespace mbed {
* }
*
* int main() {
* timer.attach(&attime, 5);
* timer.attach(&attime, 5us);
* while(1) {
* if(flip == 0) {
* led1 = !led1;
* } else {
* led2 = !led2;
* }
* ThisThread::sleep_for(200);
* ThisThread::sleep_for(200ms);
* }
* }
* @endcode
*/
class Ticker : public TimerEvent, private NonCopyable<Ticker> {
class TickerBase : public TimerEvent, private NonCopyable<TickerBase> {
public:
Ticker();
// When low power ticker is in use, then do not disable deep sleep.
Ticker(const ticker_data_t *data);
/** Attach a function to be called by the Ticker, specifying the interval in seconds
*
* The method forwards its arguments to attach_us() rather than copying them which
@ -82,17 +80,34 @@ public:
* possible given attach_us() expects an integer value for the callback interval.
* @param func pointer to the function to be called
* @param t the time between calls in seconds
* @deprecated Pass a chrono duration, not a float second count. For example use `10ms` rather than `0.01f`.
*/
#if defined(__ICCARM__)
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not a float second count. For example use `10ms` rather than `0.01f`.")
MBED_FORCEINLINE template <typename F>
#else
template <typename F> MBED_FORCEINLINE
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not a float second count. For example use `10ms` rather than `0.01f`.")
#endif
void attach(F &&func, float t)
{
attach_us(std::forward<F>(func), t * 1000000.0f);
auto float_interval = std::chrono::duration<float>(t);
attach(std::forward<F>(func), std::chrono::duration_cast<std::chrono::microseconds>(float_interval));
}
/** Attach a function to be called by the Ticker, specifying the interval in microseconds
*
* @param func pointer to the function to be called
* @param t the time between calls in micro-seconds
*
* @note setting @a t to a value shorter than it takes to process the ticker callback
* causes the system to hang. Ticker callback is called constantly with no time
* for threads scheduling.
* @deprecated Pass a chrono duration, not an integer microsecond count. For example use `10ms` rather than `10000`.
*
*/
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer microsecond count. For example use `10ms` rather than `10000`.")
void attach_us(Callback<void()> func, us_timestamp_t t);
/** Attach a function to be called by the Ticker, specifying the interval in microseconds
*
@ -104,13 +119,7 @@ public:
* for threads scheduling.
*
*/
void attach_us(Callback<void()> func, us_timestamp_t t);
virtual ~Ticker()
{
detach();
}
void attach(Callback<void()> func, std::chrono::microseconds t);
/** Detach the function
*/
@ -118,16 +127,41 @@ public:
#if !defined(DOXYGEN_ONLY)
protected:
void setup(us_timestamp_t t);
virtual void handler();
TickerBase(const ticker_data_t *data);
TickerBase(const ticker_data_t *data, bool lock_deepsleep);
protected:
us_timestamp_t _delay; /**< Time delay (in microseconds) for resetting the multishot callback. */
~TickerBase()
{
detach();
}
/** Attach a function to be called by the Ticker, specifying the absolute call time
*
* If used, handler must be overridden, as TickerBase::handler would attempt
* to reschedule. This is done by `TimeoutBase` (used by `Timeout` and `LowPowerTimeout`).
*
* @param func pointer to the function to be called
* @param abs_time the time for the call
*
* @note setting @a abs_time to a time in the past means the event will be scheduled immediately
* resulting in an instant call to the function.
*/
void attach_absolute(Callback<void()> func, TickerDataClock::time_point abs_time);
void handler() override;
std::chrono::microseconds _delay; /**< Time delay (in microseconds) for resetting the multishot callback. */
Callback<void()> _function; /**< Callback. */
bool _lock_deepsleep; /**< Flag which indicates if deep sleep should be disabled. */
#endif
private:
void setup(std::chrono::microseconds t);
void setup_absolute(TickerDataClock::time_point t);
};
class Ticker : public TickerBase {
public:
Ticker();
};
/** @}*/
} // namespace mbed

170
drivers/TickerDataClock.h Normal file
View File

@ -0,0 +1,170 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2019 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef MBED_TICKERDATACLOCK_H
#define MBED_TICKERDATACLOCK_H
#include <chrono>
#include "hal/ticker_api.h"
namespace mbed {
/**
* \defgroup drivers_TickerDataClock TickerDataClock class
* \ingroup drivers-public-api-ticker
* @{
*/
/**
* A partial implementation of a C++11 Clock representing a HAL ticker.
*
* This class allows us to create chrono time_points for objects like Timer,
* with the limitation that the tickers are not singletons. This means:
*
* * the now() function is not static - this will limit
* use with some algorithms,
* * there is no distinction between time_points for different
* tickers
*
* This "pseudo-Clock" approach has been endorsed by Howard Hinnant
* (designer of Chrono) here:
* https://stackoverflow.com/questions/56400313/why-does-the-c-standard-require-the-clocknow-function-to-be-static
*
* TickerDataClock::time_point values should only be used with mbed APIs specifically taking
* them, not passed to generic templated chrono algorithms, and it is up to the user to use them
* in conjunction with the correct TickerDataClock.
*
* operators for `->` and conversion to `ticker_data_t *` are provided allowing
* TickerDataClock to be easily substituted in place of a `ticker_data_t *`.
*/
class TickerDataClock {
public:
/** Construct a TickerDataClock referring to a ticker_data_t */
constexpr TickerDataClock(const ticker_data_t *ticker) : _ticker(ticker)
{
}
/* duration is C++11 standard microseconds, so representation will be 64-bit signed integer */
using duration = std::chrono::microseconds;
using rep = duration::rep;
using period = duration::period;
using time_point = std::chrono::time_point<TickerDataClock>;
static const bool is_steady = false;
/** Initialize a ticker and set the event handler
*
* @param handler A handler to be set
*/
void set_handler(ticker_event_handler handler)
{
return ticker_set_handler(_ticker, handler);
}
/** Remove an event from the queue
*
* @param obj The event object to be removed from the queue
*/
void remove_event(ticker_event_t *obj)
{
ticker_remove_event(_ticker, obj);
}
/** Insert an event to the queue
*
* The event will be executed in timestamp - ticker_read_us() us.
*
* @note If an event is inserted with a timestamp less than the current
* timestamp then the event will be scheduled immediately resulting in
* an instant call to event handler.
*
* @param obj The event object to be inserted to the queue
* @param timestamp The event's timestamp
* @param id The event object
*/
void insert_event(ticker_event_t *obj, time_point timestamp, uint32_t id)
{
ticker_insert_event_us(_ticker, obj, timestamp.time_since_epoch().count(), id);
}
/** Read the current (absolute) ticker's timestamp
*
* @warning Return an absolute timestamp counting from the initialization of the
* ticker.
*
* @return The current timestamp
*/
time_point now() const
{
return time_point(duration(ticker_read_us(_ticker)));
}
/** Read the next event's timestamp
*
* @param timestamp The timestamp object.
* @return 1 if timestamp is pending event, 0 if there's no event pending
*/
int get_next_timestamp(time_point *timestamp) const
{
us_timestamp_t t;
int ret = ticker_get_next_timestamp_us(_ticker, &t);
*timestamp = time_point(duration(t));
return ret;
}
/** Suspend this ticker
*
* When suspended reads will always return the same time and no
* events will be dispatched. When suspended the common layer
* will only ever call the interface function clear_interrupt()
* and that is only if ticker_irq_handler is called.
*
*/
void suspend()
{
ticker_suspend(_ticker);
}
/** Resume this ticker
*
* When resumed the ticker will ignore any time that has passed
* and continue counting up where it left off.
*/
void resume()
{
ticker_resume(_ticker);
}
constexpr const ticker_data_t *operator->() const
{
return _ticker;
}
constexpr operator const ticker_data_t *() const
{
return _ticker;
}
private:
const ticker_data_t *const _ticker;
};
inline TickerDataClock::time_point get_time_point(const ticker_event_t &event)
{
return TickerDataClock::time_point{TickerDataClock::duration{event.timestamp}};
}
/** @}*/
}
#endif /* MBED_TICKERDATACLOCK_H */

View File

@ -17,8 +17,8 @@
#ifndef MBED_TIMEOUT_H
#define MBED_TIMEOUT_H
#include "drivers/HighResClock.h"
#include "drivers/Ticker.h"
#include "platform/NonCopyable.h"
namespace mbed {
/**
@ -57,14 +57,72 @@ namespace mbed {
* }
* @endcode
*/
class Timeout : public Ticker, private NonCopyable<Timeout> {
class TimeoutBase : public TickerBase {
public:
/** Return time remaining until callback
*
* @return time remaining until callback is due
*
* @note if the callback is overdue, or has already run, the returned value will be negative
*/
std::chrono::microseconds remaining_time() const
{
return scheduled_time() - _ticker_data.now();
}
#if !defined(DOXYGEN_ONLY)
protected:
virtual void handler();
using TickerBase::TickerBase;
~TimeoutBase() = default;
void handler() final;
/** Return scheduled callback time
*
* @return scheduled callback time
*
* @note if the callback is overdue, or has already run, the returned value will be in the past
*/
TickerDataClock::time_point scheduled_time() const
{
return get_time_point(event);
}
#endif
};
class Timeout : public TimeoutBase {
public:
Timeout();
/** Clock to use with attach_absolute, guaranteeing running only while attached or manually locked */
using clock = HighResClock;
/** Clock to use with attach_absolute, running always */
using steady_clock = SteadyHighResClock;
/** @copydoc TimeoutBase::scheduled_time() */
HighResClock::time_point scheduled_time() const
{
/* Massage from virtual TickerDataClock::time_point used internally to true HighResClock::time_point */
return HighResClock::time_point{TimeoutBase::scheduled_time().time_since_epoch()};
}
/** Attach a function to be called by the Timeout, specifying the absolute time
*
* @param func pointer to the function to be called
* @param abs_time the absolute time for the call, referenced to HighResClock
*
* @note setting @a abs_time to a time in the past means the event will be scheduled immediately
* resulting in an instant call to the function.
*/
template <class F>
void attach_absolute(F &&func, HighResClock::time_point abs_time)
{
/* Massage from true HighResClock::time_point to virtual TickerDataClock::time_point used internally */
TimeoutBase::attach_absolute(std::forward<F>(func), TickerDataClock::time_point{abs_time.time_since_epoch()});
}
};
/** @}*/
} // namespace mbed

View File

@ -18,7 +18,7 @@
#define MBED_TIMER_H
#include "platform/platform.h"
#include "hal/ticker_api.h"
#include "drivers/TickerDataClock.h"
#include "platform/NonCopyable.h"
namespace mbed {
@ -51,13 +51,9 @@ namespace mbed {
* }
* @endcode
*/
class Timer : private NonCopyable<Timer> {
class TimerBase : private NonCopyable<TimerBase> {
public:
Timer();
Timer(const ticker_data_t *data);
~Timer();
/** Start the timer
*/
void start();
@ -76,40 +72,57 @@ public:
*
* @returns Time passed in seconds
*/
float read();
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Floating point operators should normally be avoided for code size. If really needed, you can use `duration<float>{elapsed_time()}.count()`")
float read() const;
/** Get the time passed in milliseconds
*
* @returns Time passed in milliseconds
*/
int read_ms();
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Use the Chrono-based elapsed_time method. If integer milliseconds are needed, you can use `duration_cast<milliseconds>(elapsed_time()).count()`")
int read_ms() const;
/** Get the time passed in microseconds
*
* @returns Time passed in microseconds
*/
int read_us();
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Use the Chrono-based elapsed_time method. If integer microseconds are needed, you can use `elapsed_time().count()`")
int read_us() const;
/** An operator shorthand for read()
*/
operator float();
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Floating point operators should normally be avoided for code size. If really needed, you can use `duration<float>{elapsed_time()}.count()`")
operator float() const;
/** Get in a high resolution type the time passed in microseconds.
* Returns a 64 bit integer.
*/
us_timestamp_t read_high_resolution_us();
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Use the Chrono-based elapsed_time method. If integer microseconds are needed, you can use `elapsed_time().count()`")
us_timestamp_t read_high_resolution_us() const;
/** Get in a high resolution type the time passed in microseconds.
* Returns a 64 bit integer chrono duration.
*/
std::chrono::microseconds elapsed_time() const;
#if !defined(DOXYGEN_ONLY)
protected:
us_timestamp_t slicetime();
int _running; // whether the timer is running
us_timestamp_t _start; // the start time of the latest slice
us_timestamp_t _time; // any accumulated time from previous slices
const ticker_data_t *_ticker_data;
TimerBase(const ticker_data_t *data);
TimerBase(const ticker_data_t *data, bool lock_deepsleep);
~TimerBase();
std::chrono::microseconds slicetime() const;
TickerDataClock::time_point _start; // the start time of the latest slice
std::chrono::microseconds _time; // any accumulated time from previous slices
TickerDataClock _ticker_data;
bool _lock_deepsleep; // flag that indicates if deep sleep should be disabled
bool _running = false; // whether the timer is running
};
#endif
class Timer : public TimerBase {
public:
Timer();
};
/** @}*/
} // namespace mbed

View File

@ -18,9 +18,12 @@
#define MBED_TIMEREVENT_H
#include "hal/ticker_api.h"
#include "platform/mbed_toolchain.h"
#include "platform/NonCopyable.h"
#include "drivers/TickerDataClock.h"
namespace mbed {
/**
* \defgroup drivers_TimerEvent TimerEvent class
* \ingroup drivers-public-api-ticker
@ -32,8 +35,8 @@ namespace mbed {
* @note Synchronization level: Interrupt safe
*/
class TimerEvent : private NonCopyable<TimerEvent> {
public:
TimerEvent();
#if !defined(DOXYGEN_ONLY)
protected:
TimerEvent(const ticker_data_t *data);
/** The handler registered with the underlying timer interrupt
@ -44,10 +47,8 @@ public:
/** Destruction removes it...
*/
virtual ~TimerEvent();
~TimerEvent();
#if !defined(DOXYGEN_ONLY)
protected:
// The handler called to service the timer event of the derived class
virtual void handler() = 0;
@ -62,9 +63,38 @@ protected:
* Ticker's present timestamp is used for reference. For timestamps
* from the past the event is scheduled after ticker's overflow.
* For reference @see convert_timestamp
*
* @deprecated use `insert(std::chrono::microseconds timestamp)`
*/
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer microsecond count. For example use `5ms` rather than `5000`.")
void insert(timestamp_t timestamp);
/** Set relative timestamp of the internal event.
* @param timestamp event's us timestamp
*
* @warning
* Do not insert more than one timestamp.
* The same @a event object is used for every @a insert/insert_absolute call.
*
* @warning
* Ticker's present timestamp is used for reference. For timestamps
* from the past the event is scheduled after ticker's overflow.
* For reference @see convert_timestamp
*/
void insert(std::chrono::microseconds timestamp);
/** Set absolute timestamp of the internal event.
* @param timestamp event's us timestamp
*
* @warning
* Do not insert more than one timestamp.
* The same @a event object is used for every @a insert/insert_absolute call.
*
* @deprecated use `insert_absolute(TickerDataClock::time_point timestamp)`
*/
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer microsecond count. For example use `_ticker_data.now() + 5ms` rather than `ticker_read_us(_ticker_data) + 5000`.")
void insert_absolute(us_timestamp_t timestamp);
/** Set absolute timestamp of the internal event.
* @param timestamp event's us timestamp
*
@ -72,7 +102,7 @@ protected:
* Do not insert more than one timestamp.
* The same @a event object is used for every @a insert/insert_absolute call.
*/
void insert_absolute(us_timestamp_t timestamp);
void insert_absolute(TickerDataClock::time_point timestamp);
/** Remove timestamp.
*/
@ -80,7 +110,7 @@ protected:
ticker_event_t event;
const ticker_data_t *_ticker_data;
TickerDataClock _ticker_data;
#endif
};

View File

@ -16,25 +16,26 @@
*/
#include "drivers/Ticker.h"
#include "drivers/TimerEvent.h"
#include "hal/ticker_api.h"
#include "platform/mbed_critical.h"
#include "hal/us_ticker_api.h"
#include "platform/CriticalSectionLock.h"
#include "platform/mbed_power_mgmt.h"
using namespace std::chrono;
namespace mbed {
Ticker::Ticker() : TimerEvent(), _delay(0), _lock_deepsleep(true)
TickerBase::TickerBase(const ticker_data_t *data) : TickerBase(data, !data->interface->runs_in_deep_sleep)
{
}
// When low power ticker is in use, then do not disable deep sleep.
Ticker::Ticker(const ticker_data_t *data) : TimerEvent(data), _delay(0), _lock_deepsleep(!data->interface->runs_in_deep_sleep)
TickerBase::TickerBase(const ticker_data_t *data, bool lock_deepsleep) : TimerEvent(data), _lock_deepsleep(lock_deepsleep)
{
}
void Ticker::detach()
void TickerBase::detach()
{
core_util_critical_section_enter();
CriticalSectionLock lock;
remove();
// unlocked only if we were attached (we locked it) and this is not low power ticker
if (_function && _lock_deepsleep) {
@ -42,36 +43,64 @@ void Ticker::detach()
}
_function = 0;
core_util_critical_section_exit();
}
void Ticker::setup(us_timestamp_t t)
void TickerBase::setup(microseconds t)
{
core_util_critical_section_enter();
remove();
_delay = t;
insert_absolute(_delay + ticker_read_us(_ticker_data));
core_util_critical_section_exit();
insert_absolute(_ticker_data.now() + t);
}
void Ticker::handler()
void TickerBase::setup_absolute(TickerDataClock::time_point t)
{
insert_absolute(event.timestamp + _delay);
remove();
insert_absolute(t);
}
void TickerBase::handler()
{
insert_absolute(get_time_point(event) + _delay);
if (_function) {
_function();
}
}
void Ticker::attach_us(Callback<void()> func, us_timestamp_t t)
void TickerBase::attach(Callback<void()> func, microseconds t)
{
core_util_critical_section_enter();
CriticalSectionLock lock;
// lock only for the initial callback setup and this is not low power ticker
if (!_function && _lock_deepsleep) {
sleep_manager_lock_deep_sleep();
}
_function = func;
setup(t);
core_util_critical_section_exit();
}
void TickerBase::attach_us(Callback<void()> func, us_timestamp_t t)
{
CriticalSectionLock lock;
// lock only for the initial callback setup and this is not low power ticker
if (!_function && _lock_deepsleep) {
sleep_manager_lock_deep_sleep();
}
_function = func;
setup(microseconds{t});
}
void TickerBase::attach_absolute(Callback<void()> func, TickerDataClock::time_point abs_time)
{
CriticalSectionLock lock;
// lock only for the initial callback setup and this is not low power ticker
if (!_function && _lock_deepsleep) {
sleep_manager_lock_deep_sleep();
}
_function = func;
setup_absolute(abs_time);
}
Ticker::Ticker() : TickerBase(get_us_ticker_data(), true)
{
}
} // namespace mbed

View File

@ -15,14 +15,44 @@
* limitations under the License.
*/
#include "drivers/Timeout.h"
#include "drivers/LowPowerTimeout.h"
#include "drivers/HighResClock.h"
#include "drivers/LowPowerClock.h"
#include "drivers/RealTimeClock.h"
using namespace std::chrono;
namespace mbed {
void Timeout::handler()
void TimeoutBase::handler()
{
Callback<void()> local = _function;
detach();
local.call();
if (_function) {
if (_lock_deepsleep) {
sleep_manager_unlock_deep_sleep();
}
_function();
_function = nullptr;
}
}
Timeout::Timeout() : TimeoutBase(get_us_ticker_data(), true)
{
}
/* A few miscellaneous out-of-line static members from various related classes,
* just to save them getting needing their own cpp file for one line.
* (In C++17 could avoid the need for this by making the members inline).
*/
const bool HighResClock::is_steady;
const bool SteadyHighResClock::is_steady;
const bool LowPowerClock::is_steady;
mstd::once_flag SteadyHighResClock::init;
const bool RealTimeClock::is_steady;
#if DEVICE_LPTICKER
LowPowerTimeout::LowPowerTimeout() : TimeoutBase(get_lp_ticker_data(), true)
{
}
#endif
} // namespace mbed

View File

@ -17,105 +17,108 @@
#include "drivers/Timer.h"
#include "hal/ticker_api.h"
#include "hal/us_ticker_api.h"
#include "platform/CriticalSectionLock.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_power_mgmt.h"
using std::milli;
using std::micro;
using namespace std::chrono;
namespace mbed {
Timer::Timer() : _running(), _start(), _time(), _ticker_data(get_us_ticker_data()), _lock_deepsleep(true)
TimerBase::TimerBase(const ticker_data_t *data) : TimerBase(data, !data->interface->runs_in_deep_sleep)
{
}
TimerBase::TimerBase(const ticker_data_t *data, bool lock_deepsleep) : _ticker_data(data), _lock_deepsleep(lock_deepsleep)
{
reset();
}
Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker_data(data),
_lock_deepsleep(!data->interface->runs_in_deep_sleep)
TimerBase::~TimerBase()
{
reset();
}
Timer::~Timer()
{
core_util_critical_section_enter();
if (_running) {
if (_lock_deepsleep) {
sleep_manager_unlock_deep_sleep();
}
}
_running = 0;
core_util_critical_section_exit();
}
void Timer::start()
void TimerBase::start()
{
core_util_critical_section_enter();
CriticalSectionLock lock;
if (!_running) {
if (_lock_deepsleep) {
sleep_manager_lock_deep_sleep();
}
_start = ticker_read_us(_ticker_data);
_running = 1;
_start = _ticker_data.now();
_running = true;
}
core_util_critical_section_exit();
}
void Timer::stop()
void TimerBase::stop()
{
core_util_critical_section_enter();
CriticalSectionLock lock;
_time += slicetime();
if (_running) {
if (_lock_deepsleep) {
sleep_manager_unlock_deep_sleep();
}
}
_running = 0;
core_util_critical_section_exit();
_running = false;
}
int Timer::read_us()
int TimerBase::read_us() const
{
return read_high_resolution_us();
return duration<int, micro>(elapsed_time()).count();
}
float Timer::read()
float TimerBase::read() const
{
return (float)read_high_resolution_us() / 1000000.0f;
return duration<float>(elapsed_time()).count();
}
int Timer::read_ms()
int TimerBase::read_ms() const
{
return read_high_resolution_us() / 1000;
return duration_cast<duration<int, milli>>(elapsed_time()).count();
}
us_timestamp_t Timer::read_high_resolution_us()
us_timestamp_t TimerBase::read_high_resolution_us() const
{
core_util_critical_section_enter();
us_timestamp_t time = _time + slicetime();
core_util_critical_section_exit();
return time;
return duration_cast<duration<us_timestamp_t, micro>>(elapsed_time()).count();
}
us_timestamp_t Timer::slicetime()
microseconds TimerBase::elapsed_time() const
{
us_timestamp_t ret = 0;
core_util_critical_section_enter();
CriticalSectionLock lock;
return _time + slicetime();
}
microseconds TimerBase::slicetime() const
{
CriticalSectionLock lock;
microseconds ret;
if (_running) {
ret = ticker_read_us(_ticker_data) - _start;
ret = _ticker_data.now() - _start;
}
core_util_critical_section_exit();
return ret;
}
void Timer::reset()
void TimerBase::reset()
{
core_util_critical_section_enter();
_start = ticker_read_us(_ticker_data);
_time = 0;
core_util_critical_section_exit();
CriticalSectionLock lock;
_start = _ticker_data.now();
_time = 0s;
}
Timer::operator float()
TimerBase::operator float() const
{
return duration<float>(elapsed_time()).count();
}
Timer::Timer() : TimerBase(get_us_ticker_data(), true)
{
return read();
}
} // namespace mbed

View File

@ -19,21 +19,18 @@
#include <stddef.h>
#include "hal/us_ticker_api.h"
namespace mbed {
using namespace std::chrono;
TimerEvent::TimerEvent() : event(), _ticker_data(get_us_ticker_data())
{
ticker_set_handler(_ticker_data, (&TimerEvent::irq));
}
namespace mbed {
TimerEvent::TimerEvent(const ticker_data_t *data) : event(), _ticker_data(data)
{
ticker_set_handler(_ticker_data, (&TimerEvent::irq));
_ticker_data.set_handler(irq);
}
void TimerEvent::irq(uint32_t id)
{
TimerEvent *timer_event = (TimerEvent *)id;
TimerEvent *timer_event = reinterpret_cast<TimerEvent *>(id);
timer_event->handler();
}
@ -48,14 +45,24 @@ void TimerEvent::insert(timestamp_t timestamp)
ticker_insert_event(_ticker_data, &event, timestamp, (uint32_t)this);
}
void TimerEvent::insert(microseconds timestamp)
{
insert_absolute(_ticker_data.now() + timestamp);
}
void TimerEvent::insert_absolute(us_timestamp_t timestamp)
{
ticker_insert_event_us(_ticker_data, &event, timestamp, (uint32_t)this);
}
void TimerEvent::insert_absolute(TickerDataClock::time_point timestamp)
{
_ticker_data.insert_event(&event, timestamp, (uint32_t)this);
}
void TimerEvent::remove()
{
ticker_remove_event(_ticker_data, &event);
_ticker_data.remove_event(&event);
}
} // namespace mbed

View File

@ -465,6 +465,21 @@ int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *time
return ret;
}
int ticker_get_next_timestamp_us(const ticker_data_t *const data, us_timestamp_t *timestamp)
{
int ret = 0;
/* if head is NULL, there are no pending events */
core_util_critical_section_enter();
if (data->queue->head != NULL) {
*timestamp = data->queue->head->timestamp;
ret = 1;
}
core_util_critical_section_exit();
return ret;
}
void ticker_suspend(const ticker_data_t *const ticker)
{
core_util_critical_section_enter();

View File

@ -187,6 +187,14 @@ us_timestamp_t ticker_read_us(const ticker_data_t *const ticker);
*/
int ticker_get_next_timestamp(const ticker_data_t *const ticker, timestamp_t *timestamp);
/** Read the next event's timestamp
*
* @param ticker The ticker object.
* @param timestamp The timestamp object.
* @return 1 if timestamp is pending event, 0 if there's no event pending
*/
int ticker_get_next_timestamp_us(const ticker_data_t *const ticker, us_timestamp_t *timestamp);
/** Suspend this ticker
*
* When suspended reads will always return the same time and no