Line |
Branch |
Decision |
Exec |
Source |
1 |
|
|
|
#pragma once |
2 |
|
|
|
|
3 |
|
|
|
#include <rusefi/rusefi_time_types.h> |
4 |
|
|
|
|
5 |
|
|
|
// custom start value could be useful for testing |
6 |
|
|
|
#ifndef WRAP_AROUND_INITIAL_UPPER |
7 |
|
|
|
#define WRAP_AROUND_INITIAL_UPPER 0 |
8 |
|
|
|
#endif |
9 |
|
|
|
|
10 |
|
|
|
/** |
11 |
|
|
|
* Provide a 62-bit counter from a 32-bit counter source that wraps around. |
12 |
|
|
|
* |
13 |
|
|
|
* If you'd like it use it with a 16-bit counter, shift the source by 16 before passing it here. |
14 |
|
|
|
* This class is thread/interrupt-safe. |
15 |
|
|
|
*/ |
16 |
|
|
|
struct WrapAround62 { |
17 |
|
|
10028 |
uint64_t update(uint32_t source) { |
18 |
|
|
|
// Shift cannot be 31, as we wouldn't be able to tell if time is moving forward or |
19 |
|
|
|
// backward relative to m_upper. We do need to handle both directions as our |
20 |
|
|
|
// "thread" can be racing with other "threads" in sampling stamp and updating |
21 |
|
|
|
// m_upper. |
22 |
|
|
10028 |
constexpr unsigned shift = 30; |
23 |
|
|
|
|
24 |
|
|
10028 |
uint32_t upper = m_upper; |
25 |
|
|
10028 |
uint32_t relative_unsigned = source - (upper << shift); |
26 |
|
|
10028 |
upper += int32_t(relative_unsigned) >> shift; |
27 |
|
|
10028 |
m_upper = upper; |
28 |
|
|
|
|
29 |
|
|
|
// Yes we could just do upper<<shift, but then the result would span both halves of |
30 |
|
|
|
// the 64-bit result. Doing it this way means we only operate on one half at a |
31 |
|
|
|
// time. Source will supply those bits anyways, so we don't need them from |
32 |
|
|
|
// upper... |
33 |
|
|
10028 |
return (efitick_t(upper >> (32 - shift)) << 32) | source; |
34 |
|
|
|
} |
35 |
|
|
|
|
36 |
|
|
|
private: |
37 |
|
|
|
volatile uint32_t m_upper = WRAP_AROUND_INITIAL_UPPER; |
38 |
|
|
|
}; |
39 |
|
|
|
|