Skip to content

Commit 877d848

Browse files
committed
Add Chrono support to Ticker et al
1 parent cf2bdf6 commit 877d848

File tree

7 files changed

+222
-52
lines changed

7 files changed

+222
-52
lines changed

drivers/Ticker.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@
1717
#ifndef MBED_TICKER_H
1818
#define MBED_TICKER_H
1919

20+
#include <chrono>
2021
#include <mstd_utility>
22+
#include "drivers/TickerClock.h"
2123
#include "drivers/TimerEvent.h"
2224
#include "platform/Callback.h"
2325
#include "platform/mbed_toolchain.h"
2426
#include "platform/NonCopyable.h"
2527
#include "hal/lp_ticker_api.h"
2628

2729
namespace mbed {
30+
2831
/**
2932
* \defgroup drivers_Ticker Ticker class
3033
* \ingroup drivers-public-api-ticker
@@ -90,7 +93,8 @@ class Ticker : public TimerEvent, private NonCopyable<Ticker> {
9093
#endif
9194
void attach(F &&func, float t)
9295
{
93-
attach_us(std::forward<F>(func), t * 1000000.0f);
96+
auto float_interval = std::chrono::duration<float>(t);
97+
attach(std::forward<F>(func), std::chrono::duration_cast<std::chrono::microseconds>(float_interval));
9498
}
9599

96100
/** Attach a member function to be called by the Ticker, specifying the interval in seconds
@@ -121,8 +125,21 @@ class Ticker : public TimerEvent, private NonCopyable<Ticker> {
121125
* for threads scheduling.
122126
*
123127
*/
128+
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer microsecond count. For example use `10ms` rather than `10000`.")
124129
void attach_us(Callback<void()> func, us_timestamp_t t);
125130

131+
/** Attach a function to be called by the Ticker, specifying the interval in microseconds
132+
*
133+
* @param func pointer to the function to be called
134+
* @param t the time between calls in micro-seconds
135+
*
136+
* @note setting @a t to a value shorter than it takes to process the ticker callback
137+
* causes the system to hang. Ticker callback is called constantly with no time
138+
* for threads scheduling.
139+
*
140+
*/
141+
void attach(Callback<void()> func, TickerClock::duration t);
142+
126143
/** Attach a member function to be called by the Ticker, specifying the interval in microseconds
127144
*
128145
* @param obj pointer to the object to call the member function on
@@ -152,11 +169,10 @@ class Ticker : public TimerEvent, private NonCopyable<Ticker> {
152169

153170
#if !defined(DOXYGEN_ONLY)
154171
protected:
155-
void setup(us_timestamp_t t);
172+
void setup(TickerClock::duration t);
156173
virtual void handler();
157174

158-
protected:
159-
us_timestamp_t _delay; /**< Time delay (in microseconds) for resetting the multishot callback. */
175+
TickerClock::duration _delay; /**< Time delay (in microseconds) for resetting the multishot callback. */
160176
Callback<void()> _function; /**< Callback. */
161177
bool _lock_deepsleep; /**< Flag which indicates if deep sleep should be disabled. */
162178
#endif

drivers/TickerClock.h

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2019 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef MBED_TICKERCLOCK_H
18+
#define MBED_TICKERCLOCK_H
19+
20+
#include <chrono>
21+
#include "hal/ticker_api.h"
22+
23+
namespace mbed {
24+
/**
25+
* \defgroup drivers_TickerClock TickerClock class
26+
* \ingroup drivers-public-api-ticker
27+
* @{
28+
*/
29+
30+
/**
31+
* A partial implementation of a C++11 Clock representing a HAL ticker.
32+
*
33+
* This class allows us to create chrono time_points for objects like Timer,
34+
* with the limitation that the tickers are not singletons. This means:
35+
*
36+
* * the now() function is not static - this will limit
37+
* use with some algorithms,
38+
* * there is no distinction between time_points for different
39+
* tickers
40+
*
41+
* This "pseudo-Clock" approach has been endorsed by Howard Hinnant
42+
* (designer of Chrono) here:
43+
* https://stackoverflow.com/questions/56400313/why-does-the-c-standard-require-the-clocknow-function-to-be-static
44+
*
45+
* TickerClock::time_point values should only be used with mbed APIs specifically taking
46+
* them, not passed to generic templated chrono algorithms, and it is up to the user to use them
47+
* in conjunction with the correct TickerClock.
48+
*
49+
* operators for `->` and conversion to `ticker_data_t *` are provided allowing
50+
* TickerClock to be easily substituted in place of a `ticker_data_t *`.
51+
*/
52+
struct TickerClock {
53+
/** Construct a TickerClock referring to a ticker_data_t */
54+
constexpr TickerClock(const ticker_data_t *ticker) : _ticker(ticker)
55+
{
56+
}
57+
/* duration is C++11 standard microseconds, so representation will be 64-bit signed integer */
58+
using duration = std::chrono::microseconds;
59+
using rep = duration::rep;
60+
using period = duration::period;
61+
using time_point = std::chrono::time_point<TickerClock>;
62+
static const bool is_steady = false;
63+
time_point now() const
64+
{
65+
return time_point(duration(ticker_read_us(_ticker)));
66+
}
67+
constexpr const ticker_data_t *operator->() const
68+
{
69+
return _ticker;
70+
}
71+
constexpr operator const ticker_data_t *() const
72+
{
73+
return _ticker;
74+
}
75+
private:
76+
const ticker_data_t *_ticker;
77+
};
78+
79+
inline TickerClock::time_point get_time_point(const ticker_event_t &event)
80+
{
81+
return TickerClock::time_point(TickerClock::duration(event.timestamp));
82+
}
83+
84+
/** @}*/
85+
86+
}
87+
#endif /* MBED_TICKERCLOCK_H */

drivers/Timer.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#define MBED_TIMER_H
1919

2020
#include "platform/platform.h"
21-
#include "hal/ticker_api.h"
21+
#include "drivers/TickerClock.h"
2222
#include "platform/NonCopyable.h"
2323

2424
namespace mbed {
@@ -58,6 +58,10 @@ class Timer : private NonCopyable<Timer> {
5858
Timer(const ticker_data_t *data);
5959
~Timer();
6060

61+
using period = TickerClock::period;
62+
using duration = TickerClock::duration;
63+
using rep = TickerClock::rep;
64+
6165
/** Start the timer
6266
*/
6367
void start();
@@ -76,6 +80,7 @@ class Timer : private NonCopyable<Timer> {
7680
*
7781
* @returns Time passed in seconds
7882
*/
83+
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>(read_duration()).count()`")
7984
float read();
8085

8186
/** Get the time passed in milliseconds
@@ -92,21 +97,27 @@ class Timer : private NonCopyable<Timer> {
9297

9398
/** An operator shorthand for read()
9499
*/
100+
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>(read_duration()).count()`")
95101
operator float();
96102

97103
/** Get in a high resolution type the time passed in microseconds.
98104
* Returns a 64 bit integer.
99105
*/
100106
us_timestamp_t read_high_resolution_us();
101107

108+
/** Get in a high resolution type the time passed in microseconds.
109+
* Returns a 64 bit integer chrono duration.
110+
*/
111+
duration read_duration();
112+
102113
#if !defined(DOXYGEN_ONLY)
103114
protected:
104-
us_timestamp_t slicetime();
105-
int _running; // whether the timer is running
106-
us_timestamp_t _start; // the start time of the latest slice
107-
us_timestamp_t _time; // any accumulated time from previous slices
108-
const ticker_data_t *_ticker_data;
115+
duration slicetime();
116+
TickerClock::time_point _start; // the start time of the latest slice
117+
duration _time; // any accumulated time from previous slices
118+
TickerClock _ticker_data;
109119
bool _lock_deepsleep; // flag that indicates if deep sleep should be disabled
120+
bool _running = false; // whether the timer is running
110121
};
111122
#endif
112123

drivers/TimerEvent.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
#include "hal/ticker_api.h"
2121
#include "platform/NonCopyable.h"
22+
#include "drivers/TickerClock.h"
2223

2324
namespace mbed {
25+
2426
/**
2527
* \defgroup drivers_TimerEvent TimerEvent class
2628
* \ingroup drivers-public-api-ticker
@@ -62,25 +64,57 @@ class TimerEvent : private NonCopyable<TimerEvent> {
6264
* Ticker's present timestamp is used for reference. For timestamps
6365
* from the past the event is scheduled after ticker's overflow.
6466
* For reference @see convert_timestamp
67+
*
68+
* @deprecated use `insert(TickerClock::duration timestamp)`
6569
*/
70+
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer microsecond count. For example use `5ms` rather than `5000`.")
6671
void insert(timestamp_t timestamp);
6772

73+
/** Set relative timestamp of the internal event.
74+
* @param timestamp event's us timestamp
75+
*
76+
* @warning
77+
* Do not insert more than one timestamp.
78+
* The same @a event object is used for every @a insert/insert_absolute call.
79+
*
80+
* @warning
81+
* Ticker's present timestamp is used for reference. For timestamps
82+
* from the past the event is scheduled after ticker's overflow.
83+
* For reference @see convert_timestamp
84+
*/
85+
void insert(TickerClock::duration timestamp);
86+
6887
/** Set absolute timestamp of the internal event.
6988
* @param timestamp event's us timestamp
7089
*
7190
* @warning
7291
* Do not insert more than one timestamp.
7392
* The same @a event object is used for every @a insert/insert_absolute call.
93+
*
94+
* @deprecated use `insert_absolute(TickerClock::time_point timestamp)`
7495
*/
96+
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`.")
7597
void insert_absolute(us_timestamp_t timestamp);
7698

99+
/** Set absolute timestamp of the internal event.
100+
* @param timestamp event's us timestamp
101+
*
102+
* @note despite being an absolute time, this API has to use a chrono duration
103+
* rather than a chrono time_point
104+
*
105+
* @warning
106+
* Do not insert more than one timestamp.
107+
* The same @a event object is used for every @a insert/insert_absolute call.
108+
*/
109+
void insert_absolute(TickerClock::time_point timestamp);
110+
77111
/** Remove timestamp.
78112
*/
79113
void remove();
80114

81115
ticker_event_t event;
82116

83-
const ticker_data_t *_ticker_data;
117+
TickerClock _ticker_data;
84118
#endif
85119
};
86120

drivers/source/Ticker.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,60 +18,69 @@
1818

1919
#include "drivers/TimerEvent.h"
2020
#include "hal/ticker_api.h"
21+
#include "platform/CriticalSectionLock.h"
2122
#include "platform/mbed_critical.h"
2223
#include "platform/mbed_power_mgmt.h"
2324

2425
namespace mbed {
2526

26-
Ticker::Ticker() : TimerEvent(), _delay(0), _lock_deepsleep(true)
27+
Ticker::Ticker() : TimerEvent(), _lock_deepsleep(true)
2728
{
2829
}
2930

3031
// When low power ticker is in use, then do not disable deep sleep.
31-
Ticker::Ticker(const ticker_data_t *data) : TimerEvent(data), _delay(0), _lock_deepsleep(!data->interface->runs_in_deep_sleep)
32+
Ticker::Ticker(const ticker_data_t *data) : TimerEvent(data), _lock_deepsleep(!data->interface->runs_in_deep_sleep)
3233
{
3334
}
3435

3536
void Ticker::detach()
3637
{
37-
core_util_critical_section_enter();
38+
CriticalSectionLock lock;
3839
remove();
3940
// unlocked only if we were attached (we locked it) and this is not low power ticker
4041
if (_function && _lock_deepsleep) {
4142
sleep_manager_unlock_deep_sleep();
4243
}
4344

4445
_function = 0;
45-
core_util_critical_section_exit();
4646
}
4747

48-
void Ticker::setup(us_timestamp_t t)
48+
void Ticker::setup(TickerClock::duration t)
4949
{
50-
core_util_critical_section_enter();
50+
CriticalSectionLock lock;
5151
remove();
5252
_delay = t;
53-
insert_absolute(_delay + ticker_read_us(_ticker_data));
54-
core_util_critical_section_exit();
53+
insert_absolute(_ticker_data.now() + _delay);
5554
}
5655

5756
void Ticker::handler()
5857
{
59-
insert_absolute(event.timestamp + _delay);
58+
insert_absolute(get_time_point(event) + _delay);
6059
if (_function) {
6160
_function();
6261
}
6362
}
6463

65-
void Ticker::attach_us(Callback<void()> func, us_timestamp_t t)
64+
void Ticker::attach(Callback<void()> func, TickerClock::duration t)
6665
{
67-
core_util_critical_section_enter();
66+
CriticalSectionLock lock;
6867
// lock only for the initial callback setup and this is not low power ticker
6968
if (!_function && _lock_deepsleep) {
7069
sleep_manager_lock_deep_sleep();
7170
}
7271
_function = func;
7372
setup(t);
74-
core_util_critical_section_exit();
73+
}
74+
75+
void Ticker::attach_us(Callback<void()> func, us_timestamp_t t)
76+
{
77+
CriticalSectionLock lock;
78+
// lock only for the initial callback setup and this is not low power ticker
79+
if (!_function && _lock_deepsleep) {
80+
sleep_manager_lock_deep_sleep();
81+
}
82+
_function = func;
83+
setup(TickerClock::duration(t));
7584
}
7685

7786
} // namespace mbed

0 commit comments

Comments
 (0)