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 |