Host C Specs


Directory: src/c/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.9% 31 / 0 / 32
Functions: 100.0% 2 / 0 / 2
Branches: 79.2% 19 / 0 / 24

core/wire/weather_wire.c
Line Branch Exec Source
1 /**
2 * @file weather_wire.c
3 * @brief The forecast strips as the phone packs them, and the readers that unpack them.
4 *
5 * @ingroup lib_core
6 */
7 #include "wire/weather_wire.h"
8
9 #include "io/bytes_le.h"
10
11 // both readers here fill the caller's strip as they go rather than building a copy and handing it
12 // over at the end, which is what the agenda and the watchlist do. the difference is deliberate and
13 // comes down to the shape of the message: a column is fixed width, so one check up top settles the
14 // whole run and nothing after it can fail. the agenda and the watchlist carry a length per field,
15 // so they only learn a message is short partway through filling one, and a copy is what stops a
16 // half filled strip reaching the caller. no such moment exists here, and a copy of each strip both
17 // ways costs more than the two of them are worth
18
19 12 bool weather_hourly_decode(const uint8_t *buf, uint16_t len, WeatherHourly *out)
20 {
21
4/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 11 times.
12 if (!buf || !out || len < 3)
22 {
23 1 return false;
24 }
25
26 11 uint8_t count = buf[0];
27
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 10 times.
11 if (count > WEATHER_FORECAST_COLS)
28 {
29 // the phone's word for how many, pinned to how many there is room for
30 1 count = WEATHER_FORECAST_COLS;
31 }
32
33 // three header bytes then three bytes per column. every read below sits inside this
34
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
11 if (len < (uint16_t)(3 + count * 3))
35 {
36 4 return false;
37 }
38
39 7 out->count = count;
40 7 out->base_hour = buf[1];
41 7 out->step_hours = buf[2];
42
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
21 for (uint8_t i = 0; i < count; i++)
43 {
44 14 const uint8_t *col = buf + 3 + i * 3;
45 14 out->col[i].code = col[0];
46 14 out->col[i].temp = read_i16_le(col + 1);
47 }
48
49 7 return true;
50 }
51
52 7 bool weather_daily_decode(const uint8_t *buf, uint16_t len, WeatherDaily *out)
53 {
54
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
7 if (!buf || !out || len < 2)
55 {
56 ✗ return false;
57 }
58
59 7 uint8_t count = buf[0];
60
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6 times.
7 if (count > WEATHER_FORECAST_COLS)
61 {
62 1 count = WEATHER_FORECAST_COLS;
63 }
64
65 // two header bytes then five bytes per column, fixed width the same way
66
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (len < (uint16_t)(2 + count * 5))
67 {
68 2 return false;
69 }
70
71 5 out->count = count;
72 5 out->base_weekday = buf[1];
73
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 for (uint8_t i = 0; i < count; i++)
74 {
75 13 const uint8_t *col = buf + 2 + i * 5;
76 13 out->col[i].code = col[0];
77 13 out->col[i].temp_max = read_i16_le(col + 1);
78 13 out->col[i].temp_min = read_i16_le(col + 3);
79 }
80
81 5 return true;
82 }
83