| 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 |