mirror of https://github.com/ARMmbed/mbed-os.git
Add Chrono support to Ticker et al
parent
b9aa69a376
commit
34428f9d4c
|
@ -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())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
/** @}*/
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue