core/clock/beats.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * @file beats.c | ||
| 3 | * @brief Pure swatch .beats math, host-testable off-device. | ||
| 4 | * | ||
| 5 | * @ingroup lib_core | ||
| 6 | */ | ||
| 7 | #include "clock/beats.h" | ||
| 8 | #include "math/scale.h" | ||
| 9 | |||
| 10 | #include <string.h> | ||
| 11 | |||
| 12 | 6 | int beats_from_ms(int32_t ms_into_bmt_day) | |
| 13 | { | ||
| 14 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
|
6 | if (ms_into_bmt_day < 0) |
| 15 | { | ||
| 16 | 1 | ms_into_bmt_day = 0; | |
| 17 | } | ||
| 18 | |||
| 19 | 6 | return (int)((ms_into_bmt_day % MS_PER_DAY) / MS_PER_BEAT); | |
| 20 | } | ||
| 21 | |||
| 22 | 3 | uint32_t ms_until_next_beat(int32_t ms_into_bmt_day) | |
| 23 | { | ||
| 24 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ms_into_bmt_day < 0) |
| 25 | { | ||
| 26 | ✗ | ms_into_bmt_day = 0; | |
| 27 | } | ||
| 28 | |||
| 29 | // ms position within the current beat | ||
| 30 | 3 | int32_t into_beat = ms_into_bmt_day % MS_PER_BEAT; | |
| 31 | |||
| 32 | // result runs 1..MS_PER_BEAT and never hits 0 | ||
| 33 | // right on a boundary we report a full beat to the next flip | ||
| 34 | 3 | return (uint32_t)(MS_PER_BEAT - into_beat); | |
| 35 | } | ||
| 36 | |||
| 37 | 6 | int32_t beats_ms_from_hms(int hour, int minute, int second, uint16_t ms) | |
| 38 | { | ||
| 39 | 6 | int32_t secs = hour * SECS_PER_HOUR + minute * SECS_PER_MIN + second; | |
| 40 | |||
| 41 | // caps just under a day of ms (86.4 million) so int32 holds it exactly | ||
| 42 | 6 | return (((secs + BMT_UTC_OFFSET_S) % SECS_PER_DAY) * MS_PER_SEC) + ms; | |
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Where the first .beats token starts in a string, or -1 when there is none. The token is three | ||
| 47 | * fixed characters, so a plain walk finds it with strncmp, which the firmware already exports. | ||
| 48 | * strstr is not exported, so it would link about 1.4 KB of newlib into every face that references | ||
| 49 | * the date readout. | ||
| 50 | * | ||
| 51 | * @param text The string to search. | ||
| 52 | * @return The offset of the first token, or -1 when there is none. | ||
| 53 | */ | ||
| 54 | 22 | static int token_at(const char *text) | |
| 55 | { | ||
| 56 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 12 times.
|
83 | for (int at = 0; text[at]; at++) |
| 57 | { | ||
| 58 | // only a brace can start the token, so most characters skip the call | ||
| 59 |
4/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 3 times.
|
71 | if (text[at] == BEATS_TOKEN[0] && strncmp(text + at, BEATS_TOKEN, BEATS_TOKEN_LEN) == 0) |
| 60 | { | ||
| 61 | 10 | return at; | |
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | 12 | return -1; | |
| 66 | } | ||
| 67 | |||
| 68 | 4 | bool beats_has_token(const char *format) | |
| 69 | { | ||
| 70 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
|
4 | return format && token_at(format) >= 0; |
| 71 | } | ||
| 72 | |||
| 73 | 10 | void beats_expand_token(char *text, int beats) | |
| 74 | { | ||
| 75 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!text) |
| 76 | { | ||
| 77 | ✗ | return; | |
| 78 | } | ||
| 79 | |||
| 80 | // clamped so the reading is always three digits, which is what lets the swap happen in place | ||
| 81 | 10 | beats = clamp_int(beats, 0, 999); | |
| 82 | |||
| 83 | // written by hand rather than with snprintf, which would want a buffer sized for any int and | ||
| 84 | // then warn about truncating one down to three | ||
| 85 | char digits[BEATS_TOKEN_LEN]; | ||
| 86 | 10 | digits[0] = (char)('0' + (beats / 100)); | |
| 87 | 10 | digits[1] = (char)('0' + (beats / 10) % 10); | |
| 88 | 10 | digits[2] = (char)('0' + (beats % 10)); | |
| 89 | |||
| 90 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 10 times.
|
19 | for (int at = token_at(text); at >= 0; text += at + BEATS_TOKEN_LEN, at = token_at(text)) |
| 91 | { | ||
| 92 | 9 | memcpy(text + at, digits, BEATS_TOKEN_LEN); | |
| 93 | } | ||
| 94 | } | ||
| 95 |