pebble/io/stores/store_poll.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * @file store_poll.h | ||
| 3 | * @brief Wall-clock deadlines for the stores that poll the phone. | ||
| 4 | * | ||
| 5 | * @ingroup lib_stores | ||
| 6 | */ | ||
| 7 | #pragma once | ||
| 8 | #include <pebble.h> | ||
| 9 | #include <time.h> | ||
| 10 | |||
| 11 | /** | ||
| 12 | * @addtogroup lib_stores | ||
| 13 | * @{ | ||
| 14 | */ | ||
| 15 | |||
| 16 | /** | ||
| 17 | * @brief The next wall-clock second a poll of this interval falls due. | ||
| 18 | * | ||
| 19 | * Counted from the epoch rather than from launch, so two watches started minutes apart poll at | ||
| 20 | * the same moments and a relaunch does not shift the phase. | ||
| 21 | * | ||
| 22 | * @param poll_min Minutes between polls. Must be above 0. | ||
| 23 | * @param now The current wall-clock time. | ||
| 24 | * @return The second the next poll is due. | ||
| 25 | */ | ||
| 26 | 15 | static inline time_t store_poll_next(int poll_min, time_t now) | |
| 27 | { | ||
| 28 | 15 | time_t interval = (time_t)poll_min * SECONDS_PER_MINUTE; | |
| 29 | 15 | return ((now / interval) + 1) * interval; | |
| 30 | } | ||
| 31 | |||
| 32 | /** | ||
| 33 | * @brief Whether @p next has come round, moving it on to the following deadline when it has. | ||
| 34 | * | ||
| 35 | * A clock that jumps forward just fires once and carries on. One that jumps back would strand the | ||
| 36 | * deadline more than an interval ahead, so that case is pulled back in. | ||
| 37 | * | ||
| 38 | * @param poll_min Minutes between polls. 0 or less means polling is off and this is never due. | ||
| 39 | * @param[in,out] next The store's deadline, read and updated in place. | ||
| 40 | * @param now The current wall-clock time. | ||
| 41 | * @return Whether a poll should go out now. | ||
| 42 | */ | ||
| 43 | 13 | static inline bool store_poll_due(int poll_min, time_t *next, time_t now) | |
| 44 | { | ||
| 45 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
|
13 | if (poll_min <= 0) |
| 46 | { | ||
| 47 | 2 | return false; | |
| 48 | } | ||
| 49 | |||
| 50 | 11 | time_t interval = (time_t)poll_min * SECONDS_PER_MINUTE; | |
| 51 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 10 times.
|
11 | if (*next > now + interval) |
| 52 | { | ||
| 53 | 1 | *next = store_poll_next(poll_min, now); | |
| 54 | } | ||
| 55 | |||
| 56 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | if (now < *next) |
| 57 | { | ||
| 58 | 5 | return false; | |
| 59 | } | ||
| 60 | |||
| 61 | 6 | *next = store_poll_next(poll_min, now); | |
| 62 | 6 | return true; | |
| 63 | } | ||
| 64 | |||
| 65 | /** | ||
| 66 | * @brief Whether a reading is worth asking for again now that the phone is back. | ||
| 67 | * | ||
| 68 | * The phone's side may have been closed the whole time it was away, so a face catches up a reading | ||
| 69 | * that went stale meanwhile. Only a reading that never arrived, or one at least its own interval old, | ||
| 70 | * is asked for, so bluetooth dropping in and out cannot fetch faster than the normal polling. Polling | ||
| 71 | * turned off is left alone, the same as its store. | ||
| 72 | * | ||
| 73 | * @param age_s Seconds since the reading arrived, or below 0 when it never has. | ||
| 74 | * @param poll_min Minutes between polls. 0 or less means polling is off. | ||
| 75 | * @return Whether to ask for the reading again. | ||
| 76 | */ | ||
| 77 | 4 | static inline bool store_poll_reconnect_due(int age_s, int poll_min) | |
| 78 | { | ||
| 79 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
|
4 | if (poll_min <= 0) |
| 80 | { | ||
| 81 | 1 | return false; | |
| 82 | } | ||
| 83 | // a clock set back makes a saved reading's age negative too, so it reads as never arrived and the | ||
| 84 | // reconnect asks again. the first answer resets the age, and a reconnect means the phone is there | ||
| 85 | // to give one, so it costs about one fetch. counting that age as fresh instead would skip every | ||
| 86 | // reconnect fetch until the clock caught up, which can be hours | ||
| 87 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
|
3 | return age_s < 0 || age_s >= poll_min * SECONDS_PER_MINUTE; |
| 88 | } | ||
| 89 | |||
| 90 | /** @brief One store's polling: its interval, whether it polls at all, and when it is next due. */ | ||
| 91 | typedef struct | ||
| 92 | { | ||
| 93 | time_t next; ///< Wall-clock second the next recurring poll is due | ||
| 94 | int poll_min; ///< Minutes between polls. 0 or less means no recurring poll | ||
| 95 | bool live; ///< True on a live face. A store seeded with fixtures never polls | ||
| 96 | } StorePoll; | ||
| 97 | |||
| 98 | /** | ||
| 99 | * @brief Take a store's interval and whether it is live, as its init and its reconfigure both do. | ||
| 100 | * | ||
| 101 | * Both are always recorded. The deadline only moves when polling is on, and then to the next | ||
| 102 | * interval boundary, so a save can bring a poll nearer but never make one come faster than the | ||
| 103 | * interval allows. | ||
| 104 | * | ||
| 105 | * @param[in,out] poll The store's polling state. | ||
| 106 | * @param poll_min Minutes between polls. 0 or less turns polling off. | ||
| 107 | * @param live Whether the store is live. | ||
| 108 | * @param now The current wall-clock time. | ||
| 109 | * @return Whether polling is on, which is when a store may arm its first or catch-up fetch. | ||
| 110 | */ | ||
| 111 | bool store_poll_set(StorePoll *poll, int poll_min, bool live, time_t now); | ||
| 112 | |||
| 113 | /** | ||
| 114 | * @brief A store's turn on the face's cadence: whether a poll should go out now. | ||
| 115 | * | ||
| 116 | * @param[in,out] poll The store's polling state. The deadline moves on when a poll is due. | ||
| 117 | * @param now The current wall-clock time. | ||
| 118 | * @return Whether to ask the phone now. | ||
| 119 | */ | ||
| 120 | bool store_poll_turn(StorePoll *poll, time_t now); | ||
| 121 | |||
| 122 | /** @} */ | ||
| 123 |